Community
Participate
Working Groups
Build Identifier: 20081104192500 This is related but not exactly the same as the problem outlined in Bug 147711: "Add an option to generate aj-synthetics with true synthetic flag." It appears that introducing an interface (via declare parents) generates non-synthetic public members on the target class. This causes the JAXB processor to throw an IllegalAnnotationException like so: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions Property ajc$interField$com_myproject_aspects_EncodableMixin$Impl$com_myproject_Encodable$encoded Reproducible: Always Steps to Reproduce: 1. Create an interface named com.myproject.Encodable with a method 2. Extend the interface with a static implementation aspect which provides the default implementation (called com.myproject.aspects.EncodableMixin$Impl) which implements that method. 3. Attempt to weave a class generated from JAXB (annotated with @XmlType.propOrder) like this: declare parents : com.myproject.objectmodel..* 4. Attempt to use JAXB classes as a web service client (I used CXF but that should not matter - happens with Sun's JAXB reference impl).
If the problem is purely the ajc$ prefixed annotation on these members, then I'd be tempted to just remove that rather than mess with the syntheticness. Are you able to confirm which annotation it is having trouble with? I've been thinking about removing those annotations anyway.
The trouble is definitely with @XmlType. JAXB is expecting that the propOrder attribute list every non-synthetic public field on the class... at least when @XmlAccessorType is set to XmlAccessType.FIELD. This is so JAXB knows how to serialize the Java object in the correct sequence the XML is expecting. I can see if there is a workaround to get JAXB to generate this as PUBLIC_MEMBER instead. If I can do that, I would think that it would be looking for a public getter/setter pair to determine valid fields. Not sure if I can do that, though.
Andy, to clarify... it's not the annotation; it's the boolean ajc$ field that's the issue.
Update on the workaround... Basically, it's not going to work. I cannot figure out a reasonable way (short of rewriting XJC through a plugin) to get the @XmlAccessorType on that object set to XmlAccessType.PROPERTY (that's what I meant, not PUBLIC_MEMBER). Even if I set that annotation manually, there are other JAXB annotations on the field levels that override the PROPERTY setting. Is there another way I can introduce methods onto a series of target classes without inducing this ajc$ property to be created?
My bad... I thought I posted this part of the error, but I didn't. Here is the actual error message: Property ajc$interField$com_myproject_aspects_EncodableMixin$Impl$com_myproject_Encodable$encoded is present but not specified in @XmlType.propOrder
To recreate you mention creating an interface and then implementing it via an aspect, but then the error relates to a field (property) - are you also ITD'ing a field on the interface? a field called encoded? What visibilty are you specifying for it? --- AspectJ 1.6.9 does actually make changes in the area of ITD fields. They no longer have a mangled name unless necessary so an ITD of private Object <target>.encode would manifest simply as private Object encode in the target type, rather than the mangled form: ajc$interField$com_myproject_aspects_EncodableMixin$Impl$com_myproject_Encodable$encoded However, I only did that for ITDs onto a class, I have not yet done it for ITD fields onto an interface. Here is the difference: --- A.java aspect A { private int C.ii; private int I.jj; } interface I { } class C implements I {} --- AspectJ168 compiled, javap -private C: class C extends java.lang.Object implements I{ public int ajc$interField$A$ii; public int ajc$interField$A$I$jj; C(); public int ajc$interFieldGet$A$I$jj(); public void ajc$interFieldSet$A$I$jj(int); } AspectJ169 compiled, javap -private C: class C extends java.lang.Object implements I{ private int ii; public int ajc$interField$A$I$jj; C(); public int ajc$interFieldGet$A$I$jj(); public void ajc$interFieldSet$A$I$jj(int); public static int ajc$get$ii(C); public static void ajc$set$ii(C, int); } Notice on 1.6.9 the field 'ii' retains the declared name and (perhaps more importantly) the declared visibility. I presume if the change was made not to mangle the declaration for itd fields on interfaces then the JAXB related attributes won't be wrong because the field is not public.
Sorry, I didn't explain that very well. Here is the code I am using: public interface Encodable { boolean isEncodingEnabled(); void enableEncoding(); void disableEncoding(); } public interface EncodableMixin extends Encodable { public static aspect Impl { private boolean Encodable.encoded = true; public boolean Encodable.isEncodingEnabled() { return encoded; } public void Encodable.enableEncoding() { this.encoded = true; } public void Encodable.disableEncoding() { this.encoded = false; } } } So your presumption is correct. I am introducing a private boolean to an interface as a default implementation. When the field gets added to the target class, it comes over with a public mangled name. When you say it mangles it only when necessary, I'm assuming that this would mean that if there were already a field named 'encoded' on the object it would need to mangle it? However, private visibility won't help in this case, either (I even tested it to make sure). @XmlAccessType.FIELD defines what this setting does in the javadoc: "Every non static, non transient field in a JAXB-bound class will be bound to XML, unless annotated by {@link XmlTransient}." In thinking about this some more, I'm wondering if this really shouldn't be classified as a bug at all. Since I am introducing fields onto a class who semantic dictates that all non-static, non-transient fields not marked with @XmlTransient should be serialized, I still need to follow that semantic. (It's not an implementation artifact of AspectJ as is the case with applying advice to members). Do you agree? Should I mark this as closed?
I think I agree - if there are JAXB requirements on some type and you changed that type via ITD, you still have to obey the rules of JAXB. However, you could just mark the field as transient, then it will end up transient in the target: private transient boolean Encodable.encoded = true; that would seem to avoid your JAXB problem. Of course, that depends on what encoded means in your scenario I guess, and whether you would be ok with that field not being serialized.
Before I close it - can you say if including 'transient' in the ITD field declaration helped you?
Yes, making the field transient did the trick. Obviously it introduces a slightly different semantic but that is perfectly acceptable in my case. Still, I imagine that it would be nice if interface introduction worked the same as class introduction in terms of the visibility of the member.
closing as transient on ITD helps the situation. Work on changing how itds on interfaces work likely to be done under bug 288282