Home > front end >  Jackson deserialise JSON with many dynamic nodes
Jackson deserialise JSON with many dynamic nodes

Time:11-01

I'm trying to deserialize a JSON file with the format of

{
  "English": {
    "hex": "FF0000"
  },
  "Spanish": {
    "hex": "0000FF"
  },
  "Japanese": {
    "hex": "FFFF00"
  }
}

But I don't want to create a class for each language (thousands) so I wrote a custom LanguageDeserializer which gives me back the List<Language> that I want

static class LanguageDeserializer extends StdDeserializer<ArrayList<Language>> {

//...

@Override
public ArrayList<Language> deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException {
    final JsonNode node = jp.getCodec().readTree(jp);
    final Iterator<Map.Entry<String, JsonNode>> nodes = node.fields();

    final ArrayList<Language> results = new ArrayList<>();

    while (nodes.hasNext()) {
        // Builds up the object from the nodes

        results.add(builder.build());
    }

    return results;
}

I have a parent class to wrap the results:

public class LanguageWrapper {

    @JsonDeserialize(using = Language.LanguageDeserializer.class)
    public List<Language> languages = new ArrayList<>();

}

So when I try and use it

final LanguageWrapper languageWrapper = objectMapper.readValue(new ClassPathResource("data/languages.json").getFile(), LanguageWrapper.class);

The languages list is always empty.

Can I do this without needing the LanguageDeserializer or how do I make it work?

CodePudding user response:

Yeah was clearly overthinking it. As @chrylis suggested a Map was the right direction to go in.

Simple as:

final TypeReference<HashMap<String, Language>> typeRef = new TypeReference<>() {};
final HashMap<String, Language> hashMap = objectMapper.readValue(new ClassPathResource("data/languages.json").getFile(), typeRef);

CodePudding user response:

If list (and plain Language class) suits you better, you can do:

TypeReference<Map<String, Map<String, String>>> typeReference = new TypeReference<>() {};
List<Language> languages = new ObjectMapper().readValue(new ClassPathResource("data/languages.json").getFile(), typeReference)
                .entrySet()
                .stream()
                .map(entry -> new Language(entry.getKey(), entry.getValue().get("hex")))
                .collect(Collectors.toList());
  • Related