POJO Creation from JSON Array (BufferReader) - java

I am trying to unmarshal the following JSON
[{
"myId": "12851cb3087f51b4fb392b1fea36eef9508",
"secondaryId": "787CFD4A-6B1D-4415-AD56-D075B535B890",
"my_key": "keyABCD",
"email": ""
}, {
"myId": "12851cb3087f51b4fb392b1fea36eef9508",
"secondaryId": "BFACD2F0-F5EF-4F05-AA6B-00E18CA907EF",
"my_key": "keyABCD",
"email": ""
}, {
"myId": "12851cb3087f51b4fb392b1fea36eef9508",
"secondaryId": "567DE8C0-B5B5-4961-B97A-A2DD374AEED1",
"my_key": "keyABCD",
"email": ""
}, {
"myId": "12851cb3087f51b4fb392b1fea36eef9508",
"secondaryId": "78a52d90-be6c-4d80-b79d-0e256028ba01",
"my_key": "keyABCD",
"email": "test#email.com"
}, {
"myId": "12851cb3087f51b4fb392b1fea36eef9508",
"secondaryId": "aeb148e7-fc88-4a71-8baa-63b6528e463e",
"my_key": "keyABCD",
"email": ""
}]
and already have a bufferreader (myBufferedReader) which has the above json. POJO
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#ToString
#AllArgsConstructor
public class MyPOJO {
#Getter #Setter private String myId;
#Getter #Setter private String secondaryId;
#Getter #Setter private String my_key;
#Getter #Setter private String email;
}
On using below mapper -
ObjectMapper mapper = new ObjectMapper();
List<MyPOJO> eventList = mapper.readValue(myBufferedReader.readLine(),mapper.getTypeFactory().constructCollectionType(List.class, MyPOJO.class));
getting error. Please help. - (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
If above is not the correct way, please suggest the best way to read from bufferreader and create list of pojo class mapped with json.
Regards,
Dan

Add your default constructor, empty constructor, by adding #NoArgConstructor top of your POJO class.
Then simply convert your buffer reader JSON string to a list of POJO like this:
List<MyPOJO> eventList = mapper.readValue(myBufferedReader, new TypeReference<List<MyPOJO>>(){});

Well, I am not a Master of all things Java JSON. I have a tool which I use whenever I need to parse JSON. Be aware that there are multiple tools for parsing JSON String's, but I am only going to post the solution for the version that I use. I, personally, do not get into Java's Component Annotations because they add such a tremendous amount of complexity, and do not add anything to value of the code. I am not here to prove my points, but I don't get into Java Beans.
There is a library called the GSON Library that (supposedly) can map JSON String's directly to Java Object's (POJO's as you called them). I am, unfortunately, unfamiliar with the GSON Tool, and it might actually be able to "automatically" build a class MyPOJO using Annotations as you have requested.
Here is my solution, which just uses the standard JSON Parsing Library which I call javax.json.* below. You would have to retrieve the JSON JAR by looking for it using a Google Search.
import java.io.*;
import javax.json.*;
public class S
{
// I am just going to create the class for parsing this
// If there is a GSON way to do this "Automatically", then you
// should not use this Answer I have written to Stack Overflow
public static class MyPOJO
{
public final String myId;
public final String secondaryId;
public final String myKey;
public final String email;
public MyPOJO(String myId, String secondaryId, String myKey, String email)
{ this.myId=myId; this.secondaryId=secondaryId; this.myKey=myKey; this.email=email; }
public String toString()
{
return
"myId: " + myId + '\n' +
"seoondaryId: " + secondaryId + '\n' +
"myKey: " + myKey + '\n' +
"email: " + email + "\n\n";
}
}
public static void main(String[] argv) throws IOException
{
// This reads the 'input.json' file into the Json parser using
// a simple java.io.FileReader
Reader r = new FileReader("input.json");
// This reads the file, and retrieves the JsonArray that you
// have provided in your original post.
JsonArray ja = Json
.createReader(r)
.readArray();
for (JsonObject jo : ja.getValuesAs(JsonObject.class))
{
String myId = jo.getString("myId");
String secondaryId = jo.getString("secondaryId");
String myKey = jo.getString("my_key");
String email = jo.getString("email");
// What *I* would do is to get rid of the Component Annotation, and simply
// use a Constructor. I don't strongly believe in Java's Annotation Classes,
// and I never use them. If you can find an AUTOMATED WAY to do all of this,
// YOU SHOULD ... - if you are willing to learn it all.
// I HAVE NOT! :)
// If there is an easy way to **DIRECTLY MAP** a JSON Object to a specified
// class - and I believe that the GSON library is capable of directly mapping
// JSON Object's to GSON Java POJO's (Java Object's), but I have not used them
// before. My own personal belief is that if it were easier, then learning the
// GSON JAR Library and Java Documentation (JavaDoc) for GSON.
// Here, though, a Constructor is what I would prefer myself.
MyPOJO mp = new MyPOJO(myId, secondaryId, myKey, email);
System.out.println(mp.toString());
}
}
}
The following is output by the above class to the Shell Terminal:
#cloudshell:~$ java S
myId: 12851cb3087f51b4fb392b1fea36eef9508
seoondaryId: 787CFD4A-6B1D-4415-AD56-D075B535B890
myKey: keyABCD
email:
myId: 12851cb3087f51b4fb392b1fea36eef9508
seoondaryId: BFACD2F0-F5EF-4F05-AA6B-00E18CA907EF
myKey: keyABCD
email:
myId: 12851cb3087f51b4fb392b1fea36eef9508
seoondaryId: 567DE8C0-B5B5-4961-B97A-A2DD374AEED1
myKey: keyABCD
email:
myId: 12851cb3087f51b4fb392b1fea36eef9508
seoondaryId: 78a52d90-be6c-4d80-b79d-0e256028ba01
myKey: keyABCD
email: test#email.com
myId: 12851cb3087f51b4fb392b1fea36eef9508
seoondaryId: aeb148e7-fc88-4a71-8baa-63b6528e463e
myKey: keyABCD
email:

Related

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.

Gson doesn't get the full string value

I want to get the value of the key "FullName" from this json response:
{
"Succeeded": true,
"DebugError": "",
"SystemUser": {
"ID": 94,
"FullName": "John Smith",
"Email": "abcd#gmail.com",
"PhoneNumber": "0000000000",
"Country": "USA"
}
}
Inside the onResponse method I did this:
// code..
#Override
public void onResponse(JSONObject response) {
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(response.getJSONObject("SystemUser").get("FullName").toString()));
reader.setLenient(true);
String name = gson.fromJson(reader, String.class);
Log.i( " name: ", name + "");
// I tried to use getString("FullName") but shows the same result.
}
// code..
The value in Logcat is => name: John
Why didn't print the full name (John Smith) ??
Seems like your GSON implementation is redundant. Just use
response.getJSONObject("SystemUser").getString("FullName")
Rather than proceeding this way you can go for a better approach. Most of the apps have complex json structures, for which this kinda approach is not advisable.
Create a model class by copy pasting your sample json to jsonschema2pojo. Now select Target language:Java , Annotation style: Gson
Download or copy paste the generated model class and use the following (Assuming your class name as UserDetails).
UserDetails userDetails = gson.fromJson(response.toString(), UserDetails.class);
Now you have the model class populated with all the values. Retrieve which ever you want.
NOTE: Variable names and inner class names should be exactly same as the JSON structure. Better use annotation. Or else the model class will not get populated correctly

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..!

Marshalling two similar json fields to the same java field

I have a sample dummy JSON response that looks like :
{
"id": 1,
"teacher_name": "Foo",
"teacher_address": "123 Main St.",
"teacher_phone_num": 1234567891,
"student_name": "Bar",
"student_address": "546 Main St.",
"student_phone_num": 9184248576
}
The above is a silly example, but it helps illustrate the issue I am having trying to de-serialize the above into a Java class called "Employee" using Jackson:
public class Employee {
String name;
String address;
String phoneNumber;
}
The issue is that the JSON has two different prepends so I cannot annotate each field in Employee and have the object mapper map teacher_name and student_name to the name field in an Employee object. Is there a way in Jackson to specify two differently named nodes to map to the same Java field?
So in my example, I should end up with two Employee objects (I am guaranteed to have one pair per response)
It is not possible with Jackson. It is designed to map one-to-one: one json object to one java object. But you want to end up with two java objects from one json.
I would recommend you to go with strait forward way by implementing some processing level that will consume Response and map it to two Employee objects.
I think you need to write code to do the mapping whether you use annotation or not.
Simple is the best.
If you read the json as JsonNode it should be trivial to code the assignments.
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class Q44094751 {
public static void main(String[] args) throws IOException {
String json = "{\"id\": 1," +
"\"teacher_name\": \"Foo\", \"teacher_address\": \"123 Main St.\", \"teacher_phone_num\": 1234567891," +
"\"student_name\": \"Bar\", \"student_address\": \"546 Main St.\", \"student_phone_num\": 9184248576" +
"}";
ObjectMapper mapper = new ObjectMapper();
// Read
JsonNode node = mapper.readValue( json, JsonNode.class);
Employee teacher = new Employee(),
student = new Employee();
teacher.name = node.get( "teacher_name" ).toString();
teacher.address = node.get( "teacher_address" ).toString();
teacher.phoneNumber = node.get( "teacher_phone_num" ).toString();
student.name = node.get( "student_name" ).toString();
student.address = node.get( "student_address" ).toString();
student.phoneNumber = node.get( "student_phone_num" ).toString();
// Check
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
System.out.println( mapper.writeValueAsString( teacher ) );
}
public static class Employee {
String name;
String address;
String phoneNumber;
}
}
Given a "silly example", the answer that may looks silly.
For example if you have a hundred properties, a loop with reflection should work better.
If you have requirement(s) that is not reflected in the example,
please edit your question to better describe the actual problem(s) you are facing.
I believe that it is not possible with Jackson, The workarounds that I can think of are
Split it into 2 object Teacher and Student. You can still pass the same object twice but with different classes Teacher and Student, It works, but what about the id field?
Make a Java class similar to JSON.
If you would like to make it more meaning full structure then use this structure
{
"id": 1,
"teacher" :{
"name": "Foo",
"address": "123 Main St.",
"phone_num": 1234567891,
},
"student" :{
"name": "Bar",
"address": "546 Main St.",
"phone_num": 9184248576,
}
}
You may use #JsonUnwrapped annotation to unwrap the employee's properties inline in parent object. This annotation also provides the option to specify the prefix name of which will be used while ser/der the object.
Below is your example:
public static class Employee {
private String name;
private String address;
#JsonProperty("phone_num")
private String phoneNumber;
// setter / getter removed from brevity
}
public static class YourJsonObject {
private int id;
#JsonUnwrapped(prefix="teacher_")
private Employee teacher;
#JsonUnwrapped(prefix = "student_")
private Employee student;
// setter / getter removed from brevity
}
Now Configure the ObjectMapper to use the appropriate naming strategy( from your example,I see snake case strategy is desired)
Test Case:
#Test
public void peformTest() throws Exception {
final String inputJson = "{\n" +
" \"id\": 1,\n" +
" \"teacher_name\": \"Foo\",\n" +
" \"teacher_address\": \"123 Main St.\",\n" +
" \"teacher_phone_num\": 1234567891,\n" +
" \"student_name\": \"Bar\",\n" +
" \"student_address\": \"546 Main St.\",\n" +
" \"student_phone_num\": 9184248576\n" +
" }";
ObjectMapper mapper = new ObjectMapper();
// important one
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
// read your json as object
YourJsonObject myObject = mapper.readValue(inputJson, YourJsonObject.class);
assertThat(myObject.getTeacher().getName(), is("Foo"));
assertThat(myObject.getStudent().getName(), is("Bar"));
}
Hope this helps.

Json array to Java class (deserializing with Gson)

I have Json response (named as jsonResultAsText):
{
"Title": "Hi all",
"IsSecret": false,
"Agents": [
{
"ID": 3,
"Name": "John F"
},
{
"ID": 7,
"Name": "Jack D"
}
]
}
I want to deserialize it using Google's gson library.
I have classes like:
public class JsonResponse {
public String Title;
public boolean IsSecret;
public List<Agent> Agents;
}
public class Agent {
public int ID;
public String Name;
}
I want to get json data into JsonResponse class.
It's the code that I try to achieve:
JsonResponse response =
new Gson().fromJson(jsonResultAsText, JsonResponse.class);
But my Android application gives that classic error: Unfortunately, < app_name > has stopped.
I know that there are plenty examples about serializing/deserializing via gson class, but I could not find similar problem/example.
Thanks in advance.
I solve the problem.
I had forgotten to specify this line on json text I provide (on each element of Agents array):
"Since": "2012-01-07T19:11:01.719"
and in my Agent class:
public class Agent {
public int ID;
public String Name;
public DateTime Since;
}
Sure I have that import: import org.joda.time.DateTime;
When I change data type of Since variable from DateTime to String, problem gone.
Now I can deserialize it.
I am just going to learn how to send DateTime from Asp.Net Web Api to Java via Json.
Thanks for comments.

Categories