Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson JSON map key as property of contained object

Tags:

java

json

jackson

Given a structure like this:

{
  "nameOfObject": { "score": 100 },
  "anotherObject": { "score": 30 }
}

Is it possible to map this to:

class Container {
  Map<String, ScoreKeeper> scoreKeepers;
}

class ScoreKeeper {
  String name;
  int score;
}

So that you end up with the name property of the ScoreKeeper instances set to "nameOfObject" and "anotherObject", respectively?

like image 659
Nick Spacek Avatar asked Oct 08 '13 12:10

Nick Spacek


2 Answers

I am a firm believer in separating your POJOs from externalization. Read your JSON into a Map and then build you Container/ScoreKeeper objects like this (apols for any typos):

mapper = new ObjectMapper();

Map<String,Object> data = mapper.readValue(inputstream, Map.class);

Container c = new Container();

for(Map.Entry<String, Object> me : data.entrySet()) {
    String key = me.getKey();
    Map info = (Map) me.getValue();

    ScoreKeeper sk = new ScoreKeeper();
    sk.setName(key);
    Integer q = info.get("score");
    sk.setScore(q);

    c.put(key, sk);
}
like image 197
Buzz Moschetti Avatar answered Sep 28 '22 06:09

Buzz Moschetti


Alternative solution, where the key name is set on the value object by using a custom Deserializer:

@Test
public void test() throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();

    Data data = mapper.readValue("{\"users\": {\"John\": {\"id\": 20}, \"Pete\": {\"id\": 30}}}", Data.class);

    assertEquals(20, data.users.get("John").id);
    assertEquals(30, data.users.get("Pete").id);
    assertEquals("John", data.users.get("John").name);
    assertEquals("Pete", data.users.get("Pete").name);
}

public static class Data {
    @JsonDeserialize(contentUsing = Deser.class)
    public Map<String, User> users;
}

public static class User {
    public String name;
    public int id;
}

public static class Deser extends JsonDeserializer<User> {

    @Override
    public User deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String name = ctxt.getParser().getCurrentName();

        User user = p.readValueAs(User.class);

        user.name = name;  // This copies the key name to the value object

        return user;
    }
}
like image 25
john16384 Avatar answered Sep 28 '22 05:09

john16384