Skip to content

Incorrect @Nullable JSR305 annotations generated when using 'required' array #906

@jrehwaldt

Description

@jrehwaldt

Currently, the rule NotRequiredRule generates incorrect @Nullable annotations for fields that get correctly generated with @Nonnull. This happens only on nested objects, due to broken logic for checking the required array definition. When retrieving the schema content we get the root schema instead of the relevant sub schema and therefore the implementation checks against an incorrect hierarchy within the schema.

Schema

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "SchemaTest body",
  "description": "Example for incorrect @Nullable annotations.",
  "type": "object",
  "properties": {
    "sub-array": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "nonnull-field"
        ],
        "properties": {
          "nonnull-field": {
            "type": "string"
          },
          "nullable-field": {
            "type": "string"
          }
        }
      }
    }
  }
}

Behaviour

(Look for HERE in SubArray)

package tests;

import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import javax.validation.Valid;


/**
 * SchemaTest body
 * <p>
 * Example for incorrect @Nullable annotations.
 * 
 */
public class SchemaTest {

    /**
     * 
     * (Can be null)
     * 
     */
    @Nullable
    @Valid
    private List<SubArray> subArray = new ArrayList<SubArray>();

    /**
     * No args constructor for use in serialization
     * 
     */
    public SchemaTest() {
    }

    /**
     * 
     * @param subArray
     */
    public SchemaTest(List<SubArray> subArray) {
        super();
        this.subArray = subArray;
    }

    public List<SubArray> getSubArray() {
        return subArray;
    }
}
package tests;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;

public class SubArray {

    /**
     * 
     * (Can be null)
     * (Required)
     * 
     */
    @Nullable // <-- HERE ############################################
    @NotNull
    @Nonnull
    private String nonnullField;
    /**
     * 
     * (Can be null)
     * 
     */
    @Nullable
    private String nullableField;

    /**
     * No args constructor for use in serialization
     * 
     */
    public SubArray() {
    }

    /**
     * 
     * @param nonnullField
     * @param nullableField
     */
    public SubArray(String nonnullField, String nullableField) {
        super();
        this.nonnullField = nonnullField;
        this.nullableField = nullableField;
    }

    /**
     * 
     * (Required)
     * 
     */
    public String getNonnullField() {
        return nonnullField;
    }

    public String getNullableField() {
        return nullableField;
    }
}

Expected

package tests;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;

public class SubArray {

    /**
     * 
     * (Required)
     * 
     */
    @NotNull
    @Nonnull
    private String nonnullField;
    /**
     * 
     * (Can be null)
     * 
     */
    @Nullable
    private String nullableField;

    /**
     * No args constructor for use in serialization
     * 
     */
    public SubArray() {
    }

    /**
     * 
     * @param nonnullField
     * @param nullableField
     */
    public SubArray(String nonnullField, String nullableField) {
        super();
        this.nonnullField = nonnullField;
        this.nullableField = nullableField;
    }

    /**
     * 
     * (Required)
     * 
     */
    public String getNonnullField() {
        return nonnullField;
    }

    public String getNullableField() {
        return nullableField;
    }
}

Possible solutions

  1. Pass down sub schemas instead of the root schema. I saw from the code the distinction parentContent and content is already there, but never used. I think this would be the correct solution.
  2. Apply NotRequiredRule for all fields that do not get RequiredRule called instead of this separate handling as it stands now. Haven't looked into it.
  3. Workaround: Override RuleFactory to return NoopRule for NotRequiredRule and extend ObjectRule to add @Nullable to all fields not annotated with @Nonnull after the original ObjectRule is done.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions