首页 文章

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

提问于
浏览
20

我们的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但问题是它甚至没有在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 回答

  • 23

    JAX-RS很好地区分了验证中的反序列化,即Jackson在设计上没有任何机制来强制值为 non-null 等 . 相反,您可以使用BeanValidation:

    • provided 范围内向 javax.validation:validation-api 添加依赖项 .

    • javax.validation.constraints.NotNull 注释添加到您的字段中 .

    有关详细信息,请转到here .

  • 2

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

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

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

  • 0

    @Required 是注入bean的Spring框架注释,因此我将其用于此目的 .

    你可以用这个代替:

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

    @NotNull String myString;

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

  • 1

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

    如果您使用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;
    

相关问题