Skip to content
Permalink
Browse files
BVAL-154: cache unconstrained types by type only and quickly return e…
…mpty descriptors on subsequent fetches
  • Loading branch information
mbenson committed Oct 17, 2018
1 parent 3da9b75 commit b421b5b9c8053390e53ad1bcf8e14f152c128b73
Showing 2 changed files with 35 additions and 7 deletions.
@@ -16,8 +16,10 @@
*/
package org.apache.bval.jsr.descriptor;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@@ -26,11 +28,13 @@
import javax.validation.metadata.ContainerDescriptor;
import javax.validation.metadata.ElementDescriptor;
import javax.validation.metadata.ExecutableDescriptor;
import javax.validation.metadata.MethodType;

import org.apache.bval.jsr.ApacheValidatorFactory;
import org.apache.bval.jsr.metadata.AnnotationBehaviorMergeStrategy;
import org.apache.bval.jsr.metadata.CompositeBuilder;
import org.apache.bval.jsr.metadata.DualBuilder;
import org.apache.bval.jsr.metadata.EmptyBuilder;
import org.apache.bval.jsr.metadata.HierarchyBuilder;
import org.apache.bval.jsr.metadata.MetadataBuilder;
import org.apache.bval.jsr.metadata.ReflectionBuilder;
@@ -55,6 +59,8 @@ public static <E extends ExecutableDescriptor> boolean isConstrained(E descripto

private final ApacheValidatorFactory validatorFactory;
private final ConcurrentMap<Class<?>, BeanD<?>> beanDescriptors = new ConcurrentHashMap<>();
// synchronization unnecessary
private final Set<Class<?>> knownUnconstrainedTypes = new HashSet<>();
private final ReflectionBuilder reflectionBuilder;

public DescriptorManager(ApacheValidatorFactory validatorFactory) {
@@ -70,13 +76,19 @@ public <T> BeanDescriptor getBeanDescriptor(Class<T> beanClass) {
if (beanDescriptors.containsKey(beanClass)) {
return beanDescriptors.get(beanClass);
}
final MetadataReader.ForBean<T> reader =
new MetadataReader(validatorFactory, beanClass).forBean(builder(beanClass));
final BeanD<T> beanD = new BeanD<>(reader);
@SuppressWarnings("unchecked")
final BeanD<T> result =
Optional.ofNullable((BeanD<T>) beanDescriptors.putIfAbsent(beanClass, beanD)).orElse(beanD);
return result;
final MetadataBuilder.ForBean<T> builder =
knownUnconstrainedTypes.contains(beanClass) ? EmptyBuilder.instance().forBean() : builder(beanClass);
final BeanD<T> beanD = new BeanD<>(new MetadataReader(validatorFactory, beanClass).forBean(builder));

if (beanD.isBeanConstrained() || !(beanD.getConstrainedConstructors().isEmpty()
&& beanD.getConstrainedMethods(MethodType.GETTER, MethodType.NON_GETTER).isEmpty())) {
@SuppressWarnings("unchecked")
final BeanD<T> result =
Optional.ofNullable((BeanD<T>) beanDescriptors.putIfAbsent(beanClass, beanD)).orElse(beanD);
return result;
}
knownUnconstrainedTypes.add(beanClass);
return beanD;
}

public void clear() {
@@ -23,6 +23,9 @@
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.lang.annotation.Documented;
@@ -165,6 +168,19 @@ public void testConstraintFinderLookingAt() {
assertEquals("Incorrect number of descriptors", 1, constraints.size());
}

@Test
public void testDescriptorCaching() {
// constrained
final BeanDescriptor personDescriptor = validator.getConstraintsForClass(Person.class);
assertNotNull(personDescriptor);
assertSame(personDescriptor, validator.getConstraintsForClass(Person.class));

// unconstrained
final BeanDescriptor objectDescriptor = validator.getConstraintsForClass(Object.class);
assertNotNull(objectDescriptor);
assertNotSame(objectDescriptor, validator.getConstraintsForClass(Object.class));
}

public static class Form {
@NotNull
public String name;

0 comments on commit b421b5b

Please sign in to comment.