Map enveloped response into a POJO - java

I am trying to map the following response:
{
"data": {
"id": "1574083",
"username": "snoopdogg",
"full_name": "Snoop Dogg",
"profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1574083_75sq_1295469061.jpg",
"bio": "This is my bio",
"website": "http://snoopdogg.com",
"counts": {
"media": 1320,
"follows": 420,
"followed_by": 3410
}
}
into an object where I only want to retrieve the username, full_name, and id fields.
Ex: something like:
public class User{
String id;
String username;
String full_name;
// getters + setters
}
Is there a way of doing this without first having to store the data object into a Map?

Use Jackson API. It should be simple:
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(jsonString, User.class); //jsonString is your actual json string.
You might want to tweak your User class to match the JSON string. E.g. your user class needs to have a 'data' field as List<Data> data; where 'Data' is another POJO. You can add the "id", "userName", etc fields in the 'Data' pojo.

You can either do it by hand via, for example, regexp or utilize any of JSON libraries like Jackson, GSON etc.

With GSON it's pretty simple. Say your json is stored in a String jsonString variable.
Gson gson = new Gson();
YourObject = gson.fromJson(jsonString, YourObject.class);
Although I'm not sure what will happen, since your jsonString doesn't have a key called User. However, this should work if you first extract data from your jsonString and name your POJO Data.

Related

How to know json structure of a big java object?

I hava a pojo with lots of classes attached to it. Wanted to know the JSON structure to be passed to the API.
Is there any way to create the json structure (with some fake data)?
Example:
public class Staff {
private String personName;
private Salary salary;
private String[] position; // Array
private List<Department> department; // List
private Map<String, Address> addressMap; // Map
// getters & setters of those too.
}
The Department has more number of POJOs within it (person joining to the department data)
Salary has rivisions of each designations.
so and so.
I am trying to get a JSON struture of this without creating it manually.
Something like this (Expected output)
{
"person_name": "person_name",
"salary": {
"joining_salary": "0",
"designation": {
"joining_designation": "joining_designation",
"some_data": "some_data"......
}
},
"department": {
"current_department": {
"latitude": 59.331132099999998,
"longitude": 18.066796700000001,
"address": {
"address_line": "address_line",
"city_name": "city_name",
"zip_code": "zip_code",
"country_code": "co" ....> Restricted to 2 charactors
}
}
},
"some_other": [
"...."
],
"some": "some"
}
You can use the com.google.code.gson library
Maven dependency is as below
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
You can try the following,
Staff staff = new Staff();
// create your objects as required
Gson gson = new Gson();
// below jsonString will have the JSON structure of staff Object
String jsonString = gson.toJson(staff)
I prefer using special and very powerful tool called “Jackson”
It can convert in both directions POJO -> JSON and JSON -> POJO
It also works with other input formats such as YAML etc
The usage is simple;
// Creates default JSON mapper
ObjectMapper mapper = new ObjectMapper();
// Initialize your root object (it could be not necessarily “Stuff”)
// including all nested classes and fields. Any dummy data is
// applicable for your purposes.
Staff staff = new Staff();
// Write object to JSON in file:
mapper.writeValue(new File("c:\\staff.json"), staff);
Jackson Dependency in Maven Repo
you can use the gson, fastjson or Jackson
https://www.2json.net/article/45

How to work with dynamic SerializedName annotation?

I have a json that i transform with gson in a realm model, over the annotaion #SerializedName.
But sometime in the json, there is a unknown key, that i want to serilized to a string.
public class example extend Realmobject{
#SerializedName("example1")
#Expose
private String exampleNr1;
#SerializedName("example2")
#Expose
private String exampleNr2;
private String someOtherValue;
Getter / Setter here...
}
The Json is like this
[
{
"example1": "1234",
"example2": "1234",
"x": "dynamic"}, {
"example1": "1454",
"example2": "165456",
"xy": "dynamic"}]
Now i will to Serialized the x and xy Key (somtimes is named xyz and so on) to the someOtherValue String.
Over the #SerializedName(value="", alternate={""}) I have no chance, because, i dont know the name of the field.
i Serialize this over
List woList = gson.fromJson(parentArray,
new TypeToken>() {}.getType());
You could translate it to a JSONObject first. Then you can loop through the set of keys inside the JSONObject.
JSONObject json = gson.fromJson(stringJson, JSONObject.class);
Iterator<String> set = json.keys();
while(set.hasNext()) {
String dynamicAttributeName = set.next();
}
json.get(dynamicAttributeName); //to get the value

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

How to save google JsonObject field into dynamoDB?

I have json request like below.
{
"color":"red",
"type":"publish",
"events":{
"some":"Yes",
"collection":[
{
"key1":"value1",
"key2":"value2"
},
{
"key3":"value3",
"key4":"value4"
}
],
"nestedObject":{
"key5":"value5",
"key6":"value6"
}
}
}
I have create POJO class with color as String, type as string, and events as JsonObject. Value of events field can be any value of json format. So I created it as JsonObject. My question is how can I store events into the data base. For dynamo we can use #DynamoDBDocument annotation to marshal other object into current POJO. Now I cant use because we have to annotate to the class to marshall. In this case JsonObject is out of my scope to annotate. Is there any other way to store JsonObject into dynamo?
You will need to use the WithJSON Method to save the string representation
String jsonDoc = json.toString();
Item item = new Item()
.withPrimaryKey("pid", "Test")
.withJSON("doc", jsonDoc);
table.putItem(item);
You can also refer to the following AWS documentation:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/JavaDocumentAPIItemCRUD.html#PutDocumentAPIJava

Retrofit2 handle JSON response that contains two models data

I'm using retrofit2 to handle http request after calling from API. Let me explain this.
I have 2 java class(POJO) created to handle user and lecturer data which is User.java and Lecturer.java respectively. For the response data such as :
{
"users": [
{
"user_id": "28",
"user_email": "john#abc.com",
"user_password": "123"
}
]
}
i can use User.java class to handle this response. Nothing complex in this file, only contains getter and setter method. Same goes to lecturer data, here is the example of lecturer data :
{
"lecturers": [
{
"lecturer_id": "3",
"user_id": "28",
"lecturer_name": "johny2"
}
]
}
i can handle it by using Lecturer.java class.
But the problem is, if the response contains both user and lecturer data on a single json, how to handle it?? . Here is the example of request :
{
"users": [
{
"user_id": "28",
"user_email": "john#abc.com",
"user_password": "123",
"lecturer_id": "3",
"lecturer_name": "johny2"
}
]
}
To solve this problem, i think i need to create another java class that contains both User and Lecturer class on it, unfortunately at here i'm stuck.
This is new file, that i tried to create (Userlecturer.java) :
public class UserLecturer {
User user;
Lecturer lecturer;
// how to implement on this part
}
Here is UserLecturer interface :
public interface UserLecturerInterface {
#GET ( "api/endpoint/here" )
Call<UserLecturer> getLecturerByUserId (#Path( "userId" ) String userId );
}
Appreciated for any helps. Ask me for more inputs if above use case did't clear enough. Thanks
I think the POJO should be:
public class Users {
String userId;
String userEmail;
String userPassword;
String lecturerId;
String lecturerName;
}
Even though there are 2 models inside the JSON, you only need 1 model for Retrofit.
If you really want to split the 1 JSON response into 2 models, I think you have to implement custom JSON converter.
Gson gson = new GsonBuilder()
.registerTypeAdapter(UserLecture.class, new JsonDeserializer<UserLecture>() {
public UserLecture deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonArray usersJsonArray = json.getAsJsonObject().getAsJsonArray("users");
JsonObject userJsonObject = usersJsonArray.getAsJsonArray().get(0).getAsJsonObject();
User user = new User();
user.setUserId(userJsonObject.get("user_id").getAsString());
user.setUserEmail(userJsonObject.get("user_email").getAsString());
user.setUserPassword(userJsonObject.get("user_password").getAsString());
Lecturer lecturer = new Lecturer();
lecturer.setLecturerId(userJsonObject.get("lecturer_id").getAsString());
lecturer.setLecturerName(userJsonObject.get("lecturer_name").getAsString());
return new UserLecture(lecturer, user);
}
})
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl([YOUR_BASE_URL])
.addConverterFactory(GsonFactoryConverter.create(gson))
.build();
This is some code I use to convert longs to Java Date objects.
Presumably, you can do the same thing for your UserLecture object. You should be able to extract the individual json objects for User and Lecture, create a new UserLecture object and let User and Lecture as objects in it.
Gson gson = new GsonBuilder().registerTypeAdapter(UserLecture.class, new JsonDeserializer<UserLecture>() {
public UserLecture deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject user = json.getAsJsonObject().getAsJsonObject("user");
JsonObject lecture = json.getAsJsonObject().getAsJsonObject("lecture");
return new UserLecture(user, lecture);
}
}).create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonFactoryConverter.create(gson))
.build();
Then inside UserLecture:
public UserLecture(JsonObject userJson, JsonObject lectureJson) {
this.user = new User();
this.user.setUserId(userJson.get("user_id").getAsInt());
this.user.serUserEmail(userJson.get("user_email").getAsString());
//so on.
}
At first let me say that the JSON you need to process here is broken by design so you should urge the guy / department / company to fix it.
Secondly, JSON processors like Jackson allow to parse polymorphic data structures like this easily, but they require some kind of type flag to distinguish one of another type (i.e. type: "user" and type: "lecturer"). There is also a way to do this without such type flags, but there is a lot more hand work involved. The last example here shows how to do it.
Yes, it is one possible solution. Gson ignores all fields, which names doesnt match #SerializedName annotation. So, you may try another solution without creating any more pojo classes- return result as String, and try to parse this string as both classes. If one result is empty- then you have another. But, if both kbjects isnt empty- then original response contain fields from both pojos

Categories