Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm working out a problem, and this part of it I could use some assistance on, I have the following JSON array:
parentArray: [{"name":"folder1","children":[],"parent":"root","type":"folder"}, {"name":"folder2","children":[],"parent":"folder1","type":"folder"}]
I need to create a method that will put the put the object with name 'folder2' in to the 'children' array of 'folder1'.
Thanks for any help or pointers.
You can achieve it in a cleaner way using gson.
Create a POJO for Parent and an array value of type Parent[]
public class Parent {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Parent[] getChildren() {
return children;
}
public void setChildren(Parent[] children) {
this.children = children;
}
private String name;
private String parent;
private String type;
private Parent[] children;
}
Easily read the json and manipulate the Parent object thus returned:
BufferedReader br = new BufferedReader(new FileReader("array.json")); //File containing your initial json
Gson gson = new Gson();
Parent[] parentObjArray = gson.fromJson(br, Parent[].class);
Parent folder2 = parentObjArray[1];
parentObjArray[0].setChildren(new Parent[] { folder2 });
System.out.println(gson.toJson(parentObjArray));
Resulting json:
[
{
"name": "folder1",
"parent": "root",
"type": "folder",
"children": [
{
"name": "folder2",
"parent": "folder1",
"type": "folder",
"children": []
}
]
},
{
"name": "folder2",
"parent": "folder1",
"type": "folder",
"children": []
}
]
The above code uses a few assumptions specifically the exact indexes of your json array. You can further generalize and manipulate the json in accordance to your requirements.
Further, the 2nd element of the array can be removed to hold a single object with a child.
EDIT:
As per your new requirement, you might want to add the files and folders too. Adopting my dirty approach I can manually set these values. However, would definitely stress on that Files and Folders can share a single data type - Parent, hence this solution becomes a good candidate to adopt a recursive approach.
So it's:
Folder1
||=> File1
||=> Folder2
||=> File2
Changed inout json:
[
{
"name": "folder1",
"children": [],
"parent": "root",
"type": "folder"
},
{
"name": "folder2",
"children": [],
"parent": "folder1",
"type": "folder"
},
{
"name": "file1",
"parent": "folder1",
"type": "file"
},
{
"name": "file2",
"parent": "folder2",
"type": "file"
}
]
Manually set these values and modify json
Gson gson = new Gson();
Parent[] parentObjArray = gson.fromJson(br, Parent[].class);
Parent file2 = parentObjArray[3];
parentObjArray[1].setChildren(new Parent[] { file2 });
Parent folder2 = parentObjArray[1];
Parent file1 = parentObjArray[2];
parentObjArray[0].setChildren(new Parent[] { file1, folder2 });
parentObjArray = new Parent[]{parentObjArray[0]};
System.out.println(gson.toJson(parentObjArray));
Modified json now:
[
{
"name": "folder1",
"parent": "root",
"type": "folder",
"children": [
{
"name": "file1",
"parent": "folder1",
"type": "file"
},
{
"name": "folder2",
"parent": "folder1",
"type": "folder",
"children": [
{
"name": "file2",
"parent": "folder2",
"type": "file"
}
]
}
]
}
]
Hope this gives you a better idea how your generic approach would be. Good luck!
I would suggest you go with plain objects and then convert them to json string.
public class Folder {
private String name;
private List<Folder> children;
private String parent;
private String type;
//Getter and setters
}
This way you can create folder from json and also write folder to json
ObjectMapper mapper = new ObjectMapper();
String temp = mapper.writeValueAsString(folderObject);
Related
I'm quite new to API testing, I am wondering how to best and simple load some body?
I created simple pojo classes, but i am having problems with nested json.
ex:
{
"listOfItems": [
{
"name": "name1",
"value": "Jack"
},
{
"name": "nameDate",
"value": "20-08-2021-08-00-00"
},
{
"name": "address",
"value": "address here",
}
{
"name": "name2",
"value": "Smith"
}
],
"something": [],
"size": 1
}
Then, in classes I used:
ClassName {
private List<ListOfItems> listOfItems;
private List<something> something;
private int size;
//setters and getters
}
and
Class ListOfItems{
private String name;
private String value;
//getters and setters
}
then in test class I am trying to use it, but have no idea how.
public Class Test {
ClassName className = new ClassName();
ListOfItems list = new ListOfItems();
//how to get list with 3x name and 3x value like in json?
className.setsize(150);
given().when().body(???).post("\endpoint").then()...
}
But I have no idea how to declare those 4 properties (name, value)
You are actually on a pretty good track, you can use Gson library to help you out, Here is the video example for your explanation which I used to learn Gson back when I needed it
I have the following json file:
{
"authors":
[{"id":"author7",
"book":[
[
{
"value":{"pages":123}}]]},
{
"id": "author3",
"book": [
[
{
"value": {
"title": "LOTR"
}
},
{
"value": {
"boolean": false
}
},
],
[
{
"value": {
"pages": 350
}
},
{
"value": {
"boolean": false
}
},
],
[
{
"value": {
"boolean": false
}
},
{
"value": {
"pages": 150
}
},
]
]
},
}
I want to be able to create an object of Author but I am having problems while mapping the Json file with the Java classes I have created.
I understand that, while mapping the json file with the java classes, Authors class should have as fields
public class Authors{
private String authorId;
private Book book;
}
Class Book should be like this
public class Book {
private List<Values> values
public Book() {
}
}
But what about class Values?
public class Values{
private int pages;
private Boolean bool;
private String title;
public Values() {
}
}
Is this the correct way to map it? Because I see that if I create an object of Values it will ask me to modify the constructor or create a new constructor for each different object that comes from Json
Thank you for reading and helping!
Easy way out would to be to define Values by type 'object' as,
public class Book {
private List<Object> values
}
This way you won't run into the issue of having properties with null values when they don't exist in the JSON. Also, the JSON would be entirely parsed into an object even if new properties are get introduced (or which may not be defined under values class, as you have done above causing those not being mapped to the object).
However, when you are using 'object', be mindful with your logic that uses this parsed object. Although, you are assured to access the properties from the object as in the JSON, you will have to conditionally check whether the nessacary property exists first in each logical context to avoid possible undefined value errors.
What Java data structure can be used to serialize to the following Json which have a set of child objects?
Example:
{
"John": {
"Type": "Person",
"age": 30,
"Sean": {
"Type": "child",
"age": 3
},
"Julian": {
"Type": "child",
"age": 4
}
},
"Paul": {
"Type": "Person",
"age": 64,
"Stella": {
"Type": "child",
"age": 10
},
"James": {
"Type": "child",
"age": 12
}
}
}
Writing John and Paul can be done by: Map<String,Person> but i cannot figure out how to nest the Child without having the 'children' property.
Example:
{
"John": {
"Type": "Person",
"age": 30,
"children": {
"Sean": {
"Type": "child",
"age": 3
},
"Julian": {
"Type": "child",
"age": 4
}
}
}
}
I am not sure it is relevant, but Gson is being used to create the Json file
I'm not sure wheher this is possible with GSON though it's possible with Jackson.
With GSON you can try custom JsonSerializer, which might look something like this:
private static class PersonTypeSerializer implements JsonSerializer<Person> {
#Override
public JsonElement serialize(Person person, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject personJson = personToJson(person);
for (Map.Entry<String, Person> child : person.getChildren().entrySet()) {
personJson.add(child.getKey(), personToJson(child.getValue()));
}
return personJson;
}
private static JsonObject personToJson(Person person) {
JsonObject personJson = new JsonObject();
personJson.addProperty("Type", person.getType());
personJson.addProperty("age", person.getAge());
return personJson;
}
}
and register to GSON instance like this:
Gson gson = new GsonBuilder().registerTypeAdapter(Person.class, new PersonTypeSerializer())
.create();
Note that code assumes that both type "Person" and "child" are represented by the same Person class. It should be pretty easy to modify this if not.
I have a List of Objects with multiple fields. Based on the API call, the List would be returned with only a specific set of fields. When I use transient - it does not serialize that particular field. But, that field should be returned for another API call. I am using Gson.
In the example below, based on the API, I wanted to print a list of Table instances with only E.g. "name" of the Table instances, or both "name" and "location", or just location. There could be 30 fields in the Table Object.
One way is to map it to a POJO for each scenario and then print it out. Is there a better way to do this? where you can select/choose/constrain which field gets serialized.
E.g.
package Testing;
import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class TestJson {
public static Gson obGson = new GsonBuilder().setPrettyPrinting().create();
public static void main(String[] args) {
ArrayList<Table> myTable = new ArrayList<Table>();
myTable.add(new Table("John", "Chicago"));
myTable.add(new Table("David", "Seattle"));
myTable.add(new Table("June", "Dallas"));
System.out.println(obGson.toJson(myTable));
}
}
class Table {
String name;
String location;
public Table (String _name, String _location) {
name = _name;
location = _location;
}
}
The output for the above looks like this. When API-1 is called then the output should like below.
[
{
"name": "John",
"location": "Chicago"
},
{
"name": "David",
"location": "Seattle"
},
{
"name": "June",
"location": "Dallas"
}
]
But when API-2 is called then the output should like below. Only return the fields that are approved for that API call.
[
{
"name": "John"
},
{
"name": "David"
},
{
"name": "June"
}
]
Similarly, the return could be managed based on the API call.
Implement ExclusionStrategy like
#RequiredArgsConstructor
public class FieldExclusionStrategy implements ExclusionStrategy {
#NonNull
private final Collection<String> serializedFields;
#Override
public boolean shouldSkipField(FieldAttributes f) {
if(serializedFields.contains(f.getName())) return false;
return true;
}
#Override
public boolean shouldSkipClass(Class<?> clazz) { return false; }
}
Use like
#Test
public void testShouldSkipField() {
Gson gson;
Table table = new Table();
Collection<String> serializedFields = new ArrayList<>();
ArrayList<Table> myTable = new ArrayList<Table>();
myTable.add(new Table("John", "Chicago"));
myTable.add(new Table("David", "Seattle"));
myTable.add(new Table("June", "Dallas"));
serializedFields.add("name");
gson = new GsonBuilder()
.setPrettyPrinting()
.addSerializationExclusionStrategy(
new FieldExclusionStrategy(serializedFields))
.create();
log.info("\n{}", gson.toJson(myTable));
serializedFields.add("location");
gson = new GsonBuilder()
.setPrettyPrinting()
.addSerializationExclusionStrategy(
new FieldExclusionStrategy(serializedFields))
.create();
log.error("\n{}", gson.toJson(myTable));
serializedFields.remove("name");
gson = new GsonBuilder()
.setPrettyPrinting()
.addSerializationExclusionStrategy(
new FieldExclusionStrategy(serializedFields))
.create();
log.error("\n{}", gson.toJson(myTable));
}
Above would log something like
2017-12-23 19:47:17.028 INFO org.example.gson.FieldExclusionStrategyTest:37 -
[
{
"name": "John"
},
{
"name": "David"
},
{
"name": "June"
}
]
2017-12-23 19:47:17.034 ERROR org.example.gson.FieldExclusionStrategyTest:44 -
[
{
"name": "John",
"location": "Chicago"
},
{
"name": "David",
"location": "Seattle"
},
{
"name": "June",
"location": "Dallas"
}
]
2017-12-23 19:47:17.035 ERROR org.example.gson.FieldExclusionStrategyTest:51 -
[
{
"location": "Chicago"
},
{
"location": "Seattle"
},
{
"location": "Dallas"
}
]
You need to build GSON again after changing list of serialized field names.
GSON caches internally the result - true|false - upon first call for some field name and does not query it again for cached field name.
And to add ExclusionStrategy you need to build GSON with GsonBuilder which then registers ExclusionStrategy (or many of them).
See also my question about this topic.
This question already has answers here:
Correct way for parsing JSON objects containing arrays in Java Servlets (with Gson for example)
(3 answers)
Closed 8 years ago.
I have this json:
{
"details": {
"interest": {
"label": "example1",
"value": "19,9",
"symbol": "%"
},
"monthly_invoice": {
"label": "example2",
"value": "29",
"symbol": "eur"
},
"start_fee": {
"label": "example3",
"value": "0",
"symbol": "eur"
},
"monthly_pay": {
"label": "example4",
"value": "58",
"symbol": "eur"
}
}
}
The Details object will contain a dinamical number of objects with the same properties (label, value, symbol). It is a way to create a class structure in java, using gson to receive this data without known the name of the objects contained (interest, monthly_invoice...)?
Thanks!
In your Java code "details" should be a
Map<String, Foo>
Where Foo is your class with the label , value and symbol properties. e.g. you JSON would parse into a class that looks like this:
public class TestObject {
public Map<String, Foo> details;
public static class Foo {
public String label;
public String value;
public String symbol;
}
}
Then in your code where you want to deserialize it to a Java instance you would do this:
Gson gson = new Gson();
TestObject testObject = gson.fromJson(json, TestObject.class);
System.out.println(testObject.details.get("interest").label);