Is it possible to change order of attributes when toJson()? - java

Let's take this example. I have a pojo class as below.
public class MyRecord{
private String name;
private String id;
//constructors and getters,setters
}
when I get the toJson(new MyRecord("MyName","myId") output for above I can get.
{
"name": "MyName",
"id": "123"
}
And I have inherited one as follows to add the dateTime.
public class MyRecordWithDateTime extends MyRecord{
private String DateTime;
//constructors and getters,setters
}
so when I called toJson(new MyRecordWithDateTime("2016-01-01", "MyName", "myId"))
The output is this
{
"name": "MyName",
"id": "123",
"dateTime": "2016-01-01"
}
but I actually need that as follows. (dateTime should come first.)
{
"dateTime": "2016-01-01",
"name": "MyName",
"id": "123"
}
Is there anyway to do that with keeping inheritance?

Maybe kinda late but just in case there is this annotation #JsonPropertyOrder

Field/member/attributes in a JSON collection do not have an order, and as far as this JSON data structure is concerned, the "order" doesn't matter.
The only reason I can imagine you are concerned with the order is for printing/presentation purposes. In that case I suggest you manually construct the JSON string yourself.

Before you put it in your JSON file, you can try to make an ordered List ( LinkedList, ArrayList or something like), then sort it as you want and after that put it in JSON.
But obviously, a better idea than mine exists!!
But the fact is: JSON doesn't need to be sorted! You just use the getter and it will find your value associated to the key! Even if it's in the last position.

Related

How to add ObjectNodes to ArrayNodes without overwriting old data

I was trying to call data from Directus API, and return certain data in JSON Format on my localhost.
I'm working on a project where we need to build an API layer.
My code:
public String findAllPersons(HttpServletResponse response, String showFields) throws IOException{
try {
// Call to the database (this part is normally not a problem
String url = "https://cuxhsjf3.directus.app/items/blog";
PersonRoot personRoot = template.getForObject(url, PersonRoot.class);
// I used the Objectmapper, since I'm going from normal data to Json.
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode personsObject = objectMapper.createObjectNode();
ArrayNode persons = objectMapper.createArrayNode();
// The array is going to loop through all the data objects from the database
for (int i = 0; i < personRoot.data.toArray().length; i++) {
// I put person objects into an array, and I return this array.
personsObject.put("id", personRoot.data.get(i).id);
personsObject.put("firstName", personRoot.data.get(i).firstName);
persons.add(personsObject);
System.out.println(persons);
}
String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(persons);
return json;
}
// The 'catch' was omitted as not related to the issue
Expected result:
{
"id": "050469ed-0501-4506-9951-794b41bf7e7f",
"firstName": "Elias"
},
{
"id": "0bfb52f7-3656-4202-8c24-2b63eaeca6a9",
"firstName": "Mathias"
},
{
"id": "3145fb95-afd7-4bc4-a62e-a8622b301db2",
"firstName": "Brent"
},
{
"id": "5b93c9b1-4bd1-4aa5-a5ca-d46e849cc58f",
"firstName": "Jef "
},
{
"id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
"firstName": "Jan"
}
}
The output I'm getting:
{
"id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
"firstName": "Jan"
},
{
"id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
"firstName": "Jan"
},
{
"id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
"firstName": "Jan"
},
{
"id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
"firstName": "Jan"
},
{
"id": "cb3d5d02-6b87-4aa1-b817-17550b3cf03c",
"firstName": "Jan"
}
}
As #markspace has pointed out in the comments, you're repeatedly adding the reference to the same ObjectNode into the same JsonArray. When you're modifying this single object, all the elements in the get updated, and what you're getting is data of the very last person replicated multiple time.
You need to move creation of the ObjectNode into the loop, so that a new node would be instantiated for each person:
for (int i = 0; i < personRoot.data.toArray().length; i++) {
ObjectNode personsObject = objectMapper.createObjectNode(); // move object-creation inside the loop
personsObject.put(...);
personsObject.put(...);
persons.add(personsObject);
}
Sidenotes
Encapsulation in your custom class PersonRoot is broken. In Java, we use access modifier like protected and private to hide and protect the data within a class instance. And class is supposed to provide behavior which allow interacting with the state of its instances instead of exposing the instance variables directly (getters are the simplest example of such behavior). This might look alien to you, if previously you were working with languages like JavaScript, but Encapsulation is one of the crucial parts of Object-oriented programming, and it's a common practice in Java to design classes in such a way so that their data is properly encapsulated.
You might also want to learn about one of the GRASP design-patterns, namely The information expert pattern. Which states that an object containing the data should be provided with behavior that facilitates interaction with the data (it's not the responsibility of the code that make use of this object).
I.e. instead of doing this: personRoot.data.toArray().length you can introduce length() method in the PersonRoot class. And instead of writing personRoot.data.get(i) there could be a method like PersonRoot.getPerson(int index).
You can also make PersonRoot implement Iterable interface, so that it could be used as a source of data within an enhanced for-loop.

Access json nested element directly in java

I have json string i want to direclty access element like childMap4.childMap3.ch3Name
and my json string is i am not able find proper solutions.
{
"is working": true,
"childMap4": {
"childMap3": {
"childMap2": {
"childMap1": {
"ch1Name": "childMap1"
},
"ch2Name": "childMap2"
},
"ch3Name": "childMap3 testing"
},
"ch4Name": "childMap4"
},
"prName": "parentMap",
"salary": 800.23,
"prName2": "parentMap field 2",
"age": 24
}
If you just want to extract the value, you should take a look at JsonPath.
Just use the method JsonPath.read([json_object], [expression]) with expression $.childMap4.childMap3.ch3Name.
Another approach would be to create proper mapping class and deserialize JSON string with a library like Jackson, but if you want just single field value taht would be an overkill.
JsonNode jsonNode = mapper.convertValue(Obj, JsonNode.class);
jsonNode.path("childMap4").path("childMap3").path("ch3Name").toString();

Rest response being captured as a map instead of custom object

I am getting the following from a rest call.
[
{
"IMAGE": "",
"DESCRIPTION": "",
"HEADER": ""
}
]
I am using these values to construct another response to the calling client.
In that response, I want it to be in lower case as follows.
[
{
"image": "",
"description": "",
"header": ""
}
]
This is what I am doing currently to convert.
// a large json response received from the rest call.
Benefit benefits = // rest call
//this is above block of response where the keys are upper case currently.
benefits.get(FURTHER_DATA); // type is Object
// casting to my custom object.
List<FurtherData> data = (List<FurtherData>) benefits.get(FURTHER_DATA);
Works fine but the key is still upper case.
When I see it in debug format, I am expecting it to be a list of my FurtherData object.
Instead it is actually showing up as a LinkedHashMap. How? Am so confused. Please help. Thanks.
This is the custom FurtherData object. Another weird thing going on here. I can comment out all the fields here. Still works. Again... how?
#Getter
#Setter
public class FurtherData {
#JsonProperty("IMAGE")
private String image;
#JsonProperty("DESCRIPTION")
private String description;
#JsonProperty("HEADER")
private String header;
}
P.S: To note, this is not myself missing out some additional logic elsewhere.
>It's all happening in following line. If I comment it out, the response doesn't have the above block of data as expected.
List<FurtherData> data = (List<FurtherData>) benefits.get(FURTHER_DATA);
This is Benefit object.
// other fields
private List<FurtherInfo> furtherInfo;

How extract the first element of a JsonArray that is an Integer and the other are JsonElements?

I'm on a Java Spring Boot project that makes API requests using RestTemplates.
Trying to implement pagination, makes the new JsonArray incoming has as first element an Integer and the rest are JsonElements.
Without pagination the value of the json incoming is:
[
{
"id":1234,
"name": null,
"...":...
},...
]
And these objects with their getter and setters correctly implented. p.d I don't need all the attributes of the incoming jsonelement.
public class WorkListBean extends WorkBean{
private List<WorkBean> lsWorkBean;
}
public class WorkBean implements Serializable {
private static final long serialVersionUID = -...L;
private long id;
private String name;
}
This returns WorkListBean[] to the client and works pretty well.
But with pagination implemented the incoming json is like this:
[
1,
{
"id":1234,
"name": null
},...
]
How could I extract this first Integer of the array?
I think maybe I could use a Deserializer with a Object Mapper to make a custom object that owns a Integer and a list or array of WorkBean. But I'm a little bit lost with this terms. Can anyone confirm am pointing in a good view?
Thanks in advance,
Grettings LaGallinaturuleta
That's a badly designed schema. Allthough it's technically allowed, putting elements of different types in the same array will make every client suffer.
If you can change the server side you're talking to, they should use a more user-friendly schema, like this:
{
"pageNumber":0,
"size":5,
"totalPages":4,
"content":[
{"studentId":"1","name":"Bryan","gender":"Male","age":20},
{"studentId":"2","name":"Ben","gender":"Male","age":22},
{"studentId":"3","name":"Lisa","gender":"Female","age":24},
{"studentId":"4","name":"Sarah","gender":"Female","age":26},
{"studentId":"5","name":"Jay","gender":"Male","age":20}
],
}
If not, you're going to need a custom deserializer indeed.

Iterate though array of object in java

I am trying to loop over the array of objects in java. I'm posting this value from client side to server side which is java.
"userList": [{
"id": "id1",
"name": "name1"
},
{
"id": "id2",
"name": "name2"
}]
Now I want to get the value of each id and name. I tried the code below:
for (Object temp : userList)
System.out.print(temp);
System.out.print(temp.getId());
}
But the output I get is:[object Object]
I'm sorry for this stupid question. But how will I get the value of id and name?
You're getting [object Object] because you didn't turn your JavaScript object into JSON on the client side before sending it to your server--you need to use something like JSON.stringify(object) in the browser.
Next, you will need to unpack your JSON into some sort of Java structure. The preferable way to do this is to let an existing tool such as Jackson or Gson map it onto a Java object that looks like:
class User {
String id;
String name;
}
How to do this will depend on your framework, but Spring MVC (for example) supports it mostly automatically.
Implement the toString method for your class according to how you want the printed output to look.
For example...
public class User {
private String id;
private String name;
// Constructors, field accessors/mutators, etc...
#Override
public String toString() {
return String.format("User {id: %s, name: %s}", this.id, this.name);
}
}
Your question does not have complete information. You certainly are skipping steps.
Before you start using the object in java you need to cast the object.
ArrayList<User> convertedUserList = (ArrayList<User>)userList;
for (User temp : convertedUserList)
System.out.print(temp);
System.out.print(temp.getId());
}

Categories