Partial JSON serialisation/de-serialization using Jackson - java

I have a problem that I cannot resolve for a while.
Lets imagine a very simple Java class
class Foo {
public String bar;
public String baz;
}
How can I accomplish that the operation of deserialisation and consequent serialisation of some JSON request is actually immutable in terms of partial JSON objects. So that if I unserialise
{
"bar": "some value",
"baz": null
}
into Foo instance and then serialise it back to JSON, I get
{
"bar": "some value",
"baz": null
}
and if I unserialize partial JSON without "baz"
{
"bar": "some value"
}
I get again a partial JSON without "baz"
{
"bar": "some value"
}

This is not possible unless you store information about which fields were present in the original JSON objects. For this purpose, you could use a wrapper around Foo which contains a Foo plus this addtional info. Below is an example.
Note: this is pseudocode. The method and class names are part from the Gson library and part invented by me on the fly, but you get the idea. I think it shouldn't be difficult to translate this using the classes of Jackson.
class DeserializedFoo {
private Foo foo;
private Set<String> includedFields = new HashSet<>();
private DeserializedFoo(){
}
public static class DeSerializer implements JsonDeserializer<DeserializedFoo> {
#Override
public DeserializedFoo deserialize(JsonElement je) {
DeserializedFoo dsFoo = new DeserializedFoo();
dsFoo.foo = parse(je);
for(JsonElement prop : je.elements()){
includedFields.add(prop.getName());
}
return dsFoo;
}
}
public static class Serializer implements JsonSerializer<DeserializedFoo> {
#Override
public JsonElement serialize(DeserializedFoo dsFoo) {
JsonElement jsonFoo = serialize(dsFoo.foo);
// Leave only fields that were present in the JSON
// element from which this was deserialized.
Iterable it = jsonFoo.elements().iterable();
while(it.hasNext()){
JsonElement prop = it.next();
if(!includedFields.contains(prop.getName()){
it.remove();
}
}
return jsonFoo;
}
}
}
You could of course use inheritance instead of a wrapper, e.g. by defining class DeserilizedFoo extends Foo and adding the includedFields field. Each approach has its benefits and drawbacks. It's up to you to decide which one fits your situation best.

You can annotated your class with #JsonInclude(Include.NON_DEFAULT) and
set the default value for baz property to a magic string which would indicate that the value should not be present in the JSON.
Here is an example:
public class JacksonIncludeNull {
final static String JSON1 = "{\n" +
" \"bar\": \"some value\",\n" +
" \"baz\": null\n" +
"}";
final static String JSON2 = "{\n" +
" \"bar\": \"some value\"\n" +
"}";
#JsonInclude(JsonInclude.Include.NON_DEFAULT)
static class Foo {
public String bar;
public String baz = "##default";
#Override
public String toString() {
return "Foo{" +
"bar='" + bar + '\'' +
", baz='" + baz + '\'' +
'}';
}
}
public static void main(String[] args) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new GuavaModule());
final Foo foo1 = mapper.readValue(JSON1, Foo.class);
System.out.println(JSON1);
System.out.println("Object: " + foo1);
System.out.println("Serialize: " + mapper.writeValueAsString(foo1));
System.out.println();
final Foo foo2 = mapper.readValue(JSON2, Foo.class);
System.out.println(JSON2);
System.out.println("Object: " + foo2);
System.out.println("Serialize: " + mapper.writeValueAsString(foo2));
}
}
Output:
{
"bar": "some value",
"baz": null
}
Object: Foo{bar='some value', baz='null'}
Serialize: {"bar":"some value","baz":null}
{
"bar": "some value"
}
Object: Foo{bar='some value', baz='##default'}
Serialize: {"bar":"some value"}

Related

Why org.json.JSONObject excludes POJO fields start with x while converting to JSON object?

Diferent results occur when mapping an object containing a field starting with "x" to org.json.JSONObject and com.fasterxml.jackson.core.ObjectMapper:
JSONObject
{"one":"One"}
ObjectMapper
{"one":"One","xOne":"xOne"}
Why does the JSONObject not include the "xOne" field?
public class Test {
private String one;
private String xOne;
public String getOne() {
return one;
}
public void setOne(String one) {
this.one = one;
}
public String getxOne() {
return xOne;
}
public void setxOne(String xOne) {
this.xOne = xOne;
}
#Override
public String toString() {
return "Test [one=" + one + ", xOne=" + xOne + "]";
}
}
public class PojoToJson {
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
Test test = new Test();
test.setOne("One");
test.setxOne("xOne");
JSONObject json = new JSONObject(test);
System.out.println("JSONObject o/p: " + json);
ObjectMapper mapper = new ObjectMapper();
String mapperString = mapper.writeValueAsString(test);
System.out.println("ObjectMapper o/p: " + mapperString);
}
}
Here is my output difference using JSONObject and ObjectMapper:
According to the Jackson reference documentation:
In absence of a registered custom strategy, the default Java property
naming strategy is used, which leaves field names as is, and removes
set/get/is prefix from methods (as well as lower-cases initial
sequence of capitalized characters).
As I understand it, this means that Jackson will understand that getxOne() actually correspond to xOne property.
org.json.JSONObject may have a different naming strategy (which I was not able to find anywhere) and hence the reason for getxOne() to work with Jackson's ObjectMapper but not with org.json.JSONObject.

Skip a hierarchy when deserialising with Gson

Let's suppose we have a json like this one, that cannot be modified.
And we want do deserilise it using Gson.
{
"user": {
"some_ids": {
"useless_key": [
"22a074ff-91bf-4599-9a9e-374d3f01b6e0",
"66c8ce85-f162-4d92-a836-198a17764efa",
"d0519a9e-bfa2-446c-bb98-746136a3e513"
]
}
}
}
We want to deserialise it in a class User like this one:
public class User {
#SerializedName("some_ids")
List<String> someIds;
}
The question:
The simple solution would be to create a UselessKey wrapper class and put the someIds list in it.
But is there a way to tell Gson to skip the node useless_keyand directly deserialise the List inside someIds ?
Since you still have to mark a field supposed to be processed differently, Gson does not provide anything like that. However you can implement such behavior. The closest thing to your request is #JsonAdapter
Suppose you have
private static final String JSON = "{\n"
+ " \"user\": {\n"
+ " \"some_ids\": {\n"
+ " \"useless_key\": [\n"
+ " \"22a074ff-91bf-4599-9a9e-374d3f01b6e0\",\n"
+ " \"66c8ce85-f162-4d92-a836-198a17764efa\",\n"
+ " \"d0519a9e-bfa2-446c-bb98-746136a3e513\"\n"
+ " ]\n"
+ " }\n"
+ " }\n"
+ "}";
public static void main(final String... args) {
final Gson gson = new Gson();
final Response response = gson.fromJson(JSON, Response.class);
out.println(response.getUser().getSomeIds());
}
The DTO Response class is defined as the follows:
final class Response {
private Response() { }
#SerializedName("user")
private final User user = null;
User getUser() { return user; }
static final class User {
private User() { }
#SerializedName("some_ids")
#JsonAdapter(IdsTypeAdapter.class)
private final List<String> someIds = null;
List<String> getSomeIds() { return someIds; }
}
}
The type adapter specified in #JsonAdapter(IdsTypeAdapter.class) above can be implemented as follows:
final class IdsTypeAdapter
extends TypeAdapter<List<String>> {
private static final String USELESS_PROPERTY = "useless_key";
private IdsTypeAdapter() {
}
#Override
public void write(final JsonWriter writer, final List<String> value) {
throw new UnsupportedOperationException();
}
#Override
public List<String> read(final JsonReader reader)
throws IOException {
reader.beginObject();
if ( !reader.nextName().equals(USELESS_PROPERTY) ) {
throw new UnsupportedOperationException("Expected: " + USELESS_PROPERTY);
}
reader.beginArray();
final List<String> ids = new ArrayList<>();
while ( reader.peek() == STRING ) {
ids.add(reader.nextString());
}
reader.endArray();
reader.endObject();
return unmodifiableList(ids);
}
}
The type adapter above is pretty easy, and promotes stream reading in order to improve performance (type adapters are also required by the #JsonAdapter annotation). And the result:
[22a074ff-91bf-4599-9a9e-374d3f01b6e0, 66c8ce85-f162-4d92-a836-198a17764efa, d0519a9e-bfa2-446c-bb98-746136a3e513]
Another option is use of JSON deserializers (can be registered in GsonBuilder), but the latter have performance impacts since they require the whole JSON tree to be built before a deserialization process begins. Another issue with JSON deserializers is that Gson does not support custom annotations, so in order to mark "special" fields you still need to create a wrapper class like class StringIds extends ArrayList<String> that later would even require a deserialization context to deserialize a given JsonElement to List<String> and then remapped back to StringIds. That's expensive. I would go with type adapters.
Just don't create the variable and getter and setter in your Model class. It will not then parse the key which is not found.

How to deserialize JSON string into different complex class types?

I have a JSONNode object that can contain any JSON content. Example :
{
"fieldA": "aStringValue",
"fieldB": 10,
"fieldC": {
"TypeAFieldA": "aValue"
},
"fieldD": {
"TypeBFieldA": "aValue",
"TypeBFieldB": {
"TypeCFieldA": "aValue",
"TypeCFieldB": "bValue"
}
}
}
I want to deserialize each JSON field in this string into different types of java objects as below :
fieldA -> String object
fieldB -> int
fieldC -> TypeA object
fieldD -> TypeB object
Assume that I know the class type that each field should deserialize into.
What is the best and most optimal way to go about this?
Edit: To further clarify my requirement :
The approach I have thought of is I have created objects for TypeA, TypeB, TypeC etc and have annotated them with relevant JsonPropery annotations.
What I am unclear about is how do I go about deserializing each field individually? For this I would need to extract the json string from the JsonNode one by one and run through an object mapper with the relevant class type?
Example: To deserialize "fieldC" and its value into a class of TypeC, don't I have to do something like :
Extract full Json string :
String jsonString = "fieldC": { "TypeAFieldA": "aValue" }";
Run it through an object mapper:
mapper.readValue( jsonString, TypeC.class );
How do I extract the full json string for each field by looping through the JsonNode? Is this the most optimal way to go about this?
You can do something like this:
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readTree(json);
JsonNode fieldA = actualObj.get("fieldA");
String fieldAObj = fieldA.asText();
JsonNode fieldB = actualObj.get("fieldB");
Integer fieldBObj = fieldB.asInt();
JsonNode fieldC = actualObj.get("fieldC");
//if you really want json string of fieldC just use fieldC.toString()
TypeA fieldCObj = mapper.treeToValue(fieldC, TypeA.class);
JsonNode fieldD = actualObj.get("fieldD");
TypeB fieldDObj = mapper.treeToValue(fieldD, TypeB.class);
And here is 100% generic version:
JsonNode actualObj = mapper.readTree(json);
Iterator<Map.Entry<String, JsonNode>> values = actualObj.fields();
Object field;
while (values.hasNext()){
Map.Entry<String, JsonNode> entry = values.next();
String key = entry.getKey();
JsonNode value = entry.getValue();
if(value.canConvertToInt()){
// Integer
field = value.asInt();
}else if(value.isTextual()){
// String
field = value.asText();
}else{
try {
field = mapper.treeToValue(value, TypeA.class);
}catch (Exception e){
field = mapper.treeToValue(value, TypeB.class);
}
}
System.out.println(key + " => "+ field);
}
Or you can use parent object with #JsonAnySetter and put all the logic where you determine object type and create object instances in this setter. Here is demo
public static class Data{
private HashMap<String,Object> data = new HashMap<String, Object>();
#JsonAnyGetter
public HashMap<String, Object> getValues(){
return data;
}
#JsonAnySetter
public void setValue(String key, JsonNode value) {
// value.toString() is json string of each field
Object resultObj = "";
if (value.canConvertToInt()) {
resultObj = String.valueOf(value);
} else if (value.isTextual()) {
resultObj = String.valueOf(value);
} else if (value.has("TypeAFieldA")) {
try {
resultObj = mapper.treeToValue(value, TypeA.class);
} catch (IOException e) {
e.printStackTrace();
}
} else if (value.has("TypeBFieldB")) {
try {
resultObj = mapper.treeToValue(value, TypeB.class);
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(key + " " + resultObj);
// can use key - resultObj pair any way you want
//for example add it to hashmap or multiple hashmaps for each class type
data.put(key, resultObj);
}
}
Test Code:
public class Main {
private static ObjectMapper mapper = new ObjectMapper();
private static final String json = "{\n" +
" \"fieldA\": \"aStringValue\",\n" +
" \"fieldB\": 10,\n" +
" \"fieldC\": {\n" +
" \"TypeAFieldA\": \"aValue\"\n" +
" },\n" +
" \"fieldD\": {\n" +
" \"TypeBFieldA\": \"aValue\",\n" +
" \"TypeBFieldB\": {\n" +
" \"TypeCFieldA\": \"aValue\",\n" +
" \"TypeCFieldB\": \"bValue\"\n" +
" }\n" +
" }\n" +
"}";
public static void main(String[] args) throws IOException, JSONException {
Data data = mapper.readValue( json, Data.class );
String json = mapper.writeValueAsString(data);
System.out.println(json);
}
public static class TypeA {
#JsonProperty("TypeAFieldA")
private String TypeAFieldA;
#Override
public String toString() {
return "TypeA{" +
"TypeAFieldA='" + TypeAFieldA + '\'' +
'}';
}
}
public static class TypeB {
#JsonProperty("TypeBFieldA")
private String TypeBFieldA;
#JsonProperty("TypeBFieldB")
private TypeC TypeBFieldB;
#Override
public String toString() {
return "TypeB{" +
"TypeBFieldA='" + TypeBFieldA + '\'' +
", TypeBFieldB=" + TypeBFieldB +
'}';
}
}
public static class TypeC {
#JsonProperty("TypeCFieldA")
private String TypeCFieldA;
#JsonProperty("TypeCFieldB")
private String TypeCFieldB;
#Override
public String toString() {
return "TypeC{" +
"TypeCFieldA='" + TypeCFieldA + '\'' +
", TypeCFieldB='" + TypeCFieldB + '\'' +
'}';
}
}
}
Result:
fieldA aStringValue
fieldB 10
fieldC TypeA{TypeAFieldA='aValue'}
fieldD TypeB{TypeBFieldA='aValue', TypeBFieldB=TypeC{TypeCFieldA='aValue', TypeCFieldB='bValue'}}
Inspired by the solutions posted here, I was able to come up with my own implementation for the problem.
I wrote a function that takes in a JsonNode, and a java.lang.reflect.Type parameter. This function would check the node for each primitive and non primitive data type that I will be using in my application and deserialize it into the appropriate type.
/**
* This function takes in a JSON node, a type info and converts the JSON into
* the given type.
* #param node - node to deserialize
* #param typeInfo - data type to deserialize into
* #throws JsonMappingException
* #throws JsonParseException
* #throws IOException
*/
private void deserializeNode ( JsonNode node, Type typeInfo ) throws JsonMappingException, JsonParseException, IOException {
Object deserializedValue = null;
if ( node.isDouble() ) {
deserializedValue = node.asDouble();
} else if ( node.isInt() ) {
deserializedValue = node.asInt();
} else if ( node.isLong() ) {
deserializedValue = node.asLong();
} else if ( node.isBoolean() ) {
deserializedValue = node.asBoolean();
} else if ( node.isArray() ) {
//Json array is translated into a Java List. If this is a known type, it will translate
//into a List<Type> instance.
CollectionType collectionType = this.getActualTypeOfCollection( typeInfo );
deserializedValue = mapper.readValue( node.toString(), collectionType );
} else if ( node.isObject() ) {
JavaType objectType = mapper.getTypeFactory().constructType( typeInfo );
deserializedValue = mapper.readValue( node.toString(), objectType );
} else if ( node.isTextual() ) {
deserializedValue = node.asText();
}
this.deserializedValues.add( deserializedValue );
}
/**
* This function returns the actual collection type of a generic parameter.
* I.e. It returns the proper Collection data complete with the generic type so
* that Jackson could determine the proper type to deserialize the field into.
* #param genericParameterType - java parameter type
* #return Jackson collection type
*/
private CollectionType getActualTypeOfCollection ( Type genericParameterType ) {
CollectionType collectionType = null;
if(genericParameterType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for ( Type parameterArgType : parameterArgTypes ) {
collectionType = mapper.getTypeFactory().constructCollectionType(List.class, (Class<?>) parameterArgType ) ;
break;
}
}
return collectionType;
}
Comments are welcome on the pros/cons of this approach.
Create a Java class, say JsonNode, and define all the given attributes with the known data types and their getter and setter methods. Then annotate each attribute with #JsonProperty attribute.
The complex objects can be defined as nested classes and defined in your JsonNode class as an attribute object of the particular nested class. The object class in turn can have attributes annotated with #JsonProperty.
Something like this -
class JsonNode {
#JsonProperty("fieldA")
private String fieldA;
#JsonProperty("fieldB")
private int fieldB;
#JsonProperty("fieldC")
private TypeA fieldC;
#JsonProperty("fieldD")
private TypeB fieldB;
getters and setters...
class TypeA {
#JsonProperty("innerFieldA")
private String innerFieldA;
getters, setters
}
class TypeA {
#JsonProperty("innerFieldB")
private String innerFieldB;
getters, setters
}
}

How to parse JSON object by Jackson if type of one field is unknown

I have a JSON response that I try to parse with Jackson, and type of one of fields is unknown.
Exapmle:
{"name" : "Catalina"}
OR
{"name" : {"First" : "Catalina", "Last" : "Kyle"}}
How I can deserialize that object into POJO:
class NamesHolder {
public String singleName;
public Map<String, String> nameMap;
}
This is synthetic example but I hope it clear for understanding.
In first case I want to have object with singleName == "Catalina" and nameMap == null, and vice versa in other case.
UPDATE
I am really sorry, at the end of day I misspelled the property name. In both cases they are the same: name.
Try making your name field an object:
class MyPojo {
public Object name;
}
The you'll have to check at runtime to see if it deserialized as a String or as a Map.
The easiest way is to rename your POJO properties to the same which you have in JSON. See below example:
class NamesHolder {
public String name;
public Map<String, String> names;
#Override
public String toString() {
return "NamesHolder{" +
"name='" + name + '\'' +
", names=" + names +
'}';
}
}
If you do not want to rename properties you can use #JsonProperty annotation. See below example:
class NamesHolder {
#JsonProperty("name")
public String singleName;
#JsonProperty("names")
public Map<String, String> nameMap;
#Override
public String toString() {
return "NamesHolder{" +
"name='" + singleName + '\'' +
", names=" + nameMap +
'}';
}
}
Two above classes work for your JSON examples. See below program:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue("{\"names\" : {\"First\" : \"Catalina\", \"Last\" : \"Kyle\"}}", NamesHolder.class));
System.out.println(mapper.readValue("{\"name\" : \"Catalina\"}", NamesHolder.class));
which prints:
NamesHolder{name='null', names={First=Catalina, Last=Kyle}}
NamesHolder{name='Catalina', names=null}
EDIT 1
In this case you have to handle it manually using Object type. See below example:
public class JacksonTest {
public static void main(String[] args) throws Exception {
String json = "{\"name\" : \"Catalina\"}";
ObjectMapper deserializerMapper = new ObjectMapper();
NamesHolder namesHolder = deserializerMapper.readValue(json, NamesHolder.class);
System.out.println(toString(namesHolder));
json = "{\"name\" : {\"First\" : \"Catalina\", \"Last\" : \"Kyle\"}}";
namesHolder = deserializerMapper.readValue(json, NamesHolder.class);
System.out.println(toString(namesHolder));
}
private static String toString(NamesHolder namesHolder) {
if (namesHolder.hasStringName()) {
return "Type: String, Value: " + namesHolder.getStringName();
} else if (namesHolder.hasMapNames()) {
return "Type: Map, Value: " + namesHolder.getMapNames();
}
return "Type: Unknown, Value: " + namesHolder;
}
}
class NamesHolder {
public Object name;
public boolean hasStringName() {
return name instanceof String;
}
public String getStringName() {
return name.toString();
}
public boolean hasMapNames() {
return name instanceof Map;
}
public Map<String, String> getMapNames() {
return (Map<String, String>) name;
}
#Override
public String toString() {
return String.valueOf(name);
}
}
Above example prints:
Type: String, Value: Catalina
Type: Map, Value: {First=Catalina, Last=Kyle}

How can i deserialize Json string where object's field's subclass is included in json string, using Java and Jackson library

I am very new to Java. I have some classes Site, Instances, CloudInstance. Class Site has an attribute instances and class CloudInstance inherits class Instance. They are as follows-
public class Site extends BaseEntity {
private String siteName;
List<Instance> instances = Lists.newArrayList();
}
public class Instance extends BaseEntity {
private String instanceId;
private String name;
}
public class CloudInstance extends Instance {
private String availabilityZone;
private String instanceType
}
I am deserializing json string as follows -
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
BaseEntity obj = null;
obj = (BaseEntity) mapper.readValue(jsonStr, Site.class);
It works fine if my jsonStr does not contain fields of class 'CloudInstance' and contains field instance with Instance class's fields.
Problem - Now i want to deserialize the jsonStr which includes 'CloudInstance' classe's fiels as well as the part of 'instances' field of class 'Site'. Ex jsonStr is as follows -
{
"id": null,
"siteName": "demo",
"instances": [
{
"instanceId": "i-8c2ee5fc",
"name": "some-node",
"availabilityZone": "some-zone",
"instanceType": "t1.micro"
}]
}
For the above jsonStr i get following error
error: Unrecognized field \"availabilityZone\" and error: Unrecognized field \"instanceType\"
With lots of if else and dirty code i can get the obj of Site including above fields. But i want to implement clean solution for this.
Is there any library which can do this? Any help id valuable. Please help..!!
Thanks in advance.
What you are trying to achieve is called polymorphic deserialization. Your example fails because Jackson needs to know what instance type should be constructed from JSON and placed to the list of instances. Please refer to this wiki page for detailed explanation.
I have modified you example to demonstrate how it could work. I've added the instance type information in the #type field in the JSON representation. Also I've made all the classes immutable using constructors annotated with the #JsonCreator annotation to create instances.
public class JacksonPolymorphism {
public static class BaseEntity {
private final String id;
protected BaseEntity(String id) {
this.id = id;
}
}
public static class Site extends BaseEntity {
private final String siteName;
private final List<Instance> instances;
#JsonCreator
public Site(#JsonProperty("id") String id,
#JsonProperty("siteName") String siteName,
#JsonProperty("instances") List<Instance> instances) {
super(id);
this.siteName = siteName;
this.instances = instances;
}
#Override
public String toString() {
return "Site{" +
"siteName='" + siteName + '\'' +
", instances=" + instances +
'}';
}
}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "#type")
#JsonTypeName(value = "simple")
public static class Instance extends BaseEntity {
private final String name;
#JsonCreator
public Instance(#JsonProperty("instanceId") String id,
#JsonProperty("name") String name) {
super(id);
this.name = name;
}
#Override
public String toString() {
return "Instance{" +
"name='" + name + '\'' +
'}';
}
}
#JsonTypeName("cloud")
public static class CloudInstance extends Instance {
private final String availabilityZone;
private final String instanceType;
public CloudInstance(#JsonProperty("instanceId") String id,
#JsonProperty("name") String name,
#JsonProperty("availabilityZone") String availabilityZone,
#JsonProperty("instanceType") String instanceType) {
super(id, name);
this.availabilityZone = availabilityZone;
this.instanceType = instanceType;
}
#Override
public String toString() {
return "CloudInstance{" +
"availabilityZone='" + availabilityZone + '\'' +
", instanceType='" + instanceType + '\'' +
'}';
}
}
public static final String JSON = "{\n" +
" \"id\": null,\n" +
" \"siteName\": \"demo\",\n" +
" \"instances\": [\n" +
" {\n" +
" \"#type\": \"cloud\",\n" +
" \"instanceId\": \"i-8c2ee5fc\",\n" +
" \"name\": \"some-node\",\n" +
" \"availabilityZone\": \"some-zone\",\n" +
" \"instanceType\": \"t1.micro\" \n" +
" }," +
" {\n" +
" \"#type\": \"simple\",\n" +
" \"instanceId\": \"ABC\",\n" +
" \"name\": \"FGF\"\n" +
" }]" +
" }";
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(CloudInstance.class);
System.out.println(mapper.readValue(JSON, Site.class));
}
}
Output:
Site{siteName='demo', instances=[CloudInstance{availabilityZone='some-zone', instanceType='t1.micro'}, Instance{name='FGF'}]}
I always had problems to deserialize JSON that contains List<...> objects with Jackson, so try to deserialize with Gson:
https://code.google.com/p/google-gson/
Take a look at the documentation in the methods fromJson and toJson.
I hope that can help,
Best regards
Never had consistent luck with Jackson or Gson, try Flex JSON instead:
JSONSerializer ser = new JSONSerializer();
String json = ser.deepSerialize(yourObject);
JSONDeserializer<YourMainType> der = new JSONDeserializer<YourMainType>();
YourMainType mainType = der.deserialize(json);
For this to work, all classes subject to serialization/deserialization must expose getters/setters consistent with Java Beans convention.
You can used GSON Library for de-serialize your Json into your class object.
There is function gson.fromJson(JSON String) which convert json string to class object.
Here is Sample code :
Gson json = new Gson();
Site site = json.fromJson(jsonStr, Site.class);
But in your code you have replace
List<Instance> instances = Lists.newArrayList();
this line in class Site with
List<CloudInstance> instances = new ArrayList<CloudInstance>();
Because your CloudInstance class extend Instance it means CloudInstance class include member of Instance class. As per json you need to do this to cast directly into class object.
May this will help you.

Categories

Resources