ObjectMapper convert to arraylist not preserving order - java

I have a json like:
{ "results": [
{
"message_id": "1"
},
{
"message_id": "2"
}
]}
When i use jackson object mapper the json returned to my collection doesnt preserve the order of messageid_1 and message id_2.
Following is my Objectmapper code:
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.readValue(json, Response.class);
Following is my Response.class
public class Response implements Serializable {
#JsonProperty("results")
LinkedList<Object> results;
public LinkedList<Object> getResults() {
return results;
}
public void setResults(LinkedList<Object> results) {
this.results = results;
}
}
Please help me a way to preserve the order of json objects in the array[Not the property order ,i meant objects order]

In version 2.11.2 the order of JSON is respected

Related

Map dynamic JSON data to pojo class in Java?

I am creating a crud form in which I am producing and consuming Json data.
Problem:
Json data I am producing is very dynamic. So I don't know how to map it to my pojo class.
What I have tried
1) Using jackson library, I created structure of my json data and
tried mapping with it. It failed as in data "**Keys**" are dynamic so mapping failed.
2) I searched and found JsonNode provided by Jackson, problem with
this is my json structure has key:[{},{}] structure like this
**key-->array of objects**, so I tried parsing it with json node but failed.
My Json Data
Type 1
{
"city_master": [
{
"citycode": [
"100",
"1130385"
]
},
{
"cityname": [
"London",
"1130383"
]
},
{
"statecode": [
"512",
"1130382"
]
}
]
}
Problem with structure is that key = "city_master" or any key in this format eg("citycode", "cityname" etc) is dynamic so can't create mapping pojo for this class.
Then I tried fixing the outer key as root and parse is as Json Node as
Type 2
{
"root": [
{
"citycode": [
"100",
"1130385"
]
},
{
"cityname": [
"London",
"1130383"
]
},
{
"statecode": [
"512",
"1130382"
]
}
]
}
In this structure I loose my key value, but I can store it else where.
With JsonNode (Type-2) I tried this
String jsonString = tdObj.getTempData(); // return's Json String
TempDataTblPojo obj = new ObjectMapper().readValue(jsonString, TempDataTblPojo.class);
JsonNode jsonNode = obj.getRoot();
System.out.println("Name = " + jsonNode);
This class TempDataTblPojo
public class TempDataTblPojo {
private JsonNode root;
public JsonNode getRoot() {
return root;
}
public void setRoot(JsonNode root) {
this.root = root;
}
}
It prints this
Name = [{"citycode":["100","1130385"]},{"cityname":["London","1130383"]},{"statecode":["512","1130382"]}]
Now how to parse this JsonNode, to get all this key-value's? Or is there is efficient or much more cleaner solution, I will be happy to accept.
Maybe this will help you.
class Pojo {
private List<PojoItem> root;
public List<PojoItem> getRoot() {
return root;
}
public void setRoot(List<PojoItem> root) {
this.root = root;
}
}
class PojoItem {
private Map<String, List<String>> items = new HashMap<>();
public Map<String, List<String>> getItems() {
return items;
}
#JsonAnySetter
public void setItem(String key, List<String> values) {
this.items.put(key, values);
}
}
And then you can get it from json using this:
Pojo result = objectMapper.readValue(json, Pojo.class);

Deserialize Lists and Objects to the same Structure with Jackson

As input for my Application I might get either a single JsonObject, or a List of them:
input1 = [ { "prop": "val1" }, { "prop": "val2" } ]
input2 = { "prop": "val" }
I can use JsonNode as target type for both inputs
objectMapper.readValue(input1, JsonNode.class);
objectMapper.readValue(input2, JsonNode.class);
And then evaluate whether the root node is a ArrayNode or ObjectNode.
I seek a way to define my custom target type, like a List<MyObject> which has one Element if a JsonObject is provided, or zero to multiple, if a List is provided.
objectMapper.readValue(input, new TypeRef<ArrayList<MyObject>>() {});
however fails for the single object - it can not construc an Array-Type from {.
I was trying to create my own type:
public class MyList extends ArrayList<MyObject> {
public String prop;
#JsonCreator
public MyList(String prop) {
super();
this.prop = prop; // Resp add(new MyObject(prop));
}
public MyList() {}
}
But Jackson refuses to use the JsonCreator for single objects.
Is there any way, I could do that (ideally without a custom serializer, unless that one can be made pretty generic)
Of course, Jackson has an easy solution for that:
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY to your help!
#EqualsAndHashCode
public class Example {
#JsonProperty public String name
}
#Test
public void experiment() {
ObjectMapper om = new ObjectMapper();
om.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
String list= "[{ \"name\": \"peter\" }]";
String single= "{ \"name\": \"peter\" }";
List<Example> respList = om.readValue(list, new TypeReference<List<Example>>() {});
List<Example> respSingle = om.readValue(single, new TypeReference<List<Example>>() {});
Assert.assertEquals(respList, respSingle)
}

How parse nested escaped json with Jackson?

Consider json:
{
"name": "myName",
"myNestedJson": "{\"key\":\"value\"}"
}
Should be parsed into classes:
public class MyDto {
String name;
Attributes myNestedJson;
}
public class Attributes {
String key;
}
Can it be parsed without writing stream parser? (Note that myNestedJson contains json escaped json string)
I think you can add a constructor to Attributes that takes a String
class Attributes {
String key;
public Attributes() {}
public Attributes(String s) {
// Here, s is {"key":"value"} you can parse it into an Attributes
// (this will use the no-arg constructor)
try {
ObjectMapper objectMapper = new ObjectMapper();
Attributes a = objectMapper.readValue(s, Attributes.class);
this.key = a.key;
} catch(Exception e) {/*handle that*/}
}
// GETTERS/SETTERS
}
Then you can parse it this way:
ObjectMapper objectMapper = new ObjectMapper();
MyDto myDto = objectMapper.readValue(json, MyDto.class);
This is a little dirty but your original JSON is too :)

How Jackson-Creating a JsonObject

I want to create a JsonObject like this:
{
Response: 200,
Lists: [
{
Test: "Math",
Result: "6",
Credit: "3"
},
{
Test: "C++",
Result: "10",
Credit: "6"
}
]
}
I know create this with lib org.json but with Jackson? i try to use
JsonNodeFactory nodeFactory = new JsonNodeFactory();
but i have this problem
The constructor JsonNodeFactory() is not visible
Make sure to use the latest version of Jackson. They moved from codehaus to FasterXML: http://wiki.fasterxml.com/JacksonHome.
You don't need to instantiate the factory. You can use the public static one: com.fasterxml.jackson.databind.node.JsonNodeFactory.instance.
JsonNodeFactory factory = JsonNodeFactory.instance;
ObjectNode root = factory.objectNode();
root.put("Response", 200);
ArrayNode list = factory.arrayNode();
list.add(...);
...
root.set("List", list);
Note that Jackson is a great library to map Java POJOs to JSON (and back). Rather than creating the JSON structure by hand, you can create Java classes that Jackson will serialize to JSON:
public class Item {
#JsonProperty("Test")
private String test;
#JsonProperty("Result")
private String result;
#JsonProperty("Credit")
private String credit;
}
public class Root {
#JsonProperty("Response")
private int response;
#JsonProperty("List")
private List<Item> list;
}
public static void main(String[] args) {
Root root = new Root();
...
String json = new ObjectMapper().writeValueAsString(root)
}
To create a JsonNode object use ObjectMapper. For example:
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readValue(JSON_STRING, JsonNode.class)
Refer to the Jackson documentation for information.

How do I configure the the jackson objectmapper to correctly deserialize to pojo?

I'm having a bit of a problem understanding how i should configure the objectMapper and pojo when deserializing. My Json is created by another application that
supports both xml and json. It returns a list with myobject, but the Json contains the type, like this:
[
{
"myobject": {
"somethingcool": "amazing",
"contactPersonsForMyObject": [
"test.test#gmail.com",
"test#test.se"
],
"myObjectId": "c85e48730501bfae41e67714c6131b7d"
}
},
{
"myobject": {
"somethingcool": "cool",
"contactPersonsForMyObject": [
"test.test2#gmail.com",
"test#test2.se"
],
"myObjectId": "c85e48730501bfae41e67714cqwerty"
}
}
]
My class:
public class MyObject {
private String myObjectId;
private String somethingcool;
private List<String> contactPersonsForMyObject;
public String getMyObjectId() {
return myObjectId;
}
public void setMyObjectId(String myObjectId) {
this.myObjectId = myObjectId;
}
public String getSomethingcool() {
return somethingcool;
}
public void setSomethingcool(String somethingcool) {
this.somethingcool = somethingcool;
}
public List<String> getContactPersonsForMyObject() {
return contactPersonsForMyObject;
}
public void setContactPersonsForMyObject(List<String> contactPersonsForMyObject) {
this.contactPersonsForMyObject = contactPersonsForMyObject;
}
}
But when doing:
List<MyObject> myObjects = mapper.convertValue(rootNode, new TypeReference<List<MyObject>>() {});
I'm getting a exception stating:
java.lang.IllegalArgumentException: Unrecognized field "myobject" (Class com.domain.MyObject), not marked as ignorable
at [Source: N/A; line: -1, column: -1] (through reference chain: com.domain.MyObject["myobject"])
It's like the mapper do not understand the extra "layer".
When serializing to get this structure it is possible to configure the mapper like this: mapper.configure(SerializationConfig.Feature.WRAP_ROOT_VALUE, true);
So there should be somehow to do the reverse?
Thank you!
You need to give it concrete classes and not interfaces. So
List<Map<String, MyObject>> myObjects = mapper.readValue(json, new TypeReference<ArrayList<HashMap<String, MyObject>>>() {
});
What you need is to use #JsonTypeInfo annotation on type (class), which will include additional type information. In your case it looks as if you wanted to include a type id as property key.
If so, inclusion method should be "as wrapper object", and you will also need to define what type id of "myobject" binds to -- this can be done by adding #JsonTypeName("myobject") for MyObject class (it needs to be included in subtype of whatever has #JsonTypeInfo, but in this case both would be added for the same class).
Your json has an extra level of nesting: you have a list of Maps of Strings to MyObjects, not a List of MyObjects. You'd need to read it like this:
List<Map<String, MyObject>> myObjects = mapper.readValue(json, new TypeReference<List<Map<String, MyObject>>>() {
});
Or else change whatever is generating this json to ditch the inner Map (IMHO that'd be better).
Change List<String> to ArrayList<String>
and then
MyObject myObject = mapper.readValue(json, MyObject.class);
Add the following constructor to MyObject class
#JsonCreator
public MyObject(#JsonProperty("myObjectId") String myObjectId,
#JsonProperty("somethingcool") String somthingcool,
#JsonProperty("contact") ArrayList<String> contactPersonsForMyObject) {
this.myObjectID = myObjectId;
this.somethingcool = somethingcool;
this.contactPersonsForMyObject = contactPersonsForMyObject;
}
and change the return value for the getter to ArrayList

Categories

Resources