/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package org.hibernate.validator.test.internal.engine.traversableresolver;
import java.lang.annotation.ElementType;
import java.util.HashSet;
import java.util.Set;
import javax.validation.Configuration;
import javax.validation.Path;
import javax.validation.TraversableResolver;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.groups.Default;
import org.testng.annotations.Test;
import static org.testng.Assert.fail;
/**
* @author Emmanuel Bernard
*/
public class CachedTraversableResolverTest {
@Test
public void testCache() {
TraversableResolver resolver = new AskOnceTR();
Configuration<?> config = Validation.byDefaultProvider()
.configure()
.traversableResolver( resolver );
ValidatorFactory factory = config.buildValidatorFactory();
Suit suit = new Suit();
suit.setTrousers( new Trousers() );
suit.setJacket( new Jacket() );
suit.setSize( 3333 );
suit.getTrousers().setLength( 32321 );
suit.getJacket().setWidth( 432432 );
Validator v = factory.getValidator();
try {
v.validate( suit, Default.class, Cloth.class );
}
catch (IllegalStateException e) {
fail( "Traversable Called several times for a given object" );
}
v = factory.usingContext().traversableResolver( new AskOnceTR() ).getValidator();
try {
v.validateProperty( suit, "size", Default.class, Cloth.class );
}
catch (IllegalStateException e) {
fail( "Traversable Called several times for a given object" );
}
v = factory.usingContext().traversableResolver( new AskOnceTR() ).getValidator();
try {
v.validateValue( Suit.class, "size", 2, Default.class, Cloth.class );
}
catch (IllegalStateException e) {
fail( "Traversable Called several times for a given object" );
}
}
private static class AskOnceTR implements TraversableResolver {
private Set<Holder> askedReach = new HashSet<Holder>();
private Set<Holder> askedCascade = new HashSet<Holder>();
private boolean isTraversable(Set<Holder> asked, Object traversableObject, Path.Node traversableProperty) {
Holder h = new Holder( traversableObject, traversableProperty );
if ( asked.contains( h ) ) {
throw new IllegalStateException( "Called twice" );
}
asked.add( h );
return true;
}
@Override
public boolean isReachable(Object traversableObject,
Path.Node traversableProperty,
Class<?> rootBeanType,
Path pathToTraversableObject,
ElementType elementType) {
return isTraversable(
askedReach,
traversableObject,
traversableProperty
);
}
@Override
public boolean isCascadable(Object traversableObject,
Path.Node traversableProperty,
Class<?> rootBeanType,
Path pathToTraversableObject,
ElementType elementType) {
return isTraversable(
askedCascade,
traversableObject,
traversableProperty
);
}
public static class Holder {
Object NULL = new Object();
Object to;
Path.Node tp;
public Holder(Object traversableObject, Path.Node traversableProperty) {
to = traversableObject == null ? NULL : traversableObject;
tp = traversableProperty;
}
@Override
public int hashCode() {
return to.hashCode() + tp.hashCode();
}
@Override
public boolean equals(Object obj) {
if ( !( obj instanceof Holder ) ) {
return false;
}
Holder that = (Holder) obj;
return to != NULL && to == that.to && tp.equals( that.tp );
}
}
}
}