Apache commons MultiValuedMap and Jackson

Viewed 767

I want to serialize/deserialize MultiValuedMap<String,Object>. Its hard to believe, that there is no example code in www. Does anyone knows an example?

Here is my code snippet import org.apache.commons.collections4.MultiValuedMap;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;

public class MultiValuedMapSerializer extends StdSerializer<MultiValuedMap<String,Object>> {
  private static final long serialVersionUID = 1L;

  public MultiValuedMapSerializer() {
    this(null);
  }

  protected MultiValuedMapSerializer(Class<MultiValuedMap<String,Object>> klass) {
    super(klass);
  }

  @Override
  public void serialize(MultiValuedMap<String,Object> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
    gen.writeStartObject();
    for (Entry<String, Object> entry : value.entries()) {
      if(entry.getValue() instanceOf MultiValuedMap){
        @SuppressWarnings("unchecked")
        MultiValuedMap<String, Object> map = (MultiValuedMap<String, Object>) value;
        if (key != null) {
          gen.writeFieldName(key);
          serialize(map, gen, provider);
        } else {
          serialize(map, gen, provider);
        }
      } else if(){....} else if(){....} ...
    }
    gen.writeEndObject();
  }
}
1 Answers

You can use the fact that org.apache.commons.collections4.MultiValuedMap can be easily converted to Map. Jackson already has a serialiser for it so all corner cases are handled automatically. It could look like below:

class MultiValuedMapJsonSerializer extends JsonSerializer<MultiValuedMap> {
    @Override
    public void serialize(MultiValuedMap value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null) {
            gen.writeNull();
            return;
        }

        gen.writeObject(value.asMap());
    }

    @Override
    public Class<MultiValuedMap> handledType() {
        return MultiValuedMap.class;
    }
}

Below, you can find an example how to register it and use:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;

import java.io.IOException;

public class JsonMultiValuedMapApp {

    public static void main(String[] args) throws IOException {
        SimpleModule collections4Module = new SimpleModule();
        collections4Module.addSerializer(new MultiValuedMapJsonSerializer());

        ObjectMapper mapper = JsonMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .addModule(collections4Module)
                .build();

        MapWrapper wrapper = new MapWrapper();
        wrapper.getMap().put("numbers", 1L);
        wrapper.getMap().put("numbers", 2L);
        wrapper.getMap().put("strings", "value");

        mapper.writeValue(System.out, wrapper);
    }
}

class MapWrapper {

    private MultiValuedMap<String, Object> map = new HashSetValuedHashMap<>();

    public MultiValuedMap<String, Object> getMap() {
        return map;
    }

    public void setMap(MultiValuedMap<String, Object> map) {
        this.map = map;
    }
}

Above code prints:

{
  "map" : {
    "strings" : [ "value" ],
    "numbers" : [ 1, 2 ]
  }
}
Related