Java - Google GSON syntax error - java

So I'm trying to parse a request that comes in JSON format, but the Google GSON library throws a syntax error.
The request looks like this: {"action":"ProjectCreation", data:{"projectName": "test project"}}.
Which doesn't look like it has a syntax error to me...
Here is the error that GSON gives me:
Exception in thread "main" com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 20 path $.
EDIT:
I fixed the syntax error in the JSON request, it now looks like this {"action":"ProjectCreation", "data":{"projectName": "test project"}}.
GSON is still throwing the same error....
EDIT:
The code responsible for parsing the request looks like this:
private Type type = new TypeToken<Map<String, Object>>(){}.getType();
private String action;
private String responseAction;
private Map<String, String> data;
private Type dataType = new TypeToken<Map<String, String>>(){}.getType();
private Gson gson = new Gson();
private String requestId;
private Client client = new Client("127.0.0.1", 5699);
/**
* Constructor for this class, sets initial parameters
* #param request
* #param _requestId
*/
public ActionThread(String request, String _requestId) {
System.out.println(request);
//Parse the request into a map
Map<String, Object> _request = gson.fromJson(request, type);
//Give action the correct naming convention
action = _request.get("action") + "Request";
responseAction = _request.get("action") + "Response";
//Parse the data into a map
String _data = _request.get("data").toString();
data = gson.fromJson(_data, dataType);
//Set the request id
requestId = _requestId;
}

_request.get("data").toString() is not the JSON representation of your data object. It's the string representation of the inner map you just parsed that is equal to {projectName=test project}.
One easy and quick way to solve this would be to convert your data object into its JSON representation and then parse it again:
Map<String, String> data = gson.fromJson(gson.toJson(_request.get("data")), dataType);
It might be worth to consider having dedicated classes as well, for instance:
class Action {
#SerializedName("action")
String name;
Data data;
}
class Data {
String projectName;
}
and then
Action action = gson.fromJson(request, Action.class);
If you want to have the nested data object as a field directly in the Action class you could also write a custom deserializer.

Related

JSON Deserializer Spring Boot

I have this entity; transferRate is persisted as json format in database :
#Entity
#Data
public class Currency implements Serializable {
#Id
private String currencyIsoCode;
private String currencyIsoNum;
#Convert(converter = JpaConverterJson.class)
private Map<String, Object> transferRate = new HashMap();
}
and in the client project iam using Rest Template to get list of currencies like that
ResponseEntity<List<Currency>> listResponse =
restTemplate.exchange(RestApiConstants.BASE_URL + CurrenciesRestApiConstants.LIST_CURRENCIES,
HttpMethod.GET, null, new ParameterizedTypeReference<>() {
});
currencyList = listResponse.getBody();
But iam getting this error
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `double` from Object value (token `JsonToken.START_OBJECT`)
The class in the client side is like that
#Data
public class Currency implements Serializable {
private String currencyIsoCode;
private String currencyIsoNum;
private Map<String, Object> transferRate;
}
What iam I doing wrong
Thank you in advance
Your field is defined as a Map<String, Object>, so Jackson tries to deserialize the map value as an Object. From JSON point of view, an object is a set of properties in curly braces. This is where the error comes from:
Cannot deserialize value of type `double` from Object value (token `JsonToken.START_OBJECT`)
Apparently on the client side you send a numeric value, so you need to define transferRate with the numeric type, e.g.:
#Convert(converter = JpaConverterJson.class)
private Map<String, Double> transferRate = new HashMap();
And use a similar type on the client:
private Map<String, Double> transferRate;

Converting a JSON with array of objects to proper Java object

I have a simple Spring Boot project in which a scheduler periodically consumes a RESTful API and converts the incoming JSON file.
The JSON file is actually an array of Objects with some Keys and Values:
[
{"CoID":1,"CoName":"کشاورزی و دامپروری مگسال","CoNameEnglish":"MagsalAgriculture & Animal Husbandry Co.","CompanySymbol":"MAGS","CoTSESymbol":"زمگسا","GroupID":1,"GroupName":"كشاورزی و دامپروری","IndustryID":1,"IndustryName":"كشاورزی، دامپروری و خدمات وابسته به آن","InstCode":"5054819322815158","TseCIsinCode":"IRO1MAGS0006","TseSIsinCode":"IRO1MAGS0001","MarketID":1,"MarketName":"بورس"},
{"CoID":2,"CoName":"ذغالسنگ نگین طبس","CoNameEnglish":"Negin Tabas Lignite Co.","CompanySymbol":"TBAS","CoTSESymbol":"کطبس","GroupID":2,"GroupName":"استخراج و انبار ذغال سنگ سخت","IndustryID":2,"IndustryName":"استخراج ذغال سنگ","InstCode":"8977369674477111","TseCIsinCode":"IRO1TBAS0004","TseSIsinCode":"IRO1TBAS0001","MarketID":1,"MarketName":"بورس"},{"CoID":3,"CoName":"معدنی و صنعتی چادرملو","CoNameEnglish":"Chadormalu Mining & Industrial Co.","CompanySymbol":"CHML","CoTSESymbol":"کچاد","GroupID":3,"GroupName":"استخراج سنگ معدن های فلزی آهنی","IndustryID":3,"IndustryName":"استخراج كانه های فلزی","InstCode":"18027801615184692","TseCIsinCode":"IRO1CHML0000","TseSIsinCode":"IRO1CHML0001","MarketID":1,"MarketName":"بورس"}
...
]
I have a class called Company with similar fields to one of objects in the array within the JSON file:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Company {
private int CoID;
private String CoName;
private String CoNameEnglish;
private String CompanySymbl;
private String CoTSESymbl;
private int GroupID;
private String GroupName;
private int IndustryID;
private String IndustryName;
private String IndustryCode;
private String TseCIsinCode;
private String TseSIsinCode;
private int MarketID;
private String MarketName;
// And proper getters, setters and constructor //
I also created a wrapping class called CompanyList:
public class CompanyList {
private ArrayList<Company> companyList;
public ArrayList<Company> getCompanyList() {
return companyList;
}
public void setCompanyList(ArrayList<Company> companyList) {
this.companyList = companyList;
}
public CompanyList() {
}
#Override
public String toString() {
return "CompanyList [companyList=" + companyList + "]";
}
}
I have tried three different ways to fulfill this requirement:
First:
Object[] forNow = restTemplate.getForObject("somewhere", Object[].class);
List<Object> cp= Arrays.asList(forNow);
This one works properly.
Second:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<Company>> response = restTemplate.exchange(
"somewhere",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Company>>(){});
List<Company> companies = response.getBody();
log.info(companies.toString());
This one is compiled successfully but returns null and 0 in all fields.
Third:
CompanyList cp = restTemplate.getForObject("somewhere", CompanyList.class);
log.info(cp.getCompanyList().toString());
This one raises an exception:
Error while extracting response for type [class ir.pisys.rest.CompanyList] and content type [application/json;charset=utf-8];
nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of ir.pisys.rest.CompanyList out of START_ARRAY token;
nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of ir.pisys.rest.CompanyList out of START_ARRAY token
So I have some questions here:
1- Is the first approach an optimized one? (Compared to others)
2- How can I fix the two other approaches?
The second and third approaches should work fine.
You need to check your json response structure.
You could use following jsons for tests (they work with your code):
Second approach:
[{"tseCIsinCode":null,"tseSIsinCode":null,"coName":"n1","industryID":0,"coID":0,"coNameEnglish":null,"companySymbl":null,"coTSESymbl":null,"groupID":0,"groupName":null,"industryName":null,"industryCode":null,"marketID":0,"marketName":null},{"tseCIsinCode":null,"tseSIsinCode":null,"coName":"n2","industryID":0,"coID":0,"coNameEnglish":null,"companySymbl":null,"coTSESymbl":null,"groupID":0,"groupName":null,"industryName":null,"industryCode":null,"marketID":0,"marketName":null}]
Third:
{"companyList":[{"coName":"n1","coID":0,"coNameEnglish":null,"companySymbl":null,"coTSESymbl":null,"groupID":0,"groupName":null,"industryID":0,"industryName":null,"industryCode":null,"tseCIsinCode":null,"tseSIsinCode":null,"marketID":0,"marketName":null},{"coName":"n2","coID":0,"coNameEnglish":null,"companySymbl":null,"coTSESymbl":null,"groupID":0,"groupName":null,"industryID":0,"industryName":null,"industryCode":null,"tseCIsinCode":null,"tseSIsinCode":null,"marketID":0,"marketName":null}]}
Update:
Second approach fix:
Change your json fields name - "CoName" -> "coName", "CoID" -> "coID" and so on. After that changes it will work pirfectly.
Third approach fix:
Wrap your json with "{\"companyList\":[...]
And change fields name as for second approach
Second Update
If you can't change json from response. You could use mapping in your Company class
#JsonProperty("CoName")
private String CoName;

Convert multiple Java Beans to JSON

I have multiple Java bean classes that are associated to each other (JSON Array + JSON Object) since they have a nested structure.
There are about 10 classes. Is there a way to collectively convert these classes or at-least one by one?
I had created these classes out of a JSON data which I don't have access to right now.
So, now, what I'm looking forward is to create a dummy JSON out of those classes.
Using GSON, I tried converting one of these Bean classes however, I got an empty result. Here is one of the beans called Attachment.java.
Attachment.java
package mypackagename;
import java.io.Serializable;
public class Attachment implements Serializable{
private Payload payload;
private String type;
public Payload getPayload() {
return payload;
}
public void setPayload(Payload payload) {
this.payload = payload;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Implementation
Gson gson = new Gson();
Attachment attachment = new Attachment();
String json = gson.toJson(attachment);
Sure you got an empty result. Because your JSON object is empty. You should add data to your object and test it again as below:
Attachment attachment = new Attachment(new Payload("Test Payload"), "Test attachment");
String json = new Gson().toJson(attachment);
Log.e("Test", "Json: " + json); // result: Json: {"payload":{"test":"Test Payload"},"type":"Test attachment"}
To avoid empty object, you have to set a default value to your payload and type becaus Gson will ignore any null value.
This section of the Gson User Guide: https://sites.google.com/site/gson/gson-user-guide#TOC-Finer-Points-with-Objects
The fourth bullet point explains how null fields are handled.

Parse Json with com.fasterxml.jackson instead of org.json

I was wondering if it is possible to do this exact operation but with the jackson library.
String repo = response.toString();
JSONObject json = new JSONObject (repo);
String nameOfUser = json.getJSONObject(facebookID).getString("name");
Thank you,
Yes. Something like:
ObjectMapper mapper = new ObjectMapper(); // reuse, usually static final
JsonNode ob = mapper.readTree(response.toString()); // or from File, URL, InputStream, Reader
String nameOfUser = ob.path(facebookID).path("name").asText();
// note: '.get()' also works, but returns nulls, 'path()' safer
although even more convenient access is often done using JSON Pointer expressions, like:
String name = ob.at("/person/id").asText();
but I assume facebookID is an id from some other source.
UPDATE: as per comment below, structure you want may actually be POJO like:
public class Response {
public User facebookID;
}
public class User {
public String id;
public String email;
public String first_name;
// ... and so forth: fields and/or getter+setter
}
and then you can bind directly into class like so:
Response resp = mapper.readValue(response.toString(), Response.class);
String name = resp.facebookID.name;
So there's more than one way to do it with Jackson.

What can be a sample JSON payload for my object structure?

I'm new to JSON hence the answer to my question would be a huge help!
I have an enum like below:
enum Error
{
private final String message;
INVALID("failed"),
VALID("succeeded");
Error(String message){
this.message = message;
}
}
And my class is like:
class Response {
String id;
Error error;
}
How do I create a sample JSON payload for this?
If you instantiate and serialize you class using Gson, you will get a JSON string that is the exactly payload you are looking for.
For example, if you execute this:
Response r = new Response();
r.id="AA";
r.error = Error.INVALID;
Gson defaultGson = new Gson();
System.out.println(defaultGson.toJson(r));
you will get
{"id":"AA","error":"INVALID"}
Of course, you could use alternative way to serialize/deserialize your enum like asked here

Categories

Resources