Jackson XmlMapper generates wrong XML entries order - java

I have an issue with generating a XML string with the Java Jackson XmlMapper: It generates the wrong order of entries in the XML string, nevertheless I use #JsonPropertyOrder and the members are in the needed order inside the class.
Please see my code:
#JsonPropertyOrder({ "craneNumber", "moveType", "reference", "unitNumber", "ISOCode", "IMOLabels", "seal", "doorDirection" })
public class OcrDataResultUnit {
#JacksonXmlElementWrapper(localName="unit")
private String craneNumber;
private String moveType;
private String reference;
private String unitNumber;
#JsonProperty("ISOCode")
private String isoCode;
#JacksonXmlElementWrapper(localName="IMOLabels")
#JsonProperty("DGSIMOClass")
private List<String> imoLabels = new ArrayList<>();
#JsonProperty("seal")
private String seal;
#JsonProperty("doorDirection")
private String doorDirection;
// all getters and setters ...
Usage:
XmlMapper mapper = new XmlMapper();
String msgXml = mapper.writeValueAsString(this);
Result:
<unit>
<craneNumber>QC01</craneNumber>
<moveType>D</moveType>
<reference>12345678901234567890123456789012</reference>
<unitNumber>ABCD00001234</unitNumber>
<ISOCode>22G1</ISOCode>
<seal>Y</seal>
<doorDirection>H</doorDirection>
<IMOLabels>
<DGSIMOClass>1.5</DGSIMOClass>
<DGSIMOClass>2.1</DGSIMOClass>
</IMOLabels>
</unit>
I get the same result without the #JsonProperty on the last to members. That was a try.
The structure is part of a bigger XML structure.
Also replaced #JsonProperty with #JacksonXmlProperty: Same result.
As far as I see #JsonPropertyOrder is correct to be used for XML as well.
Does anybody have an idea?
Maybe I am just blind - actually I hope so :-)
Thank you and best regards

In your JsonPropertyOrder annotation, the property is called "DGSIMOClass", not "IMOLabels". You should switch it out for the correct name.

Related

Issue with deserializing JSON using Jackson

I have such JSON
{"body":{"result":[{"crossStateId":1,"raceId":181564,"withOfficer":1,"documents":[{"indexed":0,"documentNumber":"zzz","isMain":1,"documentTypeId":6,"serverId":16,"countryId":327,"useDate":"2017-02-07T19:31:51.000+0000","documentSubTypeId":6,"crossId":5018177,"documentId":44973231,"personId":222,"infinity":0,"documentValid":"2023-08-25T20:00:00.000+0000"}],"directionId":2,"documentNumber":"sss","operatorUsername":"AIRPORT_84","crossDate":"2017-02-07T19:31:51.000+0000","serverId":16,"crossTypeId":1,"crossRegisterDate":"2017-02-07T19:31:52.818+0000","officerNote":"","children":[],"personNote":"","crossId":5018177,"workplaceId":82,"divisionId":2,"race":{"carriageContainer":0,"raceId":181564,"raceStateId":1,"directionId":2,"creatorId":415,"countryId":327,"transportIdByType":605,"raceDateTime":"2017-02-07T19:20:58.000+0000","raceNumber":"841 sss sss","creatorUsername":"AIRPORT_8","divisionId":2,"transportTypeId":3,"createDate":"2017-02-07T19:20:58.000+0000"},"syncState":0,"autos":[],"userId":491,"raceNumber":"841 sss sss","operatorNote":"","person":{"firstNameEn":"JUMBERI","indexed":1,"lastNameGe":"ჩოხელი","genderId":2,"personId":6027803,"personalNumber":"222","countryNameGe":"sss","birthDate":"1963-06-14T20:00:00.000+0000","lastNameEn":"sss","countryId":327,"firstNameGe":"sss"},"airplane":{"raceNumber":"841 sss sss","airCompanyId":1,"airplaneId":605,"airportId":5657,"bortNumber":"01","transportSubTypeId":78,"countryId":360},"underAge":0,"personId":6027803,"decisionId":22}],"total":8264},"errorCode":0}
I would like to deserialize it to Java class but I am interested in only some JSON fields. Anyway here are the model classes:
public class Response implements Serializable {
private Body body;
private long errorCode;
}
public class Body implements Serializable {
Result result[];
}
public class Result implements Serializable {
private long crossStateId;
private long raceId;
private Person person;
private Child children [];
private Auto autos[];
}
etc.
But for some reason I get following exception:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "body" (Class com.demo.Response), not marked as
ignorable at [Source: java.io.StringReader#6483f5ae; line: 1, column:
10] (through reference chain: com.demo.Response["body"])
Here is code(the JSON string is correctly received and has same format as I initially mentioned in the beginning):
String res = MainProgram.sendGet("someURL");
ObjectMapper objectMapper = new ObjectMapper();
Response ob = objectMapper.readValue(res, Response.class);
I would appreciate some help.
You need to create getters and setters for the fields, and you should add annotations to your fields.
Annotation:
#JsonProperty(value = "body")
private Body body;
Doing one of above will make it work.
Sidenote:
You can create your pojos from json automatically with http://www.jsonschema2pojo.org/. Just paste it in and download it, or use one of their plugins.
As mentioned by others, private fields are not auto-detect by default, so either:
Annotating fields with #JsonProperty OR
Adding setter
is needed for deserialization.
However, there is another possibility: you can use annotations #JsonAutoDetect to change minimum visibility needed, and here enable discovery of ALL fields.
Or you can even change the defaults used via ObjectMapper method (something like setVisibility(...)).

Unmarshalling json by reversing the affect of #XmlElement renaming?

I have a class defined as follows:
public class Contact implements Serializable
{
private final static long serialVersionUID = 1L;
#XmlElement(name = "last-name", required = true)
protected String lastName;
#XmlElement(name = "first-name", required = true)
protected String firstName;
#XmlElement(required = true)
protected String id;
#XmlElement(name = "primary-phone")
protected String primaryPhone;
#XmlElement(name = "cellular-phone")
protected String cellularPhone;
}
This class is being used to generate marshalled JSON versions which are communicated over the internet. On the receiving end I'm trying to unmarshall the JSON, but I'm having difficulty because of the difference in naming, i.e. for example the unmarshalling library expects a variable named primaryPhone, not primary-phone which is what I have at the receiving end.
Besides pre-processing the received JSON text to manually replace instances of primary-phone with primaryPhone, is there some other more automated way to avoid this problem ? The problem with manually converting strings is that tomorrow if the Class definition changes, the code I'm writing will also need to be updated.
Here's a code snippet showing what I'm currently doing without any manually string conversion:
String contact = "\"last-name\": \"ahmadka\"";
ObjectMapper objMapper = new ObjectMapper();
Contact cObj = objMapper.readValue(contact, Contact.class);
But with the above code I get an exception on the last line reading this:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "last-name" (class Contact), not marked as ignorable (5 known properties: "lastName", "cellularPhone", "id", "primaryPhone", "firstName", ])
at ...........//rest of the stack
Jackson by default doesn't know about JAXB annotations (i.e. #XmlRootElement). It needs to be configured with an external module in order to have this capability. On the server, you most likely have this without even knowing it.
On the client side if you want to configure the ObjectMapper, then you need to add the following module:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson2.version}</version>
</dependency>
Then just register the JAXB annotations module.
ObjectMapper objMapper = new ObjectMapper();
mapper.registerModule(new JaxbAnnotationModule());

Jackson JSON XML - different names when serializing to XML

I'd like to have different name for my element when it's serialized to XML (for example "fooXml") and different for JSON (for example "fooJson"). Is it possible?
I'm using XML annotations like:
#XmlElements({
#XmlElement(type = Foo.class, name = "fooXml"),
})
private SortedSet<Foo> fooSet;
I've tried already #JsonProperty, with without any luck.
I've also tried exporting it to getter method, like:
#XmlElement(type = Foo.class, name = "fooXml")
#JsonProperty(value = "fooJson")
public List<Foo> getFooList() {
return new ArrayList<>(fooSet);
}
But it's always ignoring JSON annotations and serializing to XML form (fooXml name).
How shall I do it?
edit: I'm using Jersey-json.
Alright, I had a need for this same functionality and found a solution that works for this:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
#JsonProperty("MyJsonName")
#JacksonXmlProperty(localName = "MyXmlName")
private MyProperty myProperty;
Works for me, and myProperty will be in the 'MyJsonName' field in Json and the 'MyXmlName' in XML.

Want to hide some fields of an object that are being mapped to JSON by Jackson

I have a User class that I want to map to JSON using Jackson.
public class User {
private String name;
private int age;
private int securityCode;
// getters and setters
}
I map this to a JSON string using -
User user = getUserFromDatabase();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(user);
I don't want to map the securityCode variable. Is there any way of configuring the mapper so that it ignores this field?
I know I can write custom data mappers or use the Streaming API but I would like to know if it possible to do it through configuration?
You have two options:
Jackson works on setters-getters of fields. So, you can just remove getter of field which you want to omit in JSON. ( If you don't need getter at other place.)
Or, you can use the #JsonIgnore annotation of Jackson on getter method of that field and you see there in no such key-value pair in resulted JSON.
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
Adding this here because somebody else may search this again in future, like me. This Answer is an extension to the Accepted Answer
You have two options:
1. Jackson works on setters-getters of fields. So, you can just remove getter of field which you want to omit in JSON. ( If you don't need getter at other place.)
2. Or, you can use the `#JsonIgnore` [annotation of Jackson][1] on getter method of that field and you see there in no such key-value pair in resulted JSON.
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
Actually, newer version of Jackson added READ_ONLY and WRITE_ONLY annotation arguments for JsonProperty. So you could also do something like this.
#JsonProperty(access = Access.WRITE_ONLY)
private String securityCode;
instead of
#JsonIgnore
public int getSecurityCode(){
return securityCode;
}
you also can gather all properties on an annotation class
#JsonIgnoreProperties( { "applications" })
public MyClass ...
String applications;
If you don't want to put annotations on your Pojos you can also use Genson.
Here is how you can exclude a field with it without any annotations (you can also use annotations if you want, but you have the choice).
Genson genson = new Genson.Builder().exclude("securityCode", User.class).create();
// and then
String json = genson.serialize(user);
Field Level:
public class User {
private String name;
private int age;
#JsonIgnore
private int securityCode;
// getters and setters
}
Class Level:
#JsonIgnoreProperties(value = { "securityCode" })
public class User {
private String name;
private int age;
private int securityCode;
}
if you are using GSON you have to mark the field/member declarations as #Expose and use the GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
Don't forget to mark your sub classes with #Expose otherwise the fields won't show.
I suggest you use this.
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private int securityCode;
This allows you to set the value of securityCode(especially if you use lombok #Setter) and also prevent the field from showing up in the GET request.
I had a similar case where I needed some property to be deserialized (JSON to Object) but not serialized (Object to JSON)
First i went for #JsonIgnore - it did prevent serialization of unwanted property, but failed to de-serialize it too. Trying value attribute didn't help either as it requires some condition.
Finally, working #JsonProperty with access attribute worked like a charm.

Save List as Strings with Java XML Annotations

I need to save some variables in a simple class using Java's XML Annotations: http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/package-summary.html
Currently the class is pretty simple and looks like this:
#XmlRootElement
public class Chart {
#XmlElement
public String url;
#XmlElement
public String values;
#XmlElement
public String projectOrFilterName;
#XmlElement
public String countComplains;
public Chart(String url, String values, String projectOrFilterName, String countComplains) {
this.url = url;
this.values = values;
this.projectOrFilterName = projectOrFilterName;
this.countComplains = countComplains;
}
}
Now I need to save the data of a list as string variables with annotations like the existing ones. Im giving the constructor some kind of a list, let's say
List<Object>
The question is, how to extract all the variables out of it, and save their toString() representations with the given XML Annotations. If that's simpler one could assume, I get a List of Strings.
Can somebody please help me with this?
Who could have known, it would be that simple ;-)
#XmlElement
public List<String> data;
That's just, what I needed. The java script part, interpreting the xml creates an array out of the list's elements and everything is fine.
Thanks for your time thinking over my question!

Categories

Resources