RestEasy,如何防止JAXB注释POJO与JSON之间的编组

时间:2014-11-12 07:16:37

标签: json jaxb jax-rs marshalling resteasy

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

我在使用RestEasy 3.0.4版。如上所述,我使用以下提供者

  1. RestEasy的杰克逊提供商
  2. RestEasy的-AXB-提供商
  3. resteasy-jettison-provider ,因为我将RestEasy集成到Spring中,而这个提供程序是一个传递依赖。
  4. 当我

    时,我意识到了这个问题
    1. XmlElementWrapper用于列表以及何时使用
    2. 我编写了一个自定义XmlAdapter,用于序列化复杂数据结构Map<String, List<String>>。使用XML MediaType的请求很好。使用JSON MediaType的请求会导致异常。杰克逊似乎利用XmlAdapter获取更多信息。事实并非如此。杰克逊能够在没有JAXB注释的情况下对地图进行编组。

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

    3. 那么,我如何防止RestEasy使用JAXB注释进行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中使用不同的格式。

1 个答案:

答案 0 :(得分:0)

问题是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注释时,模块自动注册。

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

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

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