【问题标题】:Customizing Jackson's deserialization depending on Jersey's request query param?根据 Jersey 的请求查询参数自定义 Jackson 的反序列化?
【发布时间】:2014-09-27 03:36:14
【问题描述】:

我在我的 REST api 上使用 Jackson 24.1 + Jersey 2.10。

为了以自定义格式解析日期,我有一个 Jackson 反序列化器,如下所示:

public class JsonDateSerializer extends JsonSerializer<Date>{

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");

    @Override
    public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
            throws IOException, JsonProcessingException {

        String formattedDate = dateFormat.format(date);

        gen.writeString(formattedDate);
    }

}

但我想根据用户是否包含给定的请求标头来更改反序列化日期的方式。为此,我需要在 Jackson 的反序列化器中访问 Jersey 的 HttpRequestContext 对象...

当 Jackson 的序列化器/反序列化器像这样一起使用时,是否可以访问 Jersey 的上下文?

谢谢!!

【问题讨论】:

    标签: java rest serialization jackson jersey-2.0


    【解决方案1】:

    据我所知,您无法直接从反序列化器访问 HttpRequest,但是,我在对象中使用标志做了类似的事情。

        @XmlElement(name = "date")
        public String getDate() {
            return (formatFlag) ? dateFormatter1.format(date): dateFormatter2.format(date);
        }
    

    那么formatFlag当然可以是@XmlTransient

    【讨论】:

    • 我真的需要一个能够影响所有实体的全球解决方案。不过谢谢!
    【解决方案2】:

    编辑

    是的ContextResolverFactory 为上下文解析器进行缓存...我以不同的方式工作,希望这会有所帮助 -

    为日期创建 XMLAdapter 作为 spring bean

    import java.util.Date;
    import javax.inject.Inject;
    import javax.inject.Named;
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    import org.apache.commons.lang3.time.DateFormatUtils;
    
    @Named
    public class RequestBasedXMLAdapter extends XmlAdapter<String, Date> {
        @Inject
        private RequestData requestData;
    
        @Override
        public String marshal(Date value) throws Exception {
    
            return DateFormatUtils.format(value, requestData.getMyDateFormat());
        }
    
        @Override
        public Date unmarshal(String value) throws Exception {
            // i am not interested in incoming date
            return new Date();
        }
    }
    

    创建请求范围的 bean

    import javax.inject.Named;
    import org.springframework.context.annotation.Scope;
    import org.springframework.context.annotation.ScopedProxyMode;
    
    @Named
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class RequestData {
        private String myDateFormat;
    
        public String getMyDateFormat() {
            return myDateFormat;
        }
    
        public void setMyDateFormat(String myQueryParam) {
            this.myDateFormat = myQueryParam;
        }
    }
    

    为 JAXBContext 创建上下文解析器

    1. 注入spring应用上下文
    2. 将您的 XMLAdapter 从上下文中定义为 spring bean
    3. 通过修改以下方法返回自定义 jaxbcontext(作为装饰器实现)

      public JAXBMarshaller createMarshaller() throws JAXBException {
          JAXBMarshaller marshaller = delegate.createMarshaller();
          marshaller.setAdapter(adapter);
          return marshaller;
      }
      
      public JAXBUnmarshaller createUnmarshaller() throws JAXBException {
          JAXBUnmarshaller unmarshaller = delegate.createUnmarshaller();
          unmarshaller.setAdapter(adapter);
          return unmarshaller;
      }
      

    现在在您的 Resource 类中(您已在其中定义了 GET/POST 方法)

    1. 注入请求范围的bean RequestData
    2. 从 RequestData 中的查询/标头参数设置日期格式

    将 Response 类中的 Date 字段注释为

     @XmlJavaTypeAdapter(RequestBasedXMLAdapter.class)
     private Date myCustomDate = new Date();
    

    现在您应该可以根据您的要求更改日期格式了

    另外请注意我使用的是 Moxy


    老答案

    我认为你可以通过返回不同的 ObjectMapper 来做到这一点......

    试试

    1. 为 ObjectMapper 编写一个 ContextResolver
    2. 使用@Context 注入HTTPHeader
    3. 根据您的标头参数返回差异。使用适当日期格式的映射器

    上述方法的缺点是相同的日期格式将应用于该响应中的所有日期。

    【讨论】:

    • 这不起作用,因为ContextResolvers 是单例的,并且不会在每个请求上要求新的对象映射器。它在第一次请求后被缓存。
    猜你喜欢
    • 2023-03-17
    • 2014-12-15
    • 1970-01-01
    • 2021-08-12
    • 2019-08-10
    • 1970-01-01
    • 2016-02-13
    • 2011-04-12
    • 2013-01-18
    相关资源
    最近更新 更多