Issue converting from JSON to POJO using Gson - java

I have a JSON REST endpoint response and I wanted to get the value of hotelNbr from it. How do i do it ?
{
"found": [
{
"hotelNbr": 554050442,
"hotelAddress": "119 Maven Lane, New Jersey",
}
],
"errors": []
}
I am using the below code to get it but it fails in below mentioned line:
public List<Hotel> RDS_POST_HotelDetails(String HotelName, String sUrl) throws Exception, IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// Create your http client
CloseableHttpClient httpclient = HttpClientBuilder.create().build();
// Create http Put object
HttpPost ohttppost = new HttpPost(sUrl);
// Message Body
StringEntity input = new StringEntity(
"{\"hotelNbr\":[\""+HotelName+"\" ]}"
);
// Set content type for post
input.setContentType("application/json");
// attach message body to request
ohttppost.setEntity(input);
// submit request and save response
HttpResponse response = httpclient.execute(ohttppost);
// Get response body (entity and parse to string
String sEntity = EntityUtils.toString(response.getEntity());
List<Hotel> hotelobject = new ArrayList<Hotel>();
// Create a type token representing the type of objects in your json response
// I had to use the full class path of TYPE because we also have a Type class in our project
java.lang.reflect.Type cType = new TypeToken<List<Hotel>>() {
}.getType();
// Convert to Array object using gson.fromJson(<json string>,
// <type>)
hotelObject = gson.fromJson(sEntity, cType); // I am getting error here
String hotelNumber = hotelObject.get(0).getFound().get(0).getItemNbr().toString();
}
Please find the Hotel.java class below
package com.hotels.company;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Hotel {
#SerializedName("found")
#Expose
private List<Found> found = null;
#SerializedName("errors")
#Expose
private List<Object> errors = null;
public List<Found> getFound() {
return found;
}
public void setFound(List<Found> found) {
this.found = found;
}
public List<Object> getErrors() {
return errors;
}
public void setErrors(List<Object> errors) {
this.errors = errors;
}
}
Please find Found.java class below :
package com.hotels.company;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Found {
#SerializedName("hotelNbr")
#Expose
private Integer hotelNbr;
#SerializedName("hotelAddress")
#Expose
private String hotelAddress;
public Integer getHotelNbr() {
return hotelNbr;
}
public void setHotelNbr(Integer hotelNbr) {
this.hotelNbr = hotelNbr;
}
public String getHotelAddress() {
return hotelAddress;
}
public void setHotelAddress(String hotelAddress) {
this.hotelAddress = hotelAddress;
}
}
I tried finding some examples in StackOverflow questions but didn't get solution for mine. Any help will be appreciated.

The JSON you are parsing is not well formatted..
There is a comma after "hotelAddress" remove that
Correct JSON would be:
{
"found":[
{
"hotelNbr":554050442,
"hotelAddress":"119 Maven Lane, New Jersey"
}
],
"errors":[ ]
}

I found a couple of issues:
Json is not valid. Observe there is a comma at the end of "hotelAddress": "119 Maven Lane, New Jersey",. Remove it.
You are trying to deserialize the json into List<Hotel>, but the json mentioned is not a list. Either update the json or deserialise it into Hotel object instead of List.

Related

Deserialize JSON from a JSON array

I am using Jackson and I am trying to deserialize a JSON response that looks like the following:
{
"Warnings": [{
"Message": "Account code '48s9' has been removed as it does not match a recognised account"
},
{
"Message": "Account code '48s9' has been removed as it does not match a recognised account"
}
]
}
am I correct in saying that the class would look as follows? Is there some way this can be done?
#JsonIgnoreProperties(ignoreUnknown = true)
public class WarningsClass {
private String Message;
public String getMessage() {
return Message;
}
public void setMessage(String message) {
Message = message;
}
}
was able to figure it out:
// import com.fasterxml.jackson.databind.ObjectMapper; // version 2.11.1
// import com.fasterxml.jackson.annotation.JsonProperty; // version 2.11.1
/* ObjectMapper om = new ObjectMapper();
Root root = om.readValue(myJsonString), Root.class); */
public class Warning{
#JsonProperty("Message")
public String message;
}
public class WarningsClass{
#JsonProperty("Warnings")
public List<Warning> warnings;
}
WarningsClass messageResponse = mapper.readValue(data, WarningsClass.class);
something like this would work

Firebase Android: how do I access params nested in data via RemoteMessage?

via this shape:
{
"to": "000",
"priority": "high",
"data": {
"title": "A Title",
"message": "A Message",
"link": {
"url": "http://www.espn.com",
"text": "ESPN",
}
}
}
how can I access "url" and "text"?
String messageLink = remoteMessage.getData().get("link");
gets me:
{"text":"ESPN","url":"http://www.espn.com"}
but how do I drill deeper?
remoteMessage.getData().get("link").get("text");
doesnt quite work... I have also attempted JSONObject:
JSONObject json = new JSONObject(remoteMessage.getData());
JSONObject link = json.getJSONObject("link");
but this gives me try catch errors...
Any help and direction as always is greatly appreciated!
I would use gson and define a model class. The remote message gives you a Map<String, String> and their is no matching constructor for creating a json object.
Add gson to your build.xml:
compile 'com.google.code.gson:gson:2.5'
Create a notification model:
import com.google.gson.annotations.SerializedName;
public class Notification {
#SerializedName("title")
String title;
#SerializedName("message")
String message;
#SerializedName("link")
private Link link;
public String getTitle() {
return title;
}
public String getMessage() {
return message;
}
public Link getLink() {
return link;
}
public class Link {
#SerializedName("url")
String url;
#SerializedName("text")
String text;
public String getUrl() {
return url;
}
public String getText() {
return text;
}
}
}
Deserialize a notification object from the remote message.
If all your custom keys are at the top level:
Notification notification = gson.fromJson(gson.toJson(remoteMessage.getData()), Notification.class);
If your custom json data is nested in a single key for example "data" then use:
Notification notification = gson.fromJson(remoteMessage.getData().get("data"), Notification.class);
Note in this simple case the #SerializedName() annotations are unnecessary since the field names exactly match the keys in the json, but if you for example have a key name start_time but you want to name the java field startTime you would need the annotation.
As simple as that:
String linkData = remoteMessage.getData().get("link");
JSONObject linkObject = new JSONObject(linkData);
String url = linkObject.getString("url");
String text = linkObject.getString("text");
Of course, together with proper error handling.
Faced this issue when migrating from GCM to FCM.
The following is working for my use case, so perhaps it will work for you.
JsonObject jsonObject = new JsonObject(); // com.google.gson.JsonObject
JsonParser jsonParser = new JsonParser(); // com.google.gson.JsonParser
Map<String, String> map = remoteMessage.getData();
String val;
for (String key : map.keySet()) {
val = map.get(key);
try {
jsonObject.add(key, jsonParser.parse(val));
} catch (Exception e) {
jsonObject.addProperty(key, val);
}
}
// Now you can traverse jsonObject, or use to populate a custom object:
// MyObj o = new Gson().fromJson(jsonObject, MyObj.class)

return any exception in json in rest api

Is there any simple methods to return exception in JSON using Rest api?
I've already googled this question, but all solutions i see, was about throwing exceptions during some calculations. But what if income parameters are wrong? I mean what if there is sone string instead of int input parameter?
I created some DTO class for input data:
#XmlRootElement
public class RequestDTO implements Serializable{
private static final long serialVersionUID = 1L;
#XmlElement(name = "request_id")
private String requestId;
#XmlElement(name = "site")
private List<String> sitesIds;
#XmlElement(name = "date_begin")
#JsonSerialize(using = DateSerializer.class)
#JsonDeserialize(using = DateDeserializer.class)
private Date dateBegin;
#XmlElement(name = "date_end")
#JsonSerialize(using = JsonDateSerializer.class)
#JsonDeserialize(using = JsonDateDeserializer.class)
private Date dateEnd;
#XmlElement(name = "volume")
private double volume;
// there is getters and setters
}
If i sent something like 'qwerty' instead of 'volume' field in my json request i'l see error message like Runtime. Is it possible to handle it in someway? I mean to return error in json with such structure?
public class ExceptionDTO {
private String shortExceptionMessage;
private String stackTrace;
public ExceptionDTO(String shotExceptionMessage, String stackTrace){
this.shortExceptionMessage = shotExceptionMessage;
this.stackTrace = stackTrace;
}
public String getShortExceptionMessage() {
return shortExceptionMessage;
}
public String getStackTrace() {
return stackTrace;
}
}
UPD1:
#Provider
#Singleton
public class ExceptionMapperProvider implements ExceptionMapper<Exception>{
#Override
public Response toResponse(final Exception e) {
StringBuilder trace = new StringBuilder();
IntStream.range(0, e.getStackTrace().length)
.forEach(i -> trace.append(e.getStackTrace()[i]).append('\n'));
ExceptionDTO exceptionMessage = new ExceptionDTO(
e.toString(),
trace.toString()
);
return Response.status(500).entity(exceptionMessage).build();
}
}
As it's not really clear if you are interested on checking if field or value of the payload is correct, here are a few ways to work with both.
If you want to check if the value for a field is correct (ie volume field value should be greater than zero etc), check out bean validation. This makes use of annotations on the fields you want to verify.
// for example
#Min(value = 0, message = "invalid message")
private double range;
To use your ExceptionDTO as error response whenever one of those validation fails, you can do so by creating an ExceptionMapper<ConstraintViolationException>. check it here for more details.
If you are checking for the invalid field (ie client sends ragne fields instead of range), have a look at the stack trace on what exception is being thrown. Then register an exception mapper with your ExceptionDTO as body.
For example, if UnrecognizedPropertyException is thrown then you can add:
#Provider
public class UnrecognizedPropertyExceptionMapper implements ExceptionMapper<UnrecognizedPropertyException> {
#Override
public Response toResponse(UnrecognizedPropertyException e) {
ExceptionDTO myDTO = // build response
return Response.status(BAD_REQUEST).entity(myDTO).build();
}
}
If you want to validate input parameters in the request, you should return status code 400 (Bad Request) along with the error details. You can simply send json
{ "error": { "message": "string received for parameter x, where as int expected" } with the response status code 400.
`
I did a bit of research and determined that the best way to encode a Java exception in JSON is to use a convention developed by Oasis that looks like this:
{
"error": {
"code": "400",
"message": "main error message here",
"target": "approx what the error came from",
"details": [
{
"code": "23-098a",
"message": "Disk drive has frozen up again. It needs to be replaced",
"target": "not sure what the target is"
}
],
"innererror": {
"trace": [ ... ],
"context": [ ... ]
}
}
}
details is a list that should have an entry for each nested cause exception in the chain.
innererror.trace should include the stack trace if you wish, as a list of string values.
The response status code should be 400 unless you have a good reason for making it something else, and the code in the structure should match whatever you sent.
Write one method to convert a Java exception to this format, and you are done. Use it consistently and your JS code will be able to handle and display the exception values.
More of the details of the other approaches evaluated and dismissed are covered in this blog post on JSON REST API – Exception Handling
https://agiletribe.purplehillsbooks.com/2015/09/16/json-rest-api-exception-handling/
Here is the java method to convert an exception to this format:
public static JSONObject convertToJSON(Exception e, String context) throws Exception {
JSONObject responseBody = new JSONObject();
JSONObject errorTag = new JSONObject();
responseBody.put("error", errorTag);
errorTag.put("code", 400);
errorTag.put("target", context);
JSONArray detailList = new JSONArray();
errorTag.put("details", detailList);
String lastMessage = "";
Throwable runner = e;
while (runner!=null) {
String className = runner.getClass().getName();
String msg = runner.toString();
runner = runner.getCause();
JSONObject detailObj = new JSONObject();
detailObj.put("message",msg);
int dotPos = className.lastIndexOf(".");
if (dotPos>0) {
className = className.substring(dotPos+1);
}
detailObj.put("code",className);
System.out.println(" ERR: "+msg);
detailList.put(detailObj);
}
JSONObject innerError = new JSONObject();
errorTag.put("innerError", innerError);
JSONArray stackList = new JSONArray();
runner = e;
while (runner != null) {
for (StackTraceElement ste : runner.getStackTrace()) {
String line = ste.getFileName() + ":" + ste.getMethodName() + ":" + ste.getLineNumber();
stackList.put(line);
}
stackList.put("----------------");
runner = runner.getCause();
}
errorTag.put("stack", stackList);
return responseBody;
}

Nested JSON Request with Volley -> Escaped chars

I want to make a post request with volley to a REST API.
Therefore, I create a JSONObject and put a JSON String generated from a class in it.
JSONObject jsonObject = new JSONObject();
String json = gson.toJson(MyClazz);
try {
jsonObject.put(PARAM, json);
}
catch (JSONException e1) {
e1.printStackTrace();
}
The problem is that the correct calculated JSON String gets escaped and can't be recognized on the back end.
So toJson() gives something like:
{
"device_identifier":"324234234",
"name":"NameMe",
"list":[
{"prop":"A","prop2":-10},
{"prop":"B","prop2":-12}
]
}
The jsonObject's output is like
{
"PARAM":{
\"device_identifier\":\"324234234\",
\"name\":\"NameMe\",
\"list\":[
{\"prop\":\"A\",\"prop2\":-10},
{\"prop\":\"B\","\prop2\":-12}
]
}
}
I need the PARAM for the JSON structure so I can't give it directly to the REST-API. Any ideas how I can avoid the additional escaping?
You could wrap your MyClazz object with a simple wrapper object, and then pass that wrapped object to Gson's toJson method.
Given this class based on your example JSON,
public class MyClazz {
public String device_identifier;
public String name;
public List<Prop> list;
public class Prop {
public String prop;
public Integer prop2;
}
}
here's a possible wrapper implementation. Note the use of com.google.gson.annotations.SerializedName which tells Gson to use the PARAM key in the JSON representation.
public class MyClazzWrapper {
public MyClazzWrapper(MyClazz myClazz) {
this.myClazz = myClazz;
}
#SerializedName("PARAM")
private MyClazz myClazz;
}
And here's an example using it:
Gson gson = new GsonBuilder().setPrettyPrinting().create();
MyClazz myClazz = gson.fromJson("{\"device_identifier\":\"324234234\",\"name\":\"NameMe\",\"list\":[{\"prop\":\"A\",\"prop2\":-10},{\"prop\":\"B\",\"prop2\":-12}]}", MyClazz.class);
MyClazzWrapper wrapped = new MyClazzWrapper(myClazz);
System.out.println(gson.toJson(wrapped));
The above will print:
{
"PARAM": {
"device_identifier": "324234234",
"name": "NameMe",
"list": [
{
"prop": "A",
"prop2": -10
},
{
"prop": "B",
"prop2": -12
}
]
}
}

how to convert the values from a json array to a java string

I need to take the values from a JSON array and display them. Below is the code I have used.
getresponse class will send a HTTP request to a PHP page and get the relevant JSON array and the public variable res will hold that returned JSON array.
public class JSONConverter {
public void convert(){
getresponse gr=new getresponse();
String json = gr.res;
Data data = new Gson().fromJson(json, Data.class);
System.out.println(data);
}
}
class Data {
private String city;
private int reserve_no;
public String getCity() { return city; }
public int getReserve_no() { return reserve_no; }
public void setTitle(String city) { this.city = city; }
public void setId(int reserve_no) { this.reserve_no = reserve_no; }
public String toString() {
return String.format(city);
}
}
getrespose class
public class getresponse {
public static String res;
public void counter() {
try {
URL url = new URL("http://taxi.net/fetchLatest.php");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String str;
while ((str =br.readLine()) != null) {
res=str;
}
conn.disconnect();
Below is an example of JSON array returned.
[{"reserve_no":"20","city":"city2","street":"street1234","discription":"discription123","date":"2012-10-22
04:47:54","customer":"abc"}]
This code doesn't display the city name of the JSON array returned. can someone help me with this by correcting the code or suggest a better or easier method if any? :)
Nikita already gave you the correct solution, but here it is, step by step.
I reduced your problem to this minimal test:
import com.google.gson.Gson;
public class TestGSON
{
public static void main( String[] args )
{
// that's your JSON sample
String json = "[{\"reserve_no\":\"20\",\"city\":\"city2\",\"street\":\"street1234\",\"discription\":\"discription123\",\"date\":\"2012-10-22 04:47:54\",\"customer\":\"abc\"}]";
// note: we tell Gson to expect an **array** of Data
Data data[] = new Gson().fromJson(json, Data[].class);
System.out.println(data[0]);
}
}
The problem is that your JSON fragment is actually an array of objects, not just an object (hence the [] around it). So, you need to tell GSon it must expect an array of Data, not just a Data object. By the way, the exception that's thrown when executing your code as-is already told you so:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
unless of course it got swallowed by an empty catch block
With respect to the Data class: think twice before you override the toString method like you did here. I would drop that method and just do
System.out.println( data[0].getCity() );
Gson maps json string to your class basing on your class properties names. So Data class has property title which is supposed to be mapped to city in json array. You need to rename you property to city so Gson can figure out where to put city from json array.
Or you can use annotations to explicitly map city to title. Check this: https://sites.google.com/site/gson/gson-user-guide#TOC-JSON-Field-Naming-Support

Categories