diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java index 68bc67d286..d080f9f0ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/ReflectHelper.java @@ -14,7 +14,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Locale; import java.util.regex.Pattern; - import javax.persistence.Transient; import org.hibernate.AssertionFailure; @@ -636,4 +635,51 @@ public final class ReflectHelper { return potentialSetter; } + + /** + * Similar to {@link #getterMethodOrNull}, except that here we are just looking for the + * corresponding getter for a field (defined as field access) if one exists. + * + * We do not look at supers, although conceivably the super could declare the method + * as an abstract - but again, that is such an edge case... + */ + public static Method findGetterMethodForFieldAccess(Field field, String propertyName) { + for ( Method method : field.getDeclaringClass().getDeclaredMethods() ) { + // if the method has parameters, skip it + if ( method.getParameterCount() != 0 ) { + continue; + } + + if ( Modifier.isStatic( method.getModifiers() ) ) { + continue; + } + + if ( ! method.getReturnType().isAssignableFrom( field.getType() ) ) { + continue; + } + + final String methodName = method.getName(); + + // try "get" + if ( methodName.startsWith( "get" ) ) { + final String stemName = methodName.substring( 3 ); + final String decapitalizedStemName = Introspector.decapitalize( stemName ); + if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { + return method; + } + + } + + // if not "get", then try "is" + if ( methodName.startsWith( "is" ) ) { + final String stemName = methodName.substring( 2 ); + String decapitalizedStemName = Introspector.decapitalize( stemName ); + if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) { + return method; + } + } + } + + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/spi/GetterFieldImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/spi/GetterFieldImpl.java index b2a571da88..5f0a4a54ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/spi/GetterFieldImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/spi/GetterFieldImpl.java @@ -33,7 +33,8 @@ public class GetterFieldImpl implements Getter { this.containerClass = containerClass; this.propertyName = propertyName; this.field = field; - this.getterMethod = ReflectHelper.getterMethodOrNull( containerClass, propertyName); + + this.getterMethod = ReflectHelper.findGetterMethodForFieldAccess( field, propertyName ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/GetterAndIsMethodChecks.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/GetterAndIsMethodChecks.java new file mode 100644 index 0000000000..bf2e525a76 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/GetterAndIsMethodChecks.java @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.jpa.compliance; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; + +import org.hibernate.boot.MetadataSources; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +/** + * @author Steve Ebersole + */ +@TestForIssue( jiraKey = "12096") +public class GetterAndIsMethodChecks extends BaseUnitTestCase { + + @Test + public void testIt() { + new MetadataSources().addAnnotatedClass( A.class ).buildMetadata().buildSessionFactory().close(); + } + + @Entity( name= "A" ) + public static class A { + @Id + private Integer id; + @OneToOne + private A b; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public boolean isB() { + return true; + } + + public A getB() { + return b; + } + + public void setB(A b) { + this.b = b; + } + } +}