-
Notifications
You must be signed in to change notification settings - Fork 20
Problem with XmlAdapter downcasting #36
Comments
Ok. As per comments on original issue: To work on this, I think I need a unit test to try to resolve this: code snippet helps, but I'd also need adapter implementation. |
I shall create and send now. Just curious- what is your release process. Once you fix can I get it immediately? |
Here is the code- Any.java package com.somiran.exp.jackson.jaxb;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(value=AnyAdapter.class, type=Any.class)
public interface Any {
public boolean isKnown();
} Known.java package com.somiran.exp.jackson.jaxb;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(value=AnyAdapter.class, type=Any.class)
public abstract class Known implements Any {
@Override
public boolean isKnown() {
return false;
}
public Known(String type) {
super();
this.type = type;
}
String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void validate();
} UnKnown.java package com.somiran.exp.jackson.jaxb;
public abstract class UnKnown implements Any {
@Override
public boolean isKnown() {
return false;
}
} Resource.java package com.somiran.exp.jackson.jaxb;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(value=AnyAdapter.class, type=Any.class)
@XmlRootElement
public class Resource extends Known {
public Resource(Integer resourceId, String resourceName) {
super("Resource");
this.resourceId = resourceId;
this.resourceName = resourceName;
}
public Integer getResourceId() {
return resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
Integer resourceId;
String resourceName;
@Override
public void validate() {
}
} ResourceList.java package com.somiran.exp.jackson.jaxb;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(value=AnyAdapter.class, type=Any.class)
@XmlRootElement
public class ResourceList extends Known{
public ResourceList(String name) {
super("ResourceList");
this.name = name;
}
List<Resource> resourceList;
String name;
@XmlElement(name="resource")
public List<Resource> getResourceList() {
return resourceList;
}
public void setResourceList(List<Resource> resourceList) {
this.resourceList = resourceList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void validate() {
}
} AnyAdapter.java package com.somiran.exp.jackson.jaxb;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AnyAdapter extends XmlAdapter<Object, Any> {
@Override
public Any unmarshal(Object source)
throws Exception {
throw new RuntimeException("Don't Unmarshal using JAXB");
}
@Override
public Object marshal(Any any)
throws Exception {
if (any == null) {
return null;
}
if (any.isKnown()) {
return any;
} else {
return null;//UnknownAdapter.getInstance().marshal((Unknown)any);
}
}
} JacksonJaxbAdapterImpl.java package com.somiran.exp.jackson.jaxb;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
public class JacksonJaxbAdapterImpl {
public ObjectMapper initializeJackson() {
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.setSerializationInclusion(Include.NON_NULL);
// Need to use JaxB Annotation.
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
SimpleModule mySimpleModule = new SimpleModule();
mySimpleModule.addSerializer(Long.class, new ToStringSerializer());
mySimpleModule.addSerializer(Double.class, new ToStringSerializer());
mapper.registerModule(mySimpleModule);
return mapper;
}
public void writeObject(Object target, Writer writer, boolean isPretty) throws Exception {
ObjectMapper mapper = initializeJackson();
try {
if(isPretty) {
mapper.writerWithDefaultPrettyPrinter().writeValue(writer,target);
} else {
mapper.writeValue(writer,target);
}
} catch (JsonGenerationException e) {
throw new RuntimeException(e);
} catch (JsonMappingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} JacksonJaxbAdapterTest.java package com.somiran.exp.jackson.jaxb;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
public class JacksonJaxbAdapterTest {
public static void main(String[] args) throws Exception {
JacksonJaxbAdapterTest test = new JacksonJaxbAdapterTest();
ResourceList report = test.makeObject();
StringWriter jacksonWriter = new StringWriter();
JacksonJaxbAdapterImpl jacksonMainClass = new JacksonJaxbAdapterImpl();
jacksonMainClass.initializeJackson();
jacksonMainClass.writeObject(report, jacksonWriter, true);
System.out.println(jacksonWriter);
}
ResourceList makeObject() {
Resource primary = new Resource(12,"primary");
Resource secondary = new Resource(13, "secondary");
List<Resource> listofRes = new ArrayList<Resource>();
listofRes.add(primary);
listofRes.add(secondary);
ResourceList report = new ResourceList("Daily");
report.setResourceList(listofRes);
return report;
} Test Method:
{
"known" : false,
"name" : "Daily",
"resource" : [ null, null ],
"type" : "ResourceList"
}
{
"known" : false,
"name" : "Daily",
"resource" : [ {
"known" : false,
"resourceId" : 12,
"resourceName" : "primary",
"type" : "Resource"
}, {
"known" : false,
"resourceId" : 13,
"resourceName" : "secondary",
"type" : "Resource"
} ],
"type" : "ResourceList"
}
|
Thanks! If I figured out how to fix it, I'll commit it, and code is available from git, so you can build it. |
Hi- Need this fix too... any date? |
Nope. I haven't had time to work on this, nor will likely have any in near future. |
I am going to look at Jackson code for the first time. Any suggestion? Pointer? idea? |
@saxenapavankumar Excellent, if you could give it a go. I would try with 2.5.0 sources (i.e. Unit test from above is quite big, and one thing that could help is trimming it down a bit. |
I looked at the code some back. The issue is with the code BeanSerializerFactory::createSerializer() and something that I didnt check. The output of the XmlAdapter::marshal() is "Object"- it makes an instance of StdDelegatingSerializer instead of BeanSerializer and that messes things up. I tried changing the adapter definition to- It gives me fields from Known class only and not the sub class (Resource)- see the response below
|
@somiranroy Right: if nominal type of |
I suspect this fix: FasterXML/jackson-databind#731 which will be in 2.5.3 (and 2.6.0) might help here. |
I do not have a way to reproduce the problem at this point, so closing. May be reopened with reproducible unit test / code. |
I like Jackson and it is awesome but this issue is killing me! - http://jira.codehaus.org/browse/JACKSON-723. This is blocking me from adopting Jackson as a JSON generator. Can you please help.
The only difference between my problem and the Jira item is that I am using JaxbAnnotationModule instead of JacksonAnnotationIntrospector.
The text was updated successfully, but these errors were encountered: