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++ ) {
|
for ( int i = 0; i < classElements.size(); i++ ) {
|
||||||
final PropertyData idClassPropertyData = classElements.get( i );
|
final PropertyData idClassPropertyData = classElements.get( i );
|
||||||
|
final String propertyName = idClassPropertyData.getPropertyName();
|
||||||
final PropertyData entityPropertyData =
|
final PropertyData entityPropertyData =
|
||||||
baseClassElementsByName.get( idClassPropertyData.getPropertyName() );
|
baseClassElementsByName.get( propertyName );
|
||||||
if ( propertyHolder.isInIdClass() ) {
|
if ( propertyHolder.isInIdClass() ) {
|
||||||
if ( entityPropertyData == null ) {
|
if ( entityPropertyData == null ) {
|
||||||
throw new AnnotationException(
|
throw new AnnotationException(
|
||||||
|
@ -852,11 +853,38 @@ public class EmbeddableBinder {
|
||||||
//the annotation overriding will be dealt with by a mechanism similar to @MapsId
|
//the annotation overriding will be dealt with by a mechanism similar to @MapsId
|
||||||
continue;
|
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
|
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(
|
static Component createEmbeddable(
|
||||||
PropertyHolder propertyHolder,
|
PropertyHolder propertyHolder,
|
||||||
PropertyData inferredData,
|
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