我开始使用一种消耗并生成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 回答
问题是
resteasy-jackson-provider
取决于jackson-module-jaxb-annotations
,它用于将JAXB注释/注释类映射到JSON . 现在正常使用ObjectMapper
,为了使用这个模块,我们需要显式注册这个模块(参见here)话虽如此,但似乎(未经任何事实确认,但看起来很可能)当为序列化创建
ObjectMapper
时,当注意到JAXB注释时,模块会自动注册 .我不知道我们可以使用任何可能的注释来解决这个问题,但解决这个问题的一种方法是为
ObjectMapper
创建ContextResolver
,我们不注册JAXB模块 .一旦我们使用我们的JAX-RS应用程序注册它,它将是用于获取
ObjectMapper
的上下文解析器 . 我们可以进一步配置ObjectMapper
,但这只是一个例子 . 测试它,它按预期工作 .