Bug 270754 - annotation processing for inherited annotations only if base and subclass are compiled at same time
Summary: annotation processing for inherited annotations only if base and subclass are...
Status: REOPENED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: APT (show other bugs)
Version: 3.4.2   Edit
Hardware: PC Windows XP
: P3 normal with 2 votes (vote)
Target Milestone: ---   Edit
Assignee: Generic inbox for the JDT-APT component CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords: helpwanted
: 336566 (view as bug list)
Depends on:
Blocks:
 
Reported: 2009-04-01 08:12 EDT by Stefan Loidl CLA
Modified: 2022-10-18 02:37 EDT (History)
9 users (show)

See Also:


Attachments
Passing test for CompilationParticipant (3.72 KB, text/plain)
2009-04-27 21:29 EDT, Walter Harley CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Loidl CLA 2009-04-01 08:12:10 EDT
Build ID: M20090211-1700

Steps To Reproduce:
1. create annotation with @Inherited  
2. create annotation processor for this annotation that checks something and may write an error
3. use annotation and processor like this:
   a. create BaseClass and apply the annotation
   b. create SubClass inheriting BaseClass


More information:
Problem: the processor seems to be called (for the SubClass!) only if a clean + build is done. For the BaseClass the processor is called on every build.

We are using the Java 6 style annotation processing. Batch Mode is NOT used. 

Perhaps some code is usefull:

@Inherited
@Documented
@Retention( RetentionPolicy.SOURCE )
@Target( ElementType.TYPE )
public @interface NameRestriction {
    String value();
}



@SupportedAnnotationTypes( "entwickler.tools.annotation.NameRestriction" )
@SupportedSourceVersion( SourceVersion.RELEASE_6 )
public class NameRestrictionProcessor extends AbstractProcessor {   
    @Override
    public boolean process( final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv ) {
        JOptionPane.showMessageDialog( null, "Hi" );
        return false;
        
    }
}




@NameRestriction(".*Class")
public class BaseClass {}



public class SubClazz extends BaseClass{}
Comment 1 Walter Harley CLA 2009-04-01 11:04:06 EDT
I suspect this is a dup of bug 269934, but I will test and confirm.
Comment 2 Walter Harley CLA 2009-04-01 13:10:33 EDT
Sorry, just waking up here, this has nothing whatsoever to do with 269934.

What you're saying is that if class Sub is a subclass of class Base, and Base is annotated with an annotation that is @Inherited, then you would expect Sub to be processed just as if it itself were annotated.  In other words, you expect the "root elements" set to contain subclasses of annotated elements, as well as the annotated elements themselves.

See also http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6250150 for discussion of a related bug in Sun's apt tool.  This report seems to confirm the expectation that @Inherited should affect the set of units to be processed (of course, javac does not support incremental compilation, but at least this is a comment on the intention of the spec).

The intersection of @Inherited and incremental compilation is a big hole in the JSR269 spec and pretty rough terrain, and I think you are running into a few different problems.

Problem #1 is that your annotation has @Retention( RetentionPolicy.SOURCE ).  It's not really clear what @Inherited means for a SOURCE annotation - you are making some unjustified assumptions there about the compiler internals, i.e., the compiler is allowed to first compile Base and then compile Sub against Base.class rather than Base.java, and in that case the annotation is lost.  So I would strongly suggest that if you want to use @Inherited it should only be for annotations with CLASS or higher retention.  I don't see any explicit discussion of that in the Jave Language Spec, but it seems prudent to me.  

The second problem is that the compiler does not consider annotations to be "structural" when it decides what units to include in an incremental compilation.  That is, changing the annotation on Base does not cause Sub to be recompiled - by contrast, changing the visibility of a method in Base would cause Sub to be recompiled.  This is bug 149768, which is fixed in Eclipse 3.5M5 and later.  If you use 3.5M5 or later you'll notice that changing the ".*Class" string in Base will cause Sub to be recompiled, just as if you'd added a method to Base.

The third problem, though, is still present in 3.5M6: changing Sub and recompiling does not trigger annotation processing on Sub.  That is, the compiler is deciding that Sub does not have annotations so it doesn't need to be processed, and it is ignoring the presence of @Inherited on the base class.  I think that is essentially the same as the Sun bug mentioned above and although it is a grey area in the spec I think we should address it.
Comment 3 Stefan Loidl CLA 2009-04-02 02:00:53 EDT
Yes- you hit the mark. Thank you for the extensive description.

Regrettably changing the retention to CLASS is not an option in this case- as we do not want to deploy the annotations. (They are meant to be used for quality ensurance only)

I've not read JSR269. However I thought if inheritance works on Clean + Compile it also should work on incremental compile. But I can clearly see your point that a base class may exist in binary form only (without SOURCE annotations)...

Hopefully any solution for this problem can be found.
Comment 4 Walter Harley CLA 2009-04-27 21:29:35 EDT
Created attachment 133471 [details]
Passing test for CompilationParticipant

I've added a test to the APT test code (pluggable.tests.BuilderTest) that demonstrates the problem when Sub is edited.

However, the attached patch to JDT test code also demonstrates that JDT appears to be calling the compilation participant with the expected files, i.e., when Sub is edited it does get reprocessed.  So the bug may be in the implementation of the APT compilation participant.
Comment 5 Walter Harley CLA 2009-04-27 22:01:21 EDT
Actually we get as far as RoundDispatcher.round(), so the problem has nothing to do with JDT core.  The problem is simply that at this point there are no unclaimed annotations, so we decide not to process anything.

Presumably we need to treat inherited annotations as if they were present in determining the set of unclaimed annotations, but that feels like it will be a little tricky to do without introducing some side effects.  We probably need to think a bit about exactly what the distinction should be between classes that inherit annotations versus classes that actually are annotated.  The JSR269 spec is quite unclear on this topic but it does call out some differences.
Comment 6 Walter Harley CLA 2009-04-28 01:17:52 EDT
I don't know whether the problem also exists for Java 5 processors but that is a lower priority.  For JSR269 processors, we collect annotations in two places: from binary types passed in as command-line .class files in RoundEnvImpl.collectAnnotations(), and from ASTs in the AnnotationDiscoveryVisitor.  In both of those places, we would need to also search the superclass hierarchy of each class being inspected, to see if the superclass is annotated with an inherited annotation.  (Note that annotation inheritance only applies to class annotations, and only to class inheritance, not interface implementation.)

One difficulty is that we need to be able to distinguish between a class that actually contains an annotation versus one that inherits an annotation, in order to correctly implement Element.getAnnotationMirrors().

Interface implementations that might be affected include:
ElementsImpl.getAllAnnotationMirrors() - should return inherited annos
ElementImpl.getAnnotationMirrors() - should *not* return inherited annos
ElementImpl.getAnnotation() - should return inherited anno
RoundEnvImpl.getElementsAnnotatedWith() - should return inherited annos

Internal methods to check:
RoundEnvImpl.getRootAnnotations()
Comment 7 Karl Koscher CLA 2010-07-21 15:43:49 EDT
I've found that this bug's description is slightly inaccurate. If you do a clean build and inherit from a class on your classpath, inherited annotations still do not get processed. I think a more accurate description of the problem is that both the base class and the subclass need to be compiled at the same time for inherited annotations to be processed.
Comment 8 Walter Harley CLA 2010-07-21 16:08:30 EDT
I agree. Changing the title accordingly.
Comment 9 Walter Harley CLA 2011-02-23 02:40:30 EST
*** Bug 336566 has been marked as a duplicate of this bug. ***
Comment 10 Gauthier JACQUES CLA 2013-09-04 07:48:08 EDT
Hi,

Do you have any plan to fix this bug sooner or later ?

Thanks, regards,

Gauthier
Comment 11 Dani Megert CLA 2013-09-04 08:44:37 EDT
(In reply to Gauthier JACQUES from comment #10)
> Hi,
> 
> Do you have any plan to fix this bug sooner or later ?
> 
> Thanks, regards,
> 
> Gauthier

No one is working on this.
Comment 12 Eclipse Genie CLA 2018-10-27 05:59:38 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 13 Marián Oravec CLA 2020-03-23 10:38:24 EDT
Problem still occurs.

If BaseClass (located in dependent JAR or Eclipse workspace) is annotated with some (Inherited) annotation, annotation processor is not called for SubClass in Eclipse.

When using javac (mvn clean install) everything works.

It would be nice if this could be fixed.
Comment 14 Till Brychcy CLA 2020-03-23 12:11:35 EDT
reopening
Comment 15 Eclipse Genie CLA 2022-10-18 02:37:11 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.