使用Json对象的Resteasy PUT或POST会导致UnrecognizedPropertyException

时间:2015-08-19 22:45:53

标签: json resteasy wildfly-8

这是关于一个带有JSON对象的REST PUT调用,它带有一个根元素,比如说:

{"place":
    {"name":"Here",
     "address":
         {"address":"somewhere under the rainbow",
          "city":
                 {"name":"Oz",
                  "country":
                    {"name":"Oz",
                     "zone":"Far Far Away"}
                  }
          }
     } 
}

使用Jaxb Annotations定义

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

1 个答案:

答案 0 :(得分:1)

你需要将Jackson添加到应用程序中(只是为了编译),因为你需要它的一些类。 Wildfly使用Jackson来反序列化JSON,并且当它看到未在POJO中建模的JSON上的属性时,默认行为将失败。例如以下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; }
}

因此杰克逊的默认行为会失败。

对于依赖项,您可以添加

<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-databindjacskon-annotations。只需抓住2.4.x版本。如果您正在使用Jars,那么这些罐子不会与您的战争打包在一起非常重要,因为该版本可能与Wildfly已有的相冲突。

现在,如果你想忽略这个类的未知属性,你可以给我们一个类的注释

@JsonIgnoreProperties(ignoreUnknown = true)
public class PlaceOffline extends GlobalElement {

或者,如果要全局配置此行为,可以看到this answer。如何配置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);

这样做的目的是在类上注释的@XmlRootElement(name="person")@JsonRootName("person")中查找类名的值。对于JAXB注释支持,您仍需要配置JAXB注释模块

mapper.registerModule(new JaxbAnnotationModule());

此模块包含在jackson-module-jaxb-annotations jar中。如果您使用Maven(具有上述依赖性),它已被拉入。