Resteasy PUT 或 POST with Json Object 导致 UnrecognizedPropertyException
Resteasy PUT or POST with Json Object causes UnrecognizedPropertyException
这是关于一个带有 JSON 对象和根元素的 REST PUT 调用,比方说,类似于 :
{"place":
{"name":"Here",
"address":
{"address":"somewhere under the rainbow",
"city":
{"name":"Oz",
"country":
{"name":"Oz",
"zone":"Far Far Away"}
}
}
}
}
使用 Jaxb 注释定义
@XmlRootElement
public class PlaceOffline extends GlobalElement {
@XmlElement
public Address address;
}
超类是
@XmlRootElement
public class GlobalElement implements Serializable {
@XmlElement
public Integer id;
@XmlElement
public String name;
@XmlElement
public String uniqueLabel;
}
我写了一个客户端,它悲惨地失败了
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "placeOffline"
然后我决定记录调用并创建一个 ContainerRequestFilter 来执行此操作
@Provider
public class RestLogFilter implements ContainerRequestFilter {
private Logger LOGGER_filter = Logger.getLogger(RestLogFilter.class.getName());
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (!MediaType.APPLICATION_JSON_TYPE.equals(requestContext.getMediaType())
|| requestContext.getEntityStream() == null) {
return;
}
InputStream inputStream = requestContext.getEntityStream();
byte[] bytes = IOUtils.readFully(inputStream , -1, true);
LOGGER_filter.info("Posted: " + new String(bytes, "UTF-8"));
requestContext.getEntityStream().mark(0);
}
}
而且,你猜怎么着?
出乎意料的成功了!没有更多的错误。实体的打印解决了这个问题。尴尬。
我认为它是一种解决方法,但它让我有点困扰,有人可以解释一下吗?解决这个问题的更优雅的方法?
我正在使用 WildFly 8.2
编辑:
它与
一起工作
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
您需要将 Jackson 添加到应用程序中(只是为了编译),因为您将需要其中的一些 classes。 Wildfly 使用 Jackson 反序列化 JSON,默认行为是当它看到 JSON 上未在 POJO 中建模的属性时失败。例如下面的 JSON
{"firstName": "stack", "lastName": "overflow"}
有一个 属性 "lastName"
不在下面的 POJO
public class Person {
private String firstName;
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getFirstName() { return firstName; }
}
所以它会因 Jackson 的默认行为而失败。
对于依赖,可以添加
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.0.9.Final</version>
<scope>provided</scope>
</dependency>
请注意 provided
范围,因为 Wildfly 已经具有此依赖项。如果您不使用 Maven,那么您真正需要的只是 jackson-databind
和 jacskon-annotations
。只需抓住 2.4.x 版本。如果您使用 Jars,请务必不要将这些 jar 与您的 war 打包在一起,因为版本可能与 Wildfly 已有的冲突。
现在,如果您只想忽略这个 class 的未知属性,您可以只为 class
添加一个注释
@JsonIgnoreProperties(ignoreUnknown = true)
public class PlaceOffline extends GlobalElement {
或者如果你想全局配置这个行为,你可以看。 ObjectMapper
的配置方法如下
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
更新
如果失败是由于 JSON 被包装,例如
{"person": {"firstName": "stack", "lastName": "overflow"}}
然后你需要设置属性
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
这样做是在 class 上注释的 @XmlRootElement(name="person")
或 @JsonRootName("person")
中查找 class 名称的值。对于 JAXB 注释支持,您仍然需要配置 JAXB 注释模块
mapper.registerModule(new JaxbAnnotationModule());
此模块包含在 jackson-module-jaxb-annotations
jar 中。如果您使用 Maven(具有上述依赖项),它已经被引入。
这是关于一个带有 JSON 对象和根元素的 REST PUT 调用,比方说,类似于 :
{"place":
{"name":"Here",
"address":
{"address":"somewhere under the rainbow",
"city":
{"name":"Oz",
"country":
{"name":"Oz",
"zone":"Far Far Away"}
}
}
}
}
使用 Jaxb 注释定义
@XmlRootElement
public class PlaceOffline extends GlobalElement {
@XmlElement
public Address address;
}
超类是
@XmlRootElement
public class GlobalElement implements Serializable {
@XmlElement
public Integer id;
@XmlElement
public String name;
@XmlElement
public String uniqueLabel;
}
我写了一个客户端,它悲惨地失败了
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "placeOffline"
然后我决定记录调用并创建一个 ContainerRequestFilter 来执行此操作
@Provider
public class RestLogFilter implements ContainerRequestFilter {
private Logger LOGGER_filter = Logger.getLogger(RestLogFilter.class.getName());
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (!MediaType.APPLICATION_JSON_TYPE.equals(requestContext.getMediaType())
|| requestContext.getEntityStream() == null) {
return;
}
InputStream inputStream = requestContext.getEntityStream();
byte[] bytes = IOUtils.readFully(inputStream , -1, true);
LOGGER_filter.info("Posted: " + new String(bytes, "UTF-8"));
requestContext.getEntityStream().mark(0);
}
}
而且,你猜怎么着?
出乎意料的成功了!没有更多的错误。实体的打印解决了这个问题。尴尬。
我认为它是一种解决方法,但它让我有点困扰,有人可以解释一下吗?解决这个问题的更优雅的方法?
我正在使用 WildFly 8.2
编辑:
它与
一起工作public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper mapper;
public ObjectMapperContextResolver() {
mapper = new ObjectMapper();
mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return mapper;
}
}
您需要将 Jackson 添加到应用程序中(只是为了编译),因为您将需要其中的一些 classes。 Wildfly 使用 Jackson 反序列化 JSON,默认行为是当它看到 JSON 上未在 POJO 中建模的属性时失败。例如下面的 JSON
{"firstName": "stack", "lastName": "overflow"}
有一个 属性 "lastName"
不在下面的 POJO
public class Person {
private String firstName;
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getFirstName() { return firstName; }
}
所以它会因 Jackson 的默认行为而失败。
对于依赖,可以添加
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.0.9.Final</version>
<scope>provided</scope>
</dependency>
请注意 provided
范围,因为 Wildfly 已经具有此依赖项。如果您不使用 Maven,那么您真正需要的只是 jackson-databind
和 jacskon-annotations
。只需抓住 2.4.x 版本。如果您使用 Jars,请务必不要将这些 jar 与您的 war 打包在一起,因为版本可能与 Wildfly 已有的冲突。
现在,如果您只想忽略这个 class 的未知属性,您可以只为 class
添加一个注释@JsonIgnoreProperties(ignoreUnknown = true)
public class PlaceOffline extends GlobalElement {
或者如果你想全局配置这个行为,你可以看ObjectMapper
的配置方法如下
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
更新
如果失败是由于 JSON 被包装,例如
{"person": {"firstName": "stack", "lastName": "overflow"}}
然后你需要设置属性
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
这样做是在 class 上注释的 @XmlRootElement(name="person")
或 @JsonRootName("person")
中查找 class 名称的值。对于 JAXB 注释支持,您仍然需要配置 JAXB 注释模块
mapper.registerModule(new JaxbAnnotationModule());
此模块包含在 jackson-module-jaxb-annotations
jar 中。如果您使用 Maven(具有上述依赖项),它已经被引入。