2

I am using Gson to convert JSON into a Java object. I have a field in the json that our wise services people coded as either an array or object depending on how many items come back in database. Question is how do model the Java object to pass into Gson converter so that I can handle both types?

json = new Gson().fromJson(reader, Order.class);

Java Classes only parses the JSON array properly

public class Order {
    private Detail detail
}

public class Detail {
    public String id;
    public List<Type> types;
    //// getters and setters
}

public class Type {
    public String typeId;
    public String typeName
    //// getters and setters
}

JSON data array

{
    "detail":{
        "id":"1234565",
        "types":{
            "type":[
                {"typeId":"1246565","typeName":"MyName1"},
                {"typeId":"1444445","typeName":"MyName2"}
            ]
        }
    }
}

JSON data object

{
    "detail":{
        "id":"1234565",
        "types":{
            "type":{"typeId":"1246565","typeName":"MyName1"}
        }
    }
}
JPM
  • 9,077
  • 13
  • 78
  • 137
  • Isn't there a way, in GSON, to ask what the type of an element is? – Hot Licks Jul 18 '14 at 17:32
  • 2
    As you allude, you're working with poor service design. Can you talk with the data services people to use only the first type (the JSON data array) even if there is only one item from the database? That would make it easier for not just you, but other developers/teams that are working with the service in the future. – Jonathan M Jul 18 '14 at 17:34
  • Eg, `isJsonArray` and `isJsonObject`. (I found these in 30 seconds, and I don't even use GSON.) – Hot Licks Jul 18 '14 at 17:34
  • I have no choice the services are set and have to stay that way due to legacy...I am just trying to no longer hand parse the objects and use Gson to auto parse. – JPM Jul 18 '14 at 17:46
  • what is you exact question? Do you want to convert both the JSON string into java object and it's not known in advance. – Braj Jul 18 '14 at 20:20
  • Its a blind parse I am trying to create the class so I don't have to do string or hand object manipulation. The real objects are huge and vastly complex with many levels. – JPM Jul 18 '14 at 21:40
  • @JPM: another way I suggest is using Streams.parse(...) which will return a general JsonElement. Then you can check if it is an object or an array. – BNK Aug 26 '15 at 00:08
  • Does this answer your question? [Make GSON accept single objects where it expects arrays](https://stackoverflow.com/questions/43412261/make-gson-accept-single-objects-where-it-expects-arrays) – Marcono1234 Jan 09 '23 at 00:09

2 Answers2

1

I figured out how to do this by using a generic object. So now I can still call using GSON and not have to do that much manual parsing only when I need when I reconstitute the Objects, and only that particular object.

json = new Gson().fromJson(reader, Order.class);

Main Object

public class Order {
    private Detail detail
}

Detail Class

public class Detail {
    public String id;
    public Types types;

    //// getters and setters
    public Types getTypes() {
        return types;
    }

    public void setTypes(Types types) {
        this.types = types;
    }
}

Types class that contains a generic Object called type so it can store either a List or a LinkedTreeMap which is how JSONObject gets parsed. You have to then manually insert it into a new Type object .

public class Types {
    private Object type;

    //// getters and setters

    public Object getType() {
        return type;
    }

    public void setType(Object type) {
        this.type = type;
    }

    public List<Type> getListType() {
        if (type instanceof List) {
            return (List<Type>) type;
        } else
            return null;
    }

    public Type getObjectType() {
        if (type instanceof Type) {
            return (Type) type;
        } else if (type instanceof Map) {
            Map<String, String> map = (Map<String, String>)type;
            Type newType = new Type((String)map.get("typeId"), (String)map.get("typeName"));
            return newType;
        }
        return null;
    }

public class Type {
    private String typeId;
    private String typeName;

    public Type() {}

    public Type(String id, String name) {
        this.typeId = id;
        this.typeName = name;
    }

    //// getters and setters
    public String getTypeId() {
        return typeId;
    }

    public void setTypeId(String typeId) {
        this.typeId = typeId;
    }

    public String getTypeName() {
        return typeName;
    }

    public void setTypeName(String typeName) {
        this.typeName = typeName;
    }
}
JPM
  • 9,077
  • 13
  • 78
  • 137
-1

Sigh!!

JsonArray typeArray; 
JsonElement typeElement = types.get("type"); 
if (typeElement.isJsonObject()) { 
    typeArray = new JsonArray();
    typeArray.add(typeElement); 
}
else {
    typeArray = (JsonArray)typeElement;
}
for (int i = 0; i < typeArray.size(); i++) {
    JsonObject typeObject = (JsonObject)(typeArray.get(i));
    typeObject.doSomethingWithThis();
}
Hot Licks
  • 47,103
  • 17
  • 93
  • 151
  • I don't want to pull apart the JSON because I need to pile this into Java objects. The Java class I have is way more complex than I am showing, with multiple levels of Java Objects. Hence why I want to do it via Gson().fromJson(). I wanted find out if there was some way through annotations or some other method to do it in the Java Object class – JPM Jul 18 '14 at 19:39
  • 1
    @JPM - Well, put it back together and process it however you want. – Hot Licks Jul 18 '14 at 19:44