Java GSON Json partial parsing - java

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.

Related

Is it possible to rename an #XmlPath annotated element while marshalling with MOXy to normalize the json representation?

I'm not sure if this is at all possible as it contradicts the semantics of #XmlPath itself, but if yes, please do help me with this.
I'm getting this json by calling some external API from my API implementation
{
"title": "Forrest Gump",
"writingCredits": {
"novel": "Winston Groom",
"screenplay": "Eric Roth"
},
"directedBy": "Robert Zemeckis",
"casts": ["Tom Hanks", "Rebecca Williams", "Sally Field"],
"releaseDate": "1994-06-07T00:00:00.000Z",
"producedBy": {
"producers": ["Wendy Finerman", "Steve Starkey"],
"co-producers": ["Charles Newrith"]
}
}
and mapping this to following POJO that'll be returned as resource from my own API
public class Film
{
private String title;
#XmlPath("writingCredits/screenplay/text()")
private String writer;
#XmlPath("directedBy/text()")
private String director;
#XmlPath("casts[0]/text()")
private String actor;
#XmlJavaTypeAdapter(DateUnmarshaller.class)
#XmlPath("releaseDate/text()")
private int releaseYear;
#XmlPath("producedBy/producers[0]/text()")
private String producer;
private String category;
//Commented getters and setters to save space
}
Here I'm able to map the necessary info to my POJO using MOXy but facing problem while marshalling the same.
While marshalling it retains the original nested structure of the received json though my POJO structure is not nested, I mean it is not referring to any other POJO.
Can I get something like this when I marshall my POJO to json:
{
"title": "Forrest Gump",
"writer": "Eric Roth",
"director": "Robert Zemeckis",
"actor": "Tom Hanks",
"releaseYear": 1994,
"producer": "Wendy Finerman"
}
but instead it showed up like this:
{
"title": "Forrest Gump",
"writingCredits": {
"screenplay": "Eric Roth"
},
"directedBy": "Robert Zemeckis",
"casts": "Tom Hanks",
"releaseDate": 1994,
"producedBy": {
"producers": "Wendy Finerman"
}
}
So, is there any way to deal with this?
And one more thing, for the category attribute I wanna decide its value if a particular json entry is present in received json, e.g. if the received json contains a json entry like
"animationInfo": {
"studio" : "pixar",
"some extra info" : [],
"and some more" : {}
}
then category should be set to "animation". Do I need to write one more XmlAdapter for it?
Thank you..!

Customized serialization of POJO to JSON in spring restTemplate

I am using the spring restTemplate to make POSTs to an endpoint and want it to convert my POJO to JSON. This is being done already. I have a list and it converts to JSONArray and does it successfully. I want to modify it a bit though where instead of it being an array, I want it to be a JSON with a key being the name of the list variable, and the value being the list.
Example is:
List<Record> records;
The above would create a JSON of
{
"records": [
{
"name": "test",
"address": "chicago"
},
{
"name": "stack",
"address": "overflow"
},
{
"name": "etc",
"address": "etc"
}
]
Rather than being [{},{},{}]
I think just simple create a DTO object which contains your List and return it. For instance:
public class SampleDTO{
private List<Record> records;
//getter setter
}
in the Controller, just return the ResponseEntity with the body is your SampleDTO
Hope this help.

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"}

Converting a specific JSON to Java Object

I am able to convert simple Json into java objects using Google Gson. The issue is I am not able to convert this specific type of response to a java object. I think this is due to the fact that I am not sure how to actually model the java classes for it. The following is the Json:
{
"List": {
"Items": [
{
"comment": "comment",
"create": "random",
"ID": 21341234,
"URL": "www.asdf.com"
},
{
"comment": "casdf2",
"create": "rafsdfom2",
"ID": 1234,
"Url": "www.asdfd.com"
}
]
},
"related": {
"Book": "ISBN",
"ID": "id"
}}
I haven't worked with Gson specifically, but I have worked with JSON / Java conversion in Jersey and JAXB.
I would say that the easiest way to translate the JSON text is to map every {..} to a Class and [..] to a List.
For example:
Class Data {
HistoryListClass HistoryList;
Relation related;
}
Class HistoryListClass {
List<History> history;
}
Class History {
String comment;
String create;
int ID;
String ttURL;
}
Class Relation {
String book;
String ID;
}
See also:
Converting JSON to Java
The "HistoryList" element in the JSON code should probably be written "historyList", and just looking at the code given, I suggest you change it to contatain the list of "History" objects directly.

Dropwizard/Jersey returns Java List as JSON without root node

I am using dropwizard which uses jersey & jackson for json. My issue is when I return a list it does not specify a root.
I have a POJO class:
public class Company {
public String id;
public String name;
public String address;
}
and my resource is set up thus:
#GET
#Path("/companies/all")
public List<Company> getAllCompanies(){
...
return companies;
}
And I get the following response:
[{
"id": "01",
"name": "Yammer Corp",
"address": "1 Finite Loop"
},
{
"id": "02",
"name": "DropWizards Inc",
"address": "4 Magic Square, Olympus"
}]
While what I want is something like below:
{"Companies" :
[{
"id": "01",
"name": "Yammer Corp",
"address": "1 Finite Loop"
},
{
"id": "02",
"name": "DropWizards Inc",
"address": "4 Magic Square, Olympus"
}
]}
Any ideas? Thanks in advance.
You need to create one more POJO wrapping the List<Company>
public class ApiResponse
{
private List<Company> Companies;
//Getter and Setter
//Public Constructor
}
The Change required in your GET Method is:
#GET
#Path("/companies/all")
public ApiResponse getAllCompanies(){
//Set your ApiResponse Object with the companies List.
ApiResponse apiResponse = new ApiResponse(companies);
return apiResponse;
}
I believe you can customize using Jackson APIs. Here is one approach which allows you to set the root of the generated JSON using ObjectWriter.
#GET
#Path("/companies/all")
public Response getAllCompanies() throws JsonProcessingException {
List<Company> companies = Lists.newArrayList();
Company yc = new Company();
yc.id = "01";
yc.name = "Yammer Corp";
yc.address = "1 Finite Loop";
companies.add(yc);
Company dw = new Company();
dw.id = "02";
dw.name = "DrowWizards Inc";
dw.address = "4 Magic Square, Olympus";
companies.add(dw);
ObjectMapper objectMapper = new ObjectMapper();
ObjectWriter writer = objectMapper.writer();
String entity = writer.withRootName("Companies").writeValueAsString(companies);
return Response.ok(entity).build();
}
If you look at your code you are asking to return a list of companies:
public List<Company> getAllCompanies(){
If you want to return a JSON object with a Companies value then you need a suitable Java object which matches this.
public class MyListOfCompanies {
List<Companies> companies;
}
And then you would ask your code to return that instead:
public MyListOfCompanies getAllCompanies(){
However, do consider if you really want to do this. If you think about the situation of someone coding to your API, would they rather receive a list of companies (as they asked for and the API implies they will obtain), or an object that serves no purpose other than to contain the list of companies?
Finally, for good REST design the common way to obtain a list of all companies is just to use the path /companies, not /companies/all.

Categories