Question

I'm using the Class AdapterDataObj to convert the Class DataObj to AdaptedDataObj, when JAXB.marshal is called.


package test;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlJavaTypeAdapter(AdapterDataObj.class)
public class DataObj { 
    public String bla = "I'm DataObj";
    public String name; 
    public DataObj(String name) { 
        this.name = name;
    }

    } 
    

package test; 
public class AdaptedDataObj {
        public String bla="I'm AdaptedDataObj";
        public  String name;

        public AdaptedDataObj(String name) {
            this.name = name;
        }
}

package test; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 
public class AdapterDataObj extends XmlAdapter { 
    @Override
    public DataObj unmarshal(AdaptedDataObj v) throws Exception {
        return null; // not needed in this case
    }

    @Override
    public AdaptedDataObj marshal(DataObj v) throws Exception {
        System.out.println("Marschal for " + v.name + " called!");
        return new AdaptedDataObj(v.name);
    } 
}

Now I put the DataObj into a new Class and JAXB.marshal is called for this class. The output looks fine. I also get the message that AdaptedDataObj is called.


package test; 
import javax.xml.bind.JAXB; 
public class Testobj { 
    public DataObj x; 
    public Testobj() {
        x = new DataObj("Hallo World");
    }

    public static void main(String[] args) throws Exception {
        System.out.println("Testobj");
        System.out.println("=================================");
        Testobj to = new Testobj();
        JAXB.marshal(to, System.out);
    } 
}

Now I change "public DataObj x;" to "public Object x;", because I want to store not only DataObj in that class.

But in this case the AdapterDataObj is not longer called. The DataObj and not the AdapterDataObj is exported as xml.

Any idea where the problem is?

I also tried without succes to add @XmlJavaTypeAdapter to the package-info.java. AdapterDataObj is still not called. I've tested with Java 1.7.0_45 and 1.8.0-ea.


package test; 
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlSeeAlso; 
@XmlSeeAlso({DataObj.class})
public class Testobj3 { 
        public Object x; 
    public Testobj3() {
        x = new DataObj("Hallo World");
    }

    public static void main(String[] args) throws Exception {
        System.out.println("Testobj3");
        System.out.println("=================================");
        Testobj3 to3 = new Testobj3();
        JAXB.marshal(to3, System.out);
    } 
}
Was it helpful?

Solution

According to JAXB 2.2 specification:

A @XmlJavaTypeAdapter that extends XmlAdapter and is specified on the class, interface or Enum type (i.e. on a program element that matches meta annotation @Target={type}) must adapt boundType at the point of reference as follows:

  1. a property/field whose reference type is boundType
  2. a property/field where boundType is used as a parametric type

So the field/property must be of given type in order to JAXB recognize that Adapter needs to be used.

For the same reason you cannot use adapters on root elements. The explanation can be found in closed JAXB issue JAXB-117:

Adapters are defined against types, not instances. In particular, the adapter is designed in such a way that it's not always possible to infer the right adapter just from an instance.

EDIT Using Object in JAXB classes is not very common. Maybe the objects you want to store have something in common, so that you can extract interface/base class that you can annotate with @XmlJavaTypeAdapter. If they don't have anything in common maybe it would be better to store them as separate properties.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top