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'}}