when I try to parse the following XML I get an error with Jackson:
<root>
<aCollection>
<language xml:lang="en">
<entry id="1" value="foo"/>
<entry id="2" value="bar"/>
<entry id="3" value="blah"/>
</language>
</aCollection>
</root>
The classes I use are:
#Data
#JacksonXmlRootElement(localName = "root")
public class RootDTO {
#JacksonXmlProperty(localName = "aCollection")
private CollectionDTO collection;
}
#Data
public class CollectionDTO {
#JacksonXmlProperty(localName = "language")
LanguageDTO language;
}
#Data
public class LanguageDTO {
#JacksonXmlProperty(localName = "entry")
EntryDTO[] entries;
}
#Data
public class EntryDTO {
#JacksonXmlProperty(isAttribute = true)
private String id;
#JacksonXmlProperty(isAttribute = true)
private String value;
}
The error is:
Can not instantiate value of type [simple type, class com.tinkerdesk.viewer.model.DTO.EntryDTO] from JSON String; no single-String constructor/factory method
If I remove the array brackets it works but of course only parses the first entry element. I found that I should maybe use #JacksonXmlElementWrapper(useWrapping = false) on top of EntryDTO[] entries; since the elements are not wrapped. However this does not comile for me because there is no useWrapping in the com.fasterxml.jackson.xml.annotate.JacksonXmlElementWrapper. My Jackson core version is 2.9.6 and xml-databind 0.6.2. Is there now a newer way to do this?
Ok nevermind I made a stupid error. The 0.6.2 version of Jackson Dataformat Xml should have made me suspicious in the first place. It seems at some point they moved to a new namespace and I was using the old namespace in gradle which sadly resolved to a maven repository that has last been updated in 2011.
Updating the namespace made it resolve 2.9.5 which has the useWrapping property. Setting this resolved the issue.
Related
I am trying to call an API in my Dropwizard application, the API returns the following class
#Getter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#EqualsAndHashCode
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Error")
public class ErrorResponse {
#NonNull
#XmlAttribute(name = "msg")
private String msg;
#XmlAttribute(name = "display")
protected String display;
#XmlAttribute(name = "action")
private String action;
#NotNull
#XmlAttribute(name = "type")
private String type;
#XmlAttribute(name = "code")
private String code;
}
return javax.ws.rs.core.Response.status(status).entity(ErrorResponse).header(CONTENT_TYPE, APPLICATION_XML).build();
when I ran the application from IntelliJ, I got this response:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Error msg="some message" display="true" action="RETRY" type="FATAL" code="error"/>
when I ran it using the jar, I got this:
<ErrorResponse>
<msg>some message</msg>
<display>true</display>
<action>RETRY</action>
<type>FATAL</type>
<code>error</code>
</ErrorResponse>
I am using dropwizard 2.0.24
Don't package your jar plain, use the maven-shade-plugin, that will include the dependencies in the jar, or, add these dependencies to your Classpath.
after deleting .m2 I got same response from IntelliJ and from the Jar.
for some reason Dropwizard 2.0.24 was ignoring my JAXB annotations, I fixed it by changing the version to 2.0.0.
thanks for your comments, much appreciated
I want to know if it's possible to ignore one or many nodes when parsing XML using Jackson ML module.
I want to be able to parse this XML
<bundle>
<id value="myBundleId"/>
<meta>
<profile value="http://myurl/profile1" />
<profile value="http://myurl/profile2" />
<tag>
<system value="https://myurl/system" />
<code value="myAppCode"/>
</tag>
</meta>
<type value="message" />
</bundle>
into this POJO object
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.Data;
#Data
public class Bundle {
#JacksonXmlElementWrapper(localName = "id")
#JacksonXmlProperty(isAttribute = true, localName = "value")
private String id;
#JacksonXmlElementWrapper(localName = "type")
#JacksonXmlProperty(isAttribute = true, localName = "value")
private String type;
}
Right now it's not working as I think the annotation #JacksonXmlElementWrapper is only working with lists.
It also gives me the following error message :
java.lang.IllegalArgumentException: Conflicting setter definitions for
property "value"
Try the following:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Bundle {
...
}
Alternatively:
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
If I recall right you can set this on the object mapper and it will avoid exceptions being thrown on unmatched nodes.
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
to bind properties you can use #JsonProperty
Jackson Annotations
If you don't mind using a different library, SimpleXml does this by default:
public class Bundle {
#XmlWrapperTag("id")
#XmlName("value")
#XmlAttribute
private String id;
#XmlWrapperTag("type")
#XmlName("value")
#XmlAttribute
private String type;
}
And then serialize and print:
final SimpleXml simple = new SimpleXml();
final Bundle bundle = simple.fromXml(xml, Bundle.class);
System.out.println(bundle.id + " : " + bundle.type);
This will print:
myBundleId : message
SimpleXml is in maven central
<dependency>
<groupId>com.github.codemonstur</groupId>
<artifactId>simplexml</artifactId>
<version>1.5.5</version>
</dependency>
I'm stucked at parsing the following xml with JAXB:
<?xml version="1.0" encoding="utf-8"?>
<dashboardreport name="exampleDashboard" version="6.5.6.1013" reportdate="2016-12-16T11:05:19.329+01:00" description="">
<data>
<incidentchartdashlet name="Incident Chart" description="" />
<chartdashlet name="WebRequestTime" showabsolutevalues="false" />
<chartdashlet name="WebServiceTime" showabsolutevalues="false" />
</data>
</dashboardreport>
I used the following java classes to unmarshal the xml:
Dashboardreport.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "dashboardreport")
public class Dashboardreport {
#XmlElementWrapper(name = "data")
#XmlElement(name = "chartdashlet")
protected List<Chartdashlet> chartdashlets;
#XmlElementWrapper(name = "data")
#XmlElement(name = "incidentchartdashlet")
protected List<Incidentchartdashlet> incidentchartdashlets;
#XmlAttribute(name = "name")
protected String name;
}
I just want to unmarshal the xml without using a wrapper class around incidentchartdashlets and chartdashlet, cause both types differ a lot.
I only can use the XmlElementWrapper annotation once, so that only chartdashlets get filled and incidentchartdashlets is null.
Is there any solution with JAXB without using a seperate wrapper class?
I assume your dashlet classes are defined like
class Chartdashlet extends Dashlet and class Incidentchartdashlet extends Dashlet.
Then the preferred JAXB way to handle your mixed list of dashlets would be
by using the #XmlElements
annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "dashboardreport")
public class Dashboardreport {
#XmlElementWrapper(name = "data")
#XmlElements({
#XmlElement(name = "chartdashlet", type = Chartdashlet.class),
#XmlElement(name = "incidentchartdashlet", type = Incidentchartdashlet.class)
})
protected List<Dashlet> dashlets;
#XmlAttribute(name = "name")
protected String name;
}
I am trying to serialize and deserialize XML in the following format:
<home>
<handle>300023</handle>
<command>login</command>
<content>
<user_id>300023</user_id>
<result>0</result>
</content>
</home>
and try to map it to the following classes:
#Data
#JacksonXmlRootElement(localName = "home")
#JsonPropertyOrder({"handle", "command", "content"})
public class Home {
private long handle;
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
visible = true,
property = "command")
#JsonSubTypes({
#JsonSubTypes.Type(value = LoginContent.class, name = "login")
})
private BaseContent content;
}
and
#Data
#JsonPropertyOrder({
"user_id",
"result"})
public class LoginContent implements BaseContent{
#JacksonXmlProperty(localName = "user_id")
private long userId;
private int result;
}
The problem occurs when I serialize with
Home home = new Home();
home.setHandle(300023);
LoginContent content = new LoginContent();
content.setUserId(300023);
content.setResult(0);
home.setContent(content);
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.findAndRegisterModules();
String xmlString = xmlMapper.writeValueAsString(home);
xmlString return as xml with correct fields but incorrect order as #JsonPropertyOrder
<home>
<handle>300023</handle>
<content>
<user_id>300023</user_id>
<result>0</result>
</content>
<command>login</command>
</home>
The implementing class type of content is based on the value of <command>, which is in the same level as <content>, hence the usage of JsonTypeInfo.As.EXTERNAL_PROPERTY.
Since the deserialization is working as expected, I excluded other implementing classes of BaseContent.
Now I am looking for a way I can make #JsonPropertyOrder effective with fields that is generated by #JsonTypeInfo. I have tried to add command field in Home.class, but it will result in a duplicated tag in the xml.
What would be the correct way to achieve this? Or is there other better way of doing this (serialize and deserialize mentioned xml with content varies based on command value with specific order)?
Thanks in advance.
I wish to have an XML structure like this:
<?xml version="1.0" encoding="UTF-8"?>
<MSG>
<CASE>
<Field1></Field1>
<Field2></Field2>
</CASE>
</MSG>
The problem is, with the #XmlElementWrapper, I need a collection of items but there will be only 1 case item. How can I have multiple root elements, for a single collection of elements? Preferably in a single class.
I want something like this, but it throws an exception.
#XmlRootElement( name="MSG")
public class XMLStructure {
#XmlElementWrapper(name="CASE")
#XmlElement(name = "Field1")
private String field1;
#XmlElementWrapper(name="CASE")
#XmlElement(name = "Field2")
private String field2;
}
In the EclipseLink MOXy implementation of JAXB (JSR-222) we have an #XmlPath extension that enables you to map this as:
#XmlRootElement( name="MSG")
#XmlAccessorType(XmlAccessType.FIELD)
public class XMLStructure {
#XmlPath("CASE/Field1/text()")
private String field1;
#XmlPath("CASE/Field2/text()")
private String field2;
}
For More Information
I have written more about the #XmlPath extension on my blog:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html