Deserialization of sometimes string and sometimes object with Gson - java

I need to parse this type of JSON data to java objects:
{"id": 1, "blob": "example text"}
{"id": 2, "blob": {"to": 1234, "from": 4321, "name": "My_Name"}}
I am using Gson, and don't know how to get around this particular problem, of "blob" sometimes being a string and sometimes an object.

One solution to your problem is to write a TypeAdapter for your class, however if you have only cases like that in your example, you can achieve the same result letting Gson do the job for you using the most generic class you can for deserialization.
What I mean is shown in the below code.
package stackoverflow.questions.q19478087;
import com.google.gson.Gson;
public class Q19478087 {
public class Test {
public int id;
public Object blob;
#Override
public String toString() {
return "Test [id=" + id + ", blob=" + blob + "]";
}
}
public static void main(String[] str){
String json1 = "{\"id\": 1, \"blob\": \"example text\"}";
String json2 = "{\"id\": 2, \"blob\": {\"to\": 1234, \"from\": 4321, \"name\": \"My_Name\"}}";
Gson g = new Gson();
Test test1 = g.fromJson(json1, Test.class);
System.out.println("Test 1: "+ test1);
Test test2 = g.fromJson(json2, Test.class);
System.out.println("Test 2: "+ test2);
}
}
and this is my execution:
Test 1: Test [id=1, blob=example text]
Test 2: Test [id=2, blob={to=1234.0, from=4321.0, name=My_Name}]
In second case, blob will be deserialized as a LinkedTreeMap, so you can access its elements using ((Map) test2.blob).get("to") for example;
Let me know if it's enough or if you are interested also in the type adapter solution.

Try this one
Your POJO
class FromToName{
String to;
String from;
String name;
#Override
public String toString() {
return "FromToName [to=" + to + ", from=" + from + ", name=" + name
+ "]";
}
}
Your conversion code
String json ="{\"id\": 1, \"blob\": \"example text\"}";
//String json = "{\"id\": 2, \"blob\": {\"to\": 1234, \"from\": 4321, \"name\": \"My_Name\"}}";
Gson gson = new Gson();
JsonElement element = gson.fromJson (json, JsonElement.class);
JsonObject jsonObj = element.getAsJsonObject();
JsonElement id = jsonObj.get("id");
System.out.println(id);
if(jsonObj.get("blob") instanceof JsonPrimitive ){
JsonElement blob = jsonObj.get("blob");
System.out.println(blob);
}else{
FromToName blob = gson.fromJson (jsonObj.get("blob"), FromToName.class);
System.out.println(blob);
}
If you have any doubt in this let me know

Take that as a JSON Element and then use isMethods() to figure out the type at runtime.
Documentation
JsonParser jp = new JsonParser();
JsonElement ele = jp.parse(jsonString).getAsJsonObject().get("blob");;
if (ele.isJsonObject()) {
//do related stuff here
} else if (ele.isJsonArray()) {
//do related stuff here
}

Related

How to convert single String containing a comma separated json values into a single json object?

I am getting some data which is a single string
"{"somekey": someValue}, {"someKey2": someValue}, {"someKey3": someValue}"
how would I return that as a single json object like this using java libraries?
{{"somekey": someValue}, {"someKey2": someValue}, {"someKey3": someValue}}
I have been trying to use the ObjectMapper class to read the value into a List but can't convert it.
List<String> list = mapper.readValue(jsonString, new TypeReference<List<String>> () {});
I have the option to retrieve the data in an array like this:
[{"somekey": someValue}, {"someKey2": someValue}, {"someKey3": someValue}]
but I still can't manage to convert it to a single json Object response
String jsonString = "{"somekey": someValue}, {"someKey2": someValue}, {"someKey3": someValue}";
Object object = new ObjectMapper().readValue(jsonString, Object.class);
Try this
If you have a JSON string that looks as follows:
String userJson = "[{'name': 'Alex','id': 1}, "
+ "{'name': 'Brian','id':2}, "
+ "{'name': 'Charles','id': 3}]";
And a corresponding POJO that looks as follows:
public class User
{
private long id;
private String name;
#Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
You could then use a library GSON to parse the JSON string into an array of User objects:
Gson gson = new Gson();
User[] userArray = gson.fromJson(userJson, User[].class);

How to convert an json response like that?

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

Java Gson parse Json object to array

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);

Jackson JSON Java nested object and arrays

I have an example nested json object like below :
{
"payload": {
"id": "1",
"apiResp": {
"apiRespDetails": {
"report": {
"reportId": "reportid1",
"reportDetails": [
{
"code": "1",
"rating": "good"
},
{
"code": "2",
"rating": "bad"
},
{
"code": "3",
"rating": "fair"
}
]
}
}
}
}
}
I only need the report object, I do not need any of its parent object details. What would be the best way to get just that using the Jackson API ?
I have created a Java Class called Report.java with fields reportId (String) and reportDetails(List of ReportDetail ) where ReportDetail is another class with String fields code , rating etc. Do I need to use some Deserializer, JsonTreeParser mechanism?Thanks.
The solution for this is jayway Java implementation for JsonPath.
JsonPath is the json equivalent for the XPath query language for XML.
the query langauge is quite powerful, as can be seen in the examples on the github readme.
Here is a quick demo to get you started:
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import com.jayway.jsonpath.*;
import net.minidev.json.JSONArray;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.*;
public class JsonPathDemo2
{
public static void main(String[] args)
{
// query: search for any report property below root
String jsonPathQuery = "$..report";
try (InputStream is = Files.newInputStream(Paths.get("C://temp/xx.json"))) {
Object parsedContent =
Configuration.defaultConfiguration().jsonProvider().parse(is, StandardCharsets.UTF_8.name());
System.out.println("hasJsonPath? " + hasJsonPath(jsonPathQuery).matches(parsedContent));
Object obj = JsonPath.read(parsedContent, jsonPathQuery);
System.out.println("parsed object is of type " + obj.getClass());
System.out.println("parsed object to-string " + obj);
JSONArray arr = (JSONArray)obj;
System.out.println("first array item is of type " + arr.get(0).getClass());
System.out.println("first array item to-string " + arr.get(0));
} catch (Exception e) {
e.printStackTrace();
}
}
}
output:
hasJsonPath? true
parsed object is of type class net.minidev.json.JSONArray
parsed object to-string [{"reportId":"reportid1","reportDetails":[{"code":"1","rating":"good"},{"code":"2","rating":"bad"},{"code":"3","rating":"fair"}]}]
first array item is of type class java.util.LinkedHashMap
first array item to-string {reportId=reportid1, reportDetails=[{"code":"1","rating":"good"},{"code":"2","rating":"bad"},{"code":"3","rating":"fair"}]}
Hi found two solutions using jackson fasterxml api.
In the first one you can just use the findValue method on the jsonNode and pass in the string value of property/object you are looking for
String jsonresponse = "above json string";
JsonFactory jsonFactory = new JsonFactory();
JsonParser jp = jsonFactory.createParser(jsonresponse);
jp.setCodec(new ObjectMapper());
JsonNode jsonNode = jp.readValueAsTree();
JsonNode reportNode = jsonNode.findValue("report");
ObjectMapper mapper = new ObjectMapper();
Report report = mapper.convertValue(reportNode, Report.class);
This other solution use JsonToken which travels the json response till you find what you are looking for
JsonFactory factory = new JsonFactory();
factory.setCodec(new ObjectMapper());
JsonParser parser = factory.createParser(jsonresponse);
while(!parser.isClosed()){
JsonToken jsonToken = parser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = parser.getCurrentName();
if("report".equals(fieldName)) {
jsonToken = parser.nextToken();
Report report = parser.readValueAs(Report.class);
} else {
jsonToken = parser.nextToken();
}
}
}

Using Jackson to manually parse JSON

Is it possible to use Jackson library to manually parse JSON?
I.e. I don't want to use ObjectMapper and convert JSON to some object, but rather I want select some individual properties from JSON, like in XPath:
For example this is my JSON:
{
"person": {
"name": "Eric",
"surname": "Ericsson",
"address" {
"city": "LA",
"street": "..."
}
}
}
And all what I want is just to get Name and the City, for this cases I don't want introduce 2 new Java classes (Person and Address) and use them with ObjectMapper, but I'm just want to read this values like in xPath:
Pseudocode:
String name = myJson.get("person").get("name")
String city = myJson.get("person").get("address").get("city")
You can use the Jackson tree model and JsonNode#at(...) method which takes the Json Pointer expression as a parameter.
Here is an example:
public class JacksonJsonPointer {
static final String JSON = "{"
+ " \"person\": {"
+ " \"name\": \"Eric\","
+ " \"surname\": \"Ericsson\","
+ " \"address\": {"
+ " \"city\": \"LA\","
+ " \"street\": \"...\""
+ " }"
+ " }"
+ "}";
public static void main(String[] args) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
final JsonNode json = mapper.readTree(JSON);
System.out.println(json.at("/person/name"));
System.out.println(json.at("/person/address/city"));
}
}
Output:
"Eric"
"LA"
Yes Using Json parser you can parse your Json, Below is a sample example you can find more in jackson documentation
JsonParser jsonParser = new JsonFactory().createJsonParser(jsonStr);
while(jsonParser.nextToken() != JsonToken.END_OBJECT){
String name = jsonParser.getCurrentName();
if("name".equals(name)) {
jsonParser.nextToken();
System.out.println(jsonParser.getText());
}
if("surname".equals(name)) {
jsonParser.nextToken();
System.out.println(jsonParser.getText());
}
if("city".equals(name)) {
jsonParser.nextToken();
System.out.println(jsonParser.getText());
}
}

Categories

Resources