Bug 386356 - Type mismatch error with annotations and generics
Summary: Type mismatch error with annotations and generics
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.2   Edit
Hardware: PC Windows 7
: P3 blocker with 1 vote (vote)
Target Milestone: 3.8.1   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL: https://svn.kuali.org/repos/rice/tags...
Whiteboard: To be verified for 4.3 M2
Keywords:
: 388948 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-07-31 17:16 EDT by Travis Schneeberger CLA
Modified: 2012-09-07 04:03 EDT (History)
8 users (show)

See Also:
srikanth_sankaran: review+


Attachments
Source demonstrating problem (12.00 KB, application/x-tar)
2012-08-08 20:25 EDT, David Hosier CLA
stephan.herrmann: iplog+
Details
fix under test (3.52 KB, patch)
2012-08-14 07:50 EDT, Stephan Herrmann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Travis Schneeberger CLA 2012-07-31 17:16:40 EDT
We have the following class which is a jaxb adapter:

public class AttributeSetAdapter extends XmlAdapter<StringMapEntry[], AttributeSet> { 
    @Override public StringMapEntry[] marshal(AttributeSet attributeSet) throws Exception {...snip...} 
    @Override public AttributeSet unmarshal(StringMapEntry[] entryArray) throws Exception { ...snip...} 
} 

The XmlAdapter class has the following signature: 

public abstract class XmlAdapter<ValueType,BoundType> { 
    protected XmlAdapter() {} 
    public abstract BoundType unmarshal(ValueType v) throws Exception; 
    public abstract ValueType marshal(BoundType v) throws Exception; 
} 

We refer to the AttributeSetAdapter.class token in an annotation in an interface method like the following:

boolean hasPermission(
  @WebParam(name = "principalId") String principalId,
  @WebParam(name = "namespaceCode") String namespaceCode,
  @WebParam(name = "permissionName") String permissionName,
  @WebParam(name = "permissionDetails") @XmlJavaTypeAdapter(value = AttributeSetAdapter.class) AttributeSet permissionDetails); 


The @ XmlJavaTypeAdapter annotation has the following signature:

@Retention(RUNTIME) @Target({PACKAGE,FIELD,METHOD,TYPE,PARAMETER})         
public @interface XmlJavaTypeAdapter { 
    Class<? extends XmlAdapter> value(); 
    Class type() default DEFAULT.class; 
    static final class DEFAULT {} 
} 


eclipse gives the following error:

Description Resource Path Location Type 
Type mismatch: cannot convert from Class<AttributeSetAdapter> to Class<? extends XmlAdapter> IdentityManagementService.java /kfs-rice-1.0.3.1/api/src/main/java/org/kuali/rice/kim/service line 203 Java Problem 

I'm using eclipse 4.2 Juno EE edition 64 bit.  I've tried compiling the project using java 1.6 & 1.7 compatibility.  This project compiles fine using older versions of eclipse and on the command line via maven.  I've tried all kinds of tweaks to the source code and different compiler settings.  Sometimes the error goes away but as soon as I do a clean the errors come back.


This projects is available @ https://svn.kuali.org/repos/rice/tags/rice-1.0.3.1/

If you need any other information or test cases or anything else I'll gladly help out. 

Thanks a lot!
Comment 1 Srikanth Sankaran CLA 2012-08-01 03:42:40 EDT
Tentatively target 3.8.1. May need resetting after analysis.
Comment 2 wasabi wasabi CLA 2012-08-06 04:51:28 EDT
A temporary workaround is removing the generic parameters from your xml adapter, so that it looks like this:

public class AttributeSetAdapter extends XmlAdapter { 
    @Override public Object marshal(Object attributeSet) throws Exception {...snip with casts...} 
    @Override public Objectt unmarshal(Object entryArray) throws Exception { ...snip with casts...} 
}
Comment 3 Srikanth Sankaran CLA 2012-08-06 06:16:34 EDT
(In reply to comment #0)

> This projects is available @
> https://svn.kuali.org/repos/rice/tags/rice-1.0.3.1/
> 
> If you need any other information or test cases or anything else I'll gladly
> help out. 

Hello Travis, could you attach a self contained minimal test case please ?
Also could you check the behavior against JDK7 ?
Comment 4 Srikanth Sankaran CLA 2012-08-08 03:37:49 EDT
Sorry, I am unable to observe the problem using the scenario described in
comment#0. Please attach a small & minimal test case. Also verify if javac7
compiles the program fine.
Comment 5 Srikanth Sankaran CLA 2012-08-08 03:40:56 EDT
Will reassess criticality once we have a test case and we are able to
ascertain if it is a real problem and that there are no workarounds.
Comment 6 David Hosier CLA 2012-08-08 20:25:17 EDT
Created attachment 219697 [details]
Source demonstrating problem

This is a maven project that demonstrates correct compilation via the command line, but failure to compile the package-info.java class that includes reference to an XmlAdapter class as described by this bug.
Comment 7 David Hosier CLA 2012-08-08 20:26:24 EDT
Also note that if you modify the package-info class and save it, it will compile fine. However, if you then clean the project, it will go back to having errors.
Comment 8 Srikanth Sankaran CLA 2012-08-09 01:53:01 EDT
Thanks for the test case - This seems to be related to the order
in which package info gets processed and the behavior change seems
to have happened at M4. With M3 a clean + build passes while with
M4 clean + build reports an error.

With the incremental build of package-info, the problem goes away.
I wonder (admittedly with little evidence) if this is due to
changes made for null annotation support that changed the order in
which some resolution happens. 

Stephan, do you want to take a look ? We should target this for 3.8.1
though I am fine if this slips RC1 and makes it to RC2 and to M2 on the
4.3 train. 

Feel free to assign it to yourself if you want to take a shot at it.
Comment 9 Srikanth Sankaran CLA 2012-08-09 02:00:28 EDT
Smaller test case: though we should verify also against the attachment
in comment#6: 

X.java:

package p;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public abstract class X extends XmlAdapter<String,X> {
}

package-info.java:

@XmlJavaTypeAdapters({ @XmlJavaTypeAdapter(value = X.class, type = X.class) })
package p;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;   
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
Comment 10 Stephan Herrmann CLA 2012-08-14 05:06:47 EDT
Sorry for the delay, I'm looking into this right now.
Comment 11 Stephan Herrmann CLA 2012-08-14 05:49:59 EDT
During debugging I'm looking at this stack fragment, which says it all:

MemberValuePair.resolveTypeExpecting(BlockScope, TypeBinding) line: 115	
NormalAnnotation(Annotation).resolveType(BlockScope) line: 321	
ArrayInitializer.resolveTypeExpecting(BlockScope, TypeBinding) line: 167	
MemberValuePair.resolveTypeExpecting(BlockScope, TypeBinding) line: 81	
SingleMemberAnnotation(Annotation).resolveType(BlockScope) line: 321	
ASTNode.resolveAnnotations(BlockScope, Annotation[], Binding) line: 677	
SourceTypeBinding.getAnnotationTagBits() line: 789	
SourceTypeBinding.initializeDeprecatedAnnotationTagBits() line: 1104	
PackageBinding.isViewedAsDeprecated() line: 227	
SourceTypeBinding(ReferenceBinding).isViewedAsDeprecated() line: 1324	
SingleTypeReference(ASTNode).isTypeUseDeprecated(TypeBinding, Scope) line: 512	
SingleTypeReference(TypeReference).internalResolveType(Scope) line: 153	
SingleTypeReference(TypeReference).resolveType(ClassScope) line: 208	
SingleTypeReference(TypeReference).resolveTypeArgument(ClassScope, ReferenceBinding, int) line: 226	
ParameterizedSingleTypeReference.internalResolveLeafType(Scope, ReferenceBinding, boolean) line: 191	
ParameterizedSingleTypeReference.internalResolveType(Scope, ReferenceBinding, boolean) line: 110	
ParameterizedSingleTypeReference.resolveType(ClassScope) line: 296	
ParameterizedSingleTypeReference(TypeReference).resolveSuperType(ClassScope) line: 186	
ClassScope.findSupertype(TypeReference) line: 1229	
ClassScope.connectSuperclass() line: 895	

We have a cyclic dependency:
- we want to connect X to its superclass XmlAdapter<String,X>
- after resolving the super type, we need to check whether it is deprecated
- to check whether XmlAdapter<String,X> is deprecated we need to check the same for X
- to check whether p.X is deprecated we need to check whether package p is deprecated
- for this we need to resolve annotations in p/package-info.java
- there we find @XmlJavaTypeAdapters({@XmlJavaTypeAdapter(value = X.class,type = X.class)})
- during resolving of the above we need to type check the MemberValuePair "value = X.class"
  - required type is "Class<? extends XmlAdapter#RAW>"
  - provided type is "Class<p.X>"
  - to show compatibility we need the superclass of p.X

Each of the above steps makes sense and the sum gives a cyclic contention.

I see two possible ways out:
(1) make any of the above steps more lazy, e.g., check if resolveAnnotations() could avoid resolving MemberValuePairs
(2) entirely postpone checking of deprecation to a later phase.

Before I dive into either strategy, does anyone have a quick guess which of the options (1) - (3) :) is most likely to succeed?
Comment 12 Srikanth Sankaran CLA 2012-08-14 06:00:10 EDT
(In reply to comment #11)

> Each of the above steps makes sense and the sum gives a cyclic contention.

So why does this happen only since 3.8 M4 ?
Comment 13 Srikanth Sankaran CLA 2012-08-14 06:00:10 EDT
(In reply to comment #11)

> Each of the above steps makes sense and the sum gives a cyclic contention.

So why does this happen only since 3.8 M4 ?
Comment 14 Stephan Herrmann CLA 2012-08-14 06:14:49 EDT
(In reply to comment #13)
> (In reply to comment #11)
> 
> > Each of the above steps makes sense and the sum gives a cyclic contention.
> 
> So why does this happen only since 3.8 M4 ?

For null annotation support one constituent of the above chain was added, the call to
  SourceTypeBinding.getAnnotationTagBits()
from
  SourceTypeBinding.initializeDeprecatedAnnotationTagBits() line: 1104	

I'm currently digging out the exact step when this was added, in order to recover the rationale.
I seem to remember, that before this addition, @Deprecated in package-info.java wasn't even working as specified. This would have been discovered because the same applied to @NonNullByDefault in package-info.java. - Re-checking...
Comment 15 Stephan Herrmann CLA 2012-08-14 06:56:47 EDT
My archaeologist tells me:
The two lines in question were added in Feb 2011. At that time I reported (bug 186342 comment 98):

"When playing with new quickfixes I noticed that two intended features
are not too well supported by the existing infrastructure in JDT/Core:

1. Defining per-package defaults using annotations in package-info.java.
2. [...]

Both features work just fine during full builds but may break, e.g., when
Java model and dom are involved, too."

At a quick check I couldn't find a JDT/Core test that breaks when I remove the lines in question, and, yes, this removal would fix the current bug.

However, since I added these for the sake of quick fixes, I should also check with the tests for quick fixes for null annotations. Unfortunately, no such tests exist in 3.8 - so I will try to use my tests from the   NullAnnotationsForFields branch. I'll report back whether I find evidence that these lines are still needed.

It is not unlikely that the issue that was solved by these lines has additionally been addressed by some other tweaks, too. Much water has flown under this bridge since then.
Comment 16 Stephan Herrmann CLA 2012-08-14 07:50:45 EDT
Created attachment 219853 [details]
fix under test
Comment 17 Stephan Herrmann CLA 2012-08-14 08:10:40 EDT
(In reply to comment #15)
> It is not unlikely that the issue that was solved by these lines has
> additionally been addressed by some other tweaks, too. Much water has flown
> under this bridge since then.

Rewinding that stream I found a change that apparently changed the game: Bug 372012.
If I remove in SourceTypeBinding ...
- the last two lines in initializeDeprecatedAnnotationTagBits() *AND*
- one block in evaluateNullAnnotations() that was introduced in bug 372012
... then I get some regressions in NullAnnotationTest.
Restoring *either* of the two changes fixes those regressions.

Ergo: bug 372012 seems to have made the call inside initializeDeprecatedAnnotationTagBits() obsolete.

Thus I propose to indeed remove those two lines as I've done in attachment 219853 [details]. This breaks the cyclic dependency documented in comment 11.

Even if on some obscure call path we now miss out to initialize annotations in package-info.java, that would be much better tolerable than this bug.

Tests are currently running against the proposed fix.
Comment 18 Stephan Herrmann CLA 2012-08-14 08:57:02 EDT
(In reply to comment #17)
> Tests are currently running against the proposed fix.

Tests showed one funny spontaneous regression:
org.eclipse.jdt.core.tests.compiler.regression.SwitchTest.testSwitchOnNull() produced no output where it should have said "NPE1NPE2NPE3NPE4NPE5".
Re-running SwitchTest alone did not reproduce that failure, nor did "Rerun Test - Failures First".
Some solar activity interfering with Eclipse?

Long story short: no reproduceable failure.
Comment 19 Srikanth Sankaran CLA 2012-08-14 10:57:33 EDT
Analysis, rationale, fix - all look reasonable - Please release for M2 and 
3.8.1 RC1 - Thanks!
Comment 20 Stephan Herrmann CLA 2012-08-14 12:02:29 EDT
Comment on attachment 219697 [details]
Source demonstrating problem

Sources from this attachment have been adopted for a test.
Comment 21 Stephan Herrmann CLA 2012-08-14 12:03:13 EDT
Released for 3.8.1 via commit d61c8fde6d93556ac9edd6dcb12c4cd9dba068e9.

Version for 4.3 M2 following soon (after retest).
Comment 22 Stephan Herrmann CLA 2012-08-14 14:53:48 EDT
Released for 4.3 M2 via commit 4b0b5e4ba4fc84b55ca6c20dd4ad4ee385e312fc
Comment 23 Srikanth Sankaran CLA 2012-08-16 02:10:10 EDT
Verified for 3.7.1 using Build id: M20120815-1000
Comment 24 Stephan Herrmann CLA 2012-08-16 05:44:42 EDT
(In reply to comment #23)
> Verified for 3.7.1 using Build id: M20120815-1000

Let's call it 3.8.1 :)
Comment 25 Stephan Herrmann CLA 2012-09-07 04:03:42 EDT
*** Bug 388948 has been marked as a duplicate of this bug. ***