Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 350378

Summary: class generated by apt is compiled, but cannot be resolved
Product: [Eclipse Project] JDT Reporter: jnizet
Component: APTAssignee: Generic inbox for the JDT-APT component <jdt-apt-inbox>
Status: CLOSED DUPLICATE QA Contact:
Severity: normal    
Priority: P3 CC: bsi.msa, eclipse, jimisola, jnizet, Lars.Vogel, markus.klink, martin.maier.moessner, pflammertsma, py.ricau
Version: 3.7   
Target Milestone: ---   
Hardware: PC   
OS: Windows 7   
Whiteboard:

Description jnizet CLA 2011-06-26 09:07:43 EDT
Build Identifier: 20110615-0604

I'm using the Hibernate Metamodel Generator (1.1.1 Final) to generate my JPA2 metamodel (see http://www.hibernate.org/subprojects/jpamodelgen.html).

All the Java source files for the metamodel are generated and compiled correctly, but one class of the project doesn't compile because a metamodel class is not resolved :
"The import fr.free.jnizet.azurfac.domain.Facture_ cannot be resolved"

If I edit and save (add a space character somewhere in the source file for example) the class which doesn't compile, everything compiles correctly.

If I change the import from 
        import fr.free.jnizet.azurfac.domain.Facture_;
to 
        import fr.free.jnizet.azurfac.domain.*;
and clean the project, everything compiles correctly.

Note that other classes referencing other metamodel-generated classes compile fine, although they use single-class imports.

It happens on Indigo, but also happened in Helios.

Reproducible: Always
Comment 1 Walter Harley CLA 2011-06-26 21:29:58 EDT
I'm not very familiar with the specifics of the Hibernate annotation processor. If I understand you correctly, Facture_ is one of the generated classes, and you've got an ordinary (not generated) class that references the generated class; and you're saying that the Facture_ class is generated correctly, but the ordinary class isn't able to resolve the type until you edit it and recompile.

I didn't quite understand what you meant about the * import.  Are you saying that if the ordinary class imports ...domain.* instead of ...domain.Facture_, then everything works properly, i.e., all classes are generated and everything compiles?
Comment 2 jnizet CLA 2011-06-27 03:27:20 EDT
(In reply to comment #1)

You got it absolutely right : Facture_ is one of the generated classes. Both the source file (Facture_.java) and the class file (Facture_.class) are generated correctly, but the ordinary class which references the generated Facture_ class can't be compiled, because the Eclipse compiler doesn't "see" the generated Facture_ class during a full clean/automatic build cycle. If I edit my ordinary class and save it, the automatic compilation is triggered and the ordinary class compiles again. But each time I clean the project, I have to repeat this operation to make the ordinary class compile.

And I noticed during my experimentations that replacing the single class import in my ordinary class (import ...domain.Facture_) by a package import (import ...domain.*) makes the problem disappear (but I don't like package imports, and this is just a workaround).
Comment 3 Markus Klink CLA 2011-11-02 09:55:13 EDT
(In reply to comment #2)
 @jnizet:
Thanks for the workaround. Works for our project too.

To summarize:
We use some hand written Annotationprocessors and the JPA metamodel generator to create some classes. Upon a new fresh build there is always one class (always the same) which cannot be referenced by the using class.

Rewriting the import statements helped as suggested. The other workaround is to select each class and just do a <space> and save.

We also have an ant build using the same apt configuration which never exhibits the problem. This must be something within eclipse. Our build id:
Build id: 20100218-1602
Comment 4 Markus Klink CLA 2012-02-14 08:37:26 EST
Just verified again - the bug still exists with Juno build id 20120202-1513. Now we are at a level where the proposed work arounds do not work anymore. Tried changing the order of annotation processors in .factoryPath but to no avail. Currently all files which are not resolved have to be touched again (or rather their non_ version in order to regenerate the _.class version, which will eliminate the reference error.
Comment 5 Pierre-Yves Ricau CLA 2012-07-07 04:08:05 EDT
Hi,

I'm the lead developer of AndroidAnnotations, an annotation processor for Android apps. We've seen that bug occurring quite a lot, but haven't been lucky enough to find a way to understand what configuration triggers it.

Here is what I know (I'll try to describe as much as I can) :


As with Hibernate Metamodel Generator, we generate classes based on annotations. If my class is named "com.test.MyClass", we generate a subclass called "com.test.MyClass_".

We sometimes reference the generated classes from the original files. For example, "com.test.other.MyOtherClass" has a "com.test.MyClass_" field. Notice the package difference, that's what causes the problems.

Incremental compilation perfectly works. Ant and Maven command line builds also works, although they initially issue some warnings / errors but still compile the classes with a second round.

Now, problems occur in those two cases :

* After doing a Project > Clean
* When Opening Eclipse
* When closing / opening the project

Problem :

All classes that reference generated classes see a "com.test.MyClass_ cannot be resolved" compile error. This error appears on the import declaration, and on the class usage.

Hacks to solve the problem :

* Use fully qualified names to reference generated classes in the code.

=> FQN = no import needed = no problem

* Put all the classes (generated and non generated) in the same package

=> Same package = no import needed = no problem

=> These two hacks, although not convenient, clearly show that the problem lies in the package declaration.

* In some cases, changing the generated output folder name seemed to trigger a build that also solved all the compile issue. But that's not the case any more. I guess there's some voodoo here.

* Touching (ie triggering incremental compilation) on impacted files (the ones that have the compile errors) solves the problems.. until next "Project > Clean".

This error has been reported to occurs at least in Eclipse Indigo and Juno, and at least on Mac OS platforms.

Is this bug reproducible ? Yes, but not fully. When you start experiencing it in a project, then it will always happen. But this problem does not occur on all projects. So each time I tried creating a sample project to reproduce it, I wasn't able to do so.
Comment 6 Pierre-Yves Ricau CLA 2012-07-07 05:28:44 EDT
Hi, it's me again.

This thing kept bothering me, so I decided it was time to take a problem that had the error an slim it down until I could reproduce it systematically.

I was able to reproduce it on a really simple Java project. AndroidAnnotations is supposed to work with Android projects, but by creating the right files it may work on any Java project. So you won't need the Android SDK to reproduce this. It also shows that this is really an Eclipse APT bug, not Android Plugin related.

Here is the Java project that reproduces the issue: https://github.com/pyricau/BugAptEclipse

The issue occurs in this class: https://github.com/pyricau/BugAptEclipse/blob/master/src/com/bug/apt/SomeClass.java

After doing a "Project > Clean"

At line 3, you'll get "The import com.bug.apt.other.SomeBean_ cannot be resolved".

At line 28, you'll get "SomeBean_ cannot be resolved to a type"

Touching the file (adding a space, then save) removes the compilation errors.

As you'll notice, this only occurs when there's another annotation in the class (not necessarily used by APT), and this annotation holds a reference to a constant value. In this case, it's an int. It's also reproduced with a String. It's not reproduced in the annotation points to a class.

I'm not sure what the annotation has to do with this bug.

Hope this help. Please do not hesitate to ask for further details.
Comment 7 Pierre-Yves Ricau CLA 2012-08-23 05:36:35 EDT
Still there in Juno, reproduced on :

Version: Juno Release
Build id: 20120614-1722
Comment 8 Martin Maier-Moessner CLA 2012-08-23 05:41:22 EDT
(In reply to comment #7)
> Still there in Juno, reproduced on :
> 
> Version: Juno Release
> Build id: 20120614-1722

I can confirm. Reproduced in Juno (20120614-1722).

In my case, I have about 200 references from main classes to generated classes. Most of them work, is always the same 15 of them have compile errors.
Comment 9 Pierre-Yves Ricau CLA 2012-08-23 10:06:13 EDT
Ok so I'm trying to isolate this problem with a good old debugger, although I know nothing about Eclipse source :) .

The problem appears because this method :

org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.findImport(char[][], int)

cannot find a ReferenceBinding for the given compoundName (which is an import of a generated type)

This only happens when the class having the imports also somewhere holds an annotation that references a constant located in another class. Weird.
Comment 10 Pierre-Yves Ricau CLA 2012-08-23 11:13:58 EDT
Going forward :

I found out that the problem appeared when org.eclipse.jdt.internal.compiler.lookup.PackageBinding.addNotFoundType(char[] simpleName) got called with the missing type as a param. In the sample project provided above, simpleName is [S, o, m, e, B, e, a, n, _] .

So I put a conditional breakpoint there, that stops when this method is called with such param.

I ended up with the following stack :


PackageBinding.addNotFoundType(char[]) line: 50	
PackageBinding.getTypeOrPackage(char[]) line: 192	
CompilationUnitScope.findImport(char[][], int) line: 487	
CompilationUnitScope.findSingleImport(char[][], int, boolean) line: 541	
CompilationUnitScope.faultInImports() line: 369	
MethodScope(Scope).getBinding(char[], int, InvocationSite, boolean) line: 1795	
MethodScope(BlockScope).getBinding(char[][], int, InvocationSite, boolean) line: 407	
QualifiedNameReference.resolveType(BlockScope) line: 930	
MemberValuePair.resolveTypeExpecting(BlockScope, TypeBinding) line: 84	
SingleMemberAnnotation(Annotation).resolveType(BlockScope) line: 300	
ASTNode.resolveAnnotations(BlockScope, Annotation[], Binding) line: 669	
FieldBinding.getAnnotationTagBits() line: 268	
SourceTypeBinding.resolveTypeFor(FieldBinding) line: 1351	
AnnotationDiscoveryVisitor.visit(FieldDeclaration, MethodScope) line: 113	
FieldDeclaration.traverse(ASTVisitor, MethodScope) line: 278	
TypeDeclaration.traverse(ASTVisitor, CompilationUnitScope) line: 1306	
CompilationUnitDeclaration.traverse(ASTVisitor, CompilationUnitScope) line: 690	
RoundEnvImpl.<init>(CompilationUnitDeclaration[], ReferenceBinding[], boolean, BaseProcessingEnvImpl) line: 58	
IdeAnnotationProcessorManager(BaseAnnotationProcessorManager).processAnnotations(CompilationUnitDeclaration[], ReferenceBinding[], boolean) line: 148	
IdeAnnotationProcessorManager.processAnnotations(CompilationUnitDeclaration[], ReferenceBinding[], boolean) line: 134	
Compiler.processAnnotations() line: 813	
Compiler.compile(ICompilationUnit[]) line: 432	
BatchImageBuilder(AbstractImageBuilder).compile(SourceFile[], SourceFile[], boolean) line: 364	
BatchImageBuilder.compile(SourceFile[], SourceFile[], boolean) line: 178	
BatchImageBuilder(AbstractImageBuilder).compile(SourceFile[]) line: 301	
BatchImageBuilder.build() line: 60	
JavaBuilder.buildAll() line: 254	
JavaBuilder.build(int, Map, IProgressMonitor) line: 173	
BuildManager$2.run() line: 728	
SafeRunner.run(ISafeRunnable) line: 42	
BuildManager.basicBuild(int, IncrementalProjectBuilder, Map<String,String>, MultiStatus, IProgressMonitor) line: 199	
BuildManager.basicBuild(IBuildConfiguration, int, IBuildContext, ICommand[], MultiStatus, IProgressMonitor) line: 239	
BuildManager$1.run() line: 292	
SafeRunner.run(ISafeRunnable) line: 42	
BuildManager.basicBuild(IBuildConfiguration, int, IBuildContext, MultiStatus, IProgressMonitor) line: 295	
BuildManager.basicBuildLoop(IBuildConfiguration[], IBuildConfiguration[], int, MultiStatus, IProgressMonitor) line: 351	
BuildManager.build(IBuildConfiguration[], IBuildConfiguration[], int, IProgressMonitor) line: 374	
AutoBuildJob.doBuild(IProgressMonitor) line: 143	
AutoBuildJob.run(IProgressMonitor) line: 241	
Worker.run() line: 54	


I don't pretend to be understand everything that happens here, but basically, this all starts because @SomeAnnotation is processed, and it references a constants value located in another class, so it looks like imports need to be resolved at that point, so all imports are processed... but I guess it's too early and the import of the generated class cannot be resolved, and therefore we put a LookupEnvironment.TheNotFoundType in the package binding for this import.

I'll continue exploring, and report progress.
Comment 11 Pierre-Yves Ricau CLA 2012-08-23 12:11:00 EDT
I simplified the use case to the maximum, now using annotations and constants from the JDK :

https://github.com/pyricau/BugAptEclipse/blob/master/src/com/bug/apt/SomeClass.java
Comment 12 Pierre-Yves Ricau CLA 2012-08-24 05:09:04 EDT
Move on to a new bug, Juno related, since this one cannot be updated : https://bugs.eclipse.org/bugs/show_bug.cgi?id=387956
Comment 13 Lars Vogel CLA 2017-03-22 06:45:39 EDT
I think this one has been solved with Bug 387956. Please reopen if that is incorrect.

*** This bug has been marked as a duplicate of bug 387956 ***