Any idea why the JSON won't map to the java object?
The code..
String result = "{\"outerclass\":{\"innerclass\":{\"booleanA\":true,\"stringB\":\"b\",\"stringC\":\"c\"}}}\n";
Gson gson = new Gson();
TempObject o = gson.fromJson(result,TempObject.class);
The POJO..
public class TempObject {
public static class outerclass {
public static class innerclass {
public static boolean booleanA;
public static String stringB;
public static String stringC;
}
}
}
OTher example..
String result = "{\"idata\":{\"result\":{\"error\":true,\"errorMessage\":\"Invalid username and/or password\",\"requestTime\":\"2011-08-26T18:39:02Z\"}}}";
Gson gson = new Gson();
UserData d = gson.fromJson(result, UserData.class);
Class..
public class UserData {
idata data;
public static class idata {
result res;
public static class result {
public boolean error;
public String errorMessage;
public String requestTime;
}
}
}
If I am not mistaken, that's because all of your fields are static, those not related to each separate object.
So I think the class should look like that:
public class TempObject {
Outerclass outerclass;
public static class Outerclass {
Innerclass innerclass;
public static class Innerclass {
public boolean booleanA;
public String stringB;
public String stringC;
}
}
}
For example, on my machine, the output of:
public class Example{
public static void main(String[] args) {
String result = "{\"outerclass\":{\"innerclass\":{\"booleanA\":true,\"stringB\":\"b\",\"stringC\":\"c\"}}}\n";
Gson gson = new Gson();
TempObject o = gson.fromJson(result, TempObject.class);
System.out.println(gson.toJson(o));
}
public static class TempObject {
Outerclass outerclass;
public static class Outerclass {
Innerclass innerclass;
public static class Innerclass {
public boolean booleanA;
public String stringB;
public String stringC;
}
}
}
}
Is:
{"outerclass":{"innerclass":{"booleanA":true,"stringB":"b","stringC":"c"}}}
You are unable to deserialize because the variable names are not matching with the keys in your Json. In your second example
String result = "{\"idata\":{\"result\":{\"error\":true,\"errorMessage\":\"Invalid username and/or password\",\"requestTime\":\"2011-08-26T18:39:02Z\"}}}";
idata data;
result res;
The object names should match with the keys in JSON but not class names.
IData idata;
Result result;
Related
In my Application i have something like this.
public class Question{}
public class MCQ extends Question{}
public class TrueAndFalse Question{}
public class Match Question{}
and in my RestController i have a service that adds question.
#RequestMapping(value = "/game/question/add", method = RequestMethod.POST)
public Question addQuuestion(#RequestParam("gameId") long id, #RequestBody Question question)
But i get an error when i try to call this service as i send json file with different structures one for MCQ, TrueAndFalse and Match.
so is it possible to deserialize the received json to Question abstract class.
And thanks in advance.
You can create a custom deserializer which will create Question instances based on json payload properties.
For example if the Question class looks like this:
public class Question {
private final String name;
#JsonCreator
Question(#JsonProperty("name") String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And sub-class TrueAndFalse:
public class TrueAndFalse extends Question {
private final String description;
#JsonCreator
TrueAndFalse(#JsonProperty("name") String name,
#JsonProperty("description") String description) {
super(name);
this.description = description;
}
public String getDescription() {
return description;
}
}
Then you can create a deserializer, which will create an instance of TrueAndFale sub-class by checking if it has description property:
public class QuestionDeserializer extends JsonDeserializer<Question> {
#Override
public Question deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
ObjectCodec codec = p.getCodec();
JsonNode tree = codec.readTree(p);
if (tree.has("description")) {
return codec.treeToValue(tree, TrueAndFalse.class);
}
// Other types...
throw new UnsupportedOperationException("Cannot deserialize to a known type");
}
}
And afterwards, make sure to register it on the object mapper:
#Configuration
public class ObjectMapperConfiguration {
#Bean
public ObjectMapper objectMapper() {
SimpleModule module = new SimpleModule();
module.addDeserializer(Question.class, new QuestionDeserializer());
return new ObjectMapper().registerModules(module);
}
}
I have a situation where the gson is returning the child object elements also when i tried to make a json string from parent object. how to eliminate the same.
Here is the code i am having.
Class Image {
private int imageID;
private String imageName;
// Getters and setters
}
Class ImageDetails extends Image {
private String imageType;
private byte[] imageData;
//Getters and setters
}
Class Test {
// Setting the image Object, and the imageDetails.
// calling the gson for json string
String jsonString = GsonString.UserFeed(ImageObject)
// This jsonString has all the elements from the ImageDetails Object also which i do not want.
}
Class GsonString {
public static String UserFeed(Object feedData) {
String feeds = null;
Gson gson = new Gson();
feeds = gson.toJson(feedData);
return feeds;
}
}
You only have to specify the class you want to serialize, using toJson(Object src,Type typeOfSrc)
A simple example:
class Bob {
private String bobName = "Bob";
}
class Pete extends Bob {
private String peteName = "Bob";
}
public static void main(String[] args) {
Object o = new Pete();
System.out.println(new Gson().toJson(o));
System.out.println(new Gson().toJson(o, Bob.class));
}
Output:
{"peteName":"Bob","bobName":"Bob"}
{"bobName":"Bob"}
I need to deserialize a gson response
Here is the format.
{"lastid":"5", "testimonials":["a","b","c"]}
Pls suggest for DTO's and conversion.
public class TestimonialsOutputDTO implements Serializable {
public String lastid;
public List<TestimonialsDTO> testimonials;
public String getLastid() {
return lastid;
}
public void setLastid(String lastid) {
this.lastid = lastid;
}
public List<TestimonialsDTO> getTestimonials() {
return testimonials;
}
public void setTestimonials(List<TestimonialsDTO> testimonials) {
this.testimonials = testimonials;
}
}
and
public class TestimonialsDTO
{
public String testimonials;
public String getTestimonials() {
return testimonials;
}
public void setTestimonials(String testimonials) {
this.testimonials = testimonials;
}
}
You can parse "testimonials":["a","b","c"] in Java List directly instead of creating your own custom pojo.
Here your model class.
public class TestimonialsOutputDTO {
public String lastid;
public List<String> testimonials;
// getter/setter
// toString()
}
We are using Jersey/Jackson to unmarshall JSON data to java DTOs. One of my DTO is an abstract class, and i would like to unmarshall the JSON data to one of his extended DTO. For example, assuming i have these DTOs :
public abstract class AnimalDTO{}
public class DogDTO extends AnimalDTO{}
public class CatDTO extends AnimalDTO{}
I would like to unmarshall this JSON data:
{Zoo: {Animals:[{"type"="DogDTO", "code"="001", "name"="chihuahua"}, {"type"="CatDTO", "code"="002", "name"="felix"}]}}
As "type" would give the type of DTO i would like to unmarshall to. But it seems that this property isn't considered. Is there something I missed, or mistook in the JSON syntax?
Thanks.
In your case you should use #JsonTypeInfo annotation.
For more information, please see below links:
JacksonFAQ.
Jackson 1.5: Polymorphic Type Handling, first steps.
Using above links I have created a simple example which serialize POJO objects with class names:
import java.io.StringWriter;
import java.util.Arrays;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
DogDTO dog = new DogDTO();
dog.setCode("001");
dog.setName("chihuahua");
CatDTO cat = new CatDTO();
cat.setCode("002");
cat.setName("felix");
Zoo zoo = new Zoo();
zoo.setAnimals(new AnimalDTO[] { dog, cat });
Data data = new Data();
data.setZoo(zoo);
ObjectMapper objectMapper = new ObjectMapper();
StringWriter writer = new StringWriter();
objectMapper.writeValue(writer, data);
System.out.println(writer);
}
}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class AnimalDTO {
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 "AnimalDTO [code=" + code + ", name=" + name + "]";
}
}
class DogDTO extends AnimalDTO {
}
class CatDTO extends AnimalDTO {
}
class Zoo {
#JsonProperty(value = "Animals")
private AnimalDTO[] animals;
public AnimalDTO[] getAnimals() {
return animals;
}
public void setAnimals(AnimalDTO[] animals) {
this.animals = animals;
}
#Override
public String toString() {
return "Zoo [animals=" + Arrays.toString(animals) + "]";
}
}
class Data {
#JsonProperty(value = "Zoo")
private Zoo zoo;
public Zoo getZoo() {
return zoo;
}
public void setZoo(Zoo zoo) {
this.zoo = zoo;
}
#Override
public String toString() {
return "Data [zoo=" + zoo + "]";
}
}
This program prints:
{"Zoo":{"Animals":[{"type":"DogDTO","code":"001","name":"chihuahua"},{"type":"CatDTO","code":"002","name":"felix"}]}}
I have a simple jersey web service and I'd like to consume / produce objects that contain map fields, like
#XmlElement
private Map<String,String> properties;
if this string goes into the web service,
{ properties: { key1: val1, key2: val2 )}
the properties field is deserialized as null with no errors. the same JSON goes in and out of GSON no problems, and in the short term I solved this by having jersey consume produce strings and using GSON to serialize / deserialize the JSON.
any ideas?
One option is to use annotated classes. So for instance a user might be represented by the following data.
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "user")
public class User {
private int uid;
public int user_id;
public String user_name;
public String email;
public URI image_url;
public List<User> friends;
public boolean admin;
public User() {
...
}
public User(final int userid) {
// Find user by id
}
}
If you return the User object as in the following piece of code, then jaxb will automatically serialize the List as a JSON list etc etc....
#GET
#Path("/{userid}")
#Produces("application/json", "application/xml")
public User showUser(#PathParam("userid") final int userid) {
return new User(userid);
}
Jersey uses JAXB for serialization. JAXB can not serialize a Map as there is no XML type for Java type Map. Also, Map is an interface and JAXB does not like interfaces.
If you are using JAXBJackson bridge to marshal, you will run into issue.
You will need to create an adapter like below and annotate your Map property with
#XmlJavaTypeAdapter(MapAdapter.class)
private Map<String,String> properties;
#XmlSeeAlso({ Adapter.class, MapElement.class })
public class MapAdapter<K,V> extends XmlAdapter<Adapter<K,V>, Map<K,V>>{
#Override
public Adapter<K,V> marshal(Map<K,V> map) throws Exception {
if ( map == null )
return null;
return new Adapter<K,V>(map);
}
#Override
public Map<K,V> unmarshal(Adapter<K,V> adapter) throws Exception {
throw new UnsupportedOperationException("Unmarshalling a list into a map is not supported");
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name="Adapter", namespace="MapAdapter")
public static final class Adapter<K,V>{
List<MapElement<K,V>> item;
public Adapter(){}
public Adapter(Map<K,V> map){
item = new ArrayList<MapElement<K,V>>(map.size());
for (Map.Entry<K, V> entry : map.entrySet()) {
item.add(new MapElement<K,V>(entry));
}
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name="MapElement", namespace="MapAdapter")
public static final class MapElement<K,V>{
#XmlAnyElement
private K key;
#XmlAnyElement
private V value;
public MapElement(){};
public MapElement(K key, V value){
this.key = key;
this.value = value;
}
public MapElement(Map.Entry<K, V> entry){
key = entry.getKey();
value = entry.getValue();
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
}