Home > Mobile >  How do you restrict custom ObjectMapper serializer to specific generic type
How do you restrict custom ObjectMapper serializer to specific generic type

Time:03-03

I would like to use a custom serializer for Maps, but only if they are <String, String> maps. I attempted to register a StdSerializer<Map,String, String>> following the advice in this post like so:

    ObjectMapper om = new ObjectMapper();
    SimpleModule maskModule = new SimpleModule();
    JavaType mapType =
        om.getTypeFactory().constructMapLikeType(Map.class, String.class, String.class);
    maskModule.addSerializer(new MapSerializer(mapType));
    om.registerModule(maskModule);

My Serializer looks as follows:

  public static class MapSerializer extends StdSerializer<Map<String, String>> {

    MapSerializer(JavaType type) {
      super(type);
    }

    @Override
    public void serialize(
        Map<String, String> value, JsonGenerator gen, SerializerProvider serializers)
        throws IOException {
      gen.writeStartObject();
      for (Map.Entry<String, String> entry : value.entrySet()) {
          gen.writeStringField(entry.getKey(), doOtherStuff(entry.getValue()));
      }
      gen.writeEndObject();
    }
  }

This works fine on Map<String, String> objects, but unfortunately it also gets called for other maps as well. How does one restrict a custom serializer to specific generic types?

CodePudding user response:

Thanks to the comment by @shmosel, I've identified that the following solution appears to allow us to intercept the serializer assignment by using a SerializerModifier.

  public static class MapSerializerModifier extends BeanSerializerModifier {
    @Override
    public JsonSerializer<?> modifyMapSerializer(SerializationConfig config, MapType valueType, BeanDescription beanDesc, JsonSerializer serializer) {
        if(valueType.getKeyType().getRawClass().equals(String.class) &&
                valueType.getContentType().getRawClass().equals(String.class)) {
          return new MapSerializer();
        }
      return serializer;
    }
  }

Then instead of registering the MapSerializer directly in the module, you register the modifier instead:

    SimpleModule maskModule = new SimpleModule();
    maskModule.setSerializerModifier(new MapSerializerModifier());
    om.registerModule(maskModule);

Now the modifier gets checked for each Map and either returns the custom serializer or the default serializer depending on the object's type properties.

  • Related