0

I'm having tough time coming up with a class that represents the following JSON. "familyRelationships" is an array of arrays. Each array has person1 and person2 identifiers and the relationship between person1 and person2. As you might've already guessed, order of the values in array is very important. For example, if "12345" and "31142" positions switch, then it means "31142" is the PARENT of "12345" which is totally wrong.

{
    "familyRelationships": [
        [
            "12345", 
            "SPOUSE", 
            "67890", 
            {
                "careTaker": false,
                "liveTogether": true
            }
        ],
        [
            "12345", 
            "PARENT", 
            "31142", 
            {
                "careTaker": true,
                "liveTogether": true
            }
        ],
        [
            "67890", 
            "PARENT", 
            "31142", 
            {
                "careTaker": true,
                "liveTogether": true
            }
        ]
    ]
}
RKodakandla
  • 3,318
  • 13
  • 59
  • 79

3 Answers3

1

That JSON isn't going to nicely become a POJO because the types contained within the arrays are not consistent:

e.g.

[
  "12345", 
  "SPOUSE", 
  "67890", 
  {
    "careTaker": false,
    "liveTogether": true
  }
]

is String,String,String,Object. The only way that works is if you have a Object[] or List<Object>. So familyRelationships should actually be a List<List<Object>>. The end result is going to require a bunch of casting (and probably some checks to make sure that the item at a given index is the class you expect), but it will work.

Chris Thompson
  • 35,167
  • 12
  • 80
  • 109
  • looks like that's the only option available. I was hoping there is some other way to do that. Thanks anyways. – RKodakandla May 05 '18 at 15:58
  • Not without some other kind of indirection. What you _could_ do is create your own list wrapper that handles the casting for you. It would still be ugly in the component, but it would shield the rest of your application from the ugliness. – Chris Thompson May 05 '18 at 21:22
1

This should be doable using a custom deserializer.

A relationship in my opinion should be modeled as a proper java class with proper names. Note that the constructor takes a JSONNode as an argument and that I have left our any getters and setters:

public class Relationship {

    private final String id1;
    private final String id2;
    private final Relation relation;
    private final boolean careTaker;
    private final boolean liveTogether;

    public Relationship(JsonNode base) {
        this.id1 = base.get(0).asText();
        this.id2 = base.get(2).asText();
        this.relation = Relation.valueOf(base.get(1).asText());
        this.careTaker = base.get(3).get("careTaker").asBoolean();
        this.liveTogether = base.get(3).get("liveTogether").asBoolean();
    }

    public enum Relation {
        PARENT,
        SPOUSE;
    }

}

We also need a class which stores the collection. This is the one that you would deserialize the top level object into (again leaving out getters and setters):

@JsonDeserialize( using = FamillyRelationshipsDeserializer.class )
public class FamillyRelationships {

    public List<Relationship> familyRelationships = new ArrayList<>();

} 

Finally we need to implement the actual JsonDeserializer referenced in the above class. It should look something like the following. I used this question as a reference:

class FamillyRelationshipsDeserializer extends JsonDeserializer<FamillyRelationships> {
    @Override
    public FamillyRelationships deserialize(JsonParser jp, DeserializationContext ctxt) throws 
            IOException, JsonProcessingException {
        FamillyRelationships relationships = new FamillyRelationships();
        JsonNode node = jp.readValueAsTree();
        JsonNode rels = node.get("familyRelationships");

        for (int i = 0; i < rels.size(); i++) {
            relationships.familyRelationships.add(new Relationship(rels.get(i));
        }

        return relationships;
    }
}

I hope this helps, I haven't actually tested any of this, it probably will not even compile, but the principles should be right. I have also assumed that the JSON is of the format you supplied. If that's not a guarantee then you will need to make the proper checks and deal with any deviations.

If you also want to be able to serialize everything then you will need to implement JsonSerializer see this question for more details.

Diasiare
  • 745
  • 1
  • 6
  • 18
0

There are some tools online to do that for you

package com.example;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"familyRelationships"
})
public class Example {

@JsonProperty("familyRelationships")
private List<List<String>> familyRelationships = null;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();

@JsonProperty("familyRelationships")
public List<List<String>> getFamilyRelationships() {
return familyRelationships;
}

@JsonProperty("familyRelationships")
public void setFamilyRelationships(List<List<String>> familyRelationships) {
this.familyRelationships = familyRelationships;
}

@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}

@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}

}

This is only 1 possiblilty made with http://www.jsonschema2pojo.org/

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • I know about that tool. The generated class doesn't help. "familyRelationships" is not an array of array of strings. Notice the object with two attributes "careTaker" and "liveTogether". – RKodakandla May 05 '18 at 15:31