Bug 303518 - Generate aj-synthetics with true synthetic flag for introduced interfaces
Summary: Generate aj-synthetics with true synthetic flag for introduced interfaces
Status: RESOLVED WONTFIX
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 1.6.9M1   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-02-22 12:02 EST by Jonathan Whitall CLA
Modified: 2010-04-16 13:10 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Whitall CLA 2010-02-22 12:02:50 EST
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).
Comment 1 Andrew Clement CLA 2010-02-22 13:07:46 EST
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.
Comment 2 Jonathan Whitall CLA 2010-02-22 15:10:05 EST
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.
Comment 3 Jonathan Whitall CLA 2010-02-22 15:14:23 EST
Andy, to clarify... it's not the annotation; it's the boolean ajc$ field that's the issue.
Comment 4 Jonathan Whitall CLA 2010-02-22 17:20:38 EST
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?
Comment 5 Jonathan Whitall CLA 2010-02-22 17:25:13 EST
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
Comment 6 Andrew Clement CLA 2010-02-22 18:27:10 EST
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.
Comment 7 Jonathan Whitall CLA 2010-02-23 09:54:49 EST
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?
Comment 8 Andrew Clement CLA 2010-02-23 12:46:55 EST
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.
Comment 9 Andrew Clement CLA 2010-03-02 15:50:50 EST
Before I close it - can you say if including 'transient' in the ITD field declaration helped you?
Comment 10 Jonathan Whitall CLA 2010-03-02 16:01:09 EST
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.
Comment 11 Andrew Clement CLA 2010-03-10 12:04:35 EST
closing as transient on ITD helps the situation.  Work on changing how itds on interfaces work likely to be done under bug 288282