简体   繁体   中英

Cannot call method which requires java.lang.Class arguments?

I'm trying to convert this ControllerAnnotationHelper into a service, and I'm getting weird issues.

No signature of method AnnotationScannerService.findAnnotatedClosures() is applicable for argument types:
(java.lang.Class, java.lang.Class) values: [class MyController, interface MyAnnotationRequired]

Here's the original method:

private static Map<String, List<Class>> findAnnotatedClosures(
      Class clazz, Class... annotationClasses) {
   def map = [:]
   for (field in clazz.declaredFields) {
      def fieldAnnotations = []
      for (annotationClass in annotationClasses) {
         if (field.isAnnotationPresent(annotationClass)) {
            fieldAnnotations << annotationClass
         }
      }
      if (fieldAnnotations) {
         map[field.name] = fieldAnnotations
      }
   }

   return map
}

and mine:

protected Map<String, List<Class>> findAnnotatedClosures(Class clazz, Class... annotationClasses) {
   def map = [:]
   for (field in clazz.declaredFields) {
      def fieldAnnotations = []
      for (annotationClass in annotationClasses) {
         if (field.isAnnotationPresent(annotationClass)) {
            fieldAnnotations << annotationClass
         }
      }
      if (fieldAnnotations) {
         map[field.name] = fieldAnnotations
      }
   }

   return map
}

With invocation:

public void test_findAnnotatedClosures() {
   Map<String, List<Class>> annotatedClosures =
        annotationScannerService.findAnnotatedClosures(MyController, MyRequiredAnnotation)
}

How can I declare this method such that I can call it with a controller class and the class of various annotation interfaces?

A non-public method in a service doesn't make much sense in general. In particular in Grails it's going to be problematic since by default services are transactional, so the instance you'll be working with will be a proxy.

Only public methods are proxied. Protected methods are valid, but would typically just be used when subclassing and calling within the class or sub/super class.

So it boils down to a Groovy/Spring thing. We're used to Groovy not being strict about access rules, but Grails services are almost purely Spring beans - Grails just lets you write them in Groovy, auto-creates the associated Spring bean, and automatically makes them transactional (unless that's disabled).

Making the method static also works since you're bypassing the proxy and going directly to the real class, and Groovy lets you call it even though it's protected.

Well, this is odd, and I can't explain it, but this invocation works only if the method is declared static and used statically. It cannot be called from an instance of the service.

Keep the method static, and it'll work. If someone else can explain this, I'll toss over the accept and upvote.

Maybe this depends on the groovy version. With groovy 1.7 all generic type info is removed, from 1.8 not. The right method declaration is:

protected Map<String, List<Class<? extends Annotation>>> findAnnotatedClosures(Class<?> clazz, Class<? extends Annotation>... annotationClasses)

because of isAnnotationPresent(Class<? extends Annotation> annotationClass)

Every class is an instance of the class Class<T> (confusing, I know), where the type parameter T is "the type of the class modeled by this Class object." In other words, your class MyController is an object of type Class<MyController> .

And every class has a hidden static field called class . If you want to access the MyController class itself, use the declaration MyController.class . This will return an instance of Class<MyController> , and all the methods and fields available to MyController.class are those available to any Class object. For example, getName() .

All in all, your invocation code should read:

public void test_findAnnotatedClosures() {
    Map<String, List<Class>> annotatedClosures =
        annotationScannerService.findAnnotatedClosures(MyController.class,
            MyRequiredAnnotation.class)
}

PS: @Stefan Kendall is correct. If the method test_findAnnotatedClosures() is not dependent on any instances, it is best— though not required —to declare it static and reference it from a static context. But that is beside the point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM