For the below code, my nested parameterized object is always deserialized as LinkedTreeMap instead of the original class
I am using GSON for json serializing & deserializing
Here are the models:
Cart containing wrapped items
public class Cart {
private String id;
private String owner;
private List<ItemWrapper> relatedItems;
.......
public List<ItemWrapper> getRelatedItems() {
return relatedItems;
}
public void setRelatedItems(List<ItemWrapper> relatedItems) {
this.relatedItems = relatedItems;
}
}
Item wrapper
public class ItemWrapper<T> {
private String type;
private String decription;
private T item;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
........
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
Car Item ..
public class Car {
private String model;
private double price;
public String getModel() {
return model;
}
.....
public void setPrice(double price) {
this.price = price;
}
}
Book Item ..
public class Book {
private String name;
private String mediaType;
public String getName() {
return name;
}
.....
public void setMediaType(String mediaType) {
this.mediaType = mediaType;
}
}
When I run the below snippet
Cart cart = gson.fromJson(
"{\"id\":\"id123\",\"owner\":\"Usama\",\"relatedItems\":[{\"type\":\"Book\",\"decription\":\"book item\",\"item\":{\"name\":\"Love\",\"mediaType\":\"pdf\"}},{\"type\":\"Car\",\"decription\":\"car item\",\"item\":{\"model\":\"BMW\",\"price\":500000.0}}]}\n"
+ "",
Cart.class);
System.out.println(cart.getClass().getName());
System.out.println(cart.getRelatedItems().get(0).getItem().getClass().getName());
I got that result
model.Cart
com.google.gson.internal.LinkedTreeMap
instead of
model.Cart
model.Book
Any idea how to fix this.
Related
We would like to type various properties in Java.
e.g. the e-mail address
But now I get the message all the time:
Could not set field value [test#test.de] value by reflection : [class customer.email] setter of customer.email;
Can not set dataType.EmailAddress field customer.email to java.lang.String
How should I proceed?
#Entity
public class customer {
#Id
#GeneratedValue
private Long id;
private String name;
private EmailAddress email;
}
public class EmailAddress {
public String value;
public EmailAddress(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public boolean setValue(String s) {
this.value = s;
return true;
}
public String mailbox() ...
public String host() ...
public String tld() ...
}
Getter and Setter from HibernateDefaultType not called.
EDIT:
At the end. I want to store a String in the database with the email-Address. In Java I want the EmailAddress Object.
it is much easier. An AttributeConverter make it very easy.
https://thorben-janssen.com/jpa-attribute-converter/
Thank you very much
EDIT:
Here is the Code:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter(autoApply = true)
public class EmailAddressConverter implements AttributeConverter<EmailAddress, String> {
#Override
public String convertToDatabaseColumn(EmailAddress emailAddress) {
return emailAddress.value;
}
#Override
public EmailAddress convertToEntityAttribute(String s) {
return new EmailAddress(s);
}
}
And in the Entity:
#Convert(converter = EmailAddressConverter.class)
private EmailAddress email;
Here is some example of making your own custom type.
public class EmailAddressDescriptor extends AbstractTypeDescriptor<String> {
protected EmailAddressDescriptor() {
super(String.class, new ImmutableMutabilityPlan<>());
}
#Override
public String toString(String value) {
return null;
}
#Override
public String fromString(String string) {
return null;
}
#Override
public <X> X unwrap(String value, Class<X> type, WrapperOptions options) {
return null;
}
#Override
public <X> String wrap(X value, WrapperOptions options) {
return null;
}
#Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
return null;
}
}
Then you would make the Email address class with all your methods
public class EmailAddress extends AbstractSingleColumnStandardBasicType<String> {
private String value;
public EmailAddress() {
super(new VarcharTypeDescriptor(), new EmailAddressDescriptor());
}
#Override
public String getName() {
return "EmailAddress";
}
#Override
public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) throws HibernateException {
return null;
}
}
public String mailbox() ...
public String host() ...
public String tld() ...
How you would use it with your entity will be something like this
#Entity
#TypeDef(name = "emailAddress", typeClass = EmailAddress.class)
public class customer {
#Id
#GeneratedValue
private Long id;
private String name;
#Type (type = "emailAddress")
private EmailAddress emailAddress;
}
Hope this helps
I am using Flickr API to get the information of images and returns the following JSON:
{"photos":{"page":1,"pages":60,"perpage":100,"total":"5964","photo":[{"id":"21577339501","owner":"85277110#N02","secret":"31e850dfeb","server":"5785","farm":6,"title":"P1390956","ispublic":1,"isfriend":0,"isfamily":0}, {"id":"21577287101","owner":"85277110#N02","secret":"412990658f","server":"611","farm":1,"title":"P1400012","ispublic":1,"isfriend":0,"isfamily":0}]
I use this code in the Spring controller to deserialize the JSON:
Collection<Photos> readValues = objectMapper.readValue(new URL(url), new TypeReference<Collection<Photos>>() { });
And returns the following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
How can I solve this problem? I didn't found solutions.
Photos.class:
public class Photos {
#JsonProperty("page")
private Integer page;
#JsonProperty("pages")
private Integer pages;
#JsonProperty("perpage")
private Integer perpage;
#JsonProperty("total")
private Integer total;
#JsonProperty("photo")
#JsonDeserialize(contentAs = Photo.class, as = ArrayList.class)
private List<Photo> photo;
public Photos() {}
public Photos(Integer page, Integer pages, Integer perpage, Integer total,
List<Photo> photo) {
super();
this.page = page;
this.pages = pages;
this.perpage = perpage;
this.total = total;
this.photo = photo;
}
public Photos(List<Photo> photo) {
super();
this.photo = photo;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getPages() {
return pages;
}
public void setPages(Integer pages) {
this.pages = pages;
}
public Integer getPerpage() {
return perpage;
}
public void setPerpage(Integer perpage) {
this.perpage = perpage;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
public List<Photo> getPhoto() {
return photo;
}
public void setPhoto(List<Photo> photo) {
this.photo = photo;
}
}
Photo.class:
public class Photo {
#JsonProperty("id")
private Integer id;
#JsonProperty("owner")
private String owner;
#JsonProperty("secret")
private String secret;
#JsonProperty("server")
private Integer server;
#JsonProperty("farm")
private Integer farm;
#JsonProperty("title")
private String title;
#JsonProperty("ispublic")
private Boolean isPublic;
#JsonProperty("isfriend")
private Boolean isFriend;
#JsonProperty("isfamily")
private Boolean isFamily;
public Photo() { }
public Photo(Integer id, String owner, String secret, Integer server,
Integer farm, String title, Boolean isPublic, Boolean isFriend,
Boolean isFamily) {
super();
this.id = id;
this.owner = owner;
this.secret = secret;
this.server = server;
this.farm = farm;
this.title = title;
this.isPublic = isPublic;
this.isFriend = isFriend;
this.isFamily = isFamily;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public Integer getServer() {
return server;
}
public void setServer(Integer server) {
this.server = server;
}
public Integer getFarm() {
return farm;
}
public void setFarm(Integer farm) {
this.farm = farm;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Boolean getIsPublic() {
return isPublic;
}
public void setIsPublic(Boolean isPublic) {
this.isPublic = isPublic;
}
public Boolean getIsFriend() {
return isFriend;
}
public void setIsFriend(Boolean isFriend) {
this.isFriend = isFriend;
}
public Boolean getIsFamily() {
return isFamily;
}
public void setIsFamily(Boolean isFamily) {
this.isFamily = isFamily;
}
}
The basic problem is that your json is not a Collection<Photos>, but a Map<String, Photos>, which has a single entry "photos" -> Photos instance.
I got your json to successfully deserialize by making the following changes...
A) Change the type being read:
Map<String, Photos> readValues = objectMapper.readValue(json, new TypeReference<Map<String, Photos>>() { });
Note that I read straight from a String (not a URL).
B) Change the type of Photo.id from Integer to Long, because your json has id values well exceeding max int size.
C) I added the missing two closing braces from your sample json to make it valid.
FYI, deserialization works with or without the #JsonDeserialize annotation on the List<Photo> photo field of Photos.
Here's some runnable code that works:
String json = "{\"photos\":{\"page\":1,\"pages\":60,\"perpage\":100,\"total\":\"5964\",\"photo\":[{\"id\":\"21577339501\",\"owner\":\"85277110#N02\",\"secret\":\"31e850dfeb\",\"server\":\"5785\",\"farm\":6,\"title\":\"P1390956\",\"ispublic\":1,\"isfriend\":0,\"isfamily\":0}, {\"id\":\"21577287101\",\"owner\":\"85277110#N02\",\"secret\":\"412990658f\",\"server\":\"611\",\"farm\":1,\"title\":\"P1400012\",\"ispublic\":1,\"isfriend\":0,\"isfamily\":0}]}}";
Map<String, Photos> readValues = new ObjectMapper().readValue(json, new TypeReference<Map<String, Photos>>() { });
java object: MyObject has a list of AnotherObject1 and AnotherObject1 also have a list of AnotherObject2
class MyObject{
private String status;
private String message;
private List<AnotherObject1> data;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<AnotherObject1> getData() {
return data;
}
public void setData(List<AnotherObject1> data) {
this.data = data;
}
}
Class AnotherObject1{
private Integer group_id;
private List<AnotherObject2> anotherList;
public Integer getGroup_id() {
return group_id;
}
public void setGroup_id(Integer group_id) {
this.group_id = group_id;
}
public List<AnotherObject2> getAnotherList() {
return smsList;
}
public void setAnotherList(List<AnotherObject2> anotherList) {
this.anotherList = anotherList;
}
}
class AnotherObject2{
private String customid;
private String customid1 ;
private Long mobile;
private String status;
private String country;
public String getCustomid() {
return customid;
}
public void setCustomid(String customid) {
this.customid = customid;
}
public String getCustomid1() {
return customid1;
}
public void setCustomid1(String customid1) {
this.customid1 = customid1;
}
public Long getMobile() {
return mobile;
}
public void setMobile(Long mobile) {
this.mobile = mobile;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
JSON String: this is my json string by which i want to make an java object using object mapper
String response="{\"status\":\"OK\",\"data\":{\"group_id\":39545922,\"0\":{\"id\":\"39545922-1\",\"customid\":\"\",\"customid1\":\"\",\"customid2\":\"\",\"mobile\":\"910123456789\",\"status\":\"XYZ\",\"country\":\"IN\"}},\"message\":\"WE R Happy.\"}"
ObjectMapper code
//convert string to response object
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
objectMapper.readValue(responseBody, MyObject.class);
exception: here is the exception
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
at [Source: {"status":"OK","data":{"group_id":39545922,"0":{"id":"39545922-1","customid":"","customid1":"","customid2":"","mobile":"910123456789","status":"GOOD","country":"IN"}},"message":"We R happy."}; line: 1, column: 15] (through reference chain: MyObject["data"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:854)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:850)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:292)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:227)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:217)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:25)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:520)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:256)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2714)
at abc.disp(RestClientImpl.java:210)
at abc.disp(RestClientImpl.java:105)
at Application.<init>(Application.java:42)
at Application.main(Application.java:45)
please guide me how to make it possible.
Your code itself is not compailable ...
private List<AnotherObject1> data; // Your class member is list of AnotherObject1
and below it is used as List of SMSDTO in getter and setter
public List<SMSDTO> getData() {
return data;
}
Problem is quite simple: you claim data should become Java List; and this requires that JSON input for it should be JSON Array. But what JSON instead has is a JSON Object.
So you either need to change POJO definition to expect something compatible with JSON Object (a POJO or java.util.Map); or JSON to contain an array for data.
First as Naveen Ramawat said your code is not compilable as it is.
In the class AnotherObject1 getSmsList should take AnotherObject2 and setSmsList should take AnotherObject2 also as parameter.
In the class MyObject setData and getData should use AnotherObject1 as parameters
Second your JSON string is not valid it should be sommething like that:
{"status":"OK","data":[{"group_id":39545922,"smsList":[{"customid":"39545922-1","customid1":"","mobile":913456789,"status":"XYZ","country":"XYZ"}]}]}
Here is the code that I used :
MyObject.java:
import java.util.List;
class MyObject {
private String status;
private String message;
private List<AnotherObject1> data;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<AnotherObject1> getData() {
return data;
}
public void setData(List<AnotherObject1> data) {
this.data = data;
}
}
AnotherObject1.java :
import java.util.List;
public class AnotherObject1 {
private Integer group_id;
private List<AnotherObject2> smsList;
public Integer getGroup_id() {
return group_id;
}
public void setGroup_id(Integer group_id) {
this.group_id = group_id;
}
public List<AnotherObject2> getSmsList() {
return smsList;
}
public void setSmsList(List<AnotherObject2> smsList) {
this.smsList = smsList;
}
}
AnotherObject2.java :
public class AnotherObject2 {
private String customid;
private String customid1;
private Long mobile;
private String status;
private String country;
public String getCustomid() {
return customid;
}
public void setCustomid(String customid) {
this.customid = customid;
}
public String getCustomid1() {
return customid1;
}
public void setCustomid1(String customid1) {
this.customid1 = customid1;
}
public Long getMobile() {
return mobile;
}
public void setMobile(Long mobile) {
this.mobile = mobile;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
To get the JSON string :
import org.json.JSONObject;
import org.json.XML;
import com.google.gson.Gson;
MyObject myObj = new MyObject();
ArrayList<AnotherObject2> smsList = new ArrayList<AnotherObject2>();
ArrayList<AnotherObject1> data = new ArrayList<AnotherObject1>();
AnotherObject1 ao1 = new AnotherObject1();
ao1.setGroup_id(39545922);
ao1.setSmsList(smsList);
AnotherObject2 sms = new AnotherObject2();
sms.setCountry("XYZ");
sms.setCustomid("39545922-1");
sms.setCustomid1("");
sms.setMobile((long) 913456789);
sms.setStatus("XYZ");
smsList.add(sms);
ao1.setSmsList(smsList);
data.add(ao1);
myObj.setStatus("OK");
myObj.setData(data);
// Build a JSON string to display
Gson gson = new Gson();
String jsonString = gson.toJson(myObj);
System.out.println(jsonString);
// Get an object from a JSON string
MyObject myObject2 = gson.fromJson(jsonString, MyObject.class);
// Display the new object
System.out.println(gson.toJson(myObject2));
I have a json string something similar
{"results":
[{"_type":"Position","_id":377078,"name":"Potsdam, Germany","type":"location","geo_position":{"latitude":52.39886,"longitude":13.06566}},
{"_type":"Position","_id":410978,"name":"Potsdam, USA","type":"location","geo_position":{"latitude":44.66978,"longitude":-74.98131}}]}
I am trying to convert to
{"results":
[{"_type":"Position","_id":377078,"name":"Potsdam, Germany","type":"location","latitude":52.39886,"longitude":13.06566},
{"_type":"Position","_id":410978,"name":"Potsdam, USA","type":"location","latitude":44.66978,"longitude":-74.98131}]}
I am converting to java and again converting back using But I am gettin null in data
SourceJSON data=new Gson().fromJson(jsonArray, SourceJSON.class);
DestinationJSON destdata = new DestinationJSON();
destdata.setLatitide(data.getGeoLocation().getLatitide());
destdata.setLongitude(data.getGeoLocation().getLongitude());
destdata.setId(data.getId());
destdata.setType(data.getType());
destdata.setName(data.getName());
destdata.set_type(data.get_type());
Gson gson = new Gson();
String json = gson.toJson(destdata);
below are my beans
public class SourceJSON implements Serializable {
private List<GEOLocation> geoLocations;
private String _type;
private String id;
private String name;
private String type;
public String get_type() {
return _type;
}
public List<GEOLocation> getGeoLocations() {
return geoLocations;
}
public void setGeoLocations(List<GEOLocation> geoLocations) {
this.geoLocations = geoLocations;
}
public void set_type(String _type) {
this._type = _type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
and
public class GEOLocation implements Serializable{
private String latitide;
private String longitude;
public String getLatitide() {
return latitide;
}
public void setLatitide(String latitide) {
this.latitide = latitide;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
}
and destination java
public class DestinationJSON implements Serializable {
private String _type;
private String id;
private String name;
private String type;
private String latitide;
private String longitude;
public String get_type() {
return _type;
}
public void set_type(String _type) {
this._type = _type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getLatitide() {
return latitide;
}
public void setLatitide(String latitide) {
this.latitide = latitide;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
}
All you need is this. You can try this class in your IDE with a simple copy&paste.
package stackoverflow.questions;
import java.util.*;
import com.google.gson.Gson;
public class Q20433539{
public static void main(String[] args){
String json = "{\"results\":"+
"[{\"_type\":\"Position\",\"_id\":377078,\"name\":\"Potsdam, Germany\",\"type\":\"location\",\"geo_position\":{\"latitude\":52.39886,\"longitude\":13.06566}},"+
"{\"_type\":\"Position\",\"_id\":410978,\"name\":\"Potsdam, USA\",\"type\":\"location\",\"geo_position\":{\"latitude\":44.66978,\"longitude\":-74.98131}}]}";
Gson gson = new Gson();
Map m = gson.fromJson(json, Map.class);
List<Map> innerList = (List<Map>) m.get("results");
for(Map result: innerList){
Map<String, Double> geo_position = (Map<String, Double>) result.get("geo_position");
result.put("latitude", geo_position.get("latitude"));
result.put("longitude", geo_position.get("longitude"));
result.remove("geo_position");
}
System.out.println(gson.toJson(m));
}
}
Of course, it works under the assumption that you always want to flat geo information.
Explanation: It's convenient to use POJO when working with Gson, but it's not the only way. Gson can also deseralize to Arrays/Maps if you do not specify the expected result. So I did, and then I manipulated the structure to unfold your data. After that, Gson can serialize Arrays/Maps structure again to your desidered JSON.
I'm using XmlAdapter for immutable objects as proposed in this blog post: http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html. This works fine, but not with references to other immutable objects in my adapters. Is there any way to handle this with JAXB?
Below there is an example which does not work if the person's xml tag comes after the company's xml tag which references the person.
Immutable objects:
#XmlJavaTypeAdapter(PersonAdapter.class)
public class Person {
private final String id;
private final String name;
public Person(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
}
#XmlJavaTypeAdapter(CompanyAdapter.class)
public class Company {
private final String name;
private final Person principal;
public Company(String name, Person principal) {
this.name = name;
this.principal = principal;
}
public String getName() {
return name;
}
public Person getPrincipal() {
return principal;
}
}
PersonAdapter:
public class PersonAdapter extends XmlAdapter<AdaptedPerson, Person> {
public static class AdaptedPerson {
#XmlID
#XmlAttribute
String id;
#XmlAttribute
String name;
}
#Override
public AdaptedPerson marshal(Person v) throws Exception {
AdaptedPerson a = new AdaptedPerson();
a.id = v.getId();
a.name = v.getName();
return a;
}
#Override
public Person unmarshal(AdaptedPerson v) throws Exception {
return new Person(v.id, v.name);
}
}
CompanyAdapter:
public class CompanyAdapter extends XmlAdapter<AdaptedCompany, Company> {
public static class AdaptedCompany {
#XmlAttribute
String name;
#XmlIDREF
#XmlAttribute
Person principal;
}
#Override
public AdaptedCompany marshal(Company v) throws Exception {
AdaptedCompany a = new AdaptedCompany();
a.name = v.getName();
a.principal = v.getPrincipal();
return a;
}
#Override
public Company unmarshal(AdaptedCompany v) throws Exception {
return new Company(v.name, v.principal);
}
}