I'm trying to serialize object to xml string with Jackson XmlMapper. My object is:
#JacksonXmlRootElement(namespace = "http://www.w3.org/2001/XMLSchema", localName = "PersonRO")
public class PersonInfo {
#JacksonXmlProperty(localName = "PersonID")
private String personId;
#JacksonXmlProperty(localName = "ReturnCode")
private Integer errorCode;
// getters, setters
}
I need to achieve following xml in output:
<PersonRO xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PersonID>00000000000001</PersonID>
<ReturnCode>150</ReturnCode>
</PersonRO>
The task seems easy, but first of all I have a problem with achieving multiple namespases (xmlns:xsd, xmlns:xsi), and also have empty namespaces for fields, although I don't need them at all.
So far my result is:
<PersonRO xmlns="http://www.w3.org/2001/XMLSchema">
<PersonID xmlns="">00000000000001</PersonID>
<ReturnCode xmlns="">150</ReturnCode>
</PersonRO>
So, how can I achieve exactly the same result as above, using Jackson XmlMapper?
(I've seen that you can configure XmlFactory, etc., but can not do it properly...)
If you need any clarification, please let me know and thank you in advance.
I have found the answer:
#JacksonXmlRootElement(localName = "PersonRO")
public class PersonInfo {
#JacksonXmlProperty(isAttribute = true, localName = "xmlns:xsd")
private final String xmlnsXsd = "http://www.w3.org/2001/XMLSchema";
#JacksonXmlProperty(isAttribute = true, localName = "xmlns:xsi")
private final String xmlnsXsi = "http://www.w3.org/2001/XMLSchema-instance";
#JacksonXmlProperty(localName = "PersonID")
private String personId;
#JacksonXmlProperty(localName = "ReturnCode")
private Integer errorCode;
// getters, setters
}
Related
so as you can see from the title my #JsonPropertyOrder is not ordering how I want... this is my class(see code bellow) and everything is ordered good except the zpp attribute, it goes between "spravce" and "ziskatele". I tried to rename it reorder it and its totally ignored.Thank you for all the answers :)
(JacksonXML ver 2.9.8)
#JacksonXmlRootElement(localName = "xmlroot")
#JsonPropertyOrder({"cnt-unik-id","kod-produktu","frekvence","datum-sjednani",
"pocatek","konec","spravce","ziskatele","objekty-unik-id","udaje","objekty-all","adresy","zpp"})
public class ContractDetail{
#JacksonXmlProperty(localName = "zpp")
private Integer zpplID;
#JacksonXmlProperty(localName = "cnt-unik-id")
private Integer id;
#JacksonXmlProperty(localName = "kod-produktu")
private Item product;
#JacksonXmlProperty(localName = "spravce")
private Item administrator;
#JacksonXmlElementWrapper(localName = "ziskatele")
#JacksonXmlProperty(localName = "xml-ziskatel")
private List<Customer> customers;
#JacksonXmlProperty(localName = "frekvence")
private Item frequency;
#JacksonXmlProperty(localName = "datum-sjednani")
private Item createdAt;
#JacksonXmlProperty(localName = "pocatek")
private Item startDate;
#JacksonXmlProperty(localName = "konec")
private Item endDate;
#JacksonXmlElementWrapper(localName = "objekty-unik-id")
#JacksonXmlProperty(localName = "int")
private List<Integer> vehicle;
#JacksonXmlProperty(localName = "xml-hodnota")
#JacksonXmlElementWrapper(localName = "udaje")
private List<Item> values;
#JacksonXmlProperty(localName = "xml-objekt")
#JacksonXmlElementWrapper(localName = "objekty-all")
private List<ObjectItem> objects;
#JacksonXmlElementWrapper(localName = "adresy")
#JacksonXmlProperty(localName = "xml-adresa")
private List<AddressItem> address;
//getters setters contructors stuff
}
Use the Java field names, instead of the XML element names.
For example, using a simplified version of your ContractDetail class:
Using this:
#JsonPropertyOrder({"id", "vehicle", "zpplID"})
Generates this:
<xmlroot>
<cnt-unik-id>123</cnt-unik-id>
<objekty-unik-id>
<int>678</int>
<int>789</int>
</objekty-unik-id>
<zpplID>456</zpplID>
</xmlroot>
And using this:
#JsonPropertyOrder({"vehicle", "zpplID", "id"})
Generates this:
<xmlroot>
<objekty-unik-id>
<int>678</int>
<int>789</int>
</objekty-unik-id>
<zpplID>456</zpplID>
<cnt-unik-id>123</cnt-unik-id>
</xmlroot>
Soo #andrewjames's answer works but If someone still needs/wants to use xml element names the solution I came up with looks like this:
#JsonPropertyOrder({"cnt-unik-id","kod-produktu","frekvence","datum-sjednani",
"pocatek","konec","spravce","ziskatele","objekty-unik-id","int","udaje","xml-hodnota","objekty-all","xml-objekt","adresy","xml-adresa","zpp"})
I have class like this:
#Root(name = "address_v1", strict = false)
public class AddressItem {
#Attribute(name = "idAddress")
private Long addressId;
#Attribute(name = "idClient")
private Long clientId;
...
}
And I have response:
...
<ax23:address xsi:type="ax24:AddressItem">
<ax24:addressId>1111</ax24:addressId>
<ax24:clientId>1109</ax24:clientId>
...
But I need:
<ax23:address xsi:type="ax24:AddressItem">
<ax24:idAddress>1111</ax24:idAddress>
<ax24:idClient>1109</ax24:idClient>
Annotation #Attribute(name = "idAddress") doesn't work. (org.simpleframework.xml.Attribute).
I use wsdl2java as wsdl creator.
try with following steps and modify your POJO class as given below,
use #Element annotation for XML Element instead of #Attribute annotation (please refer to documentation for more info)
The Element annotation is used to represent a field or method that
appears as an XML element.
set the relevant xml element names to #Root and #Element annotations
AddressItem.java
#Root(name = "ax23:address", strict = false)
public class AddressItem {
#Element(name = "ax24:addressId")
private Long addressId;
#Element(name = "ax24:clientId")
private Long clientId;
...
}
I like to store a object like:
#Table(value = "my_table")
public class MyTableDto {
#PrimaryKeyColumn(name = "uid", type = PrimaryKeyType.PARTITIONED)
#CassandraType(type = DataType.Name.UUID)
private UUID uid;
#Column(value = "child_ids")
private List<ChildIdDto> childIds;
}
Then I get the exception:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Only primitive types are allowed inside Collections for property [childIds] of type ['interface java.util.List'] in entity [de.myapplication.repository.dto.MyTableDto]
I do understand the exception, but is there another way to persist custom objects?
EDIT:
When I comment out this attribute, everything works
! Never say never, I got the solution.
To give a good example, I will list all according classes.
ParentClass.java
#Table(value = "my_table") //OPT
public class MyTableDto {
#PrimaryKeyColumn(name = "uid", type = PrimaryKeyType.PARTITIONED)
#CassandraType(type = DataType.Name.UUID)
private UUID uid;
#Column(value = "child_ids") //OPT
private List<ChildDto> childIds;
}
ChildDto.java
#UserDefinedType // THE SOLUTION
public class ChildDto {
#Column(value = "child") //OPT
#CassandraType(type = DataType.Name.TEXT) //OPT
private String groupId;
#Column(value = "description") //OPT
#CassandraType(type = Name.TEXT) //OPT
private String description;
}
The #UserDefinedType is the solution.
For more information see here.
NOTE: Each annotation with "OPT" is NOT required
I have some XML that I want to turn into an object using Jackson FasterXML. The XML looks like this:
<services>
<service id="1" name="test">
<addresses>
<postalAddress id="2" line1="123 Fake Street" city="Springfield" />
</addresses>
</service>
</services>
I am deserializing this as an object successfully with these classes:
JsonIgnoreProperties(ignoreUnknown = true)
#JacksonXmlRootElement(localName = "services")
public class ServiceWrapper {
#JacksonXmlProperty(localName = "service")
private Service service;
//Getters and setters [...]
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Service {
#JacksonXmlProperty(isAttribute = true)
private int id;
#JacksonXmlProperty(isAttribute = true)
private String name;
#JacksonXmlProperty(localName = "addresses")
private AddressWrapper addresses;
//Getters and setters [...]
}
public class AddressWrapper {
#JacksonXmlProperty(localName = "postalAddress")
private List<Address> addresses;
//Getters and setters [...]
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class Address {
#JacksonXmlProperty(isAttribute = true, localName = "id")
private int id;
#JacksonXmlProperty(isAttribute = true, localName = "line1")
private int address1;
#JacksonXmlProperty(isAttribute = true, localName = "city")
private int city;
//Getters and setters [...]
}
And the code to do the mapping:
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
ObjectMapper mapper = new XmlMapper(module);
mapper.registerModule(new JSR310Module());
mapper.configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true);
ServiceWrapper serviceWrapper = mapper.readValue(xmlString, ServiceWrapper.class);
return serviceWrapper.getService();
This all works fine, but it's a lot of overhead and ugly code to have the ServiceWrapper and AddressWrapper classes; when really all I want is the data in the <service> node and <postalAddress> node. Is it possible to tell the Jackson object to directly populate a list of Addresses in my Service class without having the AddressWrapper class to represent the <addresses> node? Similarly to take the entire xml and populate a Service class directly without needing a ServiceWrapper class?
The normal way to avoid writing/maintaining such code is to use JAXB to generate the Java code (with appropriate annotations). This process uses an XML schema (.xsd) as the input, with an optional bindings file (.xjb) to customize the generated code.
It looks like many of the JAXB annotations are supported by Jackson.
I will also note that JAXB code generator (xjc) supports plugins that allow you to do pretty much anything you want to augment the generated code (e.g., with additional methods or annotations).
I have a JSON string which will be of the following format:
{
"response": {
"execution_status": "ready",
"report": {
"cache_hit": true,
"created_on": "2013-07-29 08:42:42",
"fact_cache_error": null,
"fact_cache_hit": true,
"header_info": null,
"name": null,
"report_size": "5871",
"row_count": "33",
"url": "report-download?id=278641c223bc4e4d63df9e83d8fcb4e6"
},
"status": "OK"
}
}
The response part of the JSON is common for a bunch of response types. The report part of this JSON holds good only for this response. So I had created a Response class as shown below with getters and setters (have not included the getters and setters here for brevity):
#JsonRootName(value = "response")
public class Response implements Serializable {
private static final long serialVersionUID = -2597493920293381637L;
#JsonProperty(value = "error")
private String error;
#JsonProperty(value = "error_code")
private String errorCode;
#JsonProperty(value = "error_id")
private String errorId;
#JsonProperty(value = "error_description")
private String errorDescription;
#JsonProperty(value = "method")
private String method;
#JsonProperty(value = "service")
private String service;
#JsonProperty(value = "status")
private String status;
#JsonProperty(value = "execution_status")
private String executionStatus;
}
And then, I created a Report class with the fields in the report element as below. The ReportResponse class will extend from the Response class (again the getters and setters are not included for brevity):
public class ReportResponse extends Response {
private static final long serialVersionUID = 4950819240030644407L;
#JsonProperty(value = "cache_hit")
private Boolean cacheHit;
#JsonProperty(value = "created_on")
private Timestamp createdOn;
#JsonProperty(value = "fact_cache_error")
private String factCacheError;
#JsonProperty(value = "fact_cache_hit")
private Boolean factCacheHit;
#JsonProperty(value = "header_info")
private String headerInfo;
#JsonProperty(value = "json_request")
private String jsonRequest;
#JsonProperty(value = "name")
private String name;
#JsonProperty(value = "report_size")
private Integer reportSize;
#JsonProperty(value = "row_count")
private Integer rowCount;
#JsonProperty(value = "url")
private String url;
}
Now when I use the ObjectMapper to map to the ReportResponse object, I get the following error:
String jsonString = "{\"response\": {\"execution_status\": \"ready\", \"report\": {\"cache_hit\": true, \"created_on\": \"2013-07-29 09:53:44\", \"fact_cache_error\": null, \"fact_cache_hit\": false, \"header_info\": null, \"name\": null, \"report_size\": \"5871\", \"row_count\": \"33\", \"url\": \"report-download?id=2ff62c07fc3653b68f2073e7c1aa0517\"}, \"status\": \"OK\"}}";
ObjectMapper mapper = new ObjectMapper();
ReportResponse reportResponse = mapper.readValue(jsonString, ReportResponse.class);
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "report"
I know that I can create a separate Report class and then embed it in the ReportResponse with the #JsonProperty anotation. Is there a way I can avoid that and mark the ReportResponse class with an annotation which would map it to the "report" element in the JSON?
There is no annotation which could handle this case yet. There is a ticket requesting this feature.
Here is a brief statement from one of the owners regarding this topic.
Quote from the mentioned statement:
Tatu Saloranta: "… #JsonProperty does not support transformations, since the data binding is based on incremental parsing and does not have access to full tree representation. Supporting #JsonUnwrapped was non-trivial, but doable; and thus converse ("#JsonWrapped") would be doable, theoretically speaking. Just plenty of work. …"
I see couple of problems in your code. First thing is that you don't have report attribute in your Response class, which is required as per the json structure you have shown. Secondly you need to provide the getters and setters in your bean classes as those will be used by the jackson for marhsalling and unmarshalling of json/object.