1
7 package org.hibernate.validator.internal.metadata;
8
9 import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList;
10 import static org.hibernate.validator.internal.util.ConcurrentReferenceHashMap.Option.IDENTITY_COMPARISONS;
11 import static org.hibernate.validator.internal.util.ConcurrentReferenceHashMap.ReferenceType.SOFT;
12 import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
13
14 import java.util.ArrayList;
15 import java.util.EnumSet;
16 import java.util.List;
17
18 import org.hibernate.validator.internal.engine.ConstraintCreationContext;
19 import org.hibernate.validator.internal.engine.MethodValidationConfiguration;
20 import org.hibernate.validator.internal.engine.groups.ValidationOrderGenerator;
21 import org.hibernate.validator.internal.metadata.aggregated.BeanMetaData;
22 import org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder;
23 import org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataImpl;
24 import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptions;
25 import org.hibernate.validator.internal.metadata.core.AnnotationProcessingOptionsImpl;
26 import org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider;
27 import org.hibernate.validator.internal.metadata.provider.MetaDataProvider;
28 import org.hibernate.validator.internal.metadata.raw.BeanConfiguration;
29 import org.hibernate.validator.internal.properties.javabean.JavaBeanHelper;
30 import org.hibernate.validator.internal.util.CollectionHelper;
31 import org.hibernate.validator.internal.util.ConcurrentReferenceHashMap;
32 import org.hibernate.validator.internal.util.Contracts;
33 import org.hibernate.validator.internal.util.ExecutableHelper;
34 import org.hibernate.validator.internal.util.ExecutableParameterNameProvider;
35 import org.hibernate.validator.internal.util.classhierarchy.ClassHierarchyHelper;
36 import org.hibernate.validator.internal.util.stereotypes.Immutable;
37 import org.hibernate.validator.metadata.BeanMetaDataClassNormalizer;
38
39
56 public class BeanMetaDataManagerImpl implements BeanMetaDataManager {
57
60 private static final int DEFAULT_INITIAL_CAPACITY = 16;
61
62
65 private static final float DEFAULT_LOAD_FACTOR = 0.75f;
66
67
70 private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
71
72
76 @Immutable
77 private final List<MetaDataProvider> metaDataProviders;
78
79
82 private final ConstraintCreationContext constraintCreationContext;
83
84 private final ExecutableParameterNameProvider parameterNameProvider;
85
86
89 private final ConcurrentReferenceHashMap<Class<?>, BeanMetaData<?>> beanMetaDataCache;
90
91
94 private final ExecutableHelper executableHelper;
95
96 private final BeanMetaDataClassNormalizer beanMetaDataClassNormalizer;
97
98 private final ValidationOrderGenerator validationOrderGenerator;
99
100
105 private final MethodValidationConfiguration methodValidationConfiguration;
106
107 public BeanMetaDataManagerImpl(ConstraintCreationContext constraintCreationContext,
108 ExecutableHelper executableHelper,
109 ExecutableParameterNameProvider parameterNameProvider,
110 JavaBeanHelper javaBeanHelper,
111 BeanMetaDataClassNormalizer beanMetaDataClassNormalizer,
112 ValidationOrderGenerator validationOrderGenerator,
113 List<MetaDataProvider> optionalMetaDataProviders,
114 MethodValidationConfiguration methodValidationConfiguration) {
115 this.constraintCreationContext = constraintCreationContext;
116 this.executableHelper = executableHelper;
117 this.parameterNameProvider = parameterNameProvider;
118 this.beanMetaDataClassNormalizer = beanMetaDataClassNormalizer;
119 this.validationOrderGenerator = validationOrderGenerator;
120
121 this.methodValidationConfiguration = methodValidationConfiguration;
122
123 this.beanMetaDataCache = new ConcurrentReferenceHashMap<>(
124 DEFAULT_INITIAL_CAPACITY,
125 DEFAULT_LOAD_FACTOR,
126 DEFAULT_CONCURRENCY_LEVEL,
127 SOFT,
128 SOFT,
129 EnumSet.of( IDENTITY_COMPARISONS )
130 );
131
132 AnnotationProcessingOptions annotationProcessingOptions = getAnnotationProcessingOptionsFromNonDefaultProviders( optionalMetaDataProviders );
133 AnnotationMetaDataProvider defaultProvider = new AnnotationMetaDataProvider(
134 constraintCreationContext,
135 javaBeanHelper,
136 annotationProcessingOptions
137 );
138 List<MetaDataProvider> tmpMetaDataProviders = new ArrayList<>( optionalMetaDataProviders.size() + 1 );
139
140
141
142
143 tmpMetaDataProviders.add( defaultProvider );
144 tmpMetaDataProviders.addAll( optionalMetaDataProviders );
145
146 this.metaDataProviders = CollectionHelper.toImmutableList( tmpMetaDataProviders );
147 }
148
149 @Override
150
151
152 @SuppressWarnings("unchecked")
153 public <T> BeanMetaData<T> getBeanMetaData(Class<T> beanClass) {
154 Contracts.assertNotNull( beanClass, MESSAGES.beanTypeCannotBeNull() );
155
156 Class<? super T> normalizedBeanClass = beanMetaDataClassNormalizer.normalize( beanClass );
157
158
159 BeanMetaData<? super T> beanMetaData = (BeanMetaData<? super T>) beanMetaDataCache.get( normalizedBeanClass );
160
161 if ( beanMetaData != null ) {
162 return (BeanMetaData<T>) beanMetaData;
163 }
164
165 beanMetaData = createBeanMetaData( normalizedBeanClass );
166 BeanMetaData<? super T> previousBeanMetaData =
167 (BeanMetaData<? super T>) beanMetaDataCache.putIfAbsent( normalizedBeanClass, beanMetaData );
168
169
170 if ( previousBeanMetaData != null ) {
171 return (BeanMetaData<T>) previousBeanMetaData;
172 }
173
174 return (BeanMetaData<T>) beanMetaData;
175 }
176
177 @Override
178 public void clear() {
179 beanMetaDataCache.clear();
180 }
181
182 public int numberOfCachedBeanMetaDataInstances() {
183 return beanMetaDataCache.size();
184 }
185
186
195 private <T> BeanMetaDataImpl<T> createBeanMetaData(Class<T> clazz) {
196 BeanMetaDataBuilder<T> builder = BeanMetaDataBuilder.getInstance(
197 constraintCreationContext, executableHelper, parameterNameProvider,
198 validationOrderGenerator, clazz, methodValidationConfiguration );
199
200 for ( MetaDataProvider provider : metaDataProviders ) {
201 for ( BeanConfiguration<? super T> beanConfiguration : getBeanConfigurationForHierarchy( provider, clazz ) ) {
202 builder.add( beanConfiguration );
203 }
204 }
205
206 return builder.build();
207 }
208
209
212 private AnnotationProcessingOptions getAnnotationProcessingOptionsFromNonDefaultProviders(List<MetaDataProvider> optionalMetaDataProviders) {
213 AnnotationProcessingOptions options = new AnnotationProcessingOptionsImpl();
214 for ( MetaDataProvider metaDataProvider : optionalMetaDataProviders ) {
215 options.merge( metaDataProvider.getAnnotationProcessingOptions() );
216 }
217
218 return options;
219 }
220
221
230 private <T> List<BeanConfiguration<? super T>> getBeanConfigurationForHierarchy(MetaDataProvider provider, Class<T> beanClass) {
231 List<BeanConfiguration<? super T>> configurations = newArrayList();
232
233 for ( Class<? super T> clazz : ClassHierarchyHelper.getHierarchy( beanClass ) ) {
234 BeanConfiguration<? super T> configuration = provider.getBeanConfiguration( clazz );
235 if ( configuration != null ) {
236 configurations.add( configuration );
237 }
238 }
239
240 return configurations;
241 }
242 }
243