Skip to main content

IllegalAnnotationExceptions with property access and multiple setters

5 replies [Last post]
bradfritz
Offline
Joined: 2005-02-04

Testing with the 20051221 nightly...

I need to use property access for some of my JAXB marshalled variables
but I get IllegalAnnotationExceptions during marshalling if the class
being marshalled has more than one setter for a single property. For
example, consider a Money class with the following method signatures:

@XmlAttribute
public BigDecimal getAmount()

public void setAmount(BigDecimal amount)

public void setAmount(double amount)

When JAXB tries to marshal a Money instance, it complains with...

Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
The type of the getter is java.math.BigDecimal but that of the setter is double. They have to be the same.
this problem is related to the following location:
at public java.math.BigDecimal Money.getAmount()
at Money
this problem is related to the following location:
at public void Money.setAmount(double)
at Money

at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:66)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:330)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:198)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:76)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:368)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:561)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:508)
at JaxbMultipleSetterTest.test(JaxbMultipleSetterTest.java:10)
at JaxbMultipleSetterTest.main(JaxbMultipleSetterTest.java:6)

I have other problems[1] with using field acces and I would like to
avoid using a method-naming kludge like setAmountUsingDouble(). Is
there a better solution?

It would be nice if the RI favored mutator methods with a single
parameter that matched the return type of the annotated accessor.

This post is already pretty long and the forum doesn't seem to support
attachments, so I'll reply to this post with a full test case.

--Brad

[1] http://forums.java.net/jive/thread.jspa?threadID=967

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
bradpeabody
Offline
Joined: 2006-06-25

I ran into this same problem. I went ahead and did a fix on this and put the patch in the issue tracker:

https://jaxb.dev.java.net/issues/show_bug.cgi?id=190

For now you'll have to download and recompile from source to make it work, but hopefully it'll just be put in the next release.

(If you want this too, vote for it: https://jaxb.dev.java.net/issues/showvotes.cgi?voteon=190)

sekhar
Offline
Joined: 2003-06-25

Thanks for the detailed description of the problem and the patch. Pending more detailed investigation, I support this change i.e. favoring a mutator methods with a single parameter that matches the return type of the annotated accessor. In addition to RI changes, the following are needed and/or desirable:

- update JAXB 2.0 spec (it is currently silent on multiple setter methods.)
- it is desirable if Java Persistence API also had the same behavior for multiple setters. From a quick look at the Java Persistence API specification implies this. I will forward this to appropriate spec leads to confirm this.

bradfritz
Offline
Joined: 2005-02-04

Here is the test case I promised...

brad@blacklab /tmp$ cat Money.java JaxbMultipleSetterTest.java
// Money.java
import java.math.BigDecimal;
import javax.xml.bind.annotation.*;

@XmlAccessorType(AccessType.NONE)
@XmlRootElement(name = "money")
public class Money {
private BigDecimal amount;
@XmlAttribute
private String currency;

private Money() {
// no-arg constructor to keep JAXB-RI happy
}

public Money(double amount, String currency) {
this.amount = new BigDecimal(amount);
this.currency = currency;
}

@XmlAttribute
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public void setAmount(double amount) {
this.amount = new BigDecimal(amount);
}
}

// JaxbMultipleSetterTest.java
import javax.xml.bind.*;

public class JaxbMultipleSetterTest {

public static void main(String[] args) throws Exception {
new JaxbMultipleSetterTest().test();
}

public void test() throws Exception {
Marshaller m = JAXBContext.newInstance(Money.class).createMarshaller();
m.marshal(new Money(10.0, "USD"), System.out);
System.out.println();
}
}

brad@blacklab /tmp$ java -classpath /tmp/jaxb-api-2-20051221.jar:/tmp/jsr173-api-1.0.jar:/tmp/jaxb-impl-2-20051221.jar:/tmp/activation.jar:. JaxbMultipleSetterTest
Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
The type of the getter is java.math.BigDecimal but that of the setter is double. They have to be the same.
this problem is related to the following location:
at public java.math.BigDecimal Money.getAmount()
at Money
this problem is related to the following location:
at public void Money.setAmount(double)
at Money

at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:66)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:330)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:198)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:76)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:368)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:561)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:508)
at JaxbMultipleSetterTest.test(JaxbMultipleSetterTest.java:10)
at JaxbMultipleSetterTest.main(JaxbMultipleSetterTest.java:6)

sekhar
Offline
Joined: 2003-06-25

Try moving the @XmlAttribute from property

// @XmlAttribute
public BigDecimal getAmount() {
return amount;
}

to the field:

@XmlAttribute private BigDecimal amount;

bradfritz
Offline
Joined: 2005-02-04

sekhar wrote:

> Try moving the @XmlAttribute from property
[..]
> to the field:
>
> @XmlAttribute private BigDecimal amount;

Thank you for your reply.

Your suggestion would work for my trivial example.

In real life, my objects are part of a graph lazily loaded by
Hibernate. If I use field access, the accessor methods are bypassed
and the Hibernate-generated CGLIB subclasses don't get a chance to
load related objects from the database.

Hence the "I need to use property access" comment in my original post
and the footnote reference to:

http://forums.java.net/jive/thread.jspa?threadID=967

:-)

It looks like I am not the only one trying to keep JAXB from fighting
with Hibernate lazy loading:

http://forums.java.net/jive/thread.jspa?threadID=1129

but so far I haven't seen any good solutions.

--Brad