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

Bug 238260

Summary: APT: Can't access annotation field which returns Class
Product: [Eclipse Project] JDT Reporter: James Kingdon <jkingdon>
Component: APTAssignee: Walter Harley <eclipse>
Status: CLOSED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: eclipse
Version: 3.4   
Target Milestone: 3.4.1   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description James Kingdon CLA 2008-06-24 10:55:33 EDT
Build ID: I20080516-1333

Steps To Reproduce:
1. Call WebServiceRef.type() from annotation processor
2. Get exception:
!ENTRY org.eclipse.jdt.apt.core 4 1 2008-06-24 10:37:04.031
!MESSAGE Processor failure during reconcile
!STACK 0
com.sun.mirror.type.MirroredTypeException: Attempt to access Class object for TypeMirror org.example.test.Test
	at org.eclipse.jdt.apt.core.internal.env.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:83)

(full stack in More information)

More information:
Looks like a bug in the following code block in AnnotationInvocationHandler.invoke:

        final String qName = retType.getTypeDeclaration().getQualifiedName();
        // type of annotation member is java.lang.Class
        if( retType.isClass() && JAVA_LANG_CLASS.equals(qName) ){ 
            // need to figure out the class that's being accessed
            final ITypeBinding[] classTypes = _instance.getMemberValueTypeBinding(c_methodName);
            TypeMirror mirrorType = null;
            if( classTypes != null && classTypes.length > 0 ){
                mirrorType = Factory.createTypeMirror(classTypes[0], _instance.getEnvironment() );
            }
            if( mirrorType == null )
                mirrorType = Factory.createErrorClassType(classTypes[0]);
            throw new MirroredTypeException(mirrorType);
        }

Once execution drops into the if( retType.isClass() && JAVA_LANG_CLASS.equals(qName) ){ block, the only way out is by exception. I'm guessing that the throw statement was supposed to be gated by the same if statement that creates the new value for mirrorType in the line above.

The version on apt.core plugin is
org.eclipse.jdt.apt.core_3.3.100.v20080513-1235.jar

The full exception stack is
!ENTRY org.eclipse.jdt.apt.core 4 1 2008-06-24 10:37:04.031
!MESSAGE Processor failure during reconcile
!STACK 0
com.sun.mirror.type.MirroredTypeException: Attempt to access Class object for TypeMirror org.example.test.Test
	at org.eclipse.jdt.apt.core.internal.env.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:83)
	at $Proxy1.type(Unknown Source)
	at com.ibm.ws.ast.wsfp.annotations.processor.internal.WebServiceRefAP.process(WebServiceRefAP.java:153)
	at org.eclipse.jdt.apt.core.internal.APTDispatchRunnable.dispatchToFileBasedProcessor(APTDispatchRunnable.java:628)
	at org.eclipse.jdt.apt.core.internal.APTDispatchRunnable.access$0(APTDispatchRunnable.java:598)
	at org.eclipse.jdt.apt.core.internal.APTDispatchRunnable$ReconcileEnvCallback.run(APTDispatchRunnable.java:77)
	at org.eclipse.jdt.apt.core.internal.env.ReconcileEnv$CallbackRequestor.acceptBinding(ReconcileEnv.java:135)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:759)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:474)
	at org.eclipse.jdt.core.dom.ASTParser.createASTs(ASTParser.java:736)
	at org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv.createASTs(BaseProcessorEnv.java:855)
	at org.eclipse.jdt.apt.core.internal.env.ReconcileEnv.openPipeline(ReconcileEnv.java:108)
	at org.eclipse.jdt.apt.core.internal.env.AbstractCompilationEnv.newReconcileEnv(AbstractCompilationEnv.java:97)
	at org.eclipse.jdt.apt.core.internal.APTDispatchRunnable.reconcile(APTDispatchRunnable.java:211)
	at org.eclipse.jdt.apt.core.internal.APTDispatchRunnable.runAPTDuringReconcile(APTDispatchRunnable.java:159)
	at org.eclipse.jdt.apt.core.internal.AptCompilationParticipant.reconcile(AptCompilationParticipant.java:223)
	at org.eclipse.jdt.internal.core.ReconcileWorkingCopyOperation$1.run(ReconcileWorkingCopyOperation.java:257)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.jdt.internal.core.ReconcileWorkingCopyOperation.notifyParticipants(ReconcileWorkingCopyOperation.java:244)
	at org.eclipse.jdt.internal.core.ReconcileWorkingCopyOperation.executeOperation(ReconcileWorkingCopyOperation.java:94)
	at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:709)
	at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:770)
	at org.eclipse.jdt.internal.core.CompilationUnit.reconcile(CompilationUnit.java:1224)
	at org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile(JavaReconcilingStrategy.java:124)
	at org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.access$0(JavaReconcilingStrategy.java:108)
	at org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy$1.run(JavaReconcilingStrategy.java:89)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:37)
	at org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile(JavaReconcilingStrategy.java:87)
	at org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy.reconcile(JavaReconcilingStrategy.java:149)
	at org.eclipse.jdt.internal.ui.text.CompositeReconcilingStrategy.reconcile(CompositeReconcilingStrategy.java:86)
	at org.eclipse.jdt.internal.ui.text.JavaCompositeReconcilingStrategy.reconcile(JavaCompositeReconcilingStrategy.java:102)
	at org.eclipse.jface.text.reconciler.MonoReconciler.process(MonoReconciler.java:77)
	at org.eclipse.jface.text.reconciler.AbstractReconciler$BackgroundThread.run(AbstractReconciler.java:206)
Comment 1 Walter Harley CLA 2008-06-24 11:15:15 EDT
I agree with this analysis of the bug.  (Sorry about that...)

This should be fixed for 3.4.1.
Comment 2 Walter Harley CLA 2008-07-09 12:42:49 EDT
Now that I look closer I think this is by design.  See the documentation for com.sun.mirror.declaration.Declaration.getAnnotation(), which says:

"Attempting to read a Class object by invoking the relevant method on the returned annotation will result in a MirroredTypeException, from which the corresponding TypeMirror may be extracted."

So this exception is simply the way that a Class-typed member value is returned; you need to catch it in your own code.  Note that even if your processor code is expecting a non-Class-typed return value, APT doesn't know that; if it sees a Class-typed value in the code (even if it is a syntax error) that's what it will report.  For example, in the following code, reading the annotation's member value will cause a MirroredTypeException to be thrown:

@interface Anno { int value(); }
@Anno(String.class) class Foo {};

If there's something I'm missing here, please re-open with more detail.
Comment 3 James Kingdon CLA 2008-07-21 09:57:21 EDT
Sorry for wasting your time - I should have checked the docs.
Comment 4 Walter Harley CLA 2008-07-26 00:54:40 EDT
No need to apologize - the "docs" on this stuff are pathetic, and the behavior is counterintuitive.  It certainly threw me for a loop when I was writing the code.