Enforce not-null field in JSON object

urir picture urir · Oct 10, 2012 · Viewed 54.1k times · Source

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

Answer

r&#252;- picture rü- · Apr 17, 2014

JAX-RS separates quite nicely the deserialization from the validation, i.e. JSON-B (or 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.