How to deserialize this JSON in an elegant way using flexjson

java, json, json-deserialization, wadl

Solution

Working solution without any `Map`:

Let's define the classes bottom-up:

1. Target:

public class Target {

private String uri;
private String type;
private String name;
private String host;
private String domain;
private String description;

public String getUri() {
    return uri;
}

public void setUri(String uri) {
    this.uri = uri;
}

public String getType() {
    return type;
}

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

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getHost() {
    return host;
}

public void setHost(String host) {
    this.host = host;
}

public String getDomain() {
    return domain;
}

public void setDomain(String domain) {
    this.domain = domain;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}
}

This class represents the following JSON:

 "target": {
        "uri": "https://opam_server_host:opam_ssl_port/opam/target/9bbcbbb087174ad1900ea691a2573b61",
        "type": "ldap",
        "name": "person1-ldap",
        "host": "opam_server_host",
        "domain": "berkeley",
        "description": "Ldap target"
      }

2. TargetWrapper:

Note that `target` it is inside braces. This class simply wraps it.

public class TargetWrapper {

    private Target target;

    public Target getTarget() {
        return target;
    }

    public void setTarget(Target target) {
        this.target = target;
    }
 }

This class represents the following JSON:

{
      "target": {
        "uri": "https://opam_server_host:opam_ssl_port/opam/target/9bbcbbb087174ad1900ea691a2573b61",
        "type": "ldap",
        "name": "person1-ldap",
        "host": "opam_server_host",
        "domain": "berkeley",
        "description": "Ldap target"
      }
    }

3. RestApiResponse

This class represents the whole `JSON` returned by your api

public class RestApiResponse {

    @JSON(name="Target Collection")
    private List<TargetWrapper> targetCollection = new ArrayList<TargetWrapper>();

    @JSON(name="Target Collection")
    public List<TargetWrapper> getTarget_Collection() {
        return targetCollection;
    }
    @JSON(name="Target Collection")
    public void setTarget_Collection(List<TargetWrapper> tc) {
        this.targetCollection = tc;
    }

}

4. Let's test it!

public static void main(String[] args) {


        JSONDeserializer<RestApiResponse> js = new JSONDeserializer<RestApiResponse>();


        String input="{\"Target Collection\":[{\"target\":{\"uri\":\"https://opam_server_host:opam_ssl_port/opam/target/9bbcbbb087174ad1900ea691a2573b61\",\"type\":\"ldap\",\"name\":\"person1-ldap\",\"host\":\"opam_server_host\",\"domain\":\"berkeley\",\"description\":\"Ldap target\"}},{\"target\":{\"uri\":\"https://opam_server_host:opam_ssl_port/opam/target/ac246a162ce948c7b1cdcc17dfc92c15\",\"type\":\"ldap\",\"name\":\"person1-ldap2\",\"host\":\"opam_server_host:opam_ssl_port\",\"domain\":\"berkeley\",\"description\":\"Ldap target\"}}]}";

        RestApiResponse restApiResponse=js.deserialize(input,RestApiResponse.class);

        System.out.println(new JSONSerializer()
        .exclude("*.class").deepSerialize(restApiResponse));


    }

Output:

{
  "Target Collection": [
    {
      "target": {
        "description": "Ldap target",
        "domain": "berkeley",
        "host": "opam_server_host",
        "name": "person1-ldap",
        "type": "ldap",
        "uri": "https://opam_server_host:opam_ssl_port/opam/target/9bbcbbb087174ad1900ea691a2573b61"
      }
    },
    {
      "target": {
        "description": "Ldap target",
        "domain": "berkeley",
        "host": "opam_server_host:opam_ssl_port",
        "name": "person1-ldap2",
        "type": "ldap",
        "uri": "https://opam_server_host:opam_ssl_port/opam/target/ac246a162ce948c7b1cdcc17dfc92c15"
      }
    }
  ]
}

I hope it helps.

Problem

I am working with Oracle OPAM and it has a REST API that has methods like this ``` { "Target Collection":[ { "target":{ "uri":"https:\/\/opam_server_host:opam_ssl_port\/opam\/target\ /9bbcbbb087174ad1900ea691a2573b61", "type":"ldap", "name":"person1-ldap", "host":"opam_server_host", "domain":"berkeley" "description" : "Ldap target" } }, { "target":{ "uri":"https:\/\/opam_server_host:opam_ssl_port\/opam\/target\ /ac246a162ce948c7b1cdcc17dfc92c15", "type":"ldap", "name":"person1-ldap2", "host":"opam_server_host:opam_ssl_port", "domain":"berkeley" "description" : "Ldap target" } } ] } ``` I am using FlexJSON to deserialize these entities. If I could, I'd use Apache CXF to generate the beans for me, but the problem is that the WADL is under an invalid https certificate + basic authentication, and getting wadl2java to work under these conditions are taking more time than I'd like to spend (too bad it isn't WSDL, so I could just create the stubs from inside eclipse fast and easy). So I am using this cumbersome approach with flexjson to parse this REST API ``` JSONDeserializer<Map<String,List<Map<String,Map<String,String>>>>> json = new JSONDeserializer<>(); Map<String,List<Map<String,Map<String,String>>>> targetCollection = json.deserialize(new InputStreamReader(content)); List<Map<String,Map<String,String>>> col = targetCollection.get("Target Collection"); Map<String,Map<String,String>> keyVal = col.get(0); Map<String,String> targetVal = keyVal.get("target"); System.out.println(targetVal); ``` This obviously works, but it has so many brackets that reminds me LISP. It would be so much better if we could just use POJOs instead (even better if I could have then generated automatically by some GUI tool, but I know I am asking too much, we're living in 2014). I know there is some documentation about how to map attributes here : http://flexjson.sourceforge.net/#Deserialization but I really wish they have some real complex sample (including the JSON - what's the use of explaining how to deserialize without any JSON example in the documentation?) This question is obviously not new, but it seems that related questions like 1, 2 or 3 are also waiting for an answer. (P.S. except this one seems to have some info I can use) So my question is: how do I parse this JSON with FlexJSON into a structure not only made of Maps?

Original source