HHH-10172 - Throw MappingException when entity/component class defines multiple matching getters by stem name
This commit is contained in:
parent
767edb4b6e
commit
1203acbdc0
|
@ -426,18 +426,21 @@ public final class ReflectHelper {
|
||||||
|
|
||||||
// try "get"
|
// try "get"
|
||||||
if ( methodName.startsWith( "get" ) ) {
|
if ( methodName.startsWith( "get" ) ) {
|
||||||
String testStdMethod = Introspector.decapitalize( methodName.substring( 3 ) );
|
final String stemName = methodName.substring( 3 );
|
||||||
String testOldMethod = methodName.substring( 3 );
|
final String decapitalizedStemName = Introspector.decapitalize( stemName );
|
||||||
if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) {
|
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
|
||||||
|
verifyNoIsVariantExists( containerClass, propertyName, method, stemName );
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not "get", then try "is"
|
// if not "get", then try "is"
|
||||||
if ( methodName.startsWith( "is" ) ) {
|
if ( methodName.startsWith( "is" ) ) {
|
||||||
String testStdMethod = Introspector.decapitalize( methodName.substring( 2 ) );
|
final String stemName = methodName.substring( 2 );
|
||||||
String testOldMethod = methodName.substring( 2 );
|
String decapitalizedStemName = Introspector.decapitalize( stemName );
|
||||||
if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) {
|
if ( stemName.equals( propertyName ) || decapitalizedStemName.equals( propertyName ) ) {
|
||||||
|
verifyNoGetVariantExists( containerClass, propertyName, method, stemName );
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -446,6 +449,60 @@ public final class ReflectHelper {
|
||||||
return null;
|
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) {
|
public static Method findSetterMethod(Class containerClass, String propertyName, Class propertyType) {
|
||||||
Class checkClass = containerClass;
|
Class checkClass = containerClass;
|
||||||
Method setter = null;
|
Method setter = null;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
Loading…
Reference in New Issue