我开始使用一种消耗并以JSON生成输出的服务。我使用 resteasy-jackson-provider 进行(de)编组,它从类描述中获取其信息。过了一会儿,我被要求添加XML作为MediaType。所以我用JAXB注释注释了我的DTO并添加了 resteasy-jaxb-provider 。结果,我观察到生成的JSON输出来自JAXB注释,它与原始格式不同。
我在使用RestEasy 3.0.4版。如上所述,我使用以下提供者
当我
时,我意识到了这个问题XmlElementWrapper
用于列表以及何时使用我编写了一个自定义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)
那么,我如何防止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中使用不同的格式。
答案 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
,但这只是一个例子。测试它,它按预期工作。