package org.hibernate.validator.referenceguide.chapter09;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.annotation.ElementType;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.validation.ConstraintTarget;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import javax.validation.metadata.BeanDescriptor;
import javax.validation.metadata.ConstraintDescriptor;
import javax.validation.metadata.ConstructorDescriptor;
import javax.validation.metadata.CrossParameterDescriptor;
import javax.validation.metadata.GroupConversionDescriptor;
import javax.validation.metadata.MethodDescriptor;
import javax.validation.metadata.MethodType;
import javax.validation.metadata.ParameterDescriptor;
import javax.validation.metadata.PropertyDescriptor;
import javax.validation.metadata.ReturnValueDescriptor;
import javax.validation.metadata.Scope;
import org.hibernate.validator.referenceguide.chapter09.Car.SeverityInfo;
import org.junit.BeforeClass;
import org.junit.Test;
public class CarTest {
private static Validator validator;
@BeforeClass
public static void setUpValidator() {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
@Test
public void testBeanDescriptor() {
//tag::testBeanDescriptor[]
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
assertTrue( carDescriptor.isBeanConstrained() );
//one class-level constraint
assertEquals( 1, carDescriptor.getConstraintDescriptors().size() );
//manufacturer, licensePlate, driver
assertEquals( 3, carDescriptor.getConstrainedProperties().size() );
//property has constraint
assertNotNull( carDescriptor.getConstraintsForProperty( "licensePlate" ) );
//property is marked with @Valid
assertNotNull( carDescriptor.getConstraintsForProperty( "driver" ) );
//constraints from getter method in interface and implementation class are returned
assertEquals(
2,
carDescriptor.getConstraintsForProperty( "manufacturer" )
.getConstraintDescriptors()
.size()
);
//property is not constrained
assertNull( carDescriptor.getConstraintsForProperty( "modelName" ) );
//driveAway(int), load(List<Person>, List<PieceOfLuggage>)
assertEquals( 2, carDescriptor.getConstrainedMethods( MethodType.NON_GETTER ).size() );
//driveAway(int), getManufacturer(), getDriver(), load(List<Person>, List<PieceOfLuggage>)
assertEquals(
4,
carDescriptor.getConstrainedMethods( MethodType.NON_GETTER, MethodType.GETTER )
.size()
);
//driveAway(int)
assertNotNull( carDescriptor.getConstraintsForMethod( "driveAway", int.class ) );
//getManufacturer()
assertNotNull( carDescriptor.getConstraintsForMethod( "getManufacturer" ) );
//setManufacturer() is not constrained
assertNull( carDescriptor.getConstraintsForMethod( "setManufacturer", String.class ) );
//Car(String, String, Person, String)
assertEquals( 1, carDescriptor.getConstrainedConstructors().size() );
//Car(String, String, Person, String)
assertNotNull(
carDescriptor.getConstraintsForConstructor(
String.class,
String.class,
Person.class,
String.class
)
);
//end::testBeanDescriptor[]
}
@Test
public void testPropertyDescriptor() {
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
//tag::testPropertyDescriptor[]
PropertyDescriptor licensePlateDescriptor = carDescriptor.getConstraintsForProperty(
"licensePlate"
);
//"licensePlate" has two constraints, is not marked with @Valid and defines no group conversions
assertEquals( "licensePlate", licensePlateDescriptor.getPropertyName() );
assertEquals( 2, licensePlateDescriptor.getConstraintDescriptors().size() );
assertTrue( licensePlateDescriptor.hasConstraints() );
assertFalse( licensePlateDescriptor.isCascaded() );
assertTrue( licensePlateDescriptor.getGroupConversions().isEmpty() );
PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );
//"driver" has no constraints, is marked with @Valid and defines one group conversion
assertEquals( "driver", driverDescriptor.getPropertyName() );
assertTrue( driverDescriptor.getConstraintDescriptors().isEmpty() );
assertFalse( driverDescriptor.hasConstraints() );
assertTrue( driverDescriptor.isCascaded() );
assertEquals( 1, driverDescriptor.getGroupConversions().size() );
//end::testPropertyDescriptor[]
}
@Test
public void testMethodAndConstructorDescriptor() {
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
//tag::testMethodAndConstructorDescriptor[]
//driveAway(int) has a constrained parameter and an unconstrained return value
MethodDescriptor driveAwayDescriptor = carDescriptor.getConstraintsForMethod(
"driveAway",
int.class
);
assertEquals( "driveAway", driveAwayDescriptor.getName() );
assertTrue( driveAwayDescriptor.hasConstrainedParameters() );
assertFalse( driveAwayDescriptor.hasConstrainedReturnValue() );
//always returns an empty set; constraints are retrievable by navigating to
//one of the sub-descriptors, e.g. for the return value
assertTrue( driveAwayDescriptor.getConstraintDescriptors().isEmpty() );
ParameterDescriptor speedDescriptor = driveAwayDescriptor.getParameterDescriptors()
.get( 0 );
//The "speed" parameter is located at index 0, has one constraint and is not cascaded
//nor does it define group conversions
assertEquals( "speed", speedDescriptor.getName() );
assertEquals( 0, speedDescriptor.getIndex() );
assertEquals( 1, speedDescriptor.getConstraintDescriptors().size() );
assertFalse( speedDescriptor.isCascaded() );
assert speedDescriptor.getGroupConversions().isEmpty();
//getDriver() has no constrained parameters but its return value is marked for cascaded
//validation and declares one group conversion
MethodDescriptor getDriverDescriptor = carDescriptor.getConstraintsForMethod(
"getDriver"
);
assertFalse( getDriverDescriptor.hasConstrainedParameters() );
assertTrue( getDriverDescriptor.hasConstrainedReturnValue() );
ReturnValueDescriptor returnValueDescriptor = getDriverDescriptor.getReturnValueDescriptor();
assertTrue( returnValueDescriptor.getConstraintDescriptors().isEmpty() );
assertTrue( returnValueDescriptor.isCascaded() );
assertEquals( 1, returnValueDescriptor.getGroupConversions().size() );
//load(List<Person>, List<PieceOfLuggage>) has one cross-parameter constraint
MethodDescriptor loadDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
);
assertTrue( loadDescriptor.hasConstrainedParameters() );
assertFalse( loadDescriptor.hasConstrainedReturnValue() );
assertEquals(
1,
loadDescriptor.getCrossParameterDescriptor().getConstraintDescriptors().size()
);
//Car(String, String, Person, String) has one constrained parameter
ConstructorDescriptor constructorDescriptor = carDescriptor.getConstraintsForConstructor(
String.class,
String.class,
Person.class,
String.class
);
assertEquals( "Car", constructorDescriptor.getName() );
assertFalse( constructorDescriptor.hasConstrainedReturnValue() );
assertTrue( constructorDescriptor.hasConstrainedParameters() );
assertEquals(
1,
constructorDescriptor.getParameterDescriptors()
.get( 0 )
.getConstraintDescriptors()
.size()
);
//end::testMethodAndConstructorDescriptor[]
}
@Test
public void testElementDescriptor() {
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
//tag::testElementDescriptor[]
PropertyDescriptor manufacturerDescriptor = carDescriptor.getConstraintsForProperty(
"manufacturer"
);
assertTrue( manufacturerDescriptor.hasConstraints() );
assertEquals( String.class, manufacturerDescriptor.getElementClass() );
CrossParameterDescriptor loadCrossParameterDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
).getCrossParameterDescriptor();
assertTrue( loadCrossParameterDescriptor.hasConstraints() );
assertEquals( Object[].class, loadCrossParameterDescriptor.getElementClass() );
//end::testElementDescriptor[]
}
@Test
public void testConstraintFinderApi() {
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
//tag::testConstraintFinderApi[]
PropertyDescriptor manufacturerDescriptor = carDescriptor.getConstraintsForProperty(
"manufacturer"
);
//"manufacturer" constraints are declared on the getter, not the field
assertTrue(
manufacturerDescriptor.findConstraints()
.declaredOn( ElementType.FIELD )
.getConstraintDescriptors()
.isEmpty()
);
//@NotNull on Vehicle#getManufacturer() is part of another group
assertEquals(
1,
manufacturerDescriptor.findConstraints()
.unorderedAndMatchingGroups( Default.class )
.getConstraintDescriptors()
.size()
);
//@Size on Car#getManufacturer()
assertEquals(
1,
manufacturerDescriptor.findConstraints()
.lookingAt( Scope.LOCAL_ELEMENT )
.getConstraintDescriptors()
.size()
);
//@Size on Car#getManufacturer() and @NotNull on Vehicle#getManufacturer()
assertEquals(
2,
manufacturerDescriptor.findConstraints()
.lookingAt( Scope.HIERARCHY )
.getConstraintDescriptors()
.size()
);
//Combining several filter options
assertEquals(
1,
manufacturerDescriptor.findConstraints()
.declaredOn( ElementType.METHOD )
.lookingAt( Scope.HIERARCHY )
.unorderedAndMatchingGroups( Vehicle.Basic.class )
.getConstraintDescriptors()
.size()
);
//end::testConstraintFinderApi[]
}
@Test
public void testGroupConversionDescriptor() {
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
//tag::testGroupConversionDescriptor[]
PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );
Set<GroupConversionDescriptor> groupConversions = driverDescriptor.getGroupConversions();
assertEquals( 1, groupConversions.size() );
GroupConversionDescriptor groupConversionDescriptor = groupConversions.iterator()
.next();
assertEquals( Default.class, groupConversionDescriptor.getFrom() );
assertEquals( Person.Basic.class, groupConversionDescriptor.getTo() );
//end::testGroupConversionDescriptor[]
}
@Test
public void testConstraintDescriptor() {
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
//tag::testConstraintDescriptor[]
//descriptor for the @LuggageCountMatchesPassengerCount constraint on the
//load(List<Person>, List<PieceOfLuggage>) method
ConstraintDescriptor<?> constraintDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
).getCrossParameterDescriptor().getConstraintDescriptors().iterator().next();
//constraint type
assertEquals(
LuggageCountMatchesPassengerCount.class,
constraintDescriptor.getAnnotation().annotationType()
);
//standard constraint attributes
assertEquals( SeverityInfo.class, constraintDescriptor.getPayload().iterator().next() );
assertEquals(
ConstraintTarget.PARAMETERS,
constraintDescriptor.getValidationAppliesTo()
);
assertEquals( Default.class, constraintDescriptor.getGroups().iterator().next() );
assertEquals(
"There must not be more than {piecesOfLuggagePerPassenger} pieces of luggage per " +
"passenger.",
constraintDescriptor.getMessageTemplate()
);
//custom constraint attribute
assertEquals(
2,
constraintDescriptor.getAttributes().get( "piecesOfLuggagePerPassenger" )
);
//no composing constraints
assertTrue( constraintDescriptor.getComposingConstraints().isEmpty() );
//validator class
assertEquals(
Arrays.<Class<?>>asList( LuggageCountMatchesPassengerCount.Validator.class ),
constraintDescriptor.getConstraintValidatorClasses()
);
//end::testConstraintDescriptor[]
}
}