BVAL-154: cache unconstrained types by type only and quickly return empty descriptors on subsequent fetches
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
index 7c84f87..f25514c 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/descriptor/DescriptorManager.java
@@ -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 @@
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 @@
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() {
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java b/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
index d81f90a..b18030d 100644
--- a/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/BeanDescriptorTest.java
@@ -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 @@
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;