I am a bit lost here,
I have a JSON string like this:
{
"type":"fuu",
"message":"bar",
"data":{
"5":{
"post":"foo",
"type":"bar",
},
"0":{
"post":"foo",
"type":"bar",
},
"1":{
"post":"foo",
"type":"bar",
},
// and so on...
}
}
Please how do I parse it into POJOs using Gson? (I need to get the list of objects)
I am a bit confused by the number in front of the elements of the list of objects....
Try this -
Pojo.java
import java.util.Map;
public class Pojo {
private String type;
private String message;
private Map<Integer, InnerPojo> data;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map<Integer, InnerPojo> getData() {
return data;
}
public void setData(Map<Integer, InnerPojo> data) {
this.data = data;
}
#Override
public String toString() {
return "Pojo [type=" + type + ", message=" + message + ", data=" + data
+ "]";
}
}
InnerPojo.java
public class InnerPojo {
private String type;
private String post;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPost() {
return post;
}
public void setPost(String post) {
this.post = post;
}
#Override
public String toString() {
return "InnerPojo [type=" + type + ", post=" + post + "]";
}
}
Main.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.testgson.beans.Pojo;
public class Main {
private static Gson gson;
static {
gson = new GsonBuilder().create();
}
public static void main(String[] args) {
String j = "{\"type\": \"fuu\", \"message\": \"bar\", \"data\":{ \"0\":{\"post\": \"foo\", \"type\": \"bar\"}, \"1\":{\"post\": \"foo\", \"type\": \"bar\"}, \"5\":{\"post\": \"foo\", \"type\": \"bar\"}}}";
Pojo p = gson.fromJson(j, Pojo.class);
System.out.println(p);
}
}
And Result is -
Pojo [type=fuu, message=bar, data={0=InnerPojo [type=bar, post=foo], 1=InnerPojo [type=bar, post=foo], 5=InnerPojo [type=bar, post=foo]}]
For the "data" part, I'd try to parse it into a Map<Integer, TypedPost> structure, see this thread for instructions.
Related
I'm trying to send a JSON post request to https://graph.microsoft.com/v1.0/me/sendMail to send an email.
I created a POJO with getters and setters so I can set the json value dynamically.
SendEmail.java
import java.util.ArrayList;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonProperty;
public class SendEmail {
public class Body{
public String contentType;
public String content;
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getContentType() {
return contentType;
}
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
public class CcRecipient{
public EmailAddress emailAddress;
public void setEmailAddress(SendEmail.EmailAddress emailAddress) {
this.emailAddress = emailAddress;
}
public SendEmail.EmailAddress getEmailAddress() {
return emailAddress;
}
}
public class EmailAddress{
public String address;
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
}
public class Message{
public String subject;
public Body body;
public ArrayList<ToRecipient> toRecipients;
public ArrayList<CcRecipient> ccRecipients;
public void setSubject(String subject) {
this.subject = subject;
}
public String getSubject() {
return subject;
}
public void setBody(SendEmail.Body body) {
this.body = body;
}
public SendEmail.Body getBody() {
return body;
}
public void setToRecipients(ArrayList<SendEmail.ToRecipient> toRecipients) {
this.toRecipients = toRecipients;
}
public ArrayList<SendEmail.ToRecipient> getToRecipients() {
return toRecipients;
}
public void setCcRecipients(ArrayList<SendEmail.CcRecipient> ccRecipients) {
this.ccRecipients = ccRecipients;
}
public ArrayList<SendEmail.CcRecipient> getCcRecipients() {
return ccRecipients;
}
}
public class Root{
public Message message;
public String saveToSentItems;
public void setMessage(SendEmail.Message message) {
this.message = message;
}
public SendEmail.Message getMessage() {
return message;
}
public void setSaveToSentItems(String saveToSentItems) {
this.saveToSentItems = saveToSentItems;
}
public String getSaveToSentItems() {
return saveToSentItems;
}
}
public class ToRecipient{
public EmailAddress emailAddress;
public void setEmailAddress(SendEmail.EmailAddress emailAddress) {
this.emailAddress = emailAddress;
}
public SendEmail.EmailAddress getEmailAddress() {
return emailAddress;
}
}
}
Below is the test class. The jsonRequest is empty. How can I put the correct JSON values using my POJO?
Test.java
SendEmail sendEmail = new SendEmail();
SendEmail.Message message = sendEmail.new Message();
message.setSubject("Test subject");
SendEmail.Body body = sendEmail.new Body();
body.setContent("this is a test body on an email");
SendEmail.ToRecipient toRecipient = sendEmail.new ToRecipient();
SendEmail.EmailAddress emailAddress = sendEmail.new EmailAddress();
emailAddress.setAddress("dummyemail#outlook.com");
toRecipient.setEmailAddress(emailAddress);
String accessToken = connectEmail(); System.out.println("ACCESS TOKEN: "+accessToken);
HttpURLConnection connection = null;
Gson gson = new Gson();
String jsonRequest = gson.toJson(toRecipient);
try {
URL url = new URL("https://graph.microsoft.com/v1.0/me/sendMail");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization","Bearer "+accessToken);
connection.setRequestProperty("Content-Type", "application/json");
//connection.setRequestProperty("Accept", "text/plain");
connection.setUseCaches(false);
connection.setDoOutput(true);
try(OutputStream os = connection.getOutputStream()) {
System.out.println("jsonRequest: "+jsonRequest);
os.write(jsonRequest.getBytes());
}
} catch (Exception e) {
System.out.println("EXCEPTION SENDING EMAIL");
}
Below is the sample post request I need to write using values from the POJO.
{
"message": {
"subject": "Meet for lunch?",
"body": {
"contentType": "Text",
"content": "The new cafeteria is open."
},
"toRecipients": [
{
"emailAddress": {
"address": "frannis#contoso.onmicrosoft.com"
}
}
],
"ccRecipients": [
{
"emailAddress": {
"address": "danas#contoso.onmicrosoft.com"
}
}
]
},
"saveToSentItems": "false"
}
The result coming from an external API as..
BIBREF are dynamic, the we do not know how will be fetched
The index is appended to the name "BIBREF+number"
"bib_entries": {
"BIBREF0": {
"ref_id": <str>,
"title": <str>,
},
"BIBREF1": {
"ref_id": <str>,
"title": <str>,
},
...
...
"BIBREF25": {}
},
Defined a pojo as..
public class BibEntries {
private BibRef bibRef;
# ...getters/setters
public class BibRef {
private String ref_id;
private String title;
# ...getters/setters
}
}
Defined the class as:
JsonObject bibEntriesObject = jsonObject.get("bib_entries").getAsJsonObject();
BibEntries bibEntries = new Gson().fromJson(bibEntriesObject, BibEntries.class);
Learning GSON and using GenericTypes seemed confusing. How can i update the above code to read the dynamic objects (using gson 2.8.6)?
With some help from my colleague, here's the solution
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class Test {
private static final Gson gson = new
GsonBuilder().serializeNulls().setPrettyPrinting().create();
public static void main(String[] args) {
// Original Json Input
String jsonRequest = "{ \"bib_entries\": { \"BIBREF0\": { \"ref_id\": \"One\", \"title\": \"two\"},"
+ "\"BIBREF1\": { \"ref_id\": \"three\", \"title\": \"four\"} } }";
//Convert string to JsonObject
JsonObject convertedObject = new Gson().fromJson(jsonRequest, JsonObject.class);
JsonObject object = convertedObject.get("bib_entries").getAsJsonObject();
//Init Class
BibEntries bibEntries = new BibEntries();
List<BibEntries.Bibref> list = new ArrayList<>();
//Mapping the object to class
object.keySet().stream().forEach((key) -> {
// We can add more here..
BibEntries.Bibref bibref = gson.fromJson(object.get(key), BibEntries.Bibref.class);
list.add(bibref);
bibEntries.setListBibref(list);
});
//Original
System.out.println(convertedObject);
// Print the final result
System.out.println(gson.toJson(bibEntries));
}
public static class BibEntries {
List<Bibref> listBibref;
public static class Bibref {
#SerializedName("ref_id")
private String refId;
#SerializedName("title")
private String title;
public String getRefId() {
return refId;
}
public void setRefId(final String refId) {
this.refId = refId;
}
public String getTitle() {
return title;
}
public void setTitle(final String title) {
this.title = title;
}
}
public List<Bibref> getListBibref() {
return listBibref;
}
public void setListBibref(final List<Bibref> listBibref) {
this.listBibref = listBibref;
}
}
}
The format of my JSON is :
{"abc": [{
"field_1": "string_1",
"value": 0.304
},
{
"field_1": "string_2",
"value": 0.193
}]}
"abc" is variable, "field_1" and "value" are field names. I want a class in Java which stores this JSON in some format for example:
String t; // should store "abc"
List<myClass> myClassObject; // myClass should contain "field_1" and "value"
myClass.java
String field_1; // should store "string_1" and "string_2"
Double value; // should store 0.304 and 0.193
I want the class myClass.java because in future I may want to add more metadata in JSON response. This is complex object mapping, but I am not able to figure out what should my class be looking like in order to store the JSON response.
For root object do not create new POJO just use Map. Example could look like below:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder().create();
Type mapType = new TypeToken<Map<String, List<Item>>>() {
}.getType();
Map<String, List<Item>> map = gson.fromJson(new FileReader(jsonFile), mapType);
Map.Entry<String, List<Item>> first = map.entrySet().stream().findFirst().get();
Items items = new Items(first.getKey(), first.getValue());
System.out.println(items);
}
}
class Items {
private final String key;
private final List<Item> items;
public Items(String key, List<Item> items) {
this.key = key;
this.items = items;
}
public String getKey() {
return key;
}
public List<Item> getItems() {
return items;
}
#Override
public String toString() {
return "Items{" +
"key='" + key + '\'' +
", items=" + items +
'}';
}
}
class Item {
#SerializedName("field_1")
private String field;
private Double value;
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
#Override
public String toString() {
return "Item{" +
"field='" + field + '\'' +
", value=" + value +
'}';
}
}
Above code prints:
Items{key='abc', items=[Item{field='string_1', value=0.304}, Item{field='string_2', value=0.193}]}
I'm sharing you the sample code:
Main method:
import com.google.gson.Gson;
public class GsonConversion {
public static void main(String[] args) {
String json = "{\"abc\": [{" +
" \"field_1\": \"string_1\"," +
" \"value\": 0.304" +
"}," +
"{" +
" \"field_1\": \"string_2\"," +
" \"value\": 0.193" +
"}]}";
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String, List<Data>>>() {
}.getType();
Map<String, List<Data>> map = gson.fromJson(json, mapType);
Model model= new Model();
map.entrySet().stream().forEach(entry->{
model.setT(entry.getKey());
model.setAbc(entry.getValue());
});
System.out.println("Key:"+model.getT());
model.getAbc().stream().forEach(x->{
System.out.println("Field:"+x.getField_1()+" Value:"+x.getValue());
});
}
}
Parent Model Objects:
i) Model Class
import java.util.ArrayList;
public class Model {
private String t;
private ArrayList<Data> abc = new ArrayList<>();
public String getT() {
return t;
}
public void setT(String t) {
this.t = t;
}
public ArrayList<Data> getAbc() {
return abc;
}
public void setAbc(ArrayList<Data> abc) {
this.abc = abc;
}
}
ii) Data Class
public class Data {
private String field_1;
private Double value;
public Data() {
}
public String getField_1() {
return field_1;
}
public void setField_1(String field_1) {
this.field_1 = field_1;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
}
I want to extract "msg" value from below json using fasterxml.jackson - Can anyone suggest me how my model class should look like?
{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "Bad data received",
"err_data": {
"payment_details.type": {
"location": "body",
"param": "payment_details.type",
"msg": "Must be either etransfer or cheque"
}
}
}
This is what I have done, but it is always returning "null" !
#JsonInclude(JsonInclude.Include.ALWAYS)
public class MyApiResponse extends ParentResponse implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("payment_details")
private PaymentDetails payment_details;
#JsonProperty("payment_details")
public PaymentDetails getPayment_details() {
return payment_details;
}
#JsonProperty("payment_details")
public void setPayment_details(PaymentDetails payment_details) {
this.payment_details = payment_details;
}
}
ParentResponse model class extends ErrorResponse model class and this is how it looks like..
This ErrorResponse model represents above mentioned JSON.
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ErrorResponse implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("statusCode")
private int statusCode;
#JsonProperty("error")
private String error;
#JsonProperty("message")
private String message;
#JsonProperty("err_data")
private ErrData err_data;
#JsonProperty("statusCode")
public int getStatusCode() {
return statusCode;
}
#JsonProperty("statusCode")
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
#JsonProperty("message")
public String getMessage() {
return message;
}
#JsonProperty("message")
public void setMessage(String message) {
this.message = message;
}
#JsonProperty("error")
public String getError() {
return error;
}
#JsonProperty("error")
public void setError(String error) {
this.error = error;
}
#JsonProperty("err_data")
public ErrData getErr_data() {
return err_data;
}
#JsonProperty("err_data")
public void setErr_data(ErrData err_data) {
this.err_data = err_data;
}
}
err_data object is represented by below model class.
#JsonInclude(JsonInclude.Include.ALWAYS)
public class ErrData implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("email")
private Email email;
#JsonProperty("payment_details.type")
private PaymentDetailsType payment_details_type;
#JsonProperty("email")
public Email getEmail() {
return email;
}
#JsonProperty("email")
public void setEmail(Email email) {
this.email = email;
}
#JsonProperty("payment_details.type")
public PaymentDetailsType getPayment_details_type() {
return payment_details_type;
}
#JsonProperty("payment_details.type")
public void setPayment_details_type(PaymentDetailsType payment_details_type) {
this.payment_details_type = payment_details_type;
}
}
payment_details.type object represented by below class.
#JsonInclude(JsonInclude.Include.ALWAYS)
public class PaymentDetailsType extends ErrorMessage implements Serializable {
private static final long serialVersionUID = 1L;
}
#JsonInclude(JsonInclude.Include.ALWAYS)
public class Email extends ErrorMessage implements Serializable {
private static final long serialVersionUID = 1L;
}
And finally ErrorMessage which is extended by PaymentDetailsType as below.
#JsonPropertyOrder({"location", "param", "value", "msg"})
public class ErrorMessage implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("location")
private String location;
#JsonProperty("param")
private String param;
#JsonProperty("value")
private String value;
#JsonProperty("msg")
private String msg;
#JsonProperty("location")
public String getLocation() {
return location;
}
#JsonProperty("location")
public void setLocation(String location) {
this.location = location;
}
#JsonProperty("param")
public String getParam() {
return param;
}
#JsonProperty("param")
public void setParam(String param) {
this.param = param;
}
#JsonProperty("value")
public String getValue() {
return value;
}
#JsonProperty("value")
public void setValue(String value) {
this.value = value;
}
#JsonProperty("msg")
public String getMsg() {
return msg;
}
#JsonProperty("msg")
public void setMsg(String msg) {
this.msg = msg;
}
}
And finally I am trying to get "msg" field value as below -
new Gson().fromJson(response.asString(), MyApiResponse.class).getErr_data().getPayment_details_type().getMsg();
I think there is something wrong with this one - Not sure how to define getter method if field name in json as . (dot).
#JsonProperty("payment_details.type")
public PaymentDetailsType getPayment_details_type() {
return payment_details_type;
}
Similar to above, I am doing it for below json to retrieve "msg" value and it is working fine.
{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "Bad data received",
"err_data": {
"email": {
"location": "body",
"param": "email",
"value": "test # com",
"msg": "Must be a valid email"
}
}
}
This is returning correct "msg" value.
new Gson().fromJson(response.asString(), MyApiResponse.class).getErr_data().getEmail().getMsg();
Please suggest!
Thank you.
Here is a minimal example showing how to parse a JSON with Jackson, where the property names may contain dots:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
class Main {
public static void main(String[] args) throws IOException {
String json = "{" +
" \"payment_details.type\": {" +
" \"location\": \"body\"" +
" }" +
"}";
ObjectMapper mapper = new ObjectMapper();
Response response = mapper.readValue(json, Response.class);
System.out.println(response.getPaymentDetailsType().getLocation());
}
}
class Response {
#JsonProperty("payment_details.type")
private PaymentDetailsType paymentDetailsType;
public PaymentDetailsType getPaymentDetailsType() { return paymentDetailsType; }
}
class PaymentDetailsType {
private String location;
public String getLocation() { return location; }
}
Note that you only need #JsonProperty when the expected property name in JSON cannot be deduced from a setter or variable name
Its also working with #JsonProperty.
You just have to escape the dot:
#JsonProperty("payment_details\\.type")
I've make HttpsURLConnection to receive some information about my server.
The result of response is :
{"about":{"title":"NiFi","version":"1.1.0","uri":"https://localhost:443/api/","contentViewerUrl":"/nifi-content-viewer/","timezone":"CET"}}
How is possible to extract all attributes and key/value ?
About.class file
public class About {
private List<AboutObject> about;
public About()
{
// this.about = about;
}
public List<AboutObject> getAbout() {
return this.about;
}
public void setAbout(List<AboutObject> about) {
this.about = about;
}
}
AboutObject.class
public class AboutObject {
private String title;
private String uri;
private String contentViewerUrl;
private String timezone;
public String getTitle()
{
return this.title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getUri()
{
return this.uri;
}
public void setUri(String uri)
{
this.uri = uri;
}
public String getContentViewerUrl()
{
return this.contentViewerUrl;
}
public void setContentViewerUrl(String contentViewerUrl)
{
this.contentViewerUrl = contentViewerUrl;
}
public String getTimeZone()
{
return this.timezone;
}
public void setTimeZone(String timezone)
{
this.timezone = timezone;
}
}
Main.class
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
//add request header
con.setRequestProperty("User-Agent", USER_AGENT);
int responseCode = con.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
System.out.println("Contenu de in = " + in.toString());
ObjectMapper mapper = new ObjectMapper();
//Staff objStaff = new Staff();
System.out.println("Object to JSON in file");
mapper.writeValue(new File("output/file.json"), response);
System.out.println("Convert JSON string from file to Object");
//String about = mapper.readValue(new File("output/file.json"), String.class);
About about = mapper.readValue(new File("output/file.json"), About.class);
Error
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of About: no String-argument constructor/factory method to deserialize from String value ('{"about":{"title":"NiFi","version":"1.1.0","uri":"https://localhost:443/api/","contentViewerUrl":"/nifi-content-viewer/","timezone":"CET"}}') at [Source: output/file.json; line: 1, column: 1]
Thanks for you help
The test json you show doesn't have the array wrapper used in your About object. You're also missing the version field in your AboutObject and the timezone field uses the wrong case.
Your example worked when I updated your objects:
public class About {
private AboutObject about;
public AboutObject getAbout() {
return about;
}
public void setAbout(AboutObject about) {
this.about = about;
}
}
public class AboutObject {
private String title;
private String uri;
private String contentViewerUrl;
private String timezone;
private String version;
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getContentViewerUrl() {
return this.contentViewerUrl;
}
public void setContentViewerUrl(String contentViewerUrl) {
this.contentViewerUrl = contentViewerUrl;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
Test:
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String obj = "{\"about\":{\"title\":\"NiFi\",\"version\":\"1.1.0\",\"uri\":\"https://localhost:443/api/\",\"contentViewerUrl\":\"/nifi-content-viewer/\",\"timezone\":\"CET\"}}";
About about = mapper.readValue(obj, About.class);
}