From c8bf454c935fe9267965479e492acf53d400bed5 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Wed, 31 Jan 2018 23:21:01 +0100 Subject: [PATCH 1/2] [MH experiments] - private static final MH --- .../org/hibernate/validator/internal/Foo.java | 32 +++++ .../metadata/location/ConstraintLocation.java | 4 +- .../location/FooFieldConstraintLocation.java | 128 ++++++++++++++++++ .../location/FooGetterConstraintLocation.java | 128 ++++++++++++++++++ .../test/constraints/annotations/FooTest.java | 36 +++++ performance/pom.xml | 5 + .../performance/simple/FooValidation.java | 77 +++++++++++ 7 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 engine/src/main/java/org/hibernate/validator/internal/Foo.java create mode 100644 engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java create mode 100644 engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java create mode 100644 engine/src/test/java/org/hibernate/validator/test/constraints/annotations/FooTest.java create mode 100644 performance/src/main/java/org/hibernate/validator/performance/simple/FooValidation.java diff --git a/engine/src/main/java/org/hibernate/validator/internal/Foo.java b/engine/src/main/java/org/hibernate/validator/internal/Foo.java new file mode 100644 index 0000000000..6014b858f3 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/Foo.java @@ -0,0 +1,32 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.internal; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * @author Marko Bekhta + */ +public class Foo { + + @NotNull + @NotBlank + @Size(min = 5) + private String string; + + public Foo(String string) { + this.string = string; + } + + @AssertTrue + public boolean isTrue() { + return false; + } +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java index 429d7d711d..d3c85a9865 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/ConstraintLocation.java @@ -40,11 +40,11 @@ static ConstraintLocation forClass(Class declaringClass) { } static ConstraintLocation forField(Field field) { - return new FieldConstraintLocation( field ); + return new FooFieldConstraintLocation(); } static ConstraintLocation forGetter(Method getter) { - return new GetterConstraintLocation( getter ); + return new FooGetterConstraintLocation(); } static ConstraintLocation forTypeArgument(ConstraintLocation delegate, TypeVariable typeParameter, Type typeOfAnnotatedElement) { diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java new file mode 100644 index 0000000000..af85709a61 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java @@ -0,0 +1,128 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.internal.metadata.location; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Type; + +import org.hibernate.validator.internal.Foo; +import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; +import org.hibernate.validator.internal.util.StringHelper; + +/** + * Field constraint location. + * + * @author Hardy Ferentschik + * @author Gunnar Morling + */ +public class FooFieldConstraintLocation implements ConstraintLocation { + + /** + * The member the constraint was defined on. + */ + private static final MethodHandle property; + private static final Field string; + + static { + try { + string = Foo.class.getDeclaredField( "string" ); + string.setAccessible( true ); + property = MethodHandles.lookup().unreflectGetter( string ); + } + catch (IllegalAccessException | NoSuchFieldException e) { + throw new IllegalStateException( e ); + } + } + + /** + * The property name associated with the member. + */ + private final String propertyName; + + /** + * The type to be used for validator resolution for constraints at this location. + */ + private final Type typeForValidatorResolution; + + FooFieldConstraintLocation() { + this.propertyName = "string"; + this.typeForValidatorResolution = String.class; + } + + @Override + public Class getDeclaringClass() { + return Foo.class; + } + + @Override + public Member getMember() { + return string; + } + + public String getPropertyName() { + return propertyName; + } + + @Override + public Type getTypeForValidatorResolution() { + return typeForValidatorResolution; + } + + @Override + public void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path) { + path.addPropertyNode( propertyName ); + } + + @Override + public Object getValue(Object parent) { + try { + return property.invoke( parent ); + } + catch (Throwable throwable) { + throw new IllegalStateException( throwable ); + } + } + + @Override + public String toString() { + return "FieldConstraintLocation [member=" + StringHelper.toShortString( string ) + ", typeForValidatorResolution=" + + StringHelper.toShortString( typeForValidatorResolution ) + "]"; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + FooFieldConstraintLocation that = (FooFieldConstraintLocation) o; + + if ( string != null ? !string.equals( that.string ) : that.string != null ) { + return false; + } + if ( !typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = string != null ? string.hashCode() : 0; + result = 31 * result + typeForValidatorResolution.hashCode(); + return result; + } + +} diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java new file mode 100644 index 0000000000..459edbb478 --- /dev/null +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java @@ -0,0 +1,128 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.internal.metadata.location; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import org.hibernate.validator.internal.Foo; +import org.hibernate.validator.internal.engine.path.PathImpl; +import org.hibernate.validator.internal.util.ExecutableParameterNameProvider; +import org.hibernate.validator.internal.util.ReflectionHelper; +import org.hibernate.validator.internal.util.StringHelper; + +/** + * Getter method constraint location. + * + * @author Hardy Ferentschik + * @author Gunnar Morling + */ +public class FooGetterConstraintLocation implements ConstraintLocation { + + /** + * The method the constraint was defined on. + */ + private static final MethodHandle property; + private static final Method method; + + static { + try { + method = Foo.class.getMethod( "isTrue" ); + method.setAccessible( true ); + property = MethodHandles.lookup().unreflect( method ); + } + catch (IllegalAccessException | NoSuchMethodException e) { + throw new IllegalStateException( e ); + } + } + + /** + * The property name associated with the method. + */ + private final String propertyName; + + /** + * The type to be used for validator resolution for constraints at this location. + */ + private final Type typeForValidatorResolution; + + FooGetterConstraintLocation() { + this.propertyName = ReflectionHelper.getPropertyName( method ); + this.typeForValidatorResolution = ReflectionHelper.boxedType( ReflectionHelper.typeOf( method ) ); + } + + @Override + public Class getDeclaringClass() { + return method.getDeclaringClass(); + } + + @Override + public Method getMember() { + return method; + } + + public String getPropertyName() { + return propertyName; + } + + @Override + public Type getTypeForValidatorResolution() { + return typeForValidatorResolution; + } + + @Override + public void appendTo(ExecutableParameterNameProvider parameterNameProvider, PathImpl path) { + path.addPropertyNode( propertyName ); + } + + @Override + public Object getValue(Object parent) { + try { + return property.invoke( parent ); + } + catch (Throwable throwable) { + throw new IllegalStateException( throwable ); + } + } + + @Override + public String toString() { + return "GetterConstraintLocation [method=" + StringHelper.toShortString( method ) + ", typeForValidatorResolution=" + + StringHelper.toShortString( typeForValidatorResolution ) + "]"; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + FooGetterConstraintLocation that = (FooGetterConstraintLocation) o; + + if ( method != null ? !method.equals( that.method ) : that.method != null ) { + return false; + } + if ( !typeForValidatorResolution.equals( that.typeForValidatorResolution ) ) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = method.hashCode(); + result = 31 * result + typeForValidatorResolution.hashCode(); + return result; + } + +} diff --git a/engine/src/test/java/org/hibernate/validator/test/constraints/annotations/FooTest.java b/engine/src/test/java/org/hibernate/validator/test/constraints/annotations/FooTest.java new file mode 100644 index 0000000000..f96cd1d37c --- /dev/null +++ b/engine/src/test/java/org/hibernate/validator/test/constraints/annotations/FooTest.java @@ -0,0 +1,36 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.test.constraints.annotations; + +import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertThat; +import static org.hibernate.validator.testutil.ConstraintViolationAssert.violationOf; + +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Size; + +import org.hibernate.validator.internal.Foo; + +import org.testng.annotations.Test; + +/** + * @author Marko Bekhta + */ +public class FooTest extends AbstractConstrainedTest { + + @Test + public void testName() throws Exception { + Foo foo = new Foo( "ab" ); + Set> violations = validator.validate( foo ); + assertThat( violations ).containsOnlyViolations( + violationOf( Size.class ), + violationOf( AssertTrue.class ) + ); + } +} diff --git a/performance/pom.xml b/performance/pom.xml index 9f35c61b79..6e72576088 100644 --- a/performance/pom.xml +++ b/performance/pom.xml @@ -57,6 +57,11 @@ validation-api provided + + org.hibernate.validator + hibernate-validator + ${project.version} + diff --git a/performance/src/main/java/org/hibernate/validator/performance/simple/FooValidation.java b/performance/src/main/java/org/hibernate/validator/performance/simple/FooValidation.java new file mode 100644 index 0000000000..a8a7bf195f --- /dev/null +++ b/performance/src/main/java/org/hibernate/validator/performance/simple/FooValidation.java @@ -0,0 +1,77 @@ +/* + * Hibernate Validator, declare and validate application constraints + * + * License: Apache License, Version 2.0 + * See the license.txt file in the root directory or . + */ +package org.hibernate.validator.performance.simple; + +import java.util.Random; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import org.hibernate.validator.internal.Foo; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * @author Hardy Ferentschik + */ +public class FooValidation { + + private static final String[] names = { + null, + "Jacob", + "Isabella", + "Ethan", + "Sophia", + "Michael", + "Emma", + "Jayden", + "Olivia", + "William" + }; + + @State(Scope.Benchmark) + public static class ValidationState { + + public volatile Validator validator; + public volatile Random random; + + { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + random = new Random(); + } + + } + + @Benchmark + @BenchmarkMode(Mode.Throughput) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @Fork(value = 1) + @Threads(50) + @Warmup(iterations = 10) + @Measurement(iterations = 20) + public void testSimpleBeanValidation(ValidationState state, Blackhole bh) { + Foo foo = new Foo( names[state.random.nextInt( names.length )] ); + Set> violations = state.validator.validate( foo ); + bh.consume( violations ); + } + +} From 19b5af456f64bc3e9263fc7e0a74bcebdf7cc90c Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Wed, 31 Jan 2018 23:26:52 +0100 Subject: [PATCH 2/2] [MH experiments] - simple field created in constructor --- .../location/FooFieldConstraintLocation.java | 22 ++++++++---------- .../location/FooGetterConstraintLocation.java | 23 ++++++++----------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java index af85709a61..9013470acb 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooFieldConstraintLocation.java @@ -28,19 +28,9 @@ public class FooFieldConstraintLocation implements ConstraintLocation { /** * The member the constraint was defined on. */ - private static final MethodHandle property; - private static final Field string; + private final MethodHandle property; + private final Field string; - static { - try { - string = Foo.class.getDeclaredField( "string" ); - string.setAccessible( true ); - property = MethodHandles.lookup().unreflectGetter( string ); - } - catch (IllegalAccessException | NoSuchFieldException e) { - throw new IllegalStateException( e ); - } - } /** * The property name associated with the member. @@ -55,6 +45,14 @@ public class FooFieldConstraintLocation implements ConstraintLocation { FooFieldConstraintLocation() { this.propertyName = "string"; this.typeForValidatorResolution = String.class; + try { + string = Foo.class.getDeclaredField( "string" ); + string.setAccessible( true ); + property = MethodHandles.lookup().unreflectGetter( string ); + } + catch (IllegalAccessException | NoSuchFieldException e) { + throw new IllegalStateException( e ); + } } @Override diff --git a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java index 459edbb478..d63f63ee42 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java +++ b/engine/src/main/java/org/hibernate/validator/internal/metadata/location/FooGetterConstraintLocation.java @@ -28,19 +28,8 @@ public class FooGetterConstraintLocation implements ConstraintLocation { /** * The method the constraint was defined on. */ - private static final MethodHandle property; - private static final Method method; - - static { - try { - method = Foo.class.getMethod( "isTrue" ); - method.setAccessible( true ); - property = MethodHandles.lookup().unreflect( method ); - } - catch (IllegalAccessException | NoSuchMethodException e) { - throw new IllegalStateException( e ); - } - } + private final MethodHandle property; + private final Method method; /** * The property name associated with the method. @@ -53,6 +42,14 @@ public class FooGetterConstraintLocation implements ConstraintLocation { private final Type typeForValidatorResolution; FooGetterConstraintLocation() { + try { + method = Foo.class.getMethod( "isTrue" ); + method.setAccessible( true ); + property = MethodHandles.lookup().unreflect( method ); + } + catch (IllegalAccessException | NoSuchMethodException e) { + throw new IllegalStateException( e ); + } this.propertyName = ReflectionHelper.getPropertyName( method ); this.typeForValidatorResolution = ReflectionHelper.boxedType( ReflectionHelper.typeOf( method ) ); }