HHH-18839 Validate property type of `@IdClass` at bind time
This commit is contained in:
parent
82060f282d
commit
ff99ddbf14
|
@ -835,8 +835,9 @@ public class EmbeddableBinder {
|
|||
|
||||
for ( int i = 0; i < classElements.size(); i++ ) {
|
||||
final PropertyData idClassPropertyData = classElements.get( i );
|
||||
final String propertyName = idClassPropertyData.getPropertyName();
|
||||
final PropertyData entityPropertyData =
|
||||
baseClassElementsByName.get( idClassPropertyData.getPropertyName() );
|
||||
baseClassElementsByName.get( propertyName );
|
||||
if ( propertyHolder.isInIdClass() ) {
|
||||
if ( entityPropertyData == null ) {
|
||||
throw new AnnotationException(
|
||||
|
@ -852,11 +853,38 @@ public class EmbeddableBinder {
|
|||
//the annotation overriding will be dealt with by a mechanism similar to @MapsId
|
||||
continue;
|
||||
}
|
||||
if ( !hasCompatibleType( idClassPropertyData.getTypeName(), entityPropertyData.getTypeName() ) ) {
|
||||
throw new AnnotationException(
|
||||
"Property '" + propertyName + "' in @IdClass '" + idClassPropertyData.getDeclaringClass().getName()
|
||||
+ "' doesn't match type in entity class '" + baseInferredData.getPropertyType().getName()
|
||||
+ "' (expected '" + entityPropertyData.getTypeName() + "' but was '" + idClassPropertyData.getTypeName() + "')"
|
||||
);
|
||||
}
|
||||
}
|
||||
classElements.set( i, entityPropertyData ); //this works since they are in the same order
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasCompatibleType(String typeNameInIdClass, String typeNameInEntityClass) {
|
||||
return typeNameInIdClass.equals( typeNameInEntityClass )
|
||||
|| canonicalize( typeNameInIdClass ).equals( typeNameInEntityClass )
|
||||
|| typeNameInIdClass.equals( canonicalize( typeNameInEntityClass ) );
|
||||
}
|
||||
|
||||
private static String canonicalize(String typeName) {
|
||||
return switch (typeName) {
|
||||
case "boolean" -> Boolean.class.getName();
|
||||
case "char" -> Character.class.getName();
|
||||
case "int" -> Integer.class.getName();
|
||||
case "long" -> Long.class.getName();
|
||||
case "short" -> Short.class.getName();
|
||||
case "byte" -> Byte.class.getName();
|
||||
case "float" -> Float.class.getName();
|
||||
case "double" -> Double.class.getName();
|
||||
default -> typeName;
|
||||
};
|
||||
}
|
||||
|
||||
static Component createEmbeddable(
|
||||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData,
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.test.annotations.cid;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.IdClass;
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.testing.util.ServiceRegistryUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
|
||||
/**
|
||||
* @author Yanming Zhou
|
||||
*/
|
||||
public class CompositeIdTypeMismatchTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
try ( StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder().build() ) {
|
||||
final MetadataSources metadataSources = new MetadataSources( ssr );
|
||||
metadataSources.addAnnotatedClass( TestEntity.class );
|
||||
assertThatExceptionOfType( AnnotationException.class).isThrownBy( metadataSources::buildMetadata ).withMessageContaining( "doesn't match type" );
|
||||
}
|
||||
}
|
||||
|
||||
@IdClass(TestEntity.ID.class)
|
||||
@Entity
|
||||
static class TestEntity {
|
||||
|
||||
@Id
|
||||
String code;
|
||||
|
||||
|
||||
@Id
|
||||
Integer type;
|
||||
|
||||
record ID(String code, String type) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue