Skip to content

Explore MethodHandles usage #917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions engine/src/main/java/org/hibernate/validator/internal/Foo.java
Original file line number Diff line number Diff line change
@@ -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 <http://www.apache.org/licenses/LICENSE-2.0>.
*/
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
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 final MethodHandle property;
private final Field string;


/**
* 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;
try {
string = Foo.class.getDeclaredField( "string" );
string.setAccessible( true );
property = MethodHandles.lookup().unreflectGetter( string );
}
catch (IllegalAccessException | NoSuchFieldException e) {
throw new IllegalStateException( e );
}
}

@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;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
*/
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 final MethodHandle property;
private final Method method;

/**
* 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() {
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 ) );
}

@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;
}

}
Original file line number Diff line number Diff line change
@@ -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 <http://www.apache.org/licenses/LICENSE-2.0>.
*/
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<ConstraintViolation<Foo>> violations = validator.validate( foo );
assertThat( violations ).containsOnlyViolations(
violationOf( Size.class ),
violationOf( AssertTrue.class )
);
}
}
5 changes: 5 additions & 0 deletions performance/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
<artifactId>validation-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

<build>
Expand Down
Loading