2015-01-26 12 views
14

Ich habe die folgende Controller-Methode:Validierung einer Liste von Objekten im Frühjahr

@RequestMapping(value="/map/update", method=RequestMethod.POST, produces = "application/json; charset=utf-8") 
@ResponseBody 
public ResponseEntityWrapper updateMapTheme(
     HttpServletRequest request, 
     @RequestBody @Valid List<CompanyTag> categories, 
     HttpServletResponse response 
     ) throws ResourceNotFoundException, AuthorizationException { 
... 
} 

CompanyTag wird auf diese Weise definiert:

public class CompanyTag { 
    @StringUUIDValidation String key; 
    String value; 
    String color; 
    String icon; 
    Icon iconObj; 

    public String getKey() { 
     return key; 
    } 

    public void setKey(String key) { 
     this.key = key; 
    } 
    ... 
} 

Das Problem ist, dass die Validierung nicht ausgelöst wird, die CompanyTag Liste Wird nicht validiert, wird der Validierer "StringUUIDValidation" nie aufgerufen.

Wenn ich die Liste entfernen und versuchen, nur einen einzigen CompanyTag zu schicken, dh statt:

@RequestBody @Valid List<CompanyTag> categories, 

Verwendung:

@RequestBody @Valid CompanyTag category, 

es wie erwartet funktioniert, so offenbar Frühling nicht gerne Prüfe Listen von Dingen (versucht mit Array, das hat auch nicht funktioniert).

Hat jemand eine Idee, was fehlt?

Antwort

1

Die Validierung einer Sammlung funktioniert nicht direkt.

Zum Beispiel: Was soll es tun, wenn mehrere Elemente die Validierung nicht bestehen? Nach der ersten Validierung stoppen? Alle validieren (wenn ja, was ist mit der Sammlung von Nachrichten zu tun)?

Wenn Sie in Ihrer Konfiguration Spring an einen Bean Validator-Anbieter wie Hibernate Validator delegieren, sollten Sie nach Möglichkeiten suchen, einen Collection-Validator dort zu implementieren.

für Hibernate, ein ähnliches Problem wird here diskutiert

5

Ich würde vorschlagen, Ihre Liste Kategorien in eine DTO Bohne wickeln und sie validieren. Neben der Arbeitsvalidierung profitieren Sie von einer flexibleren API.

@RequestMapping(value="/map/update", method=RequestMethod.POST, produces = "application/json; charset=utf-8") 
@ResponseBody 
public ResponseEntityWrapper updateMapTheme(
    HttpServletRequest request, 
    @RequestBody @Valid TagRequest tagRequest, 
    HttpServletResponse response 
    ) throws ResourceNotFoundException, AuthorizationException { 
... 
} 

public static class TagRequest { 
    @Valid 
    List<CompanyTag> categories;  
    // Gettes setters 
} 
+1

Das ist, was ich getan habe (mit Generika zu machen, na ja, generisch), aber dies ist eine Umgehungslösung und ich frage mich, ob Spring, ein relativ aktives Framework, das ständig weiterentwickelt wird und verbessert, hat dieses Problem nicht bereits auf eine Weise gelöst, mit der ich nicht vertraut bin. – TheZuck

+0

Dies ist im Grunde kein Spring-Problem, aber eine Bean-Validierung JSR-Implementierungsbeschränkung. Welches ist in diesem Fall Hibernate Validator. Und mehr darüber, wie der Name für JSR sagt, dass dies eine "Bean-Validierung" und keine "Objekt-Validierung" ist.Sie möchten eine Liste validieren, die keine Java Bean ist. Also ich denke, die Implementierung akzeptiert ein Bean-Objekt mit Getter und Setter und dann überprüft nur die Eigenschaften, aber List ist nicht der Fall. – Babl

+0

Bitte beachten Sie, dass Sie das Format von JSON von [{}, {}] in {categories: [{}, {}]} ändern müssen. – Kacper86

18

Ich fand einen anderen Ansatz, der funktioniert. Das Grundproblem besteht darin, dass Sie eine Liste als Eingabe-Payload für Ihren Service haben möchten, aber javax.validation validiert keine Liste, nur eine JavaBean. Der Trick ist, eine benutzerdefinierte Liste Klasse zu verwenden, die sowohl als Listenfunktionen und ein JavaBean:

@RequestBody @Valid List<CompanyTag> categories 

Wechseln zu:

@RequestBody @Valid ValidList<CompanyTag> categories 

Ihre Liste Unterklasse wie folgt aussehen würde:

public class ValidList<E> implements List<E> { 

    @Valid 
    private List<E> list; 

    public ValidList() { 
     this.list = new ArrayList<E>(); 
    } 

    public ValidList(List<E> list) { 
     this.list = list; 
    } 

    // Bean-like methods, used by javax.validation but ignored by JSON parsing 

    public List<E> getList() { 
     return list; 
    } 

    public void setList(List<E> list) { 
     this.list = list; 
    } 

    // List-like methods, used by JSON parsing but ignored by javax.validation 

    @Override 
    public int size() { 
     return list.size(); 
    } 

    @Override 
    public boolean isEmpty() { 
     return list.isEmpty(); 
    } 

    // Other list methods ... 
} 
+2

Dies ist die eleganteste Art, die ich jemals gefunden habe, danke! – smartwjw

+1

Dies ist wirklich eine knackige Lösung, aber haben eine Frage - wie Validierungsmeldung in diesem Szenario zu behandeln? –

+0

Haben Sie eine elegante Lösung für den Umgang mit Nachrichten gefunden? Ich habe dies versucht, aber es wurde ConstraintViolationException ausgelöst. Ich möchte die Verwendung der Ausnahmeregelung für die Feder behandeln. (@ ControllerAdvice) – user3444718

Verwandte Themen