【问题标题】:Enforce not-null field in JSON object在 JSON 对象中强制执行非空字段
【发布时间】:2012-10-10 06:34:02
【问题描述】:

我们的 REST API 接收一些 JSON 对象输入,其中一些字段需要不为空。这些可以是字符串/整数,甚至可以是其他类实例作为参考。

我们正在尝试找到一种方法来强制这些字段不为空,而不是在 API 中进行空值检查的正确方法。 当前:

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

我们想要的是这样的:

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

我们尝试了 3 件事:

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

2) 扩展 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<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) 编写我们自己的 @Required 注释并尝试使用 ResourceFilter 进行检查,但似乎我无法从 ContainerRequest 中获取实际对象,即使我们可以,也不确定如何在 @987654326 中执行对空引用的深度检查@

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

【问题讨论】:

    标签: java json rest jackson required


    【解决方案1】:

    JAX-RS 将反序列化与验证很好地分开,即 JSON-B(或 Jackson)按设计没有机制将值强制为 non-null 等。相反,您可以为此使用 BeanValidation:

    1. provided 范围内添加对javax.validation:validation-api 的依赖项。
    2. javax.validation.constraints.NotNull 注释添加到您的字段中。

    更多详情,请转至here

    【讨论】:

    • 虽然这是个老问题,但答案看起来不错:) 谢谢!接受。
    【解决方案2】:

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

    你可以改用这个:

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

    @NotNull String myString;

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

    【讨论】:

    • @Required 我引用的是我们自己的注释。无论如何,谢谢,我现在会尝试你的建议,只是 - 我需要哪个 jar 来导入 core.validation.*
    • 链接中的注释是针对this annotation is intended to be used by static analysis tools的。但我需要这个在运行时进行严格的 API 验证。谢谢:)
    • notnullcheckweaver 仅适用于方法参数,而(如上所述)我们还希望更深入。例如,不可空输入对象 x 具有多个字段,其中一个字段 y 也不可空且更深。谢谢
    【解决方案3】:

    您可以使用 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

    【讨论】:

      【解决方案4】:

      您可以结合使用 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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-21
        • 2020-05-31
        相关资源
        最近更新 更多