Create Java objects more directly from JSON with JsonPath - java

I create Objects from JsonPath with
List<String> httpList = JsonPath.read(json, "$.*.http_url_to_repo");
List<String> idList = JsonPath.read(json, "$.*.id");
for (int i = 0; i < httpList.size(); i++)
{
back.add(new GitlabProject(httpList.get(i), idList.get(i)));
}
Is there a more direct way to create the GitlabProject objects from the JSON?
The JSON looks like
[
{
"id": 63,
"description": null,
"name": "conti-maven-plugin-mm",
"name_with_namespace": "ik / spu / other / conti-maven-plugin-mm",
"path": "conti-maven-plugin-mm",
"path_with_namespace": "ik/spu/other/conti-maven-plugin-mm",
"created_at": "2023-01-30T12:33:59.218Z",
"default_branch": "main",
"tag_list": [],
"topics": [],
"ssh_url_to_repo": "git#gitlab-test.continentale.loc:ik/spu/other/conti-maven-plugin-mm.git",
"http_url_to_repo": "https://gitlab-test.continentale.loc/ik/spu/other/conti-maven-plugin-mm.git",
"web_url": "https://gitlab-test.continentale.loc/ik/spu/other/conti-maven-plugin-mm",
....

Assuming your POJO has different property names:
public class GitlabProject {
private int id;
#JsonProperty("http_url_to_repo")
private String httpUrlToRepo;
// Constructor, getters and setters omitted for brevity
}
Use ObjectMapper from the Jackson library to deserialize the JSON array into a list of GitlabProject objects:
ObjectMapper objectMapper = new ObjectMapper();
List<GitlabProject> projects = objectMapper.readValue(json, new TypeReference<List<GitlabProject>>(){});
You can do similar thing using Google's GSON library.
List<GitlabProject> projects = new Gson().fromJson(json, new TypeToken<List<GitlabProject>>(){}.getType());
Not that you'll need to use #SerializedName if property name is different in this case.

This can be done using JsonPath itself directly.
Just define a custom mapping function.
List<GitlabProject> projects = JsonPath.parse(json)
.read("$[*]", list -> list.stream()
.map(obj -> {
String httpUrl = JsonPath.read(obj, "$.http_url_to_repo");
int id = JsonPath.read(obj, "$.id");
return new GitlabProject(httpUrl, id);
})
.collect(Collectors.toList())
);
"$[*]" - selects all elements in the JSON array
The lamda expression inside "read" method extracts all
"http_url_to_repo" and "id" values from JSON and creates
corresponding "GitlabProject".
Finally the list of objects are created using
"Collectors.toList()"

Related

How to create a JSON Array of JSON objects with a Java for loop?

I have a for loop which iterates and generates key value pairs for different employees.
I need to create a JSON array like below and write it to a JSON file at the end.
I am having trouble figuring out the ideal way to code it (JSON Objects -> JSON Array -> JSON file?).
I am open to use json-simple/GSON.
Desired JSON file format:
[
{
"employeeFirstName": "Mark",
"employeeLastName": "Williams",
"employeeDepartment": "Sales",
},
{
"employeeFirstName": "John",
"employeeLastName": "Carpenter",
"employeeDepartment": "Accounts",
},
{
"employeeFirstName": "David",
"employeeLastName": "Hunter",
"employeeDepartment": "Marketing",
},
]
I tried using a JSONObject and add it to a JSONArray. But, couldn't figure how to code it for iterations.
My current Java class:
public class Test {
public void createEmployeesJSONArrayFile(ITestContext iTestContext) {
for (ITestResult testResult : iTestContext.getFailedTests().getAllResults()) {
System.out.println("employeeFirstName: " + testResult.getEmployeeFirstName()));
System.out.println("employeeLastName: " + testResult.getEmployeeLastName());
System.out.println("employeeDepartment: " + testResult.getEmployeeDepartment());
}
}
}
What is the simplest or ideal way to achieve this?
A simple way to achieve this would be to use Gson, an API provided by Google. You could write the Collection of ITestResult objects to a file. The toJson function will take the Collection of ITestResult objects and write them to the the given Appenable object, which in this case is a BufferedWriter which points to a file.
(untested, one sec, not at workstation)
Collection<ITestResult> results = iTestContext.getFailedTests().getAllResults();
new GsonBuilder()
.create()
.toJson(results, Files.newBufferedWriter(Paths.get("path", "to", "file")));
If your goal is to write to file eventually, you can also use jackson apis.
ObjectMapper mapper = new ObjectMapper();
//To add indentation to output json
mapper.enable(SerializationFeature.INDENT_OUTPUT);
Collection<ITestResult> results = iTestContext.getFailedTests().getAllResults();
try{
mapper.writeValue(new File("/somepath/output.json"), results);
catch (IOException){
e.printStackTrace();
}
Note: Recommended to use single instance of object mapper
For following snippet:
public static final class Node {
class Employee {
private final String employeeFirstName;
private final String employeeLastName;
private final String employeeDepartment;
public Employee(String employeeFirstName, String employeeLastName, String employeeDepartment) {
this.employeeFirstName = employeeFirstName;
this.employeeLastName = employeeLastName;
this.employeeDepartment = employeeDepartment;
}
}
List<Employee> employees = Arrays.asList(
new Employee("Mark", "Williams", "Sales"),
new Employee("John", "Carpenter", "Accounts"),
new Employee("David", "Hunter", "Marketing"));
// String json = ...
}
Using gson-utils
String json = GsonUtils.writeValue(data);
Using jackson-utils
String json = JacksonUtils.writeValue(data);

What is the cleanest way to unwrap nested JSON values with Jackson in Java?

I have a JSON which looks like this (number of fields heavily reduced for the sake of example):
{
"content": {
"id": {"content": "1"},
"param1": {"content": "A"},
"param2": {"content": "55"}
}
}
Keep in mind, that I don't have control over it, I can't change it, that is what I get from API.
I've created a POJO class for this looking like that:
public class PojoClass {
private String id;
private String param1;
private String param2;
// getters and setters
}
Then I parse JSON with Jackson (I have to use it, please don't suggest GSON or else):
ObjectMapper om = new ObjectMapper();
JsonNode jsonNode = om.readTree(json).get("content");
PojoClass table = om.readValue(jsonNode.toString(), PojoClass.class);
And this doesn't work, because of id, param1 and param2 having JSON in them, not straight values. The code works fine with JSON like this:
{
"content": {
"id": "1",
"param1": "A",
"param2": "55"
}
}
But unfortunately the values I need are stored under "content" fields.
What is the cleanest way to resolve this?
I understand that I can hardcode this and extract all values into variables one by one in constructor or something, but there are a lot of them, not just 3 like in this example and obviously this is not the correct way to do it.
You can modify the JsonNode elements like "id": {"content": "1"} to {"id": "1"} inside your json string accessing them as ObjectNode elements with an iterator and after deserialize the new json obtained {"id":"1","param1":"A","param2":"55"} like below:
String content = "content";
ObjectMapper om = new ObjectMapper();
JsonNode root = om.readTree(json).get(content);
Iterator<String> it = root.fieldNames();
while (it.hasNext()) {
String fieldName = it.next();
((ObjectNode)root).set(fieldName, root.get(fieldName).get(content));
}
PojoClass table = om.readValue(root.toString(), PojoClass.class);
System.out.println(table); //it will print PojoClass{id=1, param1=A, param2=55}

Java - JSON Parsing to and Fro

I have been combing over multiple approaches with different JSON libraries, and cannot seem to find an elegant way to convert to and from with my JSON file in testing.
JSON file looks like this:
[
{
"LonelyParentKey": "Account",
"ProcessNames": [
{"Name": "ProcessOne",
"Sequence": "1"
},
{
"Name": "ProcessTwo",
"Sequence": "2"
},
{
"Name": "ProcessThree",
"Sequence": "3"
},
{
"Name": "ProcessFour",
"Sequence": "4"
}
]
}
]
In a QAF-based test using TestNG, am trying to import the values of the "ProcessName" key like this:
String lonelyParentKey = (String) data.get("LonelyParentKey");
ArrayList processNames = (ArrayList) data.get("ProcessNames");
I've seen that in the framework I'm using, I have multiple JSON library options, have been trying to use GSON after reading other SO posts.
So, next in the test code:
Gson gson = new Gson();
JSONArray jsa = new JSONArray(processNames);
What I am attempting to to create an object that contains 4 child objects in a data structure where I can access the Name and Sequence keys of each child.
In looking at my jsa object, it appears to have the structure I'm after, but how could I access the Sequence key of the first child object? In the REPL in IntelliJ IDEA, doing jsa.get(0) gives me "{"Name": "ProcessOne","Sequence": "1"}"
Seems like a situation where maps could be useful, but asking for help choosing the right data structure and suggestions on implementing.
TIA!
Not sure which library you're using, but they all offer pretty much the same methods. JSONArray looks like org.json.JSONArray, so that would be
JSONArray jsa = new JSONArray(processNames);
int sequenceFirstEntry = jsa.getJSONObject(0).getInt("Sequence");
Some JsonArray implementations also implement Iterable, then this also works
JSONArray jsa = new JSONArray(processNames);
for (JSONObject entry : jsa) {
int sequenceFirstEntry = entry.getInt("Sequence");
}
Any reason to not use DTO classes for your model?
e.g.
class Outer {
String lonelyParentKey;
List<Inner> processNames;
// getter/setter
}
and
class Inner {
String name;
String sequence;
// getter/setter
}
now your library should be able to deserialize your JSON string into a List. I have been using Jackson instead of GSON, but it should be similar in GSON:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
List<X> x = objectMapper.readValue(json, new TypeReference<List<X>>() {});

Convert a string list/set to json objects in java

I have a class named Order which contains one string list below
Set<String> items;
and when I convert this to JSON:
ObjectMapper mapperObj = new ObjectMapper();
String JSON = mapperObj.writeValueAsString(order);
System.out.println(JSON);
... I get output like below
"items":[
"xyz",
"aaa"
]
I'm looking for an output something like below
"items":[
{
"result":"xyz"
},
{
"result":"aaa"
}
]
I don't want to create a class separately for a single string.
You can use some API, like Jackson, for creating JSON object and print it into string. First create a json ArrayNode for your items. Then for each string in your items, create an ObjectNode like this,
ObjectNode node = mapper.createObjectNode();
node.put("result", "xyz");
and add them to the ArrayNode. Finally you print the JSON object out.

How to convert List to a JSON Object using GSON?

I have a List which I need to convert into JSON Object using GSON. My JSON Object has JSON Array in it.
public class DataResponse {
private List<ClientResponse> apps;
// getters and setters
public static class ClientResponse {
private double mean;
private double deviation;
private int code;
private String pack;
private int version;
// getters and setters
}
}
Below is my code in which I need to convert my List to JSON Object which has JSON Array in it -
public void marshal(Object response) {
List<DataResponse.ClientResponse> clientResponse = ((DataResponse) response).getClientResponse();
// now how do I convert clientResponse list to JSON Object which has JSON Array in it using GSON?
// String jsonObject = ??
}
As of now, I only have two items in List - So I need my JSON Object like this -
{
"apps":[
{
"mean":1.2,
"deviation":1.3
"code":100,
"pack":"hello",
"version":1
},
{
"mean":1.5,
"deviation":1.1
"code":200,
"pack":"world",
"version":2
}
]
}
What is the best way to do this?
There is a sample from google gson documentation on how to actually convert the list to json string:
Type listType = new TypeToken<List<String>>() {}.getType();
List<String> target = new LinkedList<String>();
target.add("blah");
Gson gson = new Gson();
String json = gson.toJson(target, listType);
List<String> target2 = gson.fromJson(json, listType);
You need to set the type of list in toJson method and pass the list object to convert it to json string or vice versa.
If response in your marshal method is a DataResponse, then that's what you should be serializing.
Gson gson = new Gson();
gson.toJson(response);
That will give you the JSON output you are looking for.
Assuming you also want to get json in format
{
"apps": [
{
"mean": 1.2,
"deviation": 1.3,
"code": 100,
"pack": "hello",
"version": 1
},
{
"mean": 1.5,
"deviation": 1.1,
"code": 200,
"pack": "world",
"version": 2
}
]
}
instead of
{"apps":[{"mean":1.2,"deviation":1.3,"code":100,"pack":"hello","version":1},{"mean":1.5,"deviation":1.1,"code":200,"pack":"world","version":2}]}
you can use pretty printing. To do so use
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(dataResponse);
Make sure to convert your collection to Array:
Gson().toJson(objectsList.toTypedArray(), Array<CustomObject>::class.java)
We can also use another workaround by first creating an array of myObject then convert them into list.
final Optional<List<MyObject>> sortInput = Optional.ofNullable(jsonArgument)
.map(jsonArgument -> GSON.toJson(jsonArgument, ArrayList.class))
.map(gson -> GSON.fromJson(gson, MyObject[].class))
.map(myObjectArray -> Arrays.asList(myObjectArray));
Benifits:
we are not using reflection here. :)

Categories

Resources