Принудительное поле not-null в объекте JSON

наш REST API получает некоторые входные данные объектов JSON, где некоторые поля должны быть не нулевыми. Это может быть либо строка / целое число, либо даже какой-либо другой экземпляр класса в качестве ссылки.

мы пытаемся найти способ обеспечить, чтобы это поле не было нулевым, а не corrent-способом для нулевой проверки в api. Ток:


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

то, что мы хотим иметь, это что-то вроде:


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

мы попробовали 3 вещи:

  • обновление до jackson 2.0.6 и использование аннотации com.fasterxml.Джексон.аннотация.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, и даже если бы мы могли, не знаете, как выполнить глубокую проверку нулевой ссылки в объекте.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 ответов


JAX-RS довольно хорошо отделяет десериализацию от проверки, т. е. У Джексона есть конструкция нет механизма для принудительного значения non-null, etc. Вместо этого вы можете использовать BeanValidation для этого:

  1. добавить зависимость к javax.validation:validation-api на provided объем.
  2. добавить javax.validation.constraints.NotNull аннотация к вашему полю.

для получения более подробной информации, go здесь.


вы можете использовать JSON-SCHEMA как вы можете выразить много ограничений на полях JSON с ним:http://json-schema.org/

затем вы можете генерировать из схемы свои классы java с аннотациями @NotNull JSR 303 и использовать проверку bean для вашего объекта. Он работает с Джексоном изначально, поэтому у вас не должно быть никаких проблем.

например, вы можете использовать плагин maven для этого: http://wiki.jsonschema2pojo.googlecode.com/git/site/0.3.7/generate-mojo.html


@Required является аннотацией Spring framework для инъекционных бобов, поэтому я бы сказал, что не используйте его для этой цели.

Вы можете использовать вместо этого:

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

@NotNull String myString;

для проверки выполнения попробуйте http://code.google.com/p/notnullcheckweaver/


вы можете применять not null проверка с использованием комбинации библиотеки Jackson JSON и javax.validation вместе с пакетом Hibernate validator.

если вы используете 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;