I can't understand why this JAXB IllegalAnnotationException is thrown

问题:

This is my XML file:


    
    

          
        

I made 2 classes to parse it (Fields.java and Field.java):

@XmlRootElement(name = "fields")
public class Fields {

    @XmlElement(name = "field")
    List fields = new ArrayList();
        //getter, setter
}

and

public class Field {

    @XmlAttribute(name = "mappedField")
    String mappedField;
    /getter,setter
}

But I get this exception.

[INFO] com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
[INFO]  at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:66) ~[na:1.6.0_07]
[INFO]  at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:422) ~[na:1.6.0_07]
[INFO]  at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:270) ~[na:1.6.0_07]

I can't understand why this exception rises. Exception is here:

JAXBContext context = JAXBContext.newInstance(Fields.class);

I use JDK 1.6_0.0.7. Thanks.

回答1:

The exception is due to your JAXB (JSR-222) implementation believing that there are two things mapped with the same name (a field and a property). There are a couple of options for your use case:

OPTION #1 - Annotate the Field with @XmlAccessorType(XmlAccessType.FIELD)

If you want to annotation the field then you should specify @XmlAccessorType(XmlAccessType.FIELD)

Fields.java:

package forum10795793;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "fields")
@XmlAccessorType(XmlAccessType.FIELD)
public class Fields {

    @XmlElement(name = "field")
    List fields = new ArrayList();

    public List getFields() {
        return fields;
    }

    public void setFields(List fields) {
        this.fields = fields;
    }

}

Field.java:

package forum10795793;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Field {

    @XmlAttribute(name = "mappedField")
    String mappedField;

    public String getMappedField() {
        return mappedField;
    }

    public void setMappedField(String mappedField) {
        this.mappedField = mappedField;
    }

}

OPTION #2 - Annotate the Properties

The default accessor type is XmlAccessType.PUBLIC. This means that by default JAXB implementations will map public fields and accessors to XML. Using the default setting you should annotate the public accessors where you want to override the default mapping behaviour.

Fields.java:

package forum10795793;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement(name = "fields")
public class Fields {

    List fields = new ArrayList();

    @XmlElement(name = "field")
    public List getFields() {
        return fields;
    }

    public void setFields(List fields) {
        this.fields = fields;
    }

}

Field.java:

package forum10795793;

import javax.xml.bind.annotation.*;

public class Field {

    String mappedField;

    @XmlAttribute(name = "mappedField")
    public String getMappedField() {
        return mappedField;
    }

    public void setMappedField(String mappedField) {
        this.mappedField = mappedField;
    }

}

For More Information



回答2:

I can't understand why this JAXB IllegalAnnotationException is thrown

I also was getting the ### counts of IllegalAnnotationExceptions exception and it seemed to be due to an improper dependency hierarchy in my Spring wiring.

I figured it out by putting a breakpoint in the JAXB code when it does the throw. For me this was at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(). Then I dumped the list variable which gives something like:

[org.mortbay.jetty.Handler is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
    at org.mortbay.jetty.Handler
    at public org.mortbay.jetty.Handler[] org.mortbay.jetty.handler.HandlerCollection.getHandlers()
    at org.mortbay.jetty.handler.HandlerCollection
    at org.mortbay.jetty.handler.ContextHandlerCollection
    at com.mprew.ec2.commons.server.LocalContextHandlerCollection
    at private com.mprew.ec2.commons.server.LocalContextHandlerCollection com.mprew.ec2.commons.services.jaxws_asm.SetLocalContextHandlerCollection.arg0
    at com.mprew.ec2.commons.services.jaxws_asm.SetLocalContextHandlerCollection,
org.mortbay.jetty.Handler does not have a no-arg default constructor.]
....

The does not have a no-arg default constructor seemed to me to be misleading. Maybe I wasn't understanding what the exception was saying. But it did indicate that there was a problem with my LocalContextHandlerCollection. I removed a dependency loop and the error cleared.

Hopefully this will be helpful to others.



回答3:

This is because, by default, Jaxb when serializes a pojo, looks for the annotations over the public members(getters or setters) of the properties. But, you are providing annotations on fields. so, either change and set the annotations on setters or getters of properties, or sets the XmlAccessortype to field.

Option 1::

@XmlRootElement(name = "fields")
@XmlAccessorType(XmlAccessType.FIELD)
public class Fields {

        @XmlElement(name = "field")
        List fields = new ArrayList();
        //getter, setter
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Field {

       @XmlAttribute(name = "mappedField")
       String mappedField;
       //getter,setter
}

Option 2::

@XmlRootElement(name = "fields")
public class Fields {

        List fields = new ArrayList();

        @XmlElement(name = "field")
        public List getFields() {

        }

        //setter
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Field {

       String mappedField;

       @XmlAttribute(name = "mappedField")
       public String getMappedField() {

       }

        //setter
}

For more detail and depth, check the following JDK documentation http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/XmlAccessorType.html



回答4:

One of the following may cause the exception:

  1. Add an empty public constructor to your Fields class, JAXB uses reflection to load your classes, that's why the exception is thrown.
  2. Add separate getter and setter for your list.


回答5:

I once received this message after thinking that putting @XmlTransient on a field I didn't need to serialize, in a class that was annotated with @XmlAccessorType(XmlAccessType.NONE).

In that case, removing XmlTransient resolved the issue. I am not a JAXB expert, but I suspect that because AccessType.NONE indicates that no auto-serialization should be done (i.e. fields must be specifically annotated to serialize them) that makes XmlTransient illegal since its sole purpose is to exclude a field from auto-serialization.



回答6:

I had this same issue, I was passing a spring bean back as a ResponseBody object. When I handed back an object created by new, all was good.



回答7:

I was having the same issue

My Issue

Caused by: java.security.PrivilegedActionException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions

Two classes have the same XML type name "{urn:cpq_tns_Kat_getgroupsearch}Kat_getgroupsearch". Use @XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at katrequest.cpq_tns_kat_getgroupsearch.KatGetgroupsearch
at public javax.xml.bind.JAXBElement katrequest.cpq_tns_kat_getgroupsearch.ObjectFactory.createKatGetgroupsearch(katrequest.cpq_tns_kat_getgroupsearch.KatGetgroupsearch)
at katrequest.cpq_tns_kat_getgroupsearch.ObjectFactory
this problem is related to the following location:
at cpq_tns_kat_getgroupsearch.KatGetgroupsearch

Two classes have the same XML type name "{urn:cpq_tns_Kat_getgroupsearch}Kat_getgroupsearchResponse0". Use @XmlType.name and @XmlType.namespace to assign different names to them.
this problem is related to the following location:
at katrequest.cpq_tns_kat_getgroupsearch.KatGetgroupsearchResponse0
at public javax.xml.bind.JAXBElement katrequest.cpq_tns_kat_getgroupsearch.ObjectFactory.createKatGetgroupsearchResponse0(katrequest.cpq_tns_kat_getgroupsearch.KatGetgroupsearchResponse0)
at katrequest.cpq_tns_kat_getgroupsearch.ObjectFactory
this problem is related to the following location:
at cpq_tns_kat_getgroupsearch.KatGetgroupsearchResponse0

Changed made to solve it are below

I change the respective name to namespace

@XmlAccessorType(XmlAccessType.FIELD) @XmlType(**name** =
    "Kat_getgroupsearch", propOrder = {

    @XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace =
    "Kat_getgroupsearch", propOrder = {


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(**name** = "Kat_getgroupsearchResponse0", propOrder = {

   @XmlAccessorType(XmlAccessType.FIELD)
   @XmlType(namespace = "Kat_getgroupsearchResponse0", propOrder = {

why?

As written in error log two classes have same name so we should use namespace because XML namespaces are used for providing uniquely named elements and attributes in an XML document.



回答8:

All below options worked for me.

Option 1: Annotation for FIELD at class & field level with getter/setter methods

 @XmlRootElement(name = "fields")
 @XmlAccessorType(XmlAccessType.FIELD)
    public class Fields {

        @XmlElement(name = "field")
        List fields = new ArrayList();
            //getter, setter
    }

Option 2: No Annotation for FIELD at class level(@XmlAccessorType(XmlAccessType.FIELD) and with only getter method. Adding Setter method will throw the error as we are not including the Annotation in this case. Remember, setter is not required when you explicitly set the values in your XML file.

@XmlRootElement(name = "fields")
    public class Fields {

        @XmlElement(name = "field")
        List fields = new ArrayList();
            //getter
    }

Option 3: Annotation at getter method alone. Remember we can also use the setter method here as we are not doing any FIELD level annotation in this case.

@XmlRootElement(name = "fields")
    public class Fields {

        List fields = new ArrayList();

        @XmlElement(name = "field")
        //getter

        //setter
    }

Hope this helps you!