Skip to content

Commit e5811f5

Browse files
gbadnermarko-bekhta
authored andcommitted
HV-1831 : Experiment detecting cycles in bean classes
Add support for containers; add tests for List w/ and w/o duplicated values
1 parent 9489496 commit e5811f5

File tree

3 files changed

+427
-1
lines changed

3 files changed

+427
-1
lines changed

engine/src/main/java/org/hibernate/validator/internal/engine/tracking/PredefinedScopeProcessedBeansTrackingStrategy.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
package org.hibernate.validator.internal.engine.tracking;
88

99
import java.lang.reflect.Executable;
10+
import java.lang.reflect.ParameterizedType;
11+
import java.lang.reflect.Type;
1012
import java.util.Collections;
1113
import java.util.HashMap;
1214
import java.util.HashSet;
@@ -16,6 +18,7 @@
1618
import org.hibernate.validator.internal.metadata.PredefinedScopeBeanMetaDataManager;
1719
import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
1820
import org.hibernate.validator.internal.metadata.aggregated.CascadingMetaData;
21+
import org.hibernate.validator.internal.metadata.aggregated.ContainerCascadingMetaData;
1922
import org.hibernate.validator.internal.metadata.facets.Cascadable;
2023
import org.hibernate.validator.internal.util.CollectionHelper;
2124

@@ -163,7 +166,21 @@ private <T> Set<Class<?>> getDirectCascadedBeanClasses(Class<T> beanClass ) {
163166
for ( Cascadable cascadable : beanMetaData.getCascadables() ) {
164167
final CascadingMetaData cascadingMetaData = cascadable.getCascadingMetaData();
165168
if ( cascadingMetaData.isContainer() ) {
166-
throw new UnsupportedOperationException( "Containers are not supported yet." );
169+
final ContainerCascadingMetaData containerCascadingMetaData = (ContainerCascadingMetaData) cascadingMetaData;
170+
if ( containerCascadingMetaData.getEnclosingType() instanceof ParameterizedType ) {
171+
ParameterizedType parameterizedType = (ParameterizedType) containerCascadingMetaData.getEnclosingType();
172+
for ( Type typeArgument : parameterizedType.getActualTypeArguments() ) {
173+
if ( typeArgument instanceof Class ) {
174+
directCascadedBeanClasses.add( (Class<?>) typeArgument );
175+
}
176+
else {
177+
throw new UnsupportedOperationException( "Only ParameterizedType values of type Class are supported" );
178+
}
179+
}
180+
}
181+
else {
182+
throw new UnsupportedOperationException( "Non-parameterized containers are not supported yet." );
183+
}
167184
}
168185
else {
169186
// TODO: For now, assume non-container Cascadables are always beans. Truee???
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* Hibernate Validator, declare and validate application constraints
3+
*
4+
* License: Apache License, Version 2.0
5+
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6+
*/
7+
package org.hibernate.validator.test.internal.engine.tracking;
8+
9+
import java.util.ArrayList;
10+
import java.util.Arrays;
11+
import java.util.HashSet;
12+
import java.util.List;
13+
import java.util.Set;
14+
import javax.validation.ConstraintViolation;
15+
import javax.validation.Valid;
16+
import javax.validation.Validation;
17+
import javax.validation.Validator;
18+
import javax.validation.constraints.NotNull;
19+
20+
import org.hibernate.validator.PredefinedScopeHibernateValidator;
21+
import org.hibernate.validator.PredefinedScopeHibernateValidatorFactory;
22+
import org.hibernate.validator.internal.engine.PredefinedScopeValidatorFactoryImpl;
23+
import org.hibernate.validator.internal.engine.ValidatorFactoryScopedContext;
24+
import org.hibernate.validator.internal.engine.tracking.ProcessedBeansTrackingStrategy;
25+
26+
import org.testng.annotations.Test;
27+
28+
import static org.testng.Assert.assertFalse;
29+
import static org.testng.Assert.assertTrue;
30+
31+
/**
32+
* An example of beans with cascading constraints, some cycle and others do not.
33+
*
34+
* A -> B ---> C ------> F -> G <-
35+
* | ^ | ^ ^ |
36+
* | | | | | |
37+
* | -- D <-- | | |
38+
* --------------------> E -------
39+
*
40+
* A, B, C, D, E, F, and G are beans that get validated.
41+
*
42+
* An arrow, ->, indicates a cascading constraint.
43+
*
44+
* The following are the properties with cascading List constraints:
45+
* A.bValues
46+
* .eValues
47+
* B.cValues
48+
* C.dValues
49+
* .fValues
50+
* D.bValues
51+
* E.fValues
52+
* .gValues
53+
* .gAnotherValues
54+
* F.gValues
55+
*
56+
* @author Gail Badner
57+
*
58+
*/
59+
60+
public class ProcessedBeansTrackingCyclesNoCyclesListDuplicateElementsTest {
61+
62+
@Test
63+
public void testTrackingEnabled() {
64+
65+
final ValidatorFactoryScopedContext validatorFactoryScopedContext = getValidatorFactoryScopedContext();
66+
final ProcessedBeansTrackingStrategy processedBeansTrackingStrategy =
67+
validatorFactoryScopedContext.getProcessedBeansTrackingStrategy();
68+
assertTrue( processedBeansTrackingStrategy.isEnabledForBean(
69+
A.class,
70+
true
71+
) );
72+
assertTrue( processedBeansTrackingStrategy.isEnabledForBean(
73+
B.class,
74+
true
75+
) );
76+
assertTrue( processedBeansTrackingStrategy.isEnabledForBean(
77+
C.class,
78+
true
79+
) );
80+
assertTrue( processedBeansTrackingStrategy.isEnabledForBean(
81+
D.class,
82+
true
83+
) );
84+
assertFalse( processedBeansTrackingStrategy.isEnabledForBean(
85+
E.class,
86+
true
87+
) );
88+
assertFalse( processedBeansTrackingStrategy.isEnabledForBean(
89+
F.class,
90+
true
91+
) );
92+
assertFalse( processedBeansTrackingStrategy.isEnabledForBean(
93+
G.class,
94+
false
95+
) );
96+
}
97+
98+
@Test
99+
public void testValidate() {
100+
final A a = new A();
101+
final B b = new B();
102+
final C c = new C();
103+
final D d = new D();
104+
final E e = new E();
105+
final F f = new F();
106+
final G g = new G();
107+
108+
a.bValues.add( b );
109+
a.bValues.add( b );
110+
a.eValues.add( e );
111+
a.eValues.add( e );
112+
b.cValues.add( c );
113+
b.cValues.add( c );
114+
c.dValues.add( d );
115+
c.dValues.add( d );
116+
d.bValues.add( b );
117+
d.bValues.add( b );
118+
e.fValues.add( f );
119+
e.fValues.add( f );
120+
e.gValues.add( g );
121+
e.gValues.add( g );
122+
e.gAnotherValues.add( g );
123+
e.gAnotherValues.add( g );
124+
f.gValues.add( g );
125+
f.gValues.add( g );
126+
127+
final Validator validator = getValidator();
128+
final Set<ConstraintViolation<A>> violationsA = validator.validate( a );
129+
final Set<ConstraintViolation<B>> violationsB = validator.validate( b );
130+
final Set<ConstraintViolation<C>> violationsC = validator.validate( c );
131+
final Set<ConstraintViolation<D>> violationsD = validator.validate( d );
132+
final Set<ConstraintViolation<E>> violationsE = validator.validate( e );
133+
final Set<ConstraintViolation<F>> violationsF = validator.validate( f );
134+
final Set<ConstraintViolation<G>> violationsG = validator.validate( g );
135+
}
136+
137+
private Validator getValidator() {
138+
return getValidatorFactory().getValidator();
139+
}
140+
141+
private PredefinedScopeHibernateValidatorFactory getValidatorFactory() {
142+
return Validation.byProvider( PredefinedScopeHibernateValidator.class )
143+
.configure()
144+
.builtinConstraints( new HashSet<>( Arrays.asList( NotNull.class.getName() ) ) )
145+
.initializeBeanMetaData( new HashSet<>( Arrays.asList(
146+
A.class, B.class, C.class, D.class, E.class, F.class, G.class
147+
) ) )
148+
.buildValidatorFactory().unwrap( PredefinedScopeHibernateValidatorFactory.class );
149+
}
150+
151+
private ValidatorFactoryScopedContext getValidatorFactoryScopedContext() {
152+
return ( (PredefinedScopeValidatorFactoryImpl) getValidatorFactory() ).getValidatorFactoryScopedContext();
153+
}
154+
155+
private static class A {
156+
157+
private String description;
158+
159+
private List<@Valid B> bValues = new ArrayList<>();
160+
161+
private List<@Valid E> eValues = new ArrayList<>();
162+
}
163+
164+
private static class B {
165+
@Valid
166+
private String description;
167+
168+
private List<@Valid C> cValues = new ArrayList<>();
169+
}
170+
171+
private static class C {
172+
173+
private String description;
174+
175+
private List<@Valid D> dValues = new ArrayList<>();
176+
177+
private List<@Valid F> fValues = new ArrayList<>();
178+
}
179+
180+
private static class D {
181+
182+
private String description;
183+
184+
private List<@Valid B> bValues = new ArrayList<>();
185+
}
186+
187+
private static class E {
188+
189+
private String description;
190+
191+
private List<@Valid F> fValues = new ArrayList<>();
192+
193+
private List<@Valid G> gValues = new ArrayList<>();
194+
195+
private List<@Valid G> gAnotherValues = new ArrayList<>();
196+
}
197+
198+
private static class F {
199+
200+
private String description;
201+
202+
private List<@Valid G> gValues = new ArrayList<>();
203+
}
204+
205+
private static class G {
206+
207+
private String description;
208+
}
209+
}

0 commit comments

Comments
 (0)