【问题标题】:RestEasy, how to prevent marshalling of JAXB annotated POJOs to and from JSONRestEasy,如何防止 JAXB 注释 POJO 与 JSON 之间的编组
【发布时间】:2015-01-08 23:16:06
【问题描述】:

我从一个以 JSON 格式消费和生成输出的服务开始。我使用 resteasy-jackson-provider 进行(去)编组,它从类描述中获取信息。过了一会儿,我被要求将 XML 添加为 MediaType。所以我用 JAXB 注释对我的 DTO 进行了注释,并添加了 resteasy-jaxb-provider。结果,我观察到生成的 JSON 输出来自与原始格式不同的 JAXB 注释。

我使用的是 RestEasy 版本 3.0.4。如上所述,我使用以下提供程序

  1. resteasy-jackson-provider
  2. resteasy-axb-provider
  3. resteasy-jettison-provider,因为我将 RestEasy 集成到 Spring 中,并且这个提供者是一个传递依赖。

当我意识到这个问题时

  1. XmlElementWrapper 用于列表和何时
  2. 我写了一个自定义的XmlAdapter,它序列化了一个复杂的数据结构Map<String, List<String>>。带有 XML MediaType 的请求很好。带有 JSON MediaType 的请求会导致异常。 Jackson 似乎利用XmlAdapter 获取更多信息。这不是以前的情况。 Jackson 能够在没有 JAXB 注释的情况下编组 Map。

    org.codehaus.jackson.map.exc.UnrecognizedPropertyException:无法识别的字段“customer”(类 x.y.z.OptionalParametersMapType),未标记为可忽略 在 [来源:org.apache.catalina.connector.CoyoteInputStream@77119553;行:1,列:131](通过引用链:x.y.z.Request["optional"]->x.y.zOptionalParametersMapType["customer"] ) 在 org.codehaus.jackson.map.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:53) 在 org.codehaus.jackson.map.deser.StdDeserializationContext.unknownFieldException(StdDeserializationContext.java:267) 在 org.codehaus.jackson.map.deser.std.StdDeserializer.reportUnknownProperty(StdDeserializer.java:673) 在 org.codehaus.jackson.map.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:659) 在 org.codehaus.jackson.map.deser.BeanDeserializer.handleUnknownProperty(BeanDeserializer.java:1365) 在 org.codehaus.jackson.map.deser.BeanDeserializer._handleUnknown(BeanDeserializer.java:725) 在 org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:703) 在 org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580) 在 org.codehaus.jackson.xc.XmlAdapterJsonDeserializer.deserialize(XmlAdapterJsonDeserializer.java:59) 在 org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:299) 在 org.codehaus.jackson.map.deser.SettableBeanProperty$FieldProperty.deserializeAndSet(SettableBeanProperty.java:579) 在 org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:697) 在 org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:580) 在 org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2704) 在 org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315) 在 org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:419)

那么,如何防止 RestEasy 使用 JAXB 注释来编组到 JSON 和从 JSON 中提取?

这里是请求类:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "domainRecommendationRequest")
public class Request {

    @XmlJavaTypeAdapter(OptionalParametersXmlAdapter.class)
    private Map<String, List<String>> optional = new HashMap<>();

}

这里是 XmlAdapter:

@Override
public class OptionalParametersXmlAdapter extends XmlAdapter<OptionalParametersMapType, Map<String, List<String>>> {

    public OptionalParametersMapType marshal(Map<String, List<String>> v) throws Exception {
        OptionalParametersMapType result = new OptionalParametersMapType();
        List<OptionalParameterItemType> optionalParameterItemTypes = new ArrayList<>();

        Set<String> keySet = v.keySet();

        for (String parameterName : keySet) {
            OptionalParameterItemType item = new OptionalParameterItemType();
            item.name = parameterName;
            item.values = v.get(parameterName);
            optionalParameterItemTypes.add(item);
        }

        result.parameter = optionalParameterItemTypes;

        return result;
    }
}

这是地图的包装:

public class OptionalParametersMapType {
    public List<OptionalParameterItemType> parameter = new ArrayList<>();

}

这是实际的地图条目:

public class OptionalParameterItemType {

    @XmlAttribute
    public String name;

    @XmlElementWrapper(name = "values")
    @XmlElement(name = "value")
    public List<String> values = new ArrayList<>();
}

这是我对 JSON 请求的期望:

{"optional":{"customer":["Mike"]}}

如您所见,我确实打算在 XML 中使用不同的格式。

【问题讨论】:

    标签: json jaxb jax-rs marshalling resteasy


    【解决方案1】:

    问题是resteasy-jackson-provider 依赖于jackson-module-jaxb-annotations,它用于将 JAXB 注释/带注释的类映射到 JSON。现在在ObjectMapper 的正常显式使用中,为了使用这个模块,我们需要像这样显式注册这个模块(参见here

    ObjectMapper objectMapper = new ObjectMapper();
    JaxbAnnotationModule module = new JaxbAnnotationModule();
    objectMapper.registerModule(module);
    
    -- OR --
    
    AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
    objectMapper.setAnnotationIntrospector(introspector);
    

    话虽如此,它似乎(没有任何事实证实,但看起来很可能)当为您的序列化创建 ObjectMapper 时,当注意到 JAXB 注释时,模块是自动注册。

    我不知道我们可以使用任何可能的注释来阻止此问题,但解决此问题的一种方法是为ObjectMapper 创建一个ContextResolver,我们不注册 JAXB 模块。

    @Provider
    public class ObjectMapperContextResolver 
                      implements ContextResolver<ObjectMapper> {
        @Override
        public ObjectMapper getContext(Class<?> type) {
            return new ObjectMapper();
        }  
    }
    

    一旦我们在 JAX-RS 应用程序中注册了它,它将成为用于获取 ObjectMapper 的上下文解析器。我们可以进一步配置ObjectMapper,但这只是一个示例。测试它,它按预期工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多