2016-10-05 7 views
1

Ich weiß, Hibernate-Validator unterstützt TYPE_USE Annotationen: obwohl es nicht seine eigenen definiert, können Sie benutzerdefinierte definieren und verwenden.TYPE_USE-Annotation im Hibernate-Validator

Ich könnte eine solche Annotation (Code bald) korrekt definieren und validieren, aber dann möchte ich den Fehler in einen Pfad mappen, der verwendet wird, um den Fehler für den Benutzer anzuzeigen.

Gegeben dann Probe nach

public class SampleTest { 

    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); 

    public static class LimitedSizeStringValidator implements ConstraintValidator<LimitedSize, String> { 

     private LimitedSize constraint; 

     @Override 
     public void initialize(LimitedSize constraintAnnotation) { 
      this.constraint = constraintAnnotation; 
     } 

     @Override 
     public boolean isValid(String value, ConstraintValidatorContext context) { 
      String s = Ensure.notNull(value); 
      return s.length() >= constraint.min() && 
       s.length() <= constraint.max(); 
     } 
    } 

    @Retention(RUNTIME) 
    @Documented 
    @Target({TYPE_USE}) 
    @Constraint(validatedBy = {LimitedSizeStringValidator.class}) 
    public @interface LimitedSize { 

     String message() default "{javax.validation.constraints.Size.message}"; 

     Class<?>[] groups() default {}; 

     Class<? extends Payload>[] payload() default {}; 

     int min() default 0; 

     int max() default Integer.MAX_VALUE; 
    } 

    private static class TestBean { 
     @Valid 
     private Collection<@LimitedSize(max = 3) String> strings = new ArrayList<>(); 

     @Valid 
     private Collection<InnerBean> beans = new ArrayList<>(); 
    } 

    private static class InnerBean { 
     @Min(3) 
     private final int value; 

     private InnerBean(int value) { 
      this.value = value; 
     } 
    } 

    @Test 
    public void testBeanInvalid() { 

     TestBean testBean = new TestBean(); 

     assertThat(validator.validate(testBean)).isEmpty(); 

     testBean.strings.add("ok"); 
     testBean.strings.add("ok2"); 
     testBean.beans.add(new InnerBean(4)); 
     assertThat(validator.validate(testBean)).isEmpty(); 

     testBean.strings.add("not_ok"); 
     testBean.beans.add(new InnerBean(2)); 

     Set<ConstraintViolation<TestBean>> violations = validator.validate(testBean); 
     assertThat(violations).hasSize(2); 

     StreamSupport.stream(violations.spliterator(), false) 
      .forEach(v -> { 
       System.out.println(v.getPropertyPath()); 
       System.out.println(v.getMessage()); 
       v.getPropertyPath().forEach(p -> System.out.print("'" + p.getName() + (p.getIndex() != null ? "[" + p.getIndex() + "]" : "") + "' -> ")); 
       System.out.println(); 
      }); 
    } 
} 

Ich mag die Fehler in einem Objekt wie

errors: [ 
    ["beans", "1", "value"], 
    ["strings", "2"] 
] 

Wie in meiner Probe abbilden würde, mein Ansatz ist im Moment durch die Verletzung Pfad der Navigation (http://docs.oracle.com/javaee/7/api/javax/validation/ConstraintViolation.html#getPropertyPath--), die für den ersten Fall perfekt funktioniert, aber für den zweiten fehlschlägt (ich finde keinen Weg, den Index des fehlerhaften Objekts abzurufen). Ich glaube, der Grund dafür ist, bei der Umsetzung von javax.validation.Path.PropertyNode in Hibernate-Validator (Ich bin derzeit auf Version 5.2.4.Final, und der Code sieht genauso aus wie in den verknüpften 5.2.1.Final als Referenz.

@Override 
public final Integer getIndex() { 
    if (parent == null) { 
     return null; 
    } 
    else { 
     return parent.index; 
    } 
} 

Mit TYPE_USE dieser Ansatz kann nicht funktionieren meiner Meinung nach, weil das fehlerhafte Objekt ein Blatt ist, damit kein Kind-Knoten den Index abgerufen werden kann.

Nizza genug, hibernate Implementierung von javax.validation.Path überschreibt die toString Verfahren ist derart, dass violation.getPropertyPath().toString() ist beans[1].value und strings[2] (in der Sampl e Code oben).

Also, zu den Fragen: Ist meine Navigation falsch und es gibt eine andere Möglichkeit, ein solches Mapping aus der ConstraintViolation zu extrahieren? Oder ist das ein Feature-Request für Hibernate-Entwickler (Ich kann sehen, dass vor TYPE_USE Annotationen die getIndex Ansatz sie umgesetzt war völlig in Ordnung?

Es fühlt sich einfach seltsam Ich bin der erste, der sich mit diesem Problem (Ich habe versucht, Google und konnte nicht Finden Sie etwas, das am nächsten ist: https://github.com/hibernate/hibernate-validator/pull/441), also frage ich mich, ob der Fehler meiner ist eher als eine Winterschlafbeschränkung

Antwort

1

Ich stimme zu, dass der Index für diesen Wert festgelegt werden sollte und denke, Sie ein Problem in Hibernate Validator aufgedeckt Sie öffnen ein Problem in unserem JIRA tracker?

Btw. der Begriff von Einschränkungen der TYPE_USE-Ebene werden ab Bean Validation 2.0 standardisiert. Es könnte also noch weitere Änderungen in diesem Bereich geben, insbesondere frage ich mich, was Kind dieser Knoten haben sollte (momentan ist es PROPERTY, was fraglich erscheint).

+0

danke für die schnelle Rückmeldung. hier das Problem: https://hibernate.atlassian.net/browse/HV-1121. Ich denke vielleicht sogar daran, eine PR direkt zu öffnen (aber nicht vor Sonntag sicher) – ThanksForAllTheFish

+0

Das Problem wurde in Hibernate Validator 5.3.0.Final behoben. –

Verwandte Themen