Craig, thanks for bringing up these issues.
I've been talking to the Java SE team to see if they can provide more
support for these sorts of things in the core reflection package, but
they've been hesitant to do so. Instead, they're proposing to create
a version of the javax.lang.model classes that can be backed by core
reflection. This would potentially give us a base that we could more
easily extend to add functionality important for Java EE.
Lacking that (which is certainly not committed at this point and wouldn't
help Java EE 7 in any event), another option is to add some utility or
helper methods to a Java EE spec so that we can make it easier for
everyone to handle these issues in a consistent way. I think CDI would
be a good place to add such methods, but that would be a discussion for
the CDI expert group. Perhaps one of our CDI experts here can indicate
whether this would be a worthwhile discussion to take to the CDI expert
group, or suggest a more appropriate way to address these issues.
Craig Ringer wrote on 05/02/2012 06:23 AM:
> Hi to the Java EE 7 spec leads and the -users list.
>
> I'm writing in about the first of a few issues I'm interested in seeing
> discussed and considered for Java EE 7. This first one may be a Java 8 issue as
> much as a Java EE 7 one, except that Java EE's heavy use of annotations
> (especially for CDI) will make this issue a particular pain point in Java EE.
> These issues combine to create a potential performance problem as well as a
> potential source of bugs and unnecessarily complicated code.
>
> The two issues I'm concerned about at the moment, both of which require slow and
> inefficient workarounds, are that:
>
> - Method. getAnnotations() just calls Method.getDeclaredAnnotations() rather
> than looking up the inheritance tree; and
> - Class.getMethod(...) only returns methods that are an exact match, ignoring
> polymorphism
>
> How does this matter in the real world, and how does it affect Java EE? Well,
> presuming there's a real-world effect at all, the effect on Java EE would be
> pretty clear given the role of interceptors, CDI, etc in Java EE and how reliant
> they are on interceptors. Is there a real-world problem here, though?
>
> Yes, there is. Consider this simple (if somewhat contrived) example: An
> annotation "@Traced", with an enabled=[true|false] flag and a log level
> parameter. An interceptor traps every invocation of a method annotated @Traced
> or any method of a class annotated @Traced, times it, and logs the params,
> instance hashcode, etc. The interceptor wants to allow a @Traced(enabled=false)
> annotation on a method to take precedence over @Traced(enabled=true) on a class
> at the same level. To do that, the interceptor will call
> Method.getAnnotation(Traced.class) on the method before
> Class.getAnnotation(Traced.class) on the class, using whichever is non-null
> first. Obvious, simple, and logical, right?
>
> Fine, so far as it goes, but now let's introduce inheritance.
>
> @Traced(enabled=true)
> public class SomeBase {
>
> @Traced(enabled=false)
> public void frequentlyCalledSmallMethod() {
> }
>
> public void someOtherMethod() {
> }
>
> }
>
> public class SomeSubclass extends SomeBase {
> // EMPTY CLASS
> }
>
>
> If we inject `SomeBase' and call its methods, everything works.
> someOtherMethod() gets traced, frequentlyCalledSmallMethod() doesn't because the
> Traced(enabled=false) is seen.
>
> If we inject SomeSubclass, which logically should behave identically as it is an
> empty subclass, we find that suddenly frequentlyCalledSmallMethod() is getting
> traced, because Method.getAnnotation(...) doesn't look up the inheritance tree,
> even though Class.getAnnotation() does.
>
> To work around this it's necessary to write one's own recursive search up the
> tree using Method.getDeclaredAnnotation(), Class.getDeclaredAnnotation(), and
> Class.getSuperclass(). At which point we run into the second API defect.
>
> We have no way to ask the reflection API "which method did this Method
> override?". We can ask "Which method in this class has the exact same parameters
> and name", but that won't work where permitted polymorphisms appear, so we have
> to hand write a method override resolver too!
>
>
> Both these issues make code that works on annotations, especially in
> interceptors and in annotation processors, way harder than it needs to be and
> way slower. A fix to the API introduced in Java SE 5 can't be retroactively
> introduced, but new methods that behave more sanely certainly can be, and in my
> view need to be. Even if they can't be added in Java EE 7, thought needs to be
> given to the details of how inheritance interacts with (eg) interceptors in Java
> EE, and more thought to how future improvements in the reflection API can be used.
>
> See these two posts by Marco of Encodo Systems for a write-up on the two
> specific reflection issues covered here:
>
> http://encodo.com/en/blogs.php?entry_id=10
> http://encodo.com/en/blogs.php?entry_id=12
>
> Oh, and for the record, I know the @Traced annotation is largely "solving" a
> problem already well solved many different ways. I just needed a simple and
> fairly self-contained example.
>
> --
> Craig Ringer
>
> POST Newspapers 276 Onslow Rd, Shenton Park Ph: 08 9381 3088 Fax: 08 9388 2258
> ABN: 50 008 917 717 http://www.postnewspapers.com.au/