Envers jest dodatkiem do Hibernate’a pozwalającym na automatyczne zapisywanie historii zmian encji (audytu). Envers używa pojęcia rewizji – co oznacza, że każda zmiana dowolnej (audytowalnej) encji tworzy nową rewizję. Nowy rekord jest zapisany do tabeli, a na podstawie starego zostaje utworzona rewizja i zapisana do dodatkowej tabeli wraz z poprzednimi wartościami.
Archiwum dla kategorii ‘JBoss’
JSR-303 – przepis na fasolkę. Bardzo dobrą poniekąd. Cz. 1
czwartek, Luty 11, 2010Finalna wersja specyfikacji JSR-303: Bean Validation ukazała się światu pod koniec ubiegłego roku (2009). Jest to kolejny przysmak a’la carte z renomowanej kuchni Gavin’a King’a i spółki, który doczekał się formalnej specyfikacji. Zatem – delektujmy się przez chwilę…
Dla osób niewtajemniczonych wyjaśniam, że mam na myśli produkt hibernate-validator, który jest protoplastą specyfikacji.
Wraz z nią otrzymaliśmy jej implementację referencyjną w postaci produktu hibernate-validator w wersji 4.
Świadomy tego, że bezapelacyjnie każdego ta historia urzekła przejdę do konkretów.
Dlaczego w ogóle o tym piszę? istnieje co najmniej kilka powodów:
- Jest to nowy standard w ramach Javy.
- Będzie wchodził w skład JEE 6.
- Bardzo łatwo się go używa – również na platformie SAP NetWeaver.
- Posiada nowe rozbudowane API oraz nowe możliwości rozszerzeń (np. tzw. “composite constraints”).
- W sposób przezroczysty integruje się z już posiadanym kodem.
Ponieważ jest to artykuł subiektywny, nie zamierzam w nim wymieniać wszystkich właściwości oraz różnic w specyfikacji JSR 303 w stosunku do starego hibernate-validator’a. Ze szczegółami można zawsze zapoznać się pobierając specyfikację ze stron Java Community Process.
Moim zdaniem bardzo istotna jest rozbudowa specyfikacji o możliwość definiowania mechanizmów walidacji za pomocą deskryptorów XML. Być może niektórzy czytelnicy posądzą mnie tutaj o herezję, ponieważ dziesiątki deskryptorów dostępnych w JEE to swoiste “małe piekiełko”. W przypadku walidatora jest to bardzo dobry pomysł o czym świadczą silne argumenty:
- Deskryptory pozwalają na zastosowanie walidacji w beanach dostarczanych w postaci bibliotek,
- Definicje w deskryptorach uniezależniają walidowane komponenty od API walidatora oraz własnych walidatorów w formie rozszerzeń.
Poniżej przedstawiam przykład kodu z zastosowaniem adnotacji oraz odpowiednika z zastosowaniem deskryptora xml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | // Person.java package test.beans; import javax.validation.constraints.NotNull; import javax.validation.Size; import javax.validation.constraints.Past; import java.util.List; import java.util.Date; import javax.validation.Valid; public class Person { // wymuszenie wartości różnej niż null @NotNull(message="Imię nie może być puste") private String name; // wymuszenie wartości różnej niż null @NotNull(message="Nazwisko nie może być puste") private String surname; // wymuszamy datę przeszłą w stosunku do czasu systemowego @Past(message="Należy podać datę przeszłą") private Date birthDate; // oczekiwanie, że w kolekcji będzie co najmniej jeden element @Size(min=1,message="Należy podać co najmniej jeden adres") @Valid // wskazanie aby implementacja wykonała również walidację adresów private List<Address> adrList; (...) } ---------------------------------------------------------- // Address.java package test.beans; import javax.validation.constraints.NotNull; public class Address { // wymuszenie wartości różnej niż null @NotNull(message="Miasto nie może być puste") private String city; (...) } |
Stan analogiczny do powyższego kodu możemy uzyskać za pomocą następujących definicji w deskryptorze xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <?xml version="1.0" encoding="UTF-8"?> <!-- sample-constraints.xml --> <constraint-mappings xmlns="http://jboss.org/xml/ns/javax/validation/mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"> <default-package>test.beans</default-package> <bean class="Person" ignore-annotations="true"> <field name="name"> <constraint annotation="javax.validation.constraints.NotNull"> <message>Imię nie może być puste</message> </constraint> </field> <field name="surname"> <constraint annotation="javax.validation.constraints.NotNull"> <message>Nazwisko nie może być puste</message> </constraint> </field> <field name="birthDate"> <constraint annotation="javax.validation.constraints.Past"> <message>Należy podać datę przeszłą</message> </constraint> </field> <field name="adrList"> <constraint annotation="javax.validation.constraints.Size"> <message>Należy podać co najmniej jeden adres</message> <element name="min">1</element> </constraint> <valid/> </field> </bean> <bean class="Address" ignore-annotations="true"> <field name="city"> <constraint annotation="javax.validation.constraints.NotNull"> <message>Miasto nie może być puste</message> </constraint> </field> </bean> </constraint-mappings> |
Nie jest trudno wywnioskować, że wszystkie ograniczenia zdefiniowane w kodzie źródłowym mają swoje odpowiedniki w deskryptorze. Aby powyższe przykłady uruchomić, konieczne jest jeszcze skonfigurowanie całego “silnika” walidacji.
Konfigurację realizuje się przez zamieszczenie w katalogu META-INF pliku o nazwie validation.xml, który jest deskryptorem konfiguracji JSR-303.
Oto przykład pliku:
1 2 3 4 5 6 7 8 9 | <?xml version="1.0" encoding="UTF-8"?> <validation-config xmlns="http://jboss.org/xml/ns/javax/validation/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd"> <default-provider>org.hibernate.validator.HibernateValidator</default-provider> <constraint-mapping>META-INF/sample-constraints.xml</constraint-mapping> </validation-config> |
W powyższym pliku określono następujące właściwości silnika:
- Default-provider wskazuje dostawcę implementacji JSR-303, którym jest oczywiście hibernate validator
- Constraint-mapping wskazuje na dodatkowy deskryptor xml z definicją ograniczeń, można zdefiniować wiele plików z definicją ograniczeń
Na deser pozostał mi jeszcze prościutki przykład uruchomienia walidacji w kodzie z zastosowaniem poprzednich przykładów.
Oto on:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // ValidationTest.java package test.beans; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.ValidatorFactory; public class ValidationTest { public static void main(String[] argv) { ValidationTest vt = new ValidationTest(); Person p = new Person(); p.name= "John"; t.validateBean(p); return; } public void validateBean(Person p) { ValidatorFactory vf = Validation.buildDefaultValidatorFactory(); Set<ConstraintViolation> violationSet = vf.getValidator().validate(p); for(ConstraintViolation cv : violationSet ) { System.out.println(cv.getMessage()); } return; } } |
Smacznej walidacji
Autor: Daniel Ramotowski
