JSON - Error on putting a JSON string inside a JSON object - java

I have a web-service in Java with Jersey to create and edit prices of a market. To do that, I send a JSON object containing the market informations, including another JSON object for the prices.
For example, this is the JSON I'm posting through Postman:
{
"name": "Market 01",
"address": "Market 01 street",
"prices": "{\"watermelon\": \"5.40\", \"melon\": \"2.55\"}"
}
On the web-server side, I try to create a list of the prices using GSON, but I can't get it to work. My objective here is to check on the difference between the new prices and the current prices. Below, there is my POJO Price.java, what I'm trying to do on the Controller for the edit and the Exception I'm geting on Postman:
POJO - Price.java
public class Price {
private String nome;
private Double preco;
//Getters and setters also
}
MarketController.java
Collection<Price> prices = gson.fromJson(json, new TypeToken<List<Price>>(){}.getType());
Exception raised on MarketController.java:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
EDIT: The solution that worked for me based on #A2H response:
POJO class - Price.java
public class Price {
private String name;
private Double price;
...
#Override
public String toString() {
return "{\"name\":\"" + name + "\", \"price\":" + price + "}";
}
}
POJO class - Market.java
public class Market{
...
//Include as a List<Price>
private List<Price> prices;
...
}
MarketController.java
// When going from List<Price> to JSON String
String prices = gson.toJson(market.getPrices());
// When going from JSON String to List<Price>
List<Price> prices = gson.fromJson(jsonString, new TypeToken<List<Price>>(){}.getType());
This code is well rounded for this situation, where you need to transform from List to JSON String and vice-versa.

Your POJO implies that you should have an array of prices in your JSON object.
Here's a full working example.
package test;
import java.util.List;
import com.google.gson.Gson;
public class TESTTEST {
public class MarketInfo {
String name;
String address;
List<Price> prices;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Price> getPrices() {
return prices;
}
public void setPrices(List<Price> prices) {
this.prices = prices;
}
}
public class Price {
String nome;
Double preco;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Double getPreco() {
return preco;
}
public void setPreco(Double preco) {
this.preco = preco;
}
#Override
public String toString() {
return "{\"nome\":\"" + nome + "\", \"preco\":" + preco + "}";
}
}
public static void main(String[] args) {
Gson gson = new Gson();
String jsonString = "{\"name\": \"Market 01\",\"address\": \"Market 01 street\","
+ "\"prices\": [{\"nome\":\"watermelon\",\"preco\":\"5.40\"}, {\"nome\":\"melon\",\"preco\": \"2.55\"}]}";
MarketInfo res = gson.fromJson(jsonString, MarketInfo.class);
System.out.println(res.getPrices());
}
}

That's because a List would be represented by a JSON array, not by an object as you provide. You can try to deserialize to a map (or, send an array).

Related

com.google.gson.stream.MalformedJsonException error: How to solve it?

I want to get the country details from an external api and using Gson to set the data received from the get request to class Country. The problem is that in the response, the currencies key has value which is between [](please see below) and in some cases there is a space between the currencies name values which causes the following error
com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 41 path $.currencies[0].name:
"currencies":[{"code":"BGN","name":"Bulgarian lev","symbol":"лв"}]
#RestController
public class CountryController {
#Autowired
private RestTemplate restTemplate;
private static String baseURL = "https://restcountries.com/v2/";
public Object[] getCountryDetails(String countryName){
Object[] countryDetails = restTemplate.getForObject(baseURL+"name/"+countryName+"?fields=name,alpha2Code,alpha3Code,capital,currencies", Object[].class);
return countryDetails;
}
public Country createCountryObject(String countryName) {
String response = Arrays.asList(getCountryDetails(countryName)).get(0).toString();
Gson g = new Gson();
JsonReader reader = new JsonReader(new StringReader(response.trim()));
reader.setLenient(true);
Country country = g.fromJson(reader, Country.class);
return country;
}
#GetMapping("/")
public String getAll(){
Country country = createCountryObject("bulgaria");
return country.getName();
}
}
Country.java:
package country.neighbours.tour.models;
import java.util.List;
public class Country {
private String name;
private String alpha2Code;
private String alpha3Code;
private List<String> borders;
private Object[] currencies;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getBorders() {
return borders;
}
public void setBorders(List<String> borders) {
this.borders = borders;
}
public String getAlpha2Code() {
return alpha2Code;
}
public void setAlpha2Code(String alpha2Code) {
this.alpha2Code = alpha2Code;
}
public String getAlpha3Code() {
return alpha3Code;
}
public void setAlpha3Code(String alpha3Code) {
this.alpha3Code = alpha3Code;
}
public Object[] getCurrencies() {
return currencies;
}
public void setCurrencies(Object[] currencies) {
this.currencies = currencies;
}
}
How can I get only the currency code?
It looks like you are parsing the response twice; once with restTemplate.getForObject, then you convert its result to a String (the result of your toString() call is most likely not JSON) and then you try to parse it a second time with Gson.
In case you only want to use Gson, you can use a TypeToken in the fromJson call to parse the response JSON array:
List<Country> countries = gson.fromJson(..., new TypeToken<List<Country>>() {}.getType());
Maybe someone more familiar with Spring can also explain how to use only RestTemplate.getForObject for this instead of Gson.

Use Gson to serialize complex set

I have a method, setFriends(), that takes a Set. This method is in another module and I want to send setFriends() serialized data via Gson().fromJson(). I am not sure if I have the arg string correct. I have tried the following which failed:
// my attempt to serialize
String arg = "[Friend[name=Dave, relationship=Relationship[Work]], Friend[name=Jack, relationship=Relationship[School]]]"; // not sure if this string is correct
Type type = new TypeToken<Set<Friend>>(){}.getType();
Set<Friend> payload = new Gson().fromJson(arg, type);
sendPayload(payload); // will send payload to People.setFriends()
// code from the other module:
Set<Friend>
public class People {
public void setFriends(Set<Friend> friends) { ... }
}
public class Friend {
String name;
Relationship relationship;
}
public enum Relationship {
School,
Work
}
Google Gson is a simple Java-based library to serialize Java objects to JSON and vice versa. In JSON we represent objects using {}. For nested objects we use "fieldName": {<nested object>}.
In your example I've considered relationship as an enum. And introduced Address as a nested object. JSON for the Friend object will look like this:
{
"name" : "Dave",
"relationship" : "WORK",
"address" : {"street" : "s1"}
}
There is no representation for Set structure in JSON so you put elements in list.Following is the sample java code:
public class Test
{
public static void main(String[] args)
{
String arg = "["
+ "{\"name\":\"Dave\",\"relationship\":\"WORK\",\"address\":{\"street\":\"s1\"}},"
+ "{\"name\":\"Jack\",\"relationship\":\"SCHOOL\",\"address\":{\"street\":\"s2\"}},"
+ "{\"name\":\"Dave\",\"relationship\":\"GYM\",\"address\":{\"street\":\"s3\"}}"
+ "]";
Type type = new TypeToken<Set<Friend>>(){}.getType();
Set<Friend> payload = new Gson().fromJson(arg, type);
sendPayload(payload);
}
static void sendPayload(Set<Friend> plod) {
System.out.println("Sent payload: " + plod.toString());
}
}
class Friend {
private String name;
private Relationship relationship;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public Relationship getRelationship() {
return relationship;
}
public void setRelationship(Relationship relationship) {
this.relationship = relationship;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
#Override
public int hashCode() {
return name.hashCode();
}
#Override
public boolean equals(Object obj) {
return name.equals(obj.toString());
}
}
enum Relationship {
WORK, SCHOOL, GYM
}
class Address {
String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
Output:
Sent payload: [Dave, Jack]
In my environment Gson returned LinkedHashSet object. If you want different set like sorted ones. Then you can deserialize the Json into List<Freind> then convert it to the desired set.

Converting a list of json objects to java object using gson, gets null

The Json data that i have.
[
{
"code": "24",
"name": "Rajsathan",
"districts": [
{"code":"1",
"name":"Jodhpur"},
{"code":"2",
"name":"Nagore"}
]
}
]
Reading the data from a file as inputstream.
BufferedReader br = new BufferedReader(new InputStreamReader(in));
Gson gson = new Gson();
String temp = null;
String total = null;
try {
while((temp = br.readLine()) != null) {
total+=temp;
}
} catch (Exception e){
e.printStactTrace();
}
Now i tried many different ways to convert this data to java objects, but got null when passing the complete string total or malformed json error when converting each stream from streamreader.
StatesModel data = gson.fromJson(total, StatesModel.class);
// as its a list of json
Type collectionType = new TypeToken<Collection<StatesModel>>(){}.getType();
Collection<StatesModel> json_data = gson.fromJson(total, collectionType);
But both do not work.
The Java classes for statesModel is defined as below.
public class StatesModel {
#SerializedName("code")
public String code;
#SerializedName("name")
public String name;
#SerializedName("districts")
public List<DistrictModel> districts;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<DistrictModel> getDistricts() {
return districts;
}
public void setDistricts(List<DistrictModel> districts) {
this.districts = districts;
}
}
And the districts class model being.
public class DistrictModel {
#SerializedName("code")
public String code;
#SerializedName("name")
public String name;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
what would be the right way to convert this data to iterable javaObjects.
Your JSON starts with a [ this means that we would want an array of StatesModel. This can be read from a file like this:
Reader reader = new FileReader("path_to_my_json.json");
Gson gson = new Gson();
StatesModel[] statesModels = gson.fromJson(reader, StatesModel[].class);
// do something with the array
Stream.of(statesModels).forEach(System.out::println);
StatesModel POJO:
public class StatesModel {
private String code;
private String name;
private List<DistrictModel> districts;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<DistrictModel> getDistricts() {
return districts;
}
public void setDistricts(List<DistrictModel> districts) {
this.districts = districts;
}
#Override
public String toString() {
return "StatesModel{" +
"code='" + code + '\'' +
", name='" + name + '\'' +
", districts=" + districts +
'}';
}
}
DistrictModel POJO:
public class DistrictModel {
private String code;
private String name;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "DistrictModel{" +
"code='" + code + '\'' +
", name='" + name + '\'' +
'}';
}
}
Working code can be found on github: https://github.com/Ernyoke/gson-tutorial
You have two options. Instead of using BufferReader, you can use FileReader like in below. By using FileReader, you have written cleaner code than before.
Convert JSON file to Java object
Gson gson = new Gson();
StatesModel StatesModel = gson.fromJson(new FileReader("C:\\myfile.json"), StatesModel.class);
Convert JSON string to Java object
Gson gson = new Gson();
String json = '{"code": "24", "name": "Rajsathan", "districts": [ {"code":"1", "name":"Jodhpur"}, {"code":"2", "name":"Nagore"}]}';
StatesModel StatesModel = gson.fromJson(json, StatesModel.class);

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

Ok, So I read a couple other questions with this same error, but none have been answered as working, and doesnt seem like I can get it working.
I am connecting to google in-app billing and have everything set up, but, when I try to pull my skudetails (I have 2 SKUs there now), I get the error -
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
I have a SubscriptionActivity, Result (serializable), and Details model class (serializable). Below is the code, any help will be great, thanks-
From subscriptionactivity:
Gson gson = new Gson();
try {
Result result = gson.fromJson(skuDetailsList.toString(), Result.class);
if (result != null) {
for (Details d : result.getDetails()) {
System.out.println(d.getProductId()
+ " \n " + d.getTitle() + " \n " + d.getDescription() + " \n "
+ d.getPrice());
}
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
From details model:
public class Details implements Serializable{
#SerializedName("productId")
#Expose
private String productId;
#SerializedName("type")
#Expose
private String type;
#SerializedName("price")
#Expose
private String price;
#SerializedName("price_amount_micros")
#Expose
private Integer priceAmountMicros;
#SerializedName("price_currency_code")
#Expose
private String priceCurrencyCode;
#SerializedName("subscriptionPeriod")
#Expose
private String subscriptionPeriod;
#SerializedName("freeTrialPeriod")
#Expose
private String freeTrialPeriod;
#SerializedName("title")
#Expose
private String title;
#SerializedName("description")
#Expose
private String description;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public Integer getPriceAmountMicros() {
return priceAmountMicros;
}
public void setPriceAmountMicros(Integer priceAmountMicros) {
this.priceAmountMicros = priceAmountMicros;
}
public String getPriceCurrencyCode() {
return priceCurrencyCode;
}
public void setPriceCurrencyCode(String priceCurrencyCode) {
this.priceCurrencyCode = priceCurrencyCode;
}
public String getSubscriptionPeriod() {
return subscriptionPeriod;
}
public void setSubscriptionPeriod(String subscriptionPeriod) {
this.subscriptionPeriod = subscriptionPeriod;
}
public String getFreeTrialPeriod() {
return freeTrialPeriod;
}
public void setFreeTrialPeriod(String freeTrialPeriod) {
this.freeTrialPeriod = freeTrialPeriod;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
From Result activity:
public class Result implements Serializable{
#SerializedName("SkuDetails")
#Expose
private ArrayList<Details> details = new ArrayList<Details>();
/**
*
* #return The SkuDetails
*/
public ArrayList<Details> getDetails() {
return details;
}
/**
*
* #param details
* The details
*/
public void setDetails(ArrayList<Details> details) {
this.details = details;
}
}*
Oh..and the response I was trying to parse (skuDetailsList.toString()) is:
[
SkuDetails: {
"productId": "basic_sub",
"type": "subs",
"price": "$0.99",
"price_amount_micros": 990000,
"price_currency_code": "USD",
"subscriptionPeriod": "P1M",
"freeTrialPeriod": "P4W2D",
"title": "Basic Subscription Service (DadBod Recipes)",
"description": "Basic Subscription Service for DadBodRecipes"
},
SkuDetails: {
"productId": "enterprise_sub",
"type": "subs",
"price": "$2.99",
"price_amount_micros": 2990000,
"price_currency_code": "USD",
"subscriptionPeriod": "P1M",
"freeTrialPeriod": "P4W2D",
"title": "Enterprise Subscription Service (DadBod Recipes)",
"description": "Enterprise Subscription Service for DadBodRecipes"
}
]
Issue is because, the result you're getting is as <Key-Value> pair (not as JSON object/Array, but similar to it).
So you'll need to make it to JSONObject first and then parse it using Gson like below:
Map<String, String> params = skuDetailsList;
JSONObject object = new JSONObject(params);
Result result = gson.fromJson(object.toString(), Result.class);
Do like this, hope it helps !
You are trying to parse your json
[
as
{
when you see the [ it represents a list
when you see the { it represents an object.
I'm pretty sure you know that as you built a wrapper class, but your wrapper class is also an object, not an array.
So your choices are to have your wrapper class extend ArrayList or some form of List.
Or
Tell your Json converter that the base is an Array and you want the first object in the list is an object of your type.

Using GSON giving error expected BEGIN_ARRAY but was STRING

An example JSON object is shown below:
[{"Title":"John Doe","Address":{"AddressLines":["The Place","123 New Place","London","England"],"Postcode":"NW7 XXY"},"Telephone":"0012345","Email":"","Latitude":51.5024472101345,"Longitude":-0.557585646554,"Easting":500623,"Northing":179647}]
Suppose the above object is accessed via the link www.domain.com and I have the following class to represent the data
public class LocationData extends Data{
private Address Address;
private String Telephone;
private String Email;
private String Latitude;
private String Longitude;
private String Easting;
private String Northing;
public Address getAddress() {
return Address;
}
public void setAddress(Address address) {
Address = address;
}
public String getTelephone() {
return Telephone;
}
public void setTelephone(String telephone) {
Telephone = telephone;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public String getLatitude() {
return Latitude;
}
public void setLatitude(String latitude) {
Latitude = latitude;
}
public String getLongitude() {
return Longitude;
}
public void setLongitude(String longitude) {
Longitude = longitude;
}
public String getEasting() {
return Easting;
}
public void setEasting(String easting) {
Easting = easting;
}
public String getNorthing() {
return Northing;
}
public void setNorthing(String northing) {
Northing = northing;
}
}
And the address class is as follows:
public class Address {
public String[] AddressLines;
public String Postcode;
public String getPostcode() {
return Postcode;
}
public void setPostcode(String postcode) {
Postcode = postcode;
}
public String[] getAddressLines() {
return AddressLines;
}
public void setAddressLines(String addressLines[]) {
AddressLines = addressLines;
}
}
When I try to run
LocationData[] data = gson.fromJson(this.locationServiceUrl, LocationData[].class);
return data;
I get the following error:
Expected BEGIN_ARRAY but was string at the above mentioned line of code. I am not sure if there is something wrong in the manner in which I have set up my classes. Note: I am using an array (LocationData[] data) because the service returns multiple locations although I have just included one in the example shown above. Any help as to why this is happening is much appreciated. I have looked at some of the similar errors on here but none of the fixes provided seem to work for me.
{
"finally":[
{
"Title":"John Doe",
"Address": {
"AddressLines":[
"The Place",
"123 New Place",
"London",
"England"
],
"Postcode":"NW7XXY"
},
"Telephone":"0012345",
"Email":"",
"Latitude":51.5024472101345,
"Longitude":-0.557585646554,
"Easting":500623,
"Northing":179647
}
]
}
and code to parse this JSON is :
public class mainData {
public List<LocationData> finally;
public String[] getLocationData() {
return AddressLines;
}
public void setLocationData(List<LocationData> finally) {
this.finally = finally;
}
}
it is because your string starting with [ when you parsing this type of Json with Gson then you need to prefix a label to it just i like did ( {"finally": your data }).
Actually Gson trying to map the label and its value but in your case your [ doesnt contain Label by which Gson can map.

Categories