如何将参数传递给 JsonSerializer?

Posted

技术标签:

【中文标题】如何将参数传递给 JsonSerializer?【英文标题】:How to pass parameter to 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,我在内容中回复了。谢谢。 【参考方案1】:

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

    创建自定义注释:

    @Target( ElementType.FIELD, ElementType.TYPE, ElementType.METHOD )
    @Retention(RetentionPolicy.RUNTIME)
    public @interface JsonLocalizable 
    
      public String localizationKey();
     
    

    杰克逊序列化器:

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

    注释要本地化的字段:

    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 以访问整个请求?

以上是关于如何将参数传递给 JsonSerializer?的主要内容,如果未能解决你的问题,请参考以下文章

如何将数组参数传递给函数

如何将日期对象作为第一个也是唯一的输入参数传递给 PL-SQL

如何将 POST 参数传递给 Durable Function,然后将此参数传递给 Timer Triggered 函数

将一个函数的多个返回值作为参数传递给另一个函数

如何将参数传递给 Java 线程?

将命令行参数传递给 package.json 中的 npm 脚本