【问题标题】:How to pass parameter to JsonSerializer?如何将参数传递给 JsonSerializer?
【发布时间】:2014-05-03 07:29:54
【问题描述】:

我有一个简单的数据服务:

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

还有一个匹配的 DataSerializer 实现 JsonSerializer<Data>DataSerializer 通过以下方式注册到 Jackson:

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,jackson-core:jar:2.3.1

======================更新==========

回复@andrei-i:

因为我的数据本身已经包含各种语言环境版本。 例如:

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

我想直接将区域设置从 URL 传递给 JsonSerializer ,以获取数据呈现的一个版本。

并且“可能”有其他版本(不仅仅是语言环境),因此不考虑继承数据混合语言环境。

【问题讨论】:

  • 为什么不让你的 Data 类感知区域设置:引入一个 LocaleData 类,它与 Data 具有相同的字段,但翻译可翻译的内容?
  • 嗨@@andrei-i,我在内容中回复了。谢谢。

标签: java jackson jax-rs dropwizard jsonserializer


【解决方案1】:

我知道这不是一个新问题,但这是我遇到类似问题时想到的:

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

【讨论】:

  • 以下需要添加到自定义注解@JacksonAnnotation 中才能在createContextual 方法的BeanProperty 参数中使用。
【解决方案2】:

解决方案 1. 在您的 JAX-RS 实现中为 JSON 请求注册您自己的 MessageBodyWriter 实现。您的实现可能会扩展杰克逊。此外,您可能必须注销杰克逊。在MessageBodyWriter 中,您可以使用@Context 注解注入UriInfo 实例,并通过它获取任何请求参数。

解决方案 2. 更改 Data 的架构,使其能够识别区域设置。例如,创建一个 setter setLocale(),如果设置了语言环境,它将更改返回的数据。

【讨论】:

  • H, DataMessageBodyWriter extends JsonSerializer implements MessageBodyWriter&lt;Data&gt; 看起来不错。但我必须 @Inject JacksonJsonProvider@Inject Provider&lt;ObjectMapper&gt; 。在Provider&lt;ObjectMapper&gt;的注入中,会造成循环依赖(因为ObjectMapperProvider implements Provider&lt;ObjectMapper&gt;本身需要DataMessageBodyWriter被注入)。我知道这很复杂,也许解决方案 2 更容易。
  • 你解释的时候看起来很复杂,但我的意思更简单:直接扩展 DataMessageBodyWriter extends JacksonJsonProvider 并在调用 super 之前在扩展的 writeTo 方法中简单地添加一个 if 条件,以处理你的 Data类型。
  • 我使用解决方案 2。……嗯,我认为这不是最好的解决方案。因为在 JsonSerializer 中,没有从资源层获取信息的机制。在资源层时,无法分配 POJO 的输出装饰器。 (在我的例子中,装饰参数是一个语言环境)
  • 但是您是否尝试过我的想法直接扩展 JacksonJsonProvider 以访问整个请求?
猜你喜欢
  • 1970-01-01
  • 2020-10-09
  • 2012-12-21
  • 2012-01-07
  • 2015-06-26
  • 2012-01-18
  • 2017-07-14
  • 2018-03-08
  • 2020-09-01
相关资源
最近更新 更多