I try to do exactly what is descripted in this question with MOXy. But i have some different behavior but the result is the same. It doesn't work.
I use @XmlElements and for each concret class I added a @XmlElement with name and type. For all classes without an adapter it works perfect but not for the class with the PolyAdapter.
In my case the adapter will be called to marshal the object. But all it writes is an entry like this into the xml file.
<?xml version="1.0" encoding="UTF-8"?>
<fooContainer>
<poly PolyName="PolyN$1">ABCBCD</poly>
<cPlexPoly>moxy.CPlexPoly$CPlexPolyAdapter$CCPWrapper@480bdb19</cPlexPoly>
</fooContainer>
And the unmarshaller won't be called at all.
I tested MOXy 2.5.0 and the current RC3 2.5.1 in both cases the results are the same. I also enabled the debug output and there are no warnings or error.
Or maybe there is another way to get this working
Update 1: Providing model
I created a small example showing my problem with MOXy 2.5.0
Interface:
@XmlRootElement
public interface Foo {
public List<String> getCoordinates();
}
Class without XmlAdapter:
@XmlRootElement(name="poly")
public class Poly implements Foo {
@XmlAttribute
String PolyName = "PolyN$1";
@XmlAnyElement
private List<String> coordinates = new LinkedList<>();
@Override
public List<String> getCoordinates() {
return coordinates;
}
public void addCoordinate( final String poly ) {
coordinates.add( poly );
}
}
Class with XmlAdapter:
@XmlJavaTypeAdapter(CPlexPolyAdapter.class)
public class CPlexPoly implements Foo {
private Map<String, String> values = new HashMap<>();
@Override
public List<String> getCoordinates() {
return new ArrayList<>(values.values());
}
public void addCoordinate( final String poly ) {
values.put( Integer.toString( poly.hashCode()), poly );
}
public List<String> getKeys() {
return new ArrayList<>(values.keySet());
}
public static class CPlexPolyAdapter extends XmlAdapter<CCPWrapper, CPlexPoly> {
@XmlRootElement(name="wrapper")
public static class CCPWrapper {
@XmlAnyElement
List<String> keys = new ArrayList<>();
@XmlAnyElement
List<String> values = new ArrayList<>();
}
@Override
public CPlexPoly unmarshal(CCPWrapper v) throws Exception {
// Won't be called.
return null;
}
@Override
public CCPWrapper marshal(CPlexPoly v) throws Exception {
if( v == null ) {
return null;
}
CCPWrapper wrapper = new CCPWrapper();
wrapper.values.addAll( v.getCoordinates() );
wrapper.keys.addAll( v.getKeys() );
return wrapper;
}
}
}
Simple container class:
@XmlRootElement(name="fooContainer")
public class FooContainer {
@XmlElements({
@XmlElement(name = "poly", type = Poly.class),
@XmlElement(name = "cPlexPoly", type = CPlexPoly.class)
})
public List<Foo> container = new LinkedList<>();
}
Main:
public class Main {
public static void main(String[] args) {
FooContainer fc = new FooContainer();
Poly poly = new Poly();
poly.addCoordinate("ABC");
poly.addCoordinate("BCD");
CPlexPoly cpoly = new CPlexPoly();
cpoly.addCoordinate("XYZ");
cpoly.addCoordinate("WXY");
fc.container.add( poly );
fc.container.add( cpoly );
/* Marshall */
JAXBContext context;
try {
context = JAXBContext.newInstance( FooContainer.class );
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal( fc, new FileWriter("fc.xml") );
}
catch (JAXBException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
/* UnMarshall */
}
}
I also updated the result i described above. Thx.
Update 2: Simplified Wrapper
Even with this simple wrapper containing nothing more than an attribute, nothing changes.
@XmlJavaTypeAdapter(CPlexPolyAdapter.class)
public class CPlexPoly implements Foo {
private Map<String, String> values = new HashMap<>();
@Override
public List<String> getCoordinates() {
return new ArrayList<>(values.values());
}
public void addCoordinate( final String poly ) {
values.put( Integer.toString( poly.hashCode()), poly );
}
public List<String> getKeys() {
return new ArrayList<>(values.keySet());
}
public static class CPlexPolyAdapter extends XmlAdapter<CCPWrapper, CPlexPoly> {
@XmlRootElement(name="wrapper")
public static class CCPWrapper {
@XmlAttribute
String test = "test";
}
@Override
public CPlexPoly unmarshal(CCPWrapper v) throws Exception {
// Won't be called.
return null;
}
@Override
public CCPWrapper marshal(CPlexPoly v) throws Exception {
if( v == null ) {
return null;
}
CCPWrapper wrapper = new CCPWrapper();
return wrapper;
}
}
}
So if someone has any idea what is wrong it would be very helpful. Thanks Christian
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The problem you are encountering is due to the CCPWrapper
class being mapped incorrectly. You are not allowed to have two fields/properties mapped with @XmlAnyElement
.
@XmlRootElement(name = "wrapper")
public static class CCPWrapper {
@XmlAnyElement
List<String> keys = new ArrayList<>();
@XmlAnyElement
List<String> values = new ArrayList<>();
}
When I modified your code to remove one of the @XmlAnyElement
annotations everything appeared to work correctly.
Thank you for your answer. But no I still get the same output. I even removed both lists with the XmlAnyElement annotation and just added a simple XmlAttribute. The output doesn't change. See the updated Wrapper class in question.
I just noticed that when I was trying out your code that I had added a field of type CPlexPoly
to the FooContainer
class. This in addition to my previous suggestion caused the XmlAdapter
to be applied to the container
field.
import java.util.*;
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "fooContainer")
public class FooContainer {
@XmlElement
private final CPlexPoly workaround = null;
@XmlElements({
@XmlElement(name = "poly", type = Poly.class),
@XmlElement(name = "cPlexPoly", type = CPlexPoly.class)
})
public List<Foo> container = new LinkedList<>();
}
You could do something similar as a workaround. I have opened the following bug that you can use to track our progress on the real fix:
A better workaround would be to include the CCPWrapper
class in the classes used to create the JAXBContext
as follows:
context = JAXBContext.newInstance( FooContainer.class, CCPWrapper.class );
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.