0

Hibernate Validator のメソッド検証を試しています。

想像できる最も単純な EJB を作成し、その制約に注釈を付けました。

ただし、カスタム注釈では機能しません。

public String checkString(@NotNull @NotBlank @Characters(invalidCharacters = { '1' }) String string);

最後の注釈は、String に文字セットの特定の文字 (デフォルト) が含まれており、カスタム制約であることを確認します。これは、通常の Validator 環境で機能します。

ただし、私のテストでは、標準の注釈のみが機能し、カスタム注釈は機能しません。

  this.parameterValidation.checkString(null); // Throws Exception

  this.parameterValidation.checkString(""); // Throws Exception

  this.parameterValidation.checkString("123"); // Does NOT throw Exception - why?

別のカスタム アノテーションもテストしましたが、これも非アクティブのままです。

私は何を間違っていますか?


カスタム アノテーションのコードは次のとおりです。

/**
 * Checks if a String contains only characters from the given character set. Note that this sets a parameter
 * {@code positions} with a comma-separated list of the positions of invalid characters (based on 1, not 0!).
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Constraint(validatedBy = CharactersCheck.class)
public @interface Characters {
  /**
   * The I18N key of the error message.
   */
  public static final String I18N_KEY = "ipi.msg.validation.characters";

  /**
   * Error message.
   */
  String message() default LEFT_CURLY_BRACKET + I18N_KEY + RIGHT_CURLY_BRACKET;

  /**
   * The associated violation groups.
   */
  Class<?>[] groups() default {};

  /**
   * The payload.
   */
  Class<? extends Payload>[] payload() default {};

  /**
   * The character set to which the text must conform.
   */
  CharacterSet characterSet() default CharacterSet.ISO_8859_15;

  /**
   * Additional characters which must not be found in the text.
   */
  char[] invalidCharacters() default {};

  /**
   * If this is {@code true}, carriage returns and line feeds are allowed in the text, making it a multi-line text.
   */
  boolean carriageReturnAllowed() default false;

  /**
   * Defines several {@link Characters} annotations on the same element.
   */
  @Documented
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
  @interface List {

    /**
     * The {@link Characters} annotations.
     */
    Characters[] value();
  }
}

実装は次のとおりです。

public class CharactersCheck implements ConstraintValidator<Characters, CharSequence>, MessageAttributeModifier {

  /**
   * The character set to check.
   */
  private CharacterSet characterSet;

  /**
   * Additional invalid characters.
   */
  private char[] invalidCharacters;

  /**
   * If this is {@code true}, carriage returns and line feeds are allowed in the text, making it a multi-line text.
   */
  private boolean carriageReturnAllowed;

  private SortedSet<Integer> invalidCharacterPositions;

  /**
   * {@inheritDoc}
   */
  @Override
  public void initialize(final Characters constraintAnnotation) {
    this.characterSet = constraintAnnotation.characterSet();
    this.carriageReturnAllowed = constraintAnnotation.carriageReturnAllowed();
    if (this.carriageReturnAllowed) {
      this.invalidCharacters = constraintAnnotation.invalidCharacters();
    } else {
      final int invalidCharactersLength = constraintAnnotation.invalidCharacters().length;
      this.invalidCharacters = Arrays.copyOf(constraintAnnotation.invalidCharacters(), invalidCharactersLength + 2);
      this.invalidCharacters[invalidCharactersLength] = '\r';
      this.invalidCharacters[invalidCharactersLength + 1] = '\n';
    }
    this.invalidCharacterPositions = new TreeSet<>();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isValid(final CharSequence value, final ConstraintValidatorContext context) {
    if (value == null) {
      return true;
    } else {
      setInvalidCharacterPositions(value);
      return this.invalidCharacterPositions.isEmpty();
    }
  }

  private void setInvalidCharacterPositions(final CharSequence value) {
    this.invalidCharacterPositions = CharacterChecker.checkCharacters(String.valueOf(value), this.characterSet,
        this.invalidCharacters);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void modifyAttributes(final Map<String, Object> attributes, final Context context) {
    setInvalidCharacterPositions((CharSequence) context.getValidatedValue());
    if (!this.invalidCharacterPositions.isEmpty()) {
      attributes.put(MessageVariables.POSITIONS, StringUtils.join(this.invalidCharacterPositions, ", "));
    }
  }
}

チェックがメッセージ変数を特定の Map に追加できるようにするカスタム メッセージ インターポレータを作成したことに注意してください。このために、メッセージ インターポレーター内にチェックの新しいインスタンスを作成し、このインターフェイスを使用して呼び出します。

/**
 * Modifies attributes within a validation message.
 */
public interface MessageAttributeModifier {

  /**
   * Modifies the attributes within the validation message.
   * @param attributes The existing attributes, which can be modified; the attributes already contain the values from
   * the annotation and additionally also {@link MessageVariables#VALIDATED_VALUE}
   * @param context The validation context
   */
  public void modifyAttributes(Map<String, Object> attributes, final Context context);
}
4

0 に答える 0