首页 文章

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

提问于
浏览
1

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

我在RestEasy 3.0.4版上 . 如上所述,我使用以下提供程序

  • resteasy-jackson-provider

  • resteasy-axb-provider .

  • resteasy-jettison-provider,因为我将RestEasy集成到Spring中,这个提供程序是一个传递依赖 .

我知道这个问题

  • 使用了 XmlElementWrapper 列表和时间

  • 我写了一个自定义 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;中未标记为可忽略; line:1,column:131](通过引用链:xyzRequest [“optional”] - > xyzOptionalParametersMapType [“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)at org.codehaus.jackson.xc.XmlAdapterJsonDeserializer.deserialize(Xm) lAdapterJsonDeserializer.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的编组操作?

这是请求类:

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

这是 Map 的包装:

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

}

这是实际的 Map 条目项:

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

    问题是 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 ,但这只是一个例子 . 测试它,它按预期工作 .

相关问题