2014-03-25 7 views
2

У меня есть простая служба данных:Как передать параметр JsonSerializer?

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

и соответствующий DataSerializer, который реализует JsonSerializer<Data>: DataSerializer зарегистрирован в Джексон через:

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

Это хорошо работает. Но сегодня я хочу добавить еще один параметр Locale, и надеюсь, что DataSerializer к содержимому выходных корреспондентскому:

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

В «Data» сами по себе содержит различные региональные вариации, и я надеюсь получить назначенный локал выход.

Но когда я получаю locale от параметра, я не знаю, как передать значение locale к DataSerializer ...

Есть в любом случае для достижения этой цели?

За исключением этого решения:

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

, который не то, что я хочу.

Кажется, ThreadLocal - единственный способ достичь этого, но я чувствую, что это уродливо. Какие-либо другие возможные решения?

Спасибо.

Среды: dropwizard-0.7.0-RC2, джексон-жильный: баночка: 2.3.1

===================== обновленные = =========

ответ @ Андрее-я:

Потому что сама по себе мои данные уже содержатся различные региональные версии. , например:

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

Я хочу, чтобы непосредственно передать локаль из URL в JsonSerializer, чтобы получить одну версию представления данных.

И там может быть другая версия (а не только локаль), поэтому наследование Data mix Locale не рассматривается.

+0

Почему бы не сделать ваш класс данных локали известно: ввести класс LocaleData, который имеет то же поле данных, но транслирует переводимый материал? –

+0

hi @@ andrei-i, я ответил в содержании. Благодарю. – smallufo

ответ

2

Решение 1. В вашей реализации JAX-RS зарегистрируйте свою собственную реализацию MessageBodyWriter для запросов JSON. Вероятно, ваша реализация продлит Джексона. Также, возможно, вам придется отменить регистрацию Джексона. В MessageBodyWriter вы можете ввести экземпляр UriInfo, используя аннотацию @Context, и с ней вы можете получить любой параметр запроса.

Решение 2. Измените архитектуру своего Data так, чтобы она была осведомлена о локали. Например, создайте сеттер setLocale(), который изменит возвращаемые данные, если локаль была установлена.

+0

H, 'DataMessageBodyWriter расширяет JsonSerializer реализует MessageBodyWriter ' кажется хорошим. Но я должен «@Inject JacksonJsonProvider» и «@Inject Provider ». При вводе «Provider » это вызовет циклическую зависимость (потому что 'ObjectMapperProvider реализует Provider ' сам нуждается в DataMessageBodyWriter' для ввода). Я знаю, что это очень сложно, может быть, решение 2 проще. – smallufo

+0

Кажется сложным, как вы его объяснили, но я имел в виду что-то более простое: прямое расширение DataMessageBodyWriter расширяет JacksonJsonProvider' и просто добавляет условие if в расширенном методе writeTo, прежде чем звонить супер, для обработки вашего типа данных. –

+0

@smallufo Вы решили? –

3

Я знаю, что это не новый вопрос, но вот что я придумал перед подобной проблемой:

  1. создал аннотаций:

    @Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD }) 
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface JsonLocalizable { 
    
        public String localizationKey(); 
    } 
    
  2. Джексон сериализатору:

    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. Аннотировать поле, которое вы хотите локализовать:

    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; 
        } 
    } 
    
+0

Следующее необходимо добавить в пользовательскую аннотацию @JacksonAnnotation, чтобы она была доступна в параметре BeanProperty метода createContextual. – noo