Validieren abhängiger Felder mit JEE6/Bean validation

JanHH

Top Contributor
Hallo,

folgendes Problem:

Bei einem JEE-Projekt soll eine Validierung durchgeführt werden (JSF-Seite mit Formular, ganz normal). Dabei gibts dann ein h:selectOneMenu A, und nur wenn dieses bestimmte Werte hat, wird h:inputText B angezeigt. Dass in Feld B etwas eingegeben wird, soll also nur validiert werden, wenn A den entsprechenden Wert hat.

Bisher wars ein JEE5/seam 2-Projekt. Validierung von A mittels Annotation/Hibernate validators und s:validateAll. Validierung von B in der action-Bean in der submit-Methode per java Code. Also überprüfen ob B, wenn A den entsprechenden Wert hat, nicht leer ist, ggf. eine Message an das B-Eingabefeld schicken (mit der @In FacesMessages facesMessages-Komponente, methode facesMessages.addToControl(...). ) Funktioniert soweit auch alles gut.

Nun soll das Projekt nach JEE6 portiert werden und ein Freund meinte "bei JEE6 ist vor allem das Validieren viel einfacher, vor allem sowas von Feldern, die in Abhängigkeit zueinander stehen, geht da ganz einfach, ohne viel java-Code". Ist ja schön und gut, nur WIE? Ich habe bisher nix gefunden, was vernünftig funktioniert. Die JSR303 ist ziemlich kryptisch, da finde ich eigentlich keine Antwort auf die Frage. An Tags gibts da noch rich:validateGraph und s:validateForm, mit beiden geht das "irgendwie", aber so richtig einfach auch nicht.

Konkrete Probleme:

- ganz einfache Annotationen, die ein Feld in Abhängigkeit von einem anderen validieren, gibts nicht.
- mit rich:validateGraph kann man die validierung zwar durchführen, aber das ist dann auch wieder java-Code, ausserdem gibts da das gleiche Problem wie bei der
- Standard-Methode wie bei seam 2 (in der form-Submit-Methode) geht auch nicht mehr so wie vorher, weils keine seam-FacesMessages-Komponente mit der addToControl-Methode gibt, d.h. man kann zwar die Validierung im java-Code nach wie vor ausführen, aber es ist nicht mehr so einfach möglich, die Fehler-Message an die Komponente zu heften (dort angezegit mit h:message for...).

Also, wie macht man das richtig!?

Angeblich ist es ja ganz einfach und ich kann mir auch nicht vorstellen, dass dieses durchaus relevante Thema bei der JSR303 einfach vergessen wurde. Kommt doch ständig vor, bspws. Eingabe zweier Passwörter oder e-Mail-Adressen, die übereinstimmen müssen.. fühl mich langsam verblödet.

Weiss jemand die Lösung?

Gruß+Danke
Jan
 

F.S.WhiTeY

Bekanntes Mitglied
Manchmal sollte ich mir angewöhnen richtig und gründlich zu lesen xD

Ich entschuldige mich für die unzulänglichen, nur durchs Überfliegen zustandegekommenden, Antowrten über diesen Post. Naja vilt. war es ja N1 2 Know.

Du willst also einen Anwendungsdefinierten Validierer für die Komponente ? Wenn ich doch nicht nur überflogen hätte ^^

Also folgendermaßen kann man das anstellen

Java:
@FacesValidator("irgendEtwasValidieren")
public class IrgendwasValidierer implements Validator{

public void validate(FacesContext context, UIComponent component, Object value) 
                                                throws ValidatorException {

if( bedingungFuerException ){
throw new ValidatorException(
                      new FacesMessage(FacesMessage.SEVERITY_ERROR, 
                                                    "FEHLERAUSGABE",
                                                    "FEHLERAUSGABE"));
}

}

}


und dann einfach an die komponente mit dem namen aus dem @FacesValidator

Java:
<h:inputText id="A" value="#{BLAHH.BLUBB}" validator="irgendEtwasValidieren" />
                        
                        <h:message for="A" styleClass="warning" />

Ich hoffe du verzeihst mir den Schrott aus den zwei Posts vorher -.-

IM SO SORRY ;)
 
Zuletzt bearbeitet:

JanHH

Top Contributor
Hab die zwei Postings vorher gar nicht gelesen, eben erst wieder reingeschaut ;-).

Bei so einer Validierungs-Funktion war ich auch schon, aber da hab ich doch auch nur Zugriff auf die Input-Komponente, an der das validate-Attribut hängt. Aber die Validierung hängt ja auch von anderen Variablen der entsprechenden Entity ab. Und auf diese hab ich da keinen Zugriff, oder?
 

F.S.WhiTeY

Bekanntes Mitglied
Ja und nein ^^

Der Trick an der ganzen sache ist, das du eigentlich keine zwei komponenten hast... sondern nur eine. Das ganze nennt man dann Compositkomponente in der du z.B. zwei InputText zu einer E-Mail-Muss-Gleich-Sein-Composition zusammenfasst und diese dann auch gesondert validieren kannst.

Der Aufwand für Compositkomponenten ist in etwa der gleiche wie für ein kleines Template. Muss dann nur registriert werden.

Die andere Variante ist, eine Abhängigkeit auf Immediate zu setzen und dir mit roher Gewalt über den Faces-Context die Daten zu beschaffen.

Die Dritte und von mir zumindest letzte Idee ist, das "Validieren" in der Action-Methode zu machen und dann einen Boolean für das Rendering eines Fehlers auf true zu setzen. Ist allerdings meiner meinung nach nicht sehr "schön" aber es funktioniert, hab ich auch schon gemacht. Wird halt problematisch wenn du mehr als ein paar hast was in Abhängigkeit steht, weil du deine ganze aktionmethode zuklatschen musst bzw. mit ausgelagerten Methodenaufrufen vollballerst.

Ich bin heute in der Uni und hab da nen echt Kompetenten Dozi mit JSF-Kenntnissen. Der hat auch schon ein zwei Bücher über JSF und JPA/Hibernate geschrieben. Ich werd mir mal anhören wie der das lösen würde und sag dir dann bescheid.

Ich denke aber das seine Antwort lauten wird: Ajax ActionListener. Ich hab mich mit Ajax aber noch nicht wirklich befasst ;)

So das wars erstmal.

Bis heute Abend.
 
Zuletzt bearbeitet:
G

Gast2

Gast
Geht noch einfacher...
Du kannst wie vorher eine Methode deklarieren und diese annotieren je nachdem wird die message in den context aufgenommen oder nicht:
z.b.

Java:
public class MyBean{
	@AssertTrue(message = "Unterschiedliche Passwörter!")
	public boolean isPasswordsEquals() {
		return pwd.equals("12345");
	}

dann kannst dein validator angeben
[XML]
<rich:graphValidator value="#{myBean}" id="gv">
[/XML]

und mit

[XML]<rich:message for="gv" />[/XML]

ausgeben wo du willst


hier sind dazu auch ein paar Beispiele
RichFaces Project Page - JBoss Community
 
Zuletzt bearbeitet von einem Moderator:

JanHH

Top Contributor
Davon ist aber nichts der "ganz einfache, standardmässige Weg", den mein Bekannter meinte. Sofern es den überhaupt gibt und er sich nicht geirrt hat. Die Beispiele (vielen Dank) sind allesamt nicht einfacher, als die Validierungen in der JSF-Form-submiit-Methode auszuführen.
 

JanHH

Top Contributor
Danke. Aber das ist ja noch viel schlimmer als es einfach in der submit-Methode zu prüfen.

Also mein Fazit ist irgendwie, mein Bekannter hat sich halt geirrt..
 

nocturne

Bekanntes Mitglied
Also ich mach das so:
Anstelle von passwort kann wohl jedes Feld genommen werden.
Ich habe bei anderen gesehen, dass sie auch "new Effect.Shutter()" eingebaut haben.
 

Anhänge

  • passwortmatch.jpg
    passwortmatch.jpg
    17,4 KB · Aufrufe: 43
Zuletzt bearbeitet:
G

Gast2

Gast
Davon ist aber nichts der "ganz einfache, standardmässige Weg", den mein Bekannter meinte. Sofern es den überhaupt gibt und er sich nicht geirrt hat. Die Beispiele (vielen Dank) sind allesamt nicht einfacher, als die Validierungen in der JSF-Form-submiit-Methode auszuführen.

Was genau findest du jetzt daran so schwer eine methode mit einer Annotation zu deklarieren?^^
Ich finds angenehm einfach.
 

F.S.WhiTeY

Bekanntes Mitglied
So mein Dozi hat dazu geraten den FacesContext zu benutzen und sich seinen eigenen Anwendungsdefinierten-Validierer zu schreiben.

Für dich, Jan, sehe das dann so aus :

Java:
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

/**
 *
 * @author david
 */
@FacesValidator("eigenerValidierer")
public class EigenerValidator implements Validator {

    public void validate(FacesContext context,
            UIComponent component,
            Object value)
            throws ValidatorException {
        //Hier wird die Viewroot über den FacesContext geholt und
        //die andere Componente über die ID beschafft.
        //Hier wäre das z.B. <h:inputText id="B" .... />
        //Wenn man weiß  was für eine componente es ist
        //Kann man casten, ansonsten einfach bei UIComponent bleiben
        UIInput inputA = (UIInput) FacesContext.getCurrentInstance().getViewRoot().findComponent("B");
          
        if(!value.equals(inputA)){
            throw new ValidatorException( new FacesMessage( FacesMessage.SEVERITY_ERROR,"FEHLER" , "FEHLER"));
            
        }
        
        
    }
}

und dann eifach als Validierer benutzen :

A in Abhängigkeit ( == / equals ) von B

Java:
<h:inputText id="A" value="#{BLAHH.BLUBB}" validator="irgendEtwasValidieren" />
<h:inputText id="B" value="#{BLAHH.BLUBB2}" />
                        
                        <h:message for="A" styleClass="warning" />


Ich hoffe das ist es, was du suchst.

HTH
 
G

Gast2

Gast
So mein Dozi hat dazu geraten den FacesContext zu benutzen und sich seinen eigenen Anwendungsdefinierten-Validierer zu schreiben.

Was ist der Grund dafür, dass er nicht JSR-303 verwendet, welches Richface anbietet?
So hat man das davor gemacht wie gesagt nun gehts ja leichter, einfach mal die Beispiele anschaun da stehen doch alle Möglichkeiten drin sogar vorher nachher...
 
M

maki

Gast
Danke. Aber das ist ja noch viel schlimmer als es einfach in der submit-Methode zu prüfen.

Also mein Fazit ist irgendwie, mein Bekannter hat sich halt geirrt..
Würde ich nicht so sehen, JSR 303 kann einiges mehr, ist ja schliesslich nicht an JSF gekoppelt ;)

Man kann damit eine Art "Anti corruption Layer" schreiben, der in allen Schichten genutzt werden kann, um zB. Redundanz des Validierungscodes zu vermeiden.
zB. wird jeder JPA Provider bei vorhandensein einer JSR 303 Implementierung diese Validierungen vor dem Persistieren durchführen, vollautomatisch :)

"einfacher" ist immer so eine Sache, wenn du bis jetzt immer nur in JSF validiert hast, dann ist es klar dass du es als einfacher empfindest.
 
S

Sym

Gast
Ich verstehe die Aufgabe nicht ganz.

Da das Textfeld nur angezeigt wird, wenn in der Selectbox das richtige ausgewählt, muss Du doch nicht beides validieren.

Einfach Deinen Validator an das Textfeld und fertig.
 

F.S.WhiTeY

Bekanntes Mitglied
Was ist der Grund dafür, dass er nicht JSR-303 verwendet, welches Richface anbietet?
So hat man das davor gemacht wie gesagt nun gehts ja leichter, einfach mal die Beispiele anschaun da stehen doch alle Möglichkeiten drin sogar vorher nachher...


Der Grund ist, das JanHH expliziet gesagt hat:


An Tags gibts da noch rich:validateGraph und s:validateForm, mit beiden geht das "irgendwie", aber so richtig einfach auch nicht.

und

- mit rich:validateGraph kann man die validierung zwar durchführen, aber das ist dann auch wieder java-Code, ausserdem gibts da das gleiche Problem wie bei der
- Standard-Methode wie bei seam 2 (in der form-Submit-Methode) geht auch nicht mehr so wie vorher, weils keine seam-FacesMessages-Komponente mit der addToControl-Methode gibt, d.h. man kann zwar die Validierung im java-Code nach wie vor ausführen, aber es ist nicht mehr so einfach möglich, die Fehler-Message an die Komponente zu heften (dort angezegit mit h:message for...).


Wenn er sich damit auseinander gesetzt hat und eine "reine JSF-Lösung" im sinne von keine anderen Bibliotheknen haben will, warum soll ich ihm dann Lösungen mit erweiternden Frameworks anbieten?

Jan hat das doch schon ausgeschlossen.
 
G

Gast2

Gast
Wenn er sich damit auseinander gesetzt hat und eine "reine JSF-Lösung" im sinne von keine anderen Bibliotheknen haben will, warum soll ich ihm dann Lösungen mit erweiternden Frameworks anbieten?

Jan hat das doch schon ausgeschlossen.

Bei dir ist die Validierung genauso im Java Code???

Es benutzt doch wie oben geschrieben Richfaces und die bieten eben JSR-303 an und das ist nicht von JSF abhängig wie deine Lösung. Du siehst doch an meinem Beispiel, dass es nicht schwer ist und keine weiteren Abhägikeiten in deinen JSF Context benötigt. Keine eigene zusätzliche Klasse. Nur eine Annotations der rest passiert automatisch.

Außerdem sieht man auf der Richfaces Seite, dass es auch komplett ohne Java-Code geht siehe z.B.
<f:validateLength>
 

F.S.WhiTeY

Bekanntes Mitglied
<f:validateLength> ist nen standart validierer der mit der CORE-LIB von JSF mitgebracht wird. Natürlich ist meine lösung in Javacode und deine Lösung nicht falsch oder schwer, aber er wollte deine Lösung expliziet nicht ^^

Zumindest am anfang. Wenn er keine standardvalidierer benutzen will dann hat er nun, nachdem wir sooo viel gepostet haben, wenigstens die auswahl ;)

Und Richfaces muss ich importieren sonst geht garnix... ich z.B. will derzeit keine Rich, Prime oder sonstwas-faces. Ich bleib beim Apachen in der standardimplementierung... zumidnest vorerst.
 
G

Gast2

Gast
Nun soll das Projekt nach JEE6 portiert werden und ein Freund meinte "bei JEE6 ist vor allem das Validieren viel einfacher, vor allem sowas von Feldern, die in Abhängigkeit zueinander stehen, geht da ganz einfach, ohne viel java-Code". Ist ja schön und gut, nur WIE? Ich habe bisher nix gefunden, was vernünftig funktioniert. Die JSR303 ist ziemlich kryptisch, da finde ich eigentlich keine Antwort auf die Frage. An Tags gibts da noch rich:validateGraph und s:validateForm, mit beiden geht das "irgendwie", aber so richtig einfach auch nicht.

Ich hab gezeigt, dass es ziemlich "einfach" mit JSR303 geht. Und wenn er rich:validateGraph verwendet, benutzt er Richfaces.
Und es ist ohne "vieeeel" Javacode ;).

Wollte eigentlich nur die Aussage wiederlegen dass es mit JSR-303 umständlich ist und nicht dass deine falsch ist.

Deine ist eben JSF abhängig, meine nicht ;).
 
M

maki

Gast
JanHH hat doch explizit diese Frage gestellt:
Nun soll das Projekt nach JEE6 portiert werden und ein Freund meinte "bei JEE6 ist vor allem das Validieren viel einfacher, vor allem sowas von Feldern, die in Abhängigkeit zueinander stehen, geht da ganz einfach, ohne viel java-Code". Ist ja schön und gut, nur WIE? Ich habe bisher nix gefunden, was vernünftig funktioniert. Die JSR303 ist ziemlich kryptisch, da finde ich eigentlich keine Antwort auf die Frage.
Darauf wird man ja wohl noch antworten dürfen ;)
Welche Vorteile eine eigenständige Validierung die unabhängig von der UI Technik ist, ist ja fast selbsterklärend.
 

F.S.WhiTeY

Bekanntes Mitglied
@sir

Ich fand bisher keine lösung umständlich, weder meine noch deine. Die Hibernate-Lösung hab ich mir allerdings nicht angeschaut.

JSR-303 ist einfach nur gelungen. Einfacher kann Webentwicklung nicht sein. Egal welche Faces wir nun nehmen, da sind wir uns einig ^^

@maki

Du darfst immer antworten ;) :D
 
G

Gast2

Gast
@sir

Ich fand bisher keine lösung umständlich, weder meine noch deine. Die Hibernate-Lösung hab ich mir allerdings nicht angeschaut.

JSR-303 ist einfach nur gelungen. Einfacher kann Webentwicklung nicht sein. Egal welche Faces wir nun nehmen, da sind wir uns einig ^^

Ich wollte eigentlich nur sagen dass man in JEE6 die validation API (JSR303) verwenden kann ohne zusätzliche Biblotheken einzubinden.

Klar egal welches UI du dann verwendest muss die validierung dann ausgegeben werden. Richfaces macht das zum Beispiel. Für Richfaces brauchst du zusätzliche libs, aber nicht für JSR303.
So hab ich das gemeint ;)
 

JanHH

Top Contributor
Vielen Dank für die rege Anteilnahme an meiner Frage ;-).

Natürlich geht das mit all den aufgezeigten Wegen, die meisten hab ich auch schon selber herausgefunden/ausprobiert (z.B. rich:validateGraph), aber was halt nicht zuzutreffen scheint ist die Aussage meines Bekannten "in JEE6 geht Validierung abhängiger Felder viel einfacher, ist da standardmässig mit eingebaut". Ich denke, da hat er die JSR303 nicht so gründlich gelesen.

Dass es geht, auf mehrere Arten, ist ja klar. Aber keine davon ist wirklich so viel einfacher wie die bisherige (die Validierung in der submit-methode "per Hand" zu machen). Wobei natürlich einiges dafür spricht, das von der submit-Methode in einen eigenen Validator auszulagern, um die Validierungen komplett in der entsprechenden JSF-Phase zu haben.

Das fragliche Textfeld wird immer angezeigt, bzw. von JSF gerendert; es wird beim Ändern der Menüauswahl, von der das Textfeld abhängt, selbiges per javascript ein-/ausgeblendet.
 
Zuletzt bearbeitet:
G

Gast2

Gast
Dass es geht, auf mehrere Arten, ist ja klar. Aber keine davon ist wirklich so viel einfacher wie die bisherige (die Validierung in der submit-methode "per Hand" zu machen).

Klar spricht einiges für JSR-303 anstatt deiner JSF Lösung...
Zeig mal deine bisherige Lösung ich versteh dein Problem immer noch nicht, was du mit dem annotieren einer Methode hast =)...
 
S

Sym

Gast
Das fragliche Textfeld wird immer angezeigt, bzw. von JSF gerendert; es wird beim Ändern der Menüauswahl, von der das Textfeld abhängt, selbiges per javascript ein-/ausgeblendet.
Ich wiederhole noch einmal meine Frage.

Das Textfeld ist ja nur da, wenn die Menüauswahl passt. Warum möchtest Du dann noch eine Validierung machen, ob die Menüauswahl stimmt?
 

JanHH

Top Contributor
Naja das Textfeld soll halt nicht leer sein, wenn es angezeigt wird. Aber halt auch nur dann ;-). Eine Lösung wäre vielleicht wirklich, es nicht per javascript sondern per ajax ein-/auszublenden.

Mit dem Annotieren einer Methode hab ich gar kein Problem, aber das Beispiel Bestand ja auch noch aus dem definieren der Annotation selber, und da kam dann doch relativ viel programmcode bei zusammen..
 
S

Sym

Gast
Die Not-Null-Validierung geschieht doch automatisch bei einem Submit, wenn das Feld gerendert wird. Einfach das Attribute Required auf true setzen.

Und wenn man JSF verwendet, sollte man natürlich die Ajax-Tags verwenden, wenn möglich. :)
 

JanHH

Top Contributor
Aber das Feld wird IMMER gerendert, nur halt ggf. nicht angezeigt (javascript). Fand javascript da eleganter als ajax, weil ja eigentlich kein Server-Requests notwendig ist.
 

JanHH

Top Contributor
Bei dem Beispiel von Maki (der Link von ihm) sah es so aus als ob man auch die Annotation selber explizit programmieren muss (was ja auch logisch ist, wenn es keine Standard-Validierungs-Annotation ist).
 
M

maki

Gast
Bei dem Beispiel von Maki (der Link von ihm) sah es so aus als ob man auch die Annotation selber explizit programmieren muss (was ja auch logisch ist, wenn es keine Standard-Validierungs-Annotation ist).
Ja, so ist JSR 303 gemeint.

Der Vorteil ist die wieder Verwendbarkeit der Annotationen an sich, aber auch die Wiederverwendbarkeit der Validierungen.
Ob in GUI (JSF, GWT, Wicket, etc. pp.), Businesstier, Persistenz (Hibernate, EclipseLink, JPA) die Validierungen werden direkt an dem Model angebracht, können zu Gruppen zusammengefasst werden, etc. pp.

Die Annotationen an sich sieht Anfangs schräg/komplex aus, ist sie aber gar nicht, viel ist es jedenfalls nicht ;)
Der Umfang des benötigten Validerungscodes im ConstraintValidator könnte etwas damit zu tun haben, wie komplex die Validierung ist, hat nix mehr mit dem JSR 303 selbst zu tun.
Gemessen an dem was man bekommt ist da eben doch recht wenig Javacode nötig.

Muss aber jeder selber wissen was er nimmt/braucht.
 

JanHH

Top Contributor
Wär ja auch mal eine sportliche Übung, das JSR303-mässig zu programmieren.

Da es sich insgesamt um 4 selectOneMenu mit je einem optinalen Textfeld handelt, ja auch durchaus sinnvoll, was die Wiederverwendbarkeit angeht. Werds mal probieren..
 

Ähnliche Java Themen

Neue Themen


Oben