Avoid memory leaks in child
Avoid non needed work when no validation constraints are found
Small micro-benchmarks
Fix Java 11 compilation with Java FX as an external library
diff --git a/bval-jsr/pom.xml b/bval-jsr/pom.xml
index 4efe51d..4bc0bde 100644
--- a/bval-jsr/pom.xml
+++ b/bval-jsr/pom.xml
@@ -45,6 +45,11 @@
</activation>
<dependencies>
<dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-activation_1.1_spec</artifactId>
+ <version>1.1</version>
+ </dependency>
+ <dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
@@ -262,6 +267,28 @@
<version>2.2.7</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ <version>6.1.5.Final</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-core</artifactId>
+ <version>1.25.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-generator-annprocess</artifactId>
+ <version>1.25.2</version>
+ </dependency>
+ <dependency>
+ <groupId>com.github.biboudis</groupId>
+ <artifactId>jmh-profilers</artifactId>
+ <version>0.1.4</version>
+ </dependency>
</dependencies>
<build>
@@ -299,6 +326,13 @@
<source>${project.basedir}/src/main/xsd/validation-mapping-2.0.xsd</source>
</sources>
</configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-activation_1.1_spec</artifactId>
+ <version>1.1</version>
+ </dependency>
+ </dependencies>
</plugin>
<!-- create mainClass attribute -->
@@ -431,6 +465,14 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>9</source>
+ <target>9</target>
+ </configuration>
+ </plugin>
</plugins>
</build>
</project>
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java b/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java
index 1975fe4..006bbcd 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/ParticipantFactory.java
@@ -72,7 +72,7 @@
return newInstance(loadClass(classname));
}
- <T> Set<T> loadServices(Class<T> type) {
+ <T> Set<T> loadServices(Class<T> type) { // todo: enable somehow to cache shared classloader (think tomcat/tomee)
Validate.notNull(type);
final Set<URL> resources = new LinkedHashSet<>();
final String resourceName = META_INF_SERVICES + type.getName();
@@ -85,7 +85,7 @@
log.log(Level.SEVERE, "Error searching for resource(s) " + resourceName, e);
}
}
- return resources.stream().map(this::read).flatMap(Collection::stream).<T> map(this::create)
+ return resources.stream().distinct().map(this::read).flatMap(Collection::stream).<T> map(this::create)
.collect(ToUnmodifiable.set());
}
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 caa9bb3..ef4f953 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
@@ -60,7 +60,6 @@
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) {
@@ -73,25 +72,13 @@
Validate.notNull(beanClass, IllegalArgumentException::new, "beanClass");
// cannot use computeIfAbsent due to recursion being the usual case:
- if (beanDescriptors.containsKey(beanClass)) {
- return beanDescriptors.get(beanClass);
+ final BeanD<?> existing = beanDescriptors.get(beanClass);
+ if (existing != null) {
+ return existing;
}
- final boolean constrained = !knownUnconstrainedTypes.contains(beanClass);
- final MetadataBuilder.ForBean<T> builder = constrained ? builder(beanClass) : EmptyBuilder.instance().forBean();
- final BeanD<T> beanD = new BeanD<>(new MetadataReader(validatorFactory, beanClass).forBean(builder));
-
- if (constrained) {
- // if not previously known to be unconstrained, check:
- 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;
+ final BeanD<?> value = new BeanD<>(new MetadataReader(validatorFactory, beanClass).forBean(builder(beanClass)));
+ final BeanD<?> previous = beanDescriptors.putIfAbsent(beanClass, value);
+ return previous == null ? value : previous;
}
public void clear() {
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
index bd20548..d9899db 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateBean.java
@@ -24,8 +24,11 @@
import org.apache.bval.jsr.descriptor.BeanD;
import org.apache.bval.jsr.descriptor.ConstraintD;
import org.apache.bval.jsr.util.PathImpl;
+import org.apache.bval.jsr.util.Proxies;
import org.apache.bval.util.Validate;
+import java.util.Map;
+
public final class ValidateBean<T> extends ValidationJob<T> {
private final T bean;
@@ -36,6 +39,20 @@
}
@Override
+ protected boolean hasWork() {
+ final Class<?> beanClass = bean.getClass();
+ final Map<Class<?>, Class<?>> classCache = validatorContext.getFactory().getUnwrappedClassCache();
+ Class<?> unwrappedClass = classCache.get(beanClass);
+ if (unwrappedClass == null) {
+ unwrappedClass = Proxies.classFor(beanClass);
+ classCache.putIfAbsent(beanClass, unwrappedClass);
+ }
+ return validatorContext.getFactory().getDescriptorManager()
+ .getBeanDescriptor(unwrappedClass)
+ .isBeanConstrained();
+ }
+
+ @Override
protected Frame<BeanD<T>> computeBaseFrame() {
return new BeanFrame<T>(new GraphContext(validatorContext, PathImpl.create(), bean));
}
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
index eef57f5..25ab986 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateParameters.java
@@ -185,7 +185,8 @@
@Override
protected boolean hasWork() {
- return describe() != null;
+ final ExecutableDescriptor descriptor = describe();
+ return descriptor != null && descriptor.hasConstrainedParameters();
}
protected abstract ExecutableDescriptor describe();
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
index 2cf92e3..416f7c5 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidateReturnValue.java
@@ -141,7 +141,8 @@
@Override
protected boolean hasWork() {
- return describe() != null;
+ final ExecutableDescriptor descriptor = describe();
+ return descriptor != null && descriptor.hasConstrainedReturnValue();
}
protected abstract ExecutableDescriptor describe();
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
index 3dc2bc4..7ab3ddf 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/job/ValidationJob.java
@@ -561,7 +561,6 @@
final Consumer<ConstraintViolation<T>> sink = results.consumer(Set::add);
completedValidations = new ConcurrentHashMap<>();
-
try {
baseFrame.process(groups.asStrategy(), sink);
} finally {
diff --git a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
index 89f50e3..1f0537b 100644
--- a/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
+++ b/bval-jsr/src/main/java/org/apache/bval/jsr/valueextraction/ValueExtractors.java
@@ -16,6 +16,21 @@
*/
package org.apache.bval.jsr.valueextraction;
+import org.apache.bval.jsr.metadata.ContainerElementKey;
+import org.apache.bval.util.Exceptions;
+import org.apache.bval.util.ObjectUtils;
+import org.apache.bval.util.StringUtils;
+import org.apache.bval.util.Validate;
+import org.apache.bval.util.reflection.Reflection;
+import org.apache.bval.util.reflection.Reflection.Interfaces;
+import org.apache.bval.util.reflection.TypeUtils;
+
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.metadata.ValidateUnwrappedValue;
+import javax.validation.valueextraction.UnwrapByDefault;
+import javax.validation.valueextraction.ValueExtractor;
+import javax.validation.valueextraction.ValueExtractorDeclarationException;
+import javax.validation.valueextraction.ValueExtractorDefinitionException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
@@ -31,31 +46,14 @@
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import javax.validation.ConstraintDeclarationException;
-import javax.validation.metadata.ValidateUnwrappedValue;
-import javax.validation.valueextraction.UnwrapByDefault;
-import javax.validation.valueextraction.ValueExtractor;
-import javax.validation.valueextraction.ValueExtractorDeclarationException;
-import javax.validation.valueextraction.ValueExtractorDefinitionException;
-
-import org.apache.bval.jsr.metadata.ContainerElementKey;
-import org.apache.bval.util.Exceptions;
-import org.apache.bval.util.Lazy;
-import org.apache.bval.util.ObjectUtils;
-import org.apache.bval.util.StringUtils;
-import org.apache.bval.util.Validate;
-import org.apache.bval.util.reflection.Reflection;
-import org.apache.bval.util.reflection.Reflection.Interfaces;
-import org.apache.bval.util.reflection.TypeUtils;
-
/**
* {@link ValueExtractor} collection of some level of a bean validation hierarchy.
*/
@@ -222,9 +220,8 @@
}
private final ValueExtractors parent;
- private final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> valueExtractors = new Lazy<>(TreeMap::new);
- private final Lazy<Set<ValueExtractors>> children = new Lazy<>(HashSet::new);
- private final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> searchCache = new Lazy<>(HashMap::new);
+ private final Map<ContainerElementKey, ValueExtractor<?>> valueExtractors = new ConcurrentHashMap<>();
+ private final Map<ContainerElementKey, ValueExtractor<?>> searchCache = new ConcurrentHashMap<>();
private final OnDuplicateContainerElementKey onDuplicateContainerElementKey;
public ValueExtractors() {
@@ -243,7 +240,8 @@
private ValueExtractors(ValueExtractors parent, OnDuplicateContainerElementKey onDuplicateContainerElementKey,
Map<ContainerElementKey, ValueExtractor<?>> backingMap) {
this(parent, onDuplicateContainerElementKey);
- this.valueExtractors.reset(backingMap);
+ this.valueExtractors.clear();
+ this.valueExtractors.putAll(backingMap);
}
public ValueExtractors createChild() {
@@ -251,9 +249,7 @@
}
public ValueExtractors createChild(OnDuplicateContainerElementKey onDuplicateContainerElementKey) {
- final ValueExtractors child = new ValueExtractors(this, onDuplicateContainerElementKey);
- children.get().add(child);
- return child;
+ return new ValueExtractors(this, onDuplicateContainerElementKey);
}
public void add(ValueExtractor<?> extractor) {
@@ -262,7 +258,7 @@
Exceptions.raise(IllegalStateException::new, "Computed null %s for %s",
ContainerElementKey.class.getSimpleName(), extractor);
}
- final Map<ContainerElementKey, ValueExtractor<?>> m = valueExtractors.get();
+ final Map<ContainerElementKey, ValueExtractor<?>> m = valueExtractors;
if (onDuplicateContainerElementKey == OnDuplicateContainerElementKey.EXCEPTION) {
synchronized (this) {
if (m.containsKey(key)) {
@@ -274,19 +270,19 @@
} else {
m.put(key, extractor);
}
- children.optional().ifPresent(s -> s.stream().forEach(ValueExtractors::clearCache));
+ searchCache.clear();
}
public Map<ContainerElementKey, ValueExtractor<?>> getValueExtractors() {
- final Lazy<Map<ContainerElementKey, ValueExtractor<?>>> result = new Lazy<>(HashMap::new);
+ final Map<ContainerElementKey, ValueExtractor<?>> result = new HashMap<>();
populate(result);
- return result.optional().orElseGet(Collections::emptyMap);
+ return result;
}
public ValueExtractor<?> find(ContainerElementKey key) {
- final Optional<ValueExtractor<?>> cacheHit = searchCache.optional().map(m -> m.get(key));
- if (cacheHit.isPresent()) {
- return cacheHit.get();
+ final ValueExtractor<?> cacheHit = searchCache.get(key);
+ if (cacheHit != null) {
+ return cacheHit;
}
final Map<ContainerElementKey, ValueExtractor<?>> allValueExtractors = getValueExtractors();
if (allValueExtractors.containsKey(key)) {
@@ -299,7 +295,7 @@
final Optional<ValueExtractor<?>> result =
maximallySpecific(candidates.keySet(), ve -> candidates.get(ve).getContainerClass());
if (result.isPresent()) {
- searchCache.get().put(key, result.get());
+ searchCache.put(key, result.get());
return result.get();
}
throw Exceptions.create(ConstraintDeclarationException::new, "Could not determine %s for %s",
@@ -329,12 +325,11 @@
return result;
}
- private void populate(Supplier<Map<ContainerElementKey, ValueExtractor<?>>> target) {
- Optional.ofNullable(parent).ifPresent(p -> p.populate(target));
- valueExtractors.optional().ifPresent(m -> target.get().putAll(m));
+ private void populate(Map<ContainerElementKey, ValueExtractor<?>> target) {
+ if (parent != null) {
+ parent.populate(target);
+ }
+ target.putAll(valueExtractors);
}
- private void clearCache() {
- searchCache.optional().ifPresent(Map::clear);
- }
}
diff --git a/bval-jsr/src/main/java/org/apache/bval/util/EmulatedAnnotatedType.java b/bval-jsr/src/main/java/org/apache/bval/util/EmulatedAnnotatedType.java
index 7df9655..d3799b4 100644
--- a/bval-jsr/src/main/java/org/apache/bval/util/EmulatedAnnotatedType.java
+++ b/bval-jsr/src/main/java/org/apache/bval/util/EmulatedAnnotatedType.java
@@ -43,6 +43,11 @@
public AnnotatedType[] getAnnotatedActualTypeArguments() {
return wrapArray(wrapped.getActualTypeArguments());
}
+
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ return null;
+ }
}
private static class Variable extends EmulatedAnnotatedType<TypeVariable<?>> implements AnnotatedTypeVariable {
@@ -55,6 +60,11 @@
public AnnotatedType[] getAnnotatedBounds() {
return wrapped.getAnnotatedBounds();
}
+
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ return null;
+ }
}
private static class Wildcard extends EmulatedAnnotatedType<WildcardType> implements AnnotatedWildcardType {
@@ -72,6 +82,11 @@
public AnnotatedType[] getAnnotatedUpperBounds() {
return wrapArray(wrapped.getUpperBounds());
}
+
+ @Override
+ public AnnotatedType getAnnotatedOwnerType() {
+ return null;
+ }
}
public static EmulatedAnnotatedType<?> wrap(Type type) {
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 b18030d..fa3d406 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
@@ -178,7 +178,7 @@
// unconstrained
final BeanDescriptor objectDescriptor = validator.getConstraintsForClass(Object.class);
assertNotNull(objectDescriptor);
- assertNotSame(objectDescriptor, validator.getConstraintsForClass(Object.class));
+ assertSame(objectDescriptor, validator.getConstraintsForClass(Object.class));
}
public static class Form {
diff --git a/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Benchmark.java b/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Benchmark.java
new file mode 100644
index 0000000..0092be7
--- /dev/null
+++ b/bval-jsr/src/test/java/org/apache/bval/jsr/Jsr303Benchmark.java
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bval.jsr;
+
+import org.apache.bval.jsr.example.Author;
+import org.apache.bval.jsr.example.Book;
+import org.apache.bval.jsr.example.First;
+import org.apache.bval.jsr.example.Second;
+import org.hibernate.validator.HibernateValidator;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.profile.JavaFlightRecorderProfiler;
+import org.openjdk.jmh.profile.Profiler;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+@State(Scope.Benchmark)
+public class Jsr303Benchmark {
+
+ private final ValidatorFactory bvalFactory =
+ Validation.byProvider(ApacheValidationProvider.class).configure().buildValidatorFactory();
+ private final Validator bvalValidator = bvalFactory.getValidator();
+ private final ValidatorFactory hibernateFactory =
+ Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory();
+ private final Validator hibernateValidator = hibernateFactory.getValidator();
+
+ public static void main(String[] args) throws RunnerException {
+ final Options opt = new OptionsBuilder()
+ .include(Jsr303Benchmark.class.getSimpleName())
+
+ .forks(1)
+ .threads(5)
+
+ .measurementIterations(1)
+ .measurementTime(TimeValue.seconds(20))
+
+ .warmupIterations(2)
+ .warmupTime(TimeValue.seconds(5))
+
+ .addProfiler(JavaFlightRecorderProfiler.class)
+
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ @Benchmark
+ public void bvalNoConstraints() {
+ final Set<ConstraintViolation<BookNoConstraints>> constraintViolations =
+ bvalFactory.getValidator().validate(new BookNoConstraints());
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void bvalNoConstraintsReuseValidator() {
+ final Set<ConstraintViolation<BookNoConstraints>> constraintViolations =
+ bvalValidator.validate(new BookNoConstraints());
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void bvalConstraintsSuccess() {
+ final Set<ConstraintViolation<BookSimple>> constraintViolations = bvalFactory.getValidator()
+ .validate(new BookSimple("Hello",
+ "Awesome validation",
+ 3,
+ 76));
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void bvalConstraintsSuccessReuseValidator() {
+ final Set<ConstraintViolation<BookSimple>> constraintViolations = bvalValidator
+ .validate(new BookSimple("Hello",
+ "Awesome validation",
+ 3,
+ 76));
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void bvalConstraintsFailure() {
+ final Set<ConstraintViolation<Book>> constraintViolations = bvalFactory.getValidator().validate(new Book());
+ assertTrue(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void bvalConstraintsFailureReuseValidator() {
+ final Set<ConstraintViolation<Book>> constraintViolations = bvalValidator.validate(new Book());
+ assertTrue(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void hibernateNoConstraints() {
+ final Set<ConstraintViolation<BookNoConstraints>> constraintViolations =
+ hibernateFactory.getValidator().validate(new BookNoConstraints());
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void hibernateNoConstraintsReuseValidator() {
+ final Set<ConstraintViolation<BookNoConstraints>> constraintViolations =
+ hibernateValidator.validate(new BookNoConstraints());
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void hibernateConstraintsSuccess() {
+ final Set<ConstraintViolation<BookSimple>> constraintViolations = hibernateFactory.getValidator()
+ .validate(
+ new BookSimple("Hello",
+ "Awesome" +
+ " validation",
+ 3,
+ 76));
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void hibernateConstraintsSuccessReuseValidator() {
+ final Set<ConstraintViolation<BookSimple>> constraintViolations = hibernateValidator
+ .validate(
+ new BookSimple("Hello",
+ "Awesome" +
+ " validation",
+ 3,
+ 76));
+ assertFalse(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void hibernateConstraintsFailure() {
+ final Set<ConstraintViolation<Book>> constraintViolations =
+ hibernateFactory.getValidator().validate(new Book());
+ assertTrue(constraintViolations.iterator().hasNext());
+ }
+
+ @Benchmark
+ public void hibernateConstraintsFailureReuseValidator() {
+ final Set<ConstraintViolation<Book>> constraintViolations =
+ hibernateValidator.validate(new Book());
+ assertTrue(constraintViolations.iterator().hasNext());
+ }
+
+
+ public static class BookNoConstraints {
+ private String title;
+ private String subtitle;
+ private Author author;
+ private int uselessField;
+ private int unconstraintField;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(final String title) {
+ this.title = title;
+ }
+
+ public String getSubtitle() {
+ return subtitle;
+ }
+
+ public void setSubtitle(final String subtitle) {
+ this.subtitle = subtitle;
+ }
+
+ public Author getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(final Author author) {
+ this.author = author;
+ }
+
+ public int getUselessField() {
+ return uselessField;
+ }
+
+ public void setUselessField(final int uselessField) {
+ this.uselessField = uselessField;
+ }
+
+ public int getUnconstraintField() {
+ return unconstraintField;
+ }
+
+ public void setUnconstraintField(final int unconstraintField) {
+ this.unconstraintField = unconstraintField;
+ }
+ }
+
+ public static class BookSimple {
+
+ @NotEmpty(groups = First.class)
+ private String title;
+
+ @Size(max = 30, groups = Second.class)
+ private String subtitle;
+
+ @NotNull
+ private int uselessField;
+
+ private int unconstraintField;
+
+ public BookSimple(
+ final String title,
+ final String subtitle,
+ final int uselessField,
+ final int unconstraintField) {
+
+ this.title = title;
+ this.subtitle = subtitle;
+ this.uselessField = uselessField;
+ this.unconstraintField = unconstraintField;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(final String title) {
+ this.title = title;
+ }
+
+ public String getSubtitle() {
+ return subtitle;
+ }
+
+ public void setSubtitle(final String subtitle) {
+ this.subtitle = subtitle;
+ }
+
+ public int getUselessField() {
+ return uselessField;
+ }
+
+ public void setUselessField(final int uselessField) {
+ this.uselessField = uselessField;
+ }
+
+ public int getUnconstraintField() {
+ return unconstraintField;
+ }
+
+ public void setUnconstraintField(final int unconstraintField) {
+ this.unconstraintField = unconstraintField;
+ }
+ }
+
+}