| 

.NET C# Java Javascript Exception

3
​In einem Kundenprojekt stellen wir gerade Überlegungen an, wie wir die Validierungen in der Businesslogik implementieren sollen. Dabei haben wir ein paar Randbedingungen zu beachten:

  • Es müssen mehrere Szenarien unterstützt werden. Einige Validierungen gelten global für alle Szenarien, andere sind spezifisch.

  • Teilweise werden Validierungen nur durchgeführt, wenn bestimmte Bedingungen erfüllt sind.

  • Die zu validierenden Beans sind per JAXB generierte Klassen. Deshalb kommen Frameworks, die auf Annotationen basieren, nicht in Frage.

Die Validierungen selbst sind meist einfache Werte- und Bereichsprüfungen. Alle verwendeten Werte liegen im zu prüfenden Objekt. Dieses ist in allen Szenarien vom Aufbau her identisch, jeodch unterschiedlich befüllt. Wir stellen uns vor, dass jede Validierung in einer eigenen Klasse implementiert wird und die Auswahl und Durchführung der Validierungen über ein Framework orchestriert wird.

Ich habe mir bereits die Library FluentValidator angesehen. Diese würde zwar ganz gut passen, hat aber einige Einschränkungen (nicht thread-sicher, Code-Dokumentation in chinesisch, wenig Aktivitäten), die uns zweifeln lassen, ob wir sie einsetzen sollen.

Hibernate-Validator kommt wegen des annotationsbasierten Ansatzes für uns nicht in Frage.

Kennt irgendjemand noch andere Bibliotheken bzw. Frameworks?

Danke im Voraus

Klaus
21.04.2016
luedi 2,2k 1 1 9
2 Antworten
1
Wenn du JAXB nutzt, hast du auch XSD Beschreibungen, reicht es dort nicht aus für die Felder die erlaubten Werte festzulegen?

Ansonsten kann ich aus unserer Erfahrung sagen, wir generieren Klassen auch via JAXB und die Beans sind zwar die Datenhalter, aber für jede Bean gibt es einen Decorator der die Logik der Bean enthält (Clonable, Serializable, equals, hashcode, tostring usw), sowie eine Validation Class als Inner Class, in manchen Fällen noch StepBuilder. Die "Datenbeans" die aus Jaxb kommen, werden NIE direkt genutzt.

Vielleicht zu Verdeutlichung mein Gedankengang:
MyBean.xsd --- JAXB Magie ----> com.lordpinhead.test.api.beans.internal.MyBean.java

package com.lordpinhead.test.beans;
import com.lordpinhead.test.api.beans.internal.MyBean;
.. weitere importe ..

public final class MyBeanImpl extends MyBean implements LogicInterface {

// Komplexer Konstruktor
public MyBeanImpl(...felder....) throws ValidationException {
super();
..... felder......
new MyBeanValidator().validate();
}


private class MyBeanValidator extends ValidateHelpers implements Validator {

private void validateMyComplexCondition() throws ValidationException {
... verschiedene Felder in zusammenspiel mit inhalten prüfen.....
}

@Override
public final void validate() throws ValidationException {
if (isEmptyString(getMyField)) {
throw new ValidationException ("MyField ist leer");
}
if (isException() {
if (hashCause(getException) {
.....
}
}

// Komplexe Conditions prüfen
validateMyComplexCondition();

if (isBetween(0L, 100L, getMyLongField).... usw.

..... weitere prüfungen.....
}
}
}


Manchmal ist ein Framework einfach überzogen oder völlig überfordert (mehr siehe unten), in den Helpers sind 20 Methoden und fertig, der Rest sind Conditionen oder wenn die Validation eines Feldes komplexer ist oder das zusammenspiel mehr Felder benötigt, dann eigene Methoden.

Natürlich kann man den Validator auch auslagern für Unit Tests, aber der bequemlichkeit halber habe ich ihn immer in der Decorator Klasse. Für Unit Tests reicht in der Regel Mockitor aus.

So erstellen wir die "Interna" Beans per JAXB, und "verstecken" diese eben im Package Pfad. Theoretisch kann also jemand immer um den Decorator herum programmieren.

Noch was zu Überfordert:
Ich hatte auch mit Hibernate Validator gespielt, aber wir hatten das Problem in der Client Software, wenn Feld1 den Wert X hatte, war Feld2 ein Pflichtfeld, wenn Feld1 den Wert Y hatte, war Feld2 dringend leer zu sein usw. Das konnte der Validator nicht.

Abhängig wie die Bean befüllt wird, wird die Validation auch nicht im Konstruktor gemacht, Struts Action Formen sind da ein Beispiel (aber das bringt ja was mit). An anderen Stellen nehme ich den Weg eines StepBuilderPatterns[1] wenn ich das erstellen eines Objektes und der Valiation erzwingen möchte.

Was die Validator Projekte meist unbrauchbar macht, ist also auch die Frage:
Wann kann ich validieren? Muss es im Konstruktor sein am Schluss, darf es erst sein wenn ein bestimmter Zeitpunkt erreicht ist - und wie verhindere ich das "vergessen" der validation (Execute Around Pattern [2]).

Das ist jedenfalls die Erfahrung der letzten 5 Jahre in "Historisch gewachsener Software" aus so viel Bereichen und Quellen.

1) http://rdafbn.blogspot.de/2012/07/step-builder-pattern_28.html
2) http://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom
07.10.2016
Lord_Pinhead 778 1 8
0
Danke für deine Antwort. Ich habe nicht viel Erfahrung mit JAXB, aber soweit ich es verstanden habe erfolgt auch die Konfiguration über xsd. Die xsd-Dateien, die wir zum generieren verwenden gehören zu einem unternehmensweiten Datenmodell und wir dürfen sie deshalb nicht verändern.

Mittlerweile haben wir ein eigenes Validation-Framework, welches die Prinzipien von FluentValidator aufgreift, implementiert. Damit konnten wir die Anforderungen an die Validierung in unserer Anwendung sehr gut abdecken. Der Vorteil des Ansatzes besteht darin, dass wir die Einzelvalidierungen in eigene Klassen packen und diese dann in beliebigen Kontexten zusammenstellen können. Dadurch bleibt die gesamte Validerung übersichtlich und ist gut wart- und erweiterbar. Vom Prinzip her sieht dies so aus:

public class TeilValidator extends BaseValidator<ObjectToValidate> {

@override
public boolean validate(ValidationContext context, ObjectToValidate toValidate) {
//... Validierung
return true // oder false, je nach Validierungsergebnis
}

public class ValidiereKontextIrgendwas extends BaseValidiereKontext {

public ValidierKontextIrgendwas(ValidiereKontextRequest request) {
super(request)
}

@override
public List<ValidationResult> validiere(List<ValidationResult> resultList) {
ObjectToValidate object = request.getObjectToValidate();
ValidationResult result = Validator.create()
.on(object, new Teilvalidator()
// hier köönten weitere Validatoren angegeben werden
.doValidate()
.result();
resultList.add(result);
return resultList();
}
}


Validator hat natürlich noch mehr Funktionalität (z.b. Schleifen und Bedingungen).
08.10.2016
luedi 2,2k 1 1 9

Stelle deine Java-Frage jetzt!