custom serilization in GSON library for list - java

I am using custom serialization/deserialization in GSON. for that i have custom gsonAdapter. i am using custom because of difference in property names.
My class :
public class Emp {
String name;
String age;
}
and my json payload :
{
"xyz/abc/name": "abc",
"xyz/abc/age": "10"
}
now i am having problem while converting my list of json to class.
[{
"xyz/abc/name": "abc",
"xyz/abc/age": "10"
},
{
"xyz/abc/name": "xyz",
"xyz/abc/age": "20"
}]
tried using
Type listType = new TypeToken<ArrayList<Emp>>(){}.getType();
List<Emp> yourClassList = new Gson().fromJson(jsonArray, listType)
but it returns Emp object with all fields initialized as null.
so not able to figure out what else i need to do, if anyone can throw light on the parts i am missing.

Related

Deserialize JSON with repeating keys to a list inside Java Object

If an "action" key-value pair is repeated, I want to append each associated "myObject" to a list as shown below. Is there a way to achieve this using GSON or JACKSON? Unfortunately, there is no option to edit the input JSON. If the ask is not clear, please let me know.
Input
[
{
myObject: {
name: "foo",
description: "bar"
},
action: "create",
},
{
myObject: {
name: "baz",
description: "qux"
},
action: "create",
},
];
Required Output
{
"action": "create",
"myObject": [
{
name: "foo",
description: "bar"
},
{
name: "baz",
description: "qux"
},
]
};
I am new to JSON parsing in Java and unfortunately haven't found a use case like mine on StackOverflow. I have tried configuring my ObjectMapper like so -
new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
and using
#JsonAnySetter
annotation, but haven't gotten them to work yet.
You could solve this with two separate model classes, one for the original structure and one for the transformed one. For simplicity I call them OriginalModel and TransformedModel below, you should probably pick more meaningful names. The following code uses Gson but you can probably achieve something similar with Jackson as well.
class OriginalModel {
String action;
MyObjectData myObject;
}
class TransformedModel {
String action;
List<MyObjectData> myObject;
public TransformedModel(String action, List<MyObjectData> myObject) {
this.action = action;
this.myObject = myObject;
}
}
class MyObjectData {
String name;
String description;
}
If you declare these classes as nested classes you should make them static.
Then you can first parse the JSON data with the original model class, manually create the desired result structure using the transformed class and serialize that to JSON:
Gson gson = new Gson();
List<OriginalModel> originalData = gson.fromJson(json, new TypeToken<List<OriginalModel>>() {});
// Group MyObjectData objects by action name
// Uses LinkedHashMap to preserve order
Map<String, List<MyObjectData>> actionsMap = new LinkedHashMap<>();
for (OriginalModel model : originalData) {
actionsMap.computeIfAbsent(model.action, k -> new ArrayList<>())
.add(model.myObject);
}
List<TransformedModel> transformedData = new ArrayList<>();
for (Map.Entry<String, List<MyObjectData>> entry : actionsMap.entrySet()) {
transformedData.add(new TransformedModel(entry.getKey(), entry.getValue()));
}
String transformedJson = gson.toJson(transformedData);

Unable to parse json into list of custom Java objects

I am reading JSON from a file, and when trying to unmarshal the file to a java object, I am not getting expected array of custom Java object, however, getting array of LinkedHashMap
Please see below objects
public class Result<T>{
private final Map<String, T> data = new LinkedHashMap<>();
public Map<String, T> getAccounts(){
return accounts;
}
}
JSON ->
{
"data":{
"account":[
{
"accountDetails":{
"accountId":"123",
"accountType":"Decon"
}
},
{
"accountDetails":{
"accountId":"890",
"accountType":"ACX"
}
},
{
"accountDetails":{
"accountId":"123",
"accountType":"OOOP"
}
}
]
}
}
#Getter
#Setter
#ToString
public class Accounts{
#Getter
#Setter
public static class AcountDetails{
private String accountId;
private String accountType;
}
}
I am trying to read this Json as below
String accounts = Resource.asByteSource(Resources.getResource("account.json")).asCharSource(Charsets.UTF_8).read();
ObjectMapper mapper = new ObjectMapper();
Result<List<Accounts> finalResult = mapper.readValue(accounts, Result.class);
In finalResult variable ,
I am getting a map with key as "account" and value as list
But, instead of List of "Accounts" object, I am getting list of **LinkedHashMap**
So bascially after parsing, Instead of getting array of Accounts objects, I am getting array of LinkedHashMap
Please find attached screenshot. Please advise
If you are trying to get an Array of objects, your JSON would have to look something like this:
"element": [
{
"element1": "Value 1",
"element2": "Value 1"
},
{
"element1": "Value 1",
"element2": "Value 1"
}
]
When you are defining another object as you did:
"account":[
{
"accountDetails":{
"accountId":"123",
"accountType":"Decon"
}
},
You are creating a List of an Object that contains two more Objects. In Java that's a Map.
List<Map<AccountId, AccountType>
Hope it helps
Edit for formatting purposes if "Element1" were another Object:
"element": [
{
"element1": {
"element3": "Value",
"element4": "Value"
},
"element2": "Value 1"
},
{
"element1": "Value 1",
"element2": "Value 1"
}]
First of all can you confirm what you want to do here:
Map final Map<String, T> accounts = new LinkedHashMap<>();
inside class Result? Because if it is a variable, then remove the leading Map and don't make the variable as final.
Also you will need both setters and getters for the variable.
Secondly, your json has 'data' which has a account: [] pair, so first read value from data, then from account and you will get the list.
It worked after changing
Result<List<Accounts> finalResult = mapper.readValue(accounts, Result.class);
to
Result<List<Accounts>> finalResult = mapper.readValue(accounts, new TypeReference<Result<List<Accounts>>>() {});

Java GSON Json partial parsing

Say I have a JSON object representing an entity (can be any entity) like so:
{
"entity_id": "1",
"entity_name": "employee",
"entity_json": {
"employee_id": "e01",
"employee_name": "john",
"employee_phone_numbers": [
"1234567",
"8765433"
]
}
}
Note that entity_json can represent different entities having different structures as long as it is a valid JSON. For example, the following is another entity's representation:
{
"entity_id": "1",
"entity_name": "invoice",
"entity_json": {
"invoice_id": "1011",
"items": {
"item_id": "1",
"quantity": "3",
"price": "$100"
},
"date": "01-01-2020",
"customer": {
"id": "3",
"address": {
"street": "some_street",
"country": "CZ",
...
}
}
}
}
I want to be able to partially parse this JSON into an Entity POJO using Gson in Java. That is, I'll have an entity POJO like the one shown below:
public class Entity {
private String entity_id;
private String entity_name;
private String entity_json; // <-- entity_json is a String
// getters and setters
}
/*
* entity_json (for employee) = "{ \"employee_id\": \"1\", \"employee... }"
* entity_json (for invoice) = "{ \"invoice_id\": \"1011\", \"items... }"
*/
and I'm planning on performing any operation on entity_json using JsonPath.
Is there any way I can achieve this WITHOUT having to explicitly set entity_json in the JSON structure as a string with escapes?
Any help is appreciated here. Thanks!
You can avoid using a String for your entity_json by using Gson's JsonObject.
Here is my revised Entity class:
import com.google.gson.JsonObject;
public class MyEntity {
private String entity_id;
private String entity_name;
private JsonObject entity_json;
// getters and setters not shown
}
Then you can populate instances as follows:
MyEntity myEntityOne = new Gson().fromJson(JSON_ONE, MyEntity.class);
MyEntity myEntityTwo = new Gson().fromJson(JSON_TWO, MyEntity.class);
System.out.println(myEntityOne.getEntity_json());
System.out.println(myEntityTwo.getEntity_json());
In the above code, JSON_ONE and JSON_TWO are just strings containing the two sample JSONs from your question.
The console prints out the following (snipped for brevity):
{"employee_id":"e01","employee_name":"john","employee_phone_numbers":["1234567","8765433"]}
{"invoice_id":"1011","items":{"item_id":"1","quantity":"3","price":"$100"},"date":"01-01-2020"...
You can, of course, now use Gson to further manipulate each entity_json field as needed, since each one is itself a valid JSON object.

Java collections to JSON

My program has to output following JSON format:
{ "success": {
"code": 1,
"desc": "success" },
"response": {
"res1": [
{
"Item": "item1",
"Description": [
{
"desc": "ad1",
"active": true,
"details": [
{
"Type": "Type1",
"Count": 2,
"Status": true
},
{
"Type": "TYpe2",
"Count": 3,
"Status": false
},
]
},
{
"desc": "item2",
"active": true,
"details": [
{
"Type": "Type1",
"Count": 4,
"Active": true
}
]
},
{
"Item": "item2",
"Description": [
{
"desc": "d2",
"Active": true,
"details": [
{
"Type": "Type3",
"Count": 6,
"Active": true
},
]
},
]
}
]
}
}
I have wrote following to create this json format
HashMap<String, HashMap<String, String>> m1 = new HashMap<String, HashMap<String, String>>();
HashMap<String, String> m2 = new HashMap<String, String>();
HashMap<String, ArrayList<HashMap<String, String>>> m3 = new HashMap<String, ArrayList<HashMap<String, String>>>();
For creating the mentined JSON format, I tried to put m3 and m2 in m1. But since these are not with same type, it won't allow to put.
I am using GSON to convert the collection to JSON.
Gson gson = new Gson();
String json1 = gson.toJson(m1);
My Question is: For creating that JSON format, which collection in Java I have to use?
The best way to deal with a complex JSON structure like that is to create a class with the same structure with properties that represent the underlying arrays as lists. Then, you can use gson to convert the object(s) to JSON in a straightforward way.
In other words, instead of trying to fit the structure into a combination of complex collections or existing Java classes, create a class that is an exact representation of the data, populate it, and then convert it to JSON.
Why don't you let the code generated for you?
After the pojos are created you can of course change the code to tailor your needs.
Create a ResponseWrapper class and build your json accordingly.
Sample code:
public class ResponseWrapper<T>{
private Map<String, T> wrappedObjects = new HashMap<String, T>();
public ResponseWrapper() {
}
public ResponseWrapper(String name, T wrappedObject) {
this.wrappedObjects.put(name, wrappedObject);
}
..
..
Your json can be built like this:
ResponseWrapper response = new ResponseWrapper<ResponseWrapper>();
Items[] item = ....
//item can itself have Description, etc.
response.set("res1", (ArrayList) items);
Thanks for notepad++ and its json view plugin, i can read your json data in proper format. (although your data missing a few brackets)
In my oponion, json structure can be converted into Map but i personally don't like that idea much.
The other way to do is using Java POJO to define your JSON object and then convert it to json. Excellent example here
OK. We will check your data and create Java POJO for it. It's simple and should be something like this
public class YourJsonObj {
public SuccessObj success;
public ResponseObj response;
}
where SuccessObj and ResponseObj are another structure Classes like this:
public class SuccessObj {
public Integer code;
public String desc;
}
public class ResponseObj {
public List<ResObj> res1;
}
Another sub class appear: ResObj. All you have to do is continue define it:
public class ResObj {
public String Item; // << this property's name does't make java happy
public List<DescriptionObj> Description // << this property's name does't make java happy
}
Continue to do this definition till the end of your data. And you got it.
My suggestion is to replicate the same hierarchy of the fields in your JSON example.
By the Google Gson library you can convert (in 2 lines of code) your Java object to a JSON object. Please check the following example (from the user guide of the relative project).
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
// Serialization
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
// ==> json is {"value1":1,"value2":"abc"}

How to get XStream to map back to a typed List?

I'm using XStream to map some JSON back into Java objects. I'll be dealing with a JSON string that might look like this:
{
"widgets":[
{
"widget_name": "Kenny",
"widget_type": "Character"
},
"widget_name": "Apple",
"widget_type": "Fruit"
}
]
}
Update: I believe this JSON could be interpreted as:
This JSON represents an un-named object that contains a widgets object. The widgets object, in turn, contains an array of other un-named objects. Each of these un-named objects contain two properties: widget_name and widget_type.
Each Widget in this widgetlist corresponds to a POJO:
public class Widget {
private String name;
private String type;
// ...etc.
}
I'd like the above JSON string to map back to a List<Widget>, but I can't seem to figure out how to alias the class correctly:
XStream xs = new XStream();
xs.alias("widgetlist", List.class); // Not a List<Widget> !
How can I get the xs mapper to translate widgetlist into a List<Widget>? Thanks in advance.
This piece of code worked for me, however the JSON generated is not similar to the one you have. If you were to use the JsonHierarchicalStreamDriver instead of the JettisonMappedXmlDriver you would get the same JSON as you have in your question. Downside of this is that the JsonHierarchicalStreamDriver cannot read JSON and will give an UnsupportedOperationException if you try.
XStream xstream = new XStream(new JettisonMappedXmlDriver());
xstream.setMode(XStream.NO_REFERENCES);
xstream.alias("widgetlist", List.class);
xstream.alias("widget", Widget.class);
List<Widget> widgetlist = new ArrayList<Widget>();
Widget w1 = new Widget("Kenny", "Character");
Widget w2 = new Widget("Apple", "Fruit");
widgetlist.add(w1);
widgetlist.add(w2);
String serialized = xstream.toXML(widgetlist);
System.out.println(serialized);
List<Widget> unserialized = (List<Widget>)xstream.fromXML(serialized);
System.out.println("Size: "+unserialized.size());
The generated XML by JettionMappedXmlDriver
{
"widgetlist": {
"widget": [
{
"name": "Kenny",
"type": "Character"
},
{
"name": "Apple",
"type": "Fruit"
}
]
}
}
Interpretation
The JSON is the DROP_ROOT_MODE version of the below JSON(un-named object, if you like).
You can therefore look at it as an un-named object that contains a list of Widget. The Widget object still have the same structure as described in the question.
public class WidgetList {
List<Widget> widgets;
public WidgetList() {
this.widgets = new ArrayList<>();
}
}
Xstream settings
xstream.setMode(XStream.NO_REFERENCES);
xstream.alias("widgets", List.class);
xstream.addImplicitCollection(WidgetList.class, "widgets");
xstream.alias("widgets", Widget.class);
xstream.alias("widgetsL", WidgetList.class);
JSON Output
{
"widgetsL": {
"widgets": [
{
"name": "Kenny",
"type": "Character"
},
{
"name": "Apple",
"type": "Fruit"
}
]
}
}

Categories