Related
I am trying to deserialize a two things from JSON. The format of the first one is as follows:
String json = "[{\"name\":\"Random\"," +
"\"coordinates\":[[-3.1,55.4],[-3.1,55.9],[-3.7,55.3],[-3.8,55.7],[-3.0,55.8]]}]";
This is the second:
String json2 = "[{\"name\":\"Random\"," + "\"longitude\":-3.1, \"latitude\":55}]
My code is simple, and is as follows:
ObjectMapper mapper = new ObjectMapper();
var asArray = mapper.readValue(json, NoFlyZone[].class);
var asArray2 = mapper.readValue(json, LngLat.class);
The NoFlyZone class:
record NoFlyZone(LngLat[] coordinates) {
#JsonIgnoreProperties("name")
NoFlyZone (#JsonProperty("coordinates") double[][] coordinates) {
this(doubleArrayToLngLatArray(coordinates));
}
private static LngLat[] doubleArrayToLngLatArray(double[][] coordinates) {
var coordinateArray = new LngLat[coordinates.length];
for (int i = 0; i < coordinates.length; i++) {
coordinateArray[i] = new LngLat(coordinates[i][0], coordinates[i][1]);
}
System.out.println(coordinateArray);
return coordinateArray;
}
}
And finally, the LngLat class:
record LngLat(double lng, double lat) {
LngLat (#JsonProperty("longitude") double lng,
#JsonProperty("latitude") double lat) {
this.lng = lng;
this.lat = lat;
}
}
I have tried deserialising them in the way shown above, but a MismatchedInputException is thrown when trying to deserialize the first string, with the error message "Cannot deserialize value of type uk.ac.ed.inf.LngLat from Array value (token JsonToken.START_ARRAY)...". I'm not sure why this is happening, so any help would be appreciated.
I have also tried adding the annotation
#JsonFormat(shape = JsonFormat.Shape.ARRAY)
and fixing it as detailed in Alexander's answer, but then the second string throws an error when attempting to be deserialised.
Since your record LngLat is represented as JSON-array (like "[-3.1, 55.4]") you need to customize its deserialization.
And for that you can use #JsonFormat annotation providing the attribute shape with the value of JsonFormat.Shape.ARRAY. That would instruct Jackson to populate the record properties from the array in order of their declaration.
#JsonFormat(shape = JsonFormat.Shape.ARRAY)
record LngLat(double lng, double lat) {}
And enclosing record NoFlyZone would be simplified to (special method for parsing array of LngLat is redundant):
#JsonIgnoreProperties("name")
record NoFlyZone(LngLat[] coordinates) {}
Usage example:
String json = "[{\"name\":\"Random\"," +
"\"coordinates\":[[-3.1,55.4],[-3.1,55.9],[-3.7,55.3],[-3.8,55.7],[-3.0,55.8]]}]";
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json, new TypeReference<List<NoFlyZone>>() {}));
Output:
note: toString() method of the NoFlyZone has been overridden to display the array correctly
[NoFlyZone{coordinates=[LngLat[lng=-3.1, lat=55.4], LngLat[lng=-3.1, lat=55.9], LngLat[lng=-3.7, lat=55.3], LngLat[lng=-3.8, lat=55.7], LngLat[lng=-3.0, lat=55.8]]}]
Update
If you need to support the two entirely different structures of JSON, then you also need to customize deserialization on the NoFlyZone level (because its JSON-shape differs).
One of the ways to do that is to introduce the factory method annotated with #JsonCreator. It would expect a single argument of type Map<String, JsonNode> in order to be able to funnel all the properties thought it.
We also need to set the attribute of ignoreUnknown of #JsonIgnoreProperties to true.
Note: the definition of LngLat remains the same (as shown above annotated with #JsonFormat).
#JsonIgnoreProperties(ignoreUnknown = true)
public record NoFlyZone(LngLat[] coordinates) {
#JsonCreator
public static NoFlyZone getInstance(Map<String, JsonNode> fields) throws IOException {
boolean isArray = fields.containsKey("coordinates");
LngLat[] longLat;
if (isArray) {
ObjectReader reader = new ObjectMapper().readerFor(LngLat[].class);
longLat = reader.readValue(fields.get("coordinates")); // parsing JsonNode which corresponds to "coordinates" property
} else {
longLat = new LngLat[] { // creating a single-element array
new LngLat(
Double.parseDouble(fields.get("longitude").toString()),
Double.parseDouble(fields.get("latitude").toString())
)
};
}
return new NoFlyZone(longLat);
}
// toString()
}
Usage example:
String json1 = "[{\"name\":\"Random\"," +
"\"coordinates\":[[-3.1,55.4],[-3.1,55.9],[-3.7,55.3],[-3.8,55.7],[-3.0,55.8]]}]";
String json2 = "[{\"name\":\"Random\"," + "\"longitude\":-3.1, \"latitude\":55}]";
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json1, new TypeReference<List<NoFlyZone>>() {}));
System.out.println(mapper.readValue(json2, new TypeReference<List<NoFlyZone>>() {}));
Output:
[NoFlyZone{coordinates=[LngLat[lng=-3.1, lat=55.4], LngLat[lng=-3.1, lat=55.9], LngLat[lng=-3.7, lat=55.3], LngLat[lng=-3.8, lat=55.7], LngLat[lng=-3.0, lat=55.8]]}]
[NoFlyZone{coordinates=[LngLat[lng=-3.1, lat=55.0]]}]
I have a json reponse like given below.Basically,I want to convert an object and use it.
[
{
"Id": 1290,
"N": "Türkiye",
"Fid": 196,
"EC": 10,
"CL": null,
"SID": 0
},
{
"Id": 1239,
"N": "Dünya",
"Fid": 152,
"EC": 63,
"CL": null,
"SID": 0
}
]
... Goes on
Here is what I have tried,I am using org.json library.
String jsonString = response.body().string(); // Getting json response and converting to string.
JSONObject jsonResponse = new JSONObject( jsonString ); // Not working
JSONArray jsonArray = new JSONArray( jsonString ); // Not working
JSONArray matches = new JSONArray( jsonString ).getJSONArray(0); // Not working
But I am gettin those errors
A JSONObject text must begin with '{' at 0 [character 1 line 1]
A JSONArray text must begin with '{' at 0 [character 1 line 1]
I have checked topics like Parse JSON Array without Key. But the json described not like mine.
Any idea what should ı do?
in Java you would first need to define a class which has all the attributes
public class MyClass {
private int Id;
private int N;
private int Fid;
private int EC;
private int CL;
private int Sid;
// getters, setters, no arg constructor
}
then you can use for example gson library to parse it like this:
MyClass[] myClassArray = gson.fromJson(jsonString , MyClass[].class)
I really recommend you to use the Gson library it's way better to perform data operations:
public class User {
int id;
String n;
int fid;
int ec;
String cl;
int sid;
public static User[] parse(String s){
return new GsonBuilder().create().fromJson(s, User[].class);
}
}
Have you looked into Google's Gson? It is really easy to use and you can both serialize and deserialize objects.
Here is an example:
public Company[] deserializeCompany() {
Gson gson = new Gson();
Company[] companies = gson.fromJson(companiesJSON, Company[].class);
return companies;
}
First you need to make a template class that has a member field for each key in the json. E.g. private String id for the 'Id' key in the json you provided. In my example it is the Company class.
Next you make a new Gson object using Gson gson = new Gson(); and use the .fromJson function supplying it both the Json array and the Object array type (which is of the form MyClass[].class).
First, your question is not to convert a JSON array without key. Second, there are many popular JSON libraries can achieve what you want such as org.json, Jackson, Gson and so on.
Here comes several examples:
With org.json, you can retrieve field values in a JSON array as follows:
JSONArray jsonResponse = new JSONArray(jsonStr);
System.out.println(jsonResponse.get(0).toString());
System.out.println("Id: " + jsonResponse.getJSONObject(0).get("Id"));
System.out.println("N : " + jsonResponse.getJSONObject(0).get("N"));
And the expected output should be:
{"Fid":196,"CL":null,"Id":1290,"N":"Türkiye","EC":10,"SID":0}
Id: 1290
N : Türkiye
With Jackson, you can retrieve field values in a JSON array as follows:
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String, Object>> jsonResponse = objectMapper.readValue(jsonStr, new TypeReference<List<Map<String, Object>>>() {});
System.out.println(jsonResponse.toString());
System.out.println("Id: " + jsonResponse.get(0).get("Id"));
System.out.println("N : " + jsonResponse.get(0).get("N"));
And the expected output should be:
{Id=1290, N=Türkiye, Fid=196, EC=10, CL=null, SID=0}
Id: 1290
N : Türkiye
3. Furthermore, if you define a POJO as follows:
class MyObject {
private #JsonProperty("Id") int id;
private #JsonProperty("N") String n;
private #JsonProperty("Fid") int fid;
private #JsonProperty("EC") int ec;
private #JsonProperty("CL") int cl;
private #JsonProperty("SID") int sid;
//general getters, setters and toString
}
Then you can deserialize the JSON response to your POJO by:
ObjectMapper objectMapper = new ObjectMapper();
List<MyObject> jsonResponse = objectMapper.readValue(jsonStr, new TypeReference<List<MyObject>>() {});
System.out.println(jsonResponse.get(0).toString());
System.out.println("Id: " + jsonResponse.get(0).getId());
System.out.println("N : " + jsonResponse.get(0).getN());
And the expected output should be:
MyObject{id=1290, n='Türkiye', fid=196, ec=10, cl=0, sid=0}
Id: 1290
N : Türkiye
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);
I'm trying to parse the below Json using the Gson lib in Java. When using other languages, such as C#, this JSON is parsed into an array, however it seems Gson converts this into a set of java attributes (which to be honest, makes more sense to me). Does anyone know if I can change this behaviour of the Gson lib?
{
"Outer": {
"0": {
"Attr1": 12345,
"Attr2": 67890
},
"1": {
"Attr1": 54321,
"Attr2": 09876
}
}
}
The below code demonstrates how Gson parses the array as a JsonObject. To be clear, I realise I've referenced outer as a JsonObject but I was just doing this to demonstrate the code. If I try and reference outer as an JsonArray, the code fails.
String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.setLenient()
.serializeNulls()
.create();
JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");
System.out.println(outer);
System.out.println(outer.isJsonArray());
Result:
{"0":{"Attr1":12345,"Attr2":67890},"1":{"Attr1":54321,"Attr2":"09876"}}
false
//edit
I'm using this current simple Json as an example, however my application of this code will be to parse Json that's of varying and unknown shape. I therefore need Gson to automatically parse this to an array so that the isJsonArray returns true.
TL;DR: See "Using Deserializer" section at the bottom for parsing straight to array.
That JSON does not contain any arrays. An array would use the [...] JSON syntax.
Normally, a JSON object would map to a POJO, with the name in the name/value pairs mapping to a field of the POJO.
However, a JSON object can also be mapped to a Map, which is especially useful when the names are dynamic, since POJO fields are static.
Using Map
The JSON object with numeric values as names can be mapped to a Map<Integer, ?>, e.g. to parse that JSON to POJOs, do it like this:
class Root {
#SerializedName("Outer")
public Map<Integer, Outer> outer;
#Override
public String toString() {
return "Root[outer=" + this.outer + "]";
}
}
class Outer {
#SerializedName("Attr1")
public int attr1;
#SerializedName("Attr2")
public int attr2;
#Override
public String toString() {
return "Outer[attr1=" + this.attr1 + ", attr2=" + this.attr2 + "]";
}
}
Test
Gson gson = new GsonBuilder().create();
Root root;
try (BufferedReader in = Files.newBufferedReader(Paths.get("test.json"))) {
root = gson.fromJson(in, Root.class);
}
System.out.println(root);
Output
Root[outer={0=Outer[attr1=12345, attr2=67890], 1=Outer[attr1=54321, attr2=9876]}]
Get as Array
You can then add a helper method to the Root class to get that as an array:
public Outer[] getOuterAsArray() {
if (this.outer == null)
return null;
if (this.outer.isEmpty())
return new Outer[0];
int maxKey = this.outer.keySet().stream().mapToInt(Integer::intValue).max().getAsInt();
Outer[] arr = new Outer[maxKey + 1];
this.outer.forEach((k, v) -> arr[k] = v);
return arr;
}
Test
System.out.println(Arrays.toString(root.getOuterAsArray()));
Output
[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]
Using Deserializer
However, it would likely be more useful if the conversion to array is done while parsing, so you need to write a JsonDeserializer and tell Gson about it using #JsonAdapter:
class Root {
#SerializedName("Outer")
#JsonAdapter(OuterArrayDeserializer.class)
public Outer[] outer;
#Override
public String toString() {
return "Root[outer=" + Arrays.toString(this.outer) + "]";
}
}
class OuterArrayDeserializer implements JsonDeserializer<Outer[]> {
#Override
public Outer[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// Parse JSON array normally
if (json.isJsonArray())
return context.deserialize(json, Outer[].class);
// Parse JSON object using names as array indexes
JsonObject obj = json.getAsJsonObject();
if (obj.size() == 0)
return new Outer[0];
int maxKey = obj.keySet().stream().mapToInt(Integer::parseInt).max().getAsInt();
Outer[] arr = new Outer[maxKey + 1];
for (Entry<String, JsonElement> e : obj.entrySet())
arr[Integer.parseInt(e.getKey())] = context.deserialize(e.getValue(), Outer.class);
return arr;
}
}
Same Outer class and test code as above.
Output
Root[outer=[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]]
I'll asume your JsonObject is a POJO class such like:
public Inner[] outer;
If you want an array of objects you can change your code to:
Inner[] jo = gson.fromJson(json, Inner[].class);
Jackson – Marshall String to JsonNode will be useful in your case.with following pom:-
//POM FILE
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
//JAVA CODE
//read json file data to String
byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));
//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();
//read JSON like DOM Parser
JsonNode rootNode = objectMapper.readTree(jsonData);
JsonNode idNode = rootNode.path("id");
System.out.println("id = "+idNode.asInt());
JsonNode phoneNosNode = rootNode.path("phoneNumbers");
Iterator<JsonNode> elements = phoneNosNode.elements();
while(elements.hasNext()){
JsonNode phone = elements.next();
System.out.println("Phone No = "+phone.asLong());
}
You can use the JsonNode class's method findParent findValue and findPath which reduce your code as compare to another parsing library.
Please refer below code
1.To get an array of Objects (outerArray)
2.You can extract a JsonArray (outerJsonArray) containing values of inner objects in Outer (in case keys aren't significant for further use)
String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().serializeNulls().create();
JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");
Object[] outerArray = outer.entrySet().toArray();
// outerArray: [0={"Attr1":12345,"Attr2":67890}, 1={"Attr1":54321,"Attr2":"09876"}]
JsonArray outerJsonArray = new JsonArray();
outer.keySet().stream().forEach(key -> {
outerJsonArray.add(outer.get(key));
});
//jsonArray=[{"Attr1":12345,"Attr2":67890},{"Attr1":54321,"Attr2":"09876"}]
System.out.println(outer);
System.out.println(outerJsonArray.isJsonArray() + " " + outerJsonArray);
I'm pretty new to world of jackson, and wanted to read the value of specific field from list of jsons (which is a response body of third-party api).
for a single json, using objectMapper works fine.
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(sampleString);
JsonNode idNode = rootNode.path("id");
System.out.println("id: "+ idNode.asText());
But I want to parse list of jsons (which is a string coming from a response body)
.So for example I receive this body:
[
{
"id":10,
"firstName":"Jack",
"primaryPhone":"9999999999",
"email":"jack#me.com"
},
{
"id":4,
"firstName":"Mark",
"primaryPhone":"9999999991",
"email":"mark#me.com"
},
{
"id":12,
"firstName":"Susaan",
"primaryPhone":"9999999992",
"email":"susan23#me.com"
}
]
I want to read the ids first, and if I find a specific id, return some other info from that block.
For example if id=4, read the firstName and email of that person.
But I'm not sure how to parsee list of json.
Any suggestions/comments is appreciated.
You can try,
JsonNode array = objectMapper.readValue(sampleString, JsonNode.class);
for(int i=0;i<array.length;i++){
JsonNode jsonNode = array.get(i);
JsonNode idNode = jsonNode.get("id");
String id = idNode.asText();
if(id.equals("4")){
JsonNode firstNameNode = jsonNode.get("firstName");
String firstName = firstNameNode.asText();
System.out.println("firstName = " + firstName);
JsonNode emailNode = jsonNode.get("email");
String email = emailNode.asText();
System.out.println("email = " + email);
break;
}
}
You can use Json Path.
So, the query would be something like this:
$[?(#.id == 4)].firstName
You can create a POJO like the one below:
class Record {
private Long id;
private String firstName;
//Getters and setters
}
And deserialise the json into List of these POJOS, e.g.:
ObjectMapper mapper = new ObjectMapper();
List<Record> records = mapper.readValue("", new TypeReference<List<Record>>() { });
Once done, you can filter out the records with stream, e.g.:
List<Record> filtered = records.stream()
.filter(r -> r.getId() = 12)
.collect(Collectors.toList());