在JSON对象中强制执行非空字段

时间:2012-10-10 06:34:03

标签: java json rest jackson required

我们的REST API收到一些JSON对象输入,其中某些字段必须不为null。那些可以是String / Integer,也可以是其他类实例作为参考。

我们正试图找到一种方法来强制将这些字段设为非空,而不是在api中进行空检查的正确方法。 电流:


    if (myObject.getSomeOtherObject() == null)
    throw new SomeException();

我们想拥有的是:


    class MyObject{
    @Required
    OtherObject someOtherObject;
    ...
    }

我们尝试了3件事:

  • 升级到jackson 2.0.6并使用注释 com.fasterxml.jackson.annotation.JsonProperty 但是,这看起来不起作用。 找到那些参考: http://jira.codehaus.org/browse/JACKSON-767

  • 扩展JsonDeserializer以检查null,但问题是它甚至没有在空输入上执行。


    public class NotNullDeserializer<T> extends JsonDeserializer<T> {

        @Override
        public T deserialize(JsonParser jsonparser, DeserializationContext deserializationcontext) throws IOException, JsonProcessingException {

            ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
            Class type = (Class) superClass.getActualTypeArguments()[0];

            T t = jsonparser.readValueAs(type);

            if (t == null){
                String classNameField = type.getName();
                String field = jsonparser.getCurrentName();
                throw new WrongInputException("The field '"+field+"' of type '"+classNameField+"' should not be null.");
            }

            return t;
        }

    }

    public class NotNullAddressDeserializer extends NotNullDeserializer<Address> {

    }

    @JsonDeserialize(using=NotNullAddressDeserializer.class)
        Address to;

  • 编写我们自己的@Required注释并尝试使用ResourceFilter进行检查,但似乎我无法从ContainerRequest获取实际对象,即使我们可以,也不确定如何在object.otherObject.someObject中执行对空引用的深度检查.fieldNotNullable

    private class Filter implements ResourceFilter, ContainerRequestFilter {

        private final ArrayList requiredParameters;

        protected Filter() {
            requiredParameters = null;
        }

        protected Filter(ArrayList requiredParameters) {
            this.requiredParameters = requiredParameters;
        }

        @Override
        public ContainerRequestFilter getRequestFilter() {
            return this;
        }

        @Override
        public ContainerResponseFilter getResponseFilter() {
            return null;
        }


        @Override
        public ContainerRequest filter(ContainerRequest request) {
            if (requiredParameters != null && requiredParameters.size() > 0) {
                MultivaluedMap params = request.getQueryParameters();
                params.putAll(request.getFormParameters());
                StringBuffer missingParams = new StringBuffer();
                for (String reqParam : requiredParameters) {
                    List paramValues = params.get(reqParam);
                    if (paramValues == null || paramValues != null && paramValues.size() == 0)
                        missingParams.append(reqParam + ",");
                }
                if (missingParams.length() > 0)
                    throw new WrongInputException("Required parameters are missing: " + missingParams);
            }
            return request;
        }
    }


任何帮助和见解表示赞赏。

4 个答案:

答案 0 :(得分:23)

JAX-RS很好地将反序列化与验证区分开来,即杰克逊有按设计没有机制来强制值为non-null等。相反,你可以使用BeanValidation来实现:

  1. javax.validation:validation-api范围内向provided添加依赖项。
  2. javax.validation.constraints.NotNull注释添加到您的字段中。
  3. 有关详细信息,请转到here

答案 1 :(得分:2)

您可以使用JSON-SCHEMA,因为您可以使用它来表达JSON字段的许多约束:http://json-schema.org/

然后,您可以使用@NotNull JSR 303注释从模式生成java类,并在对象上使用bean验证。它本身与杰克逊合作,所以你不应该有任何问题。

例如,您可以使用maven插件执行此操作:http://wiki.jsonschema2pojo.googlecode.com/git/site/0.3.7/generate-mojo.html

答案 2 :(得分:1)

@Required是注入bean的Spring框架注释,所以我要说不要将它用于此目的。

你可以改用这个:

http://robaustin.wikidot.com/annotations-and-notnull

@NotNull String myString;

对于运行时检查,请尝试http://code.google.com/p/notnullcheckweaver/

答案 3 :(得分:0)

您可以结合使用Jackson JSON库和not null以及Hibernate验证程序包来强制执行javax.validation验证。

如果您正在使用Maven,则可以使用以下依赖项:

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson-version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${jackson-version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>${hibernate-validator.version}</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator-annotation-processor</artifactId>
        <version>${hibernate-validator.version}</version>
    </dependency>

    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>3.0.0</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>javax.el</artifactId>
        <version>2.2.6</version>
    </dependency>

</dependencies>

然后,您的代码将必须将一些JSON转换为带注释的对象,并且您将需要使用javax.validation.Validator来验证对象。以下是一些示例代码,演示了如何完成此操作(请参见相关的validate方法):

public class ShareLocationService {

    private ObjectMapper mapper = new ObjectMapper();

    private ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

    // Materialize the Java object which contains the validation annotations
    public ShareLocation readFrom(String json) throws IOException {
        return mapper.readerFor(ShareLocation.class).readValue(json);
    }

    // validate and collect the set of validations
    public Set<String> validate(String json) throws IOException {
        ShareLocation shareMyLocation = readFrom(json);
        Validator validator = factory.getValidator();
        Set<ConstraintViolation<ShareLocation>> violations = validator.validate(shareMyLocation);
        return violations.stream().map(Object::toString).collect(Collectors.toSet());
    }
}

这是使用验证注释的示例类:

public class ShareLocation {
    @JsonProperty("Source")
    @NotNull
    private String source;
    @JsonProperty("CompanyCode")
    private String companyCode;
    @JsonProperty("FirstName")
    private String firstName;
    @JsonProperty("LastName")
    private String lastName;
    @JsonProperty("Email")
    private String email;
    @JsonProperty("MobileNumber")
    private String mobileNumber;
    @JsonProperty("Latitude")
    @NotNull
    private Double latitude;
    @JsonProperty("Longitude")
    @NotNull
    private Double longitude;
    @JsonProperty("LocationDateTime")
    @NotNull
    private String locationDateTime;