Enforce not-null field in JSON object

╄→尐↘猪︶ㄣ 提交于 2019-11-27 03:04:58

问题


Our REST API receives some JSON objects input where some fields are required to be not null. Those can be either String/Integer or even might be some other class instance as reference.

We are trying to find a way to enforce those field to be not null, instead of the correct way for null check in the API. Current:

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

What we want to have is something like:

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

We have tried 3 things:

1) Upgrade to jackson 2.0.6 and use annotation com.fasterxml.jackson.annotation.JsonProperty But, this just looks not working. Found those references: http://jira.codehaus.org/browse/JACKSON-767

2) Extending JsonDeserializer to check null but the problem is that it does not even executed on the null input.

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

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

        ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
        Class<T> type = (Class<T>) 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;

3) Writing our own @Required annotation and trying to check with ResourceFilter, but it seems I cannot get the actual object from the ContainerRequest and even if we could, not sure how to execute deep check of null reference in object.otherObject.someObject.fieldNotNullable

private class Filter implements ResourceFilter, ContainerRequestFilter {
    private final ArrayList<String> requiredParameters;

    protected Filter() {
        requiredParameters = null;
    }

    protected Filter(ArrayList<String> 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<String, String> params = request.getQueryParameters();
            params.putAll(request.getFormParameters());
            StringBuffer missingParams = new StringBuffer();
            for (String reqParam : requiredParameters) {
                List<String> 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;
    }
}

回答1:


JAX-RS separates quite nicely the deserialization from the validation, i.e. Jackson has by design no mechanism to enforce values to be non-null, etc. Instead, you can use BeanValidation for that:

  1. Add a dependency to javax.validation:validation-api in provided scope.
  2. Add the javax.validation.constraints.NotNull annotation to your field.

For more details, go here.




回答2:


You can use JSON-SCHEMA as you can express many constraints on JSON fields with it: http://json-schema.org/

Then you can generate from the schema your java classes with @NotNull JSR 303 annotations and use bean validation on your object. It works with Jackson natively, so you should not have any problem.

For instance, you can use the maven plugin to do so: http://wiki.jsonschema2pojo.googlecode.com/git/site/0.3.7/generate-mojo.html




回答3:


@Required is a Spring framework annotation for injected beans, so I'd say don't use it for this purpose.

You can use this one instead:

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

@NotNull String myString;

For runtime checks, try http://code.google.com/p/notnullcheckweaver/




回答4:


You can enforce not null validation using a combination of the Jackson JSON library and the javax.validation together with the Hibernate validator package.

If you are using Maven these are the dependencies you can use:

<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>

Then your code will have to convert some JSON into your annotated object and you will need to validate the object using javax.validation.Validator. Here is some sample code demonstrating how this can be done (see the relevant validate method):

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());
    }
}

Here is a sample class using the validation annotations:

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;


来源:https://stackoverflow.com/questions/12813319/enforce-not-null-field-in-json-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!