HHH-10172 - Throw MappingException when entity/component class defines multiple matching getters by stem name

(cherry picked from commit 1203acbdc0)
This commit is contained in:
Steve Ebersole 2015-10-07 12:26:07 -05:00
parent e49da05654
commit 4ee6b88b2b
3 changed files with 158 additions and 6 deletions

View File

@ -426,18 +426,21 @@ public final class ReflectHelper {
// try "get"
if ( methodName.startsWith( "get" ) ) {
String testStdMethod = Introspector.decapitalize( methodName.substring( 3 ) );
String testOldMethod = methodName.substring( 3 );
if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) {
final String stemName = methodName.substring( 3 );
final String decapitalizedStemName = Introspector.decapitalize( stemName );
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
verifyNoIsVariantExists( containerClass, propertyName, method, stemName );
return method;
}
}
// if not "get", then try "is"
if ( methodName.startsWith( "is" ) ) {
String testStdMethod = Introspector.decapitalize( methodName.substring( 2 ) );
String testOldMethod = methodName.substring( 2 );
if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) {
final String stemName = methodName.substring( 2 );
String decapitalizedStemName = Introspector.decapitalize( stemName );
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
verifyNoGetVariantExists( containerClass, propertyName, method, stemName );
return method;
}
}
@ -446,6 +449,60 @@ public final class ReflectHelper {
return null;
}
private static void verifyNoIsVariantExists(
Class containerClass,
String propertyName,
Method getMethod,
String stemName) {
// verify that the Class does not also define a method with the same stem name with 'is'
try {
final Method isMethod = containerClass.getDeclaredMethod( "is" + stemName );
// No such method should throw the caught exception. So if we get here, there was
// such a method.
checkGetAndIsVariants( containerClass, propertyName, getMethod, isMethod );
}
catch (NoSuchMethodException ignore) {
}
}
private static void checkGetAndIsVariants(
Class containerClass,
String propertyName,
Method getMethod,
Method isMethod) {
// Check the return types. If they are the same, its ok. If they are different
// we are in a situation where we could not reasonably know which to use.
if ( !isMethod.getReturnType().equals( getMethod.getReturnType() ) ) {
throw new MappingException(
String.format(
Locale.ROOT,
"In trying to locate getter for property [%s], Class [%s] defined " +
"both a `get` [%s] and `is` [%s] variant",
propertyName,
containerClass.getName(),
getMethod.toString(),
isMethod.toString()
)
);
}
}
private static void verifyNoGetVariantExists(
Class containerClass,
String propertyName,
Method isMethod,
String stemName) {
// verify that the Class does not also define a method with the same stem name with 'is'
try {
final Method getMethod = containerClass.getDeclaredMethod( "get" + stemName );
// No such method should throw the caught exception. So if we get here, there was
// such a method.
checkGetAndIsVariants( containerClass, propertyName, getMethod, isMethod );
}
catch (NoSuchMethodException ignore) {
}
}
public static Method findSetterMethod(Class containerClass, String propertyName, Class propertyType) {
Class checkClass = containerClass;
Method setter = null;

View File

@ -0,0 +1,83 @@
/*
* 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.property;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.MappingException;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.testing.TestForIssue;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.fail;
/**
* Originally written to verify fix for HHH-10172
*
* @author Steve Ebersole
*/
public class GetAndIsVariantGetterTest {
private static StandardServiceRegistry ssr;
@BeforeClass
public static void prepare() {
ssr = new StandardServiceRegistryBuilder( ).build();
}
@AfterClass
public static void release() {
if ( ssr != null ) {
StandardServiceRegistryBuilder.destroy( ssr );
}
}
@Test
@TestForIssue( jiraKey = "HHH-10172" )
public void testHbmXml() {
try {
new MetadataSources( ssr )
.addResource( "org/hibernate/property/TheEntity.hbm.xml" )
.buildMetadata();
fail( "Expecting a failure" );
}
catch (MappingException ignore) {
// expected
}
}
@Test
@TestForIssue( jiraKey = "HHH-10172" )
public void testAnnotations() {
new MetadataSources( ssr )
.addAnnotatedClass( TheEntity.class )
.buildMetadata();
}
@Entity
public static class TheEntity {
private Integer id;
public boolean isId() {
return false;
}
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!--
~ 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>.
-->
<hibernate-mapping xmlns="http://www.hibernate.org/xsd/hibernate-mapping">
<class name="org.hibernate.property.GetAndIsVariantGetterTest$TheEntity">
<id name="id"/>
</class>
</hibernate-mapping>