How to pass parameter to JsonSerializer?

smallufo picture smallufo · Mar 25, 2014 · Viewed 8.1k times · Source

I have a simple data service :

@GET
public Data getData(@QueryParam("id") Long id) {
  Data data = dataService.getData(id);
  return data;
}

And a matching DataSerializer that implements JsonSerializer<Data> : The DataSerializer is registered to Jackson via :

simpleModule.addSerializer(Data.class , dataSerializer);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(simpleModule);

It works well. But today , I want to add another Locale parameter , and hope the DataSerializer to output correspondent content :

@GET
public Data getData(@QueryParam("id") Long id , @QueryParam("locale") Locale locale)

The 'Data' itself contains various locale variations , and I hope to get the assigned locale output.

But when I get the locale from the parameter , I don't know how to pass the locale value to the DataSerializer

Is there anyway to achieve this ?

Except this solution :

Data data = dataService.getData(id.get() , locale);

which is not what I want.

It seems ThreadLocal is the only way to achieve this , but I feel that is ugly. Any other feasible solutions ?

Thanks.

Environments : dropwizard-0.7.0-rc2 , jackson-core:jar:2.3.1

===================== updated ==========

reply to @andrei-i :

Because my data itself already contains various locale versions. for example :

Data helloData = dataService.get("hello");
helloData.getName(Locale.English) == "Hello";
helloData.getName(Locale.France) == "Bonjour";
helloData.getName(Locale.Germany) == "Hallo";

I want to directly pass the locale from URL to JsonSerializer , to get one version of the data presentation.

And there 'may' be other version (not just locale) , so , inheriting Data mixing Locale is not considered.

Answer

macko picture macko · Feb 14, 2015

I know that this is not a new question but here is what I came up with facing the similar problem:

  1. created custom annotation:

    @Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface JsonLocalizable {
    
      public String localizationKey();
    } 
    
  2. Jackson serializer:

     public class LocalizingSerializer extends StdSerializer<String> implements ContextualSerializer {
    
          private String localizationKey;
    
          public LocalizingSerializer() {
            super(String.class);
          }
    
          public LocalizingSerializer(String key) {
            super(String.class);
    
            this.localizationKey = key;
          }
    
          @Override
          public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
    
            String localizedValue = //.... get the value using localizationKey
    
            jgen.writeString(localizedValue);
          }
    
          @Override
          public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
    
            String key = null;
            JsonLocalizable ann = null;
    
            if (property != null) {
              ann = property.getAnnotation(JsonLocalizable.class);
            }
    
            if (ann != null) {
              key = ann.localizationKey();
            }
    
            //if key== null??
    
            return new LocalizingSerializer(key);
          }
        }
    
  3. Annotate the field you want to localize:

    public class TestClass {
    
        @JsonSerialize(using = LocalizingSerializer.class)
        @JsonLocalizable(localizationKey = "my.key")
        private String field;
    
        public String getField() {
          return this.field;
        }
    
        public void setField(String field) {
          this.field = field;
        }
    }