more consistent formatting for error messages

This commit is contained in:
Gavin King 2022-10-23 20:12:14 +02:00
parent 412319819e
commit 264d3c711c
60 changed files with 654 additions and 731 deletions

1
.gitignore vendored
View File

@ -52,4 +52,3 @@ databases/postgis/
# Vim
*.swp
*.swo

View File

@ -15,13 +15,13 @@ import org.hibernate.id.IdentifierGenerator;
/**
* Meta-annotation used to mark another annotation as providing configuration
* for a custom {@link org.hibernate.id.IdentifierGenerator}.
* for a custom {@link IdentifierGenerator}.
*/
@Target( value = ElementType.ANNOTATION_TYPE )
@Retention( RetentionPolicy.RUNTIME )
public @interface IdGeneratorType {
/**
* The IdentifierGenerator being configured
* The {@link IdentifierGenerator} being configured
*/
Class<? extends IdentifierGenerator> value();
}

View File

@ -17,7 +17,7 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Specify an explicit BasicJavaType to use for a particular
* Specify an explicit {@link BasicJavaType} to use for a particular
* column mapping. <ul>
* <li>
* When applied to a Map-valued attribute, describes the Map value. Use

View File

@ -7,7 +7,6 @@
package org.hibernate.annotations;
import java.lang.annotation.Retention;
import jakarta.persistence.Column;
import jakarta.persistence.FetchType;
import static java.lang.annotation.ElementType.FIELD;
@ -15,8 +14,9 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* This is the collection-valued form of @Any definitions. Defines a ToMany-style association pointing
* to one of several entity types depending on a local discriminator.
* Declares a many-valued association targeting one of several entity types,
* depending on a local discriminator column. This is the collection-valued
* form of {@link Any}.
*
* @see Any
*
@ -27,10 +27,14 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface ManyToAny {
/**
* Defines whether the value of the field or property should be lazily loaded or must be
* eagerly fetched. The EAGER strategy is a requirement on the persistence provider runtime
* that the value must be eagerly fetched. The LAZY strategy is applied when bytecode
* enhancement is used. If not specified, defaults to EAGER.
* Specifies whether the value of the field or property should be fetched
* lazily or eagerly:
* <ul>
* <li>{@link FetchType#EAGER}, the default, requires that the association
* be fetched immediately, but
* <li>{@link FetchType#LAZY} is a hint which has no effect unless bytecode
* enhancement is enabled.
* </ul>
*/
FetchType fetch() default FetchType.EAGER;
}

View File

@ -15,9 +15,9 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Applies a custom {@link UserType} for the column mapping
*
* Generally, mutually exclusive with the compositional approach of
* Specifies a custom {@link UserType} for the annotated attribute mapping.
* <p>
* This is usually mutually exclusive with the compositional approach of
* {@link JavaType}, {@link JdbcType}, etc.
*/
@java.lang.annotation.Target({METHOD, FIELD})
@ -25,16 +25,15 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
public @interface Type {
/**
* The custom type implementor class
* The implementation class which implements {@link UserType}.
*/
Class<? extends UserType<?>> value();
/**
* Parameters to be injected into the custom type after
* it is instantiated.
*
* The type should implement {@link org.hibernate.usertype.ParameterizedType}
* to receive the parameters
* Parameters to be injected into the custom type after it is
* instantiated. The {@link UserType} implementation must implement
* {@link org.hibernate.usertype.ParameterizedType} to receive the
* parameters.
*/
Parameter[] parameters() default {};
}

View File

@ -114,8 +114,9 @@ import jakarta.persistence.Entity;
import jakarta.persistence.MapsId;
/**
* The implementation of the in-flight Metadata collector contract.
*
* The implementation of the {@linkplain InFlightMetadataCollector in-flight
* metadata collector contract}.
* <p>
* The usage expectation is that this class is used until all Metadata info is
* collected and then {@link #buildMetadataInstance} is called to generate
* the complete (and immutable) Metadata object.
@ -161,7 +162,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
private final Set<String> defaultNamedNativeQueryNames = new HashSet<>();
private final Set<String> defaultSqlResultSetMappingNames = new HashSet<>();
private final Set<String> defaultNamedProcedureNames = new HashSet<>();
private Map<Class, MappedSuperclass> mappedSuperClasses;
private Map<Class<?>, MappedSuperclass> mappedSuperClasses;
private Map<XClass, Map<String, PropertyData>> propertiesAnnotatedWithMapsId;
private Map<XClass, Map<String, PropertyData>> propertiesAnnotatedWithIdAndToOne;
private Map<String, String> mappedByResolver;
@ -1845,24 +1846,21 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
Map<String, Set<FkSecondPass>> isADependencyOf,
String startTable,
String currentTable) {
Set<FkSecondPass> dependencies = isADependencyOf.get( currentTable );
// bottom out
if ( dependencies == null || dependencies.size() == 0 ) {
return;
}
for ( FkSecondPass sp : dependencies ) {
String dependentTable = sp.getValue().getTable().getQualifiedTableName().render();
if ( dependentTable.compareTo( startTable ) == 0 ) {
throw new AnnotationException( "Foreign key circularity dependency involving the following tables: " + startTable + ", " + dependentTable );
}
buildRecursiveOrderedFkSecondPasses( orderedFkSecondPasses, isADependencyOf, startTable, dependentTable );
if ( !orderedFkSecondPasses.contains( sp ) ) {
orderedFkSecondPasses.add( 0, sp );
if ( dependencies != null ) {
for ( FkSecondPass sp : dependencies ) {
String dependentTable = sp.getValue().getTable().getQualifiedTableName().render();
if ( dependentTable.compareTo( startTable ) == 0 ) {
throw new AnnotationException( "Circular foreign key dependency involving tables '"
+ startTable + "' and '" + dependentTable + "'" );
}
buildRecursiveOrderedFkSecondPasses( orderedFkSecondPasses, isADependencyOf, startTable, dependentTable );
if ( !orderedFkSecondPasses.contains( sp ) ) {
orderedFkSecondPasses.add( 0, sp );
}
}
}
// else bottom out
}
private void processEndOfQueue(List<FkSecondPass> endOfQueueFkSecondPasses) {
@ -2177,7 +2175,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
sb.append( columnName ).append( ", " );
}
sb.setLength( sb.length() - 2 );
sb.append( ") on table " ).append( table.getName() ).append( ": database column " );
sb.append( ") on table '" ).append( table.getName() ).append( "' since the column " );
for ( Column column : unbound ) {
sb.append("'").append( column.getName() ).append( "', " );
}
@ -2185,7 +2183,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
sb.append("'").append( column.getName() ).append( "', " );
}
sb.setLength( sb.length() - 2 );
sb.append( " not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)" );
sb.append( " was not found (specify the correct column name, which depends on the naming strategy, and may not be the same as the entity property name)" );
throw new AnnotationException( sb.toString() );
}
}

View File

@ -449,7 +449,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
throw new AnnotationException(
String.format(
Locale.ROOT,
"`%s` should specify either `%s` or `%s` - %s",
"'%s' should specify either '%s' or '%s' (was '%s')",
AvailableSettings.DEFAULT_LIST_SEMANTICS,
java.util.List.class.getName(),
java.util.Collection.class.getName(),

View File

@ -79,7 +79,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final Map<String,PersistentClass> entityBindingMap;
private final List<Component> composites;
private final Map<Class, MappedSuperclass> mappedSuperclassMap;
private final Map<Class<?>, MappedSuperclass> mappedSuperclassMap;
private final Map<String,Collection> collectionBindingMap;
private final Map<String, TypeDefinition> typeDefinitionMap;
private final Map<String, FilterDefinition> filterDefinitionMap;
@ -99,7 +99,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
MetadataBuildingOptions metadataBuildingOptions,
Map<String, PersistentClass> entityBindingMap,
List<Component> composites,
Map<Class, MappedSuperclass> mappedSuperclassMap,
Map<Class<?>, MappedSuperclass> mappedSuperclassMap,
Map<String, Collection> collectionBindingMap,
Map<String, TypeDefinition> typeDefinitionMap,
Map<String, FilterDefinition> filterDefinitionMap,
@ -398,29 +398,40 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
final ConfigurationService cfgService = sessionFactoryServiceRegistry.getService( ConfigurationService.class );
final ClassLoaderService classLoaderService = sessionFactoryServiceRegistry.getService( ClassLoaderService.class );
for ( Map.Entry<?,?> entry : ( (Map<?, ?>) cfgService.getSettings() ).entrySet() ) {
if ( !(entry.getKey() instanceof String) ) {
continue;
}
final String propertyName = (String) entry.getKey();
if ( ! propertyName.startsWith( AvailableSettings.EVENT_LISTENER_PREFIX ) ) {
continue;
}
final String eventTypeName = propertyName.substring( AvailableSettings.EVENT_LISTENER_PREFIX.length() + 1 );
final EventType eventType = EventType.resolveEventTypeByName( eventTypeName );
final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType );
for ( String listenerImpl : LISTENER_SEPARATION_PATTERN.split( ( (String) entry.getValue() ) ) ) {
eventListenerGroup.appendListener( instantiate( listenerImpl, classLoaderService ) );
for ( Map.Entry<String,Object> entry : cfgService.getSettings().entrySet() ) {
final String propertyName = entry.getKey();
if ( propertyName.startsWith( AvailableSettings.EVENT_LISTENER_PREFIX ) ) {
final String eventTypeName = propertyName.substring( AvailableSettings.EVENT_LISTENER_PREFIX.length() + 1 );
final EventType<?> eventType = EventType.resolveEventTypeByName( eventTypeName );
final String listeners = (String) entry.getValue();
appendListeners( eventListenerRegistry, classLoaderService, listeners, eventType );
}
}
}
private Object instantiate(String listenerImpl, ClassLoaderService classLoaderService) {
private <T> void appendListeners(
EventListenerRegistry eventListenerRegistry,
ClassLoaderService classLoaderService,
String listeners,
EventType<T> eventType) {
final EventListenerGroup<T> eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType );
for ( String listenerImpl : LISTENER_SEPARATION_PATTERN.split( listeners ) ) {
@SuppressWarnings("unchecked")
T listener = (T) instantiate( listenerImpl, classLoaderService );
if ( !eventType.baseListenerInterface().isInstance( listener ) ) {
throw new HibernateException( "Event listener '" + listenerImpl + "' must implement '"
+ eventType.baseListenerInterface().getName() + "'");
}
eventListenerGroup.appendListener( listener );
}
}
private static Object instantiate(String listenerImpl, ClassLoaderService classLoaderService) {
try {
return classLoaderService.classForName( listenerImpl ).newInstance();
}
catch (Exception e) {
throw new HibernateException( "Could not instantiate requested listener [" + listenerImpl + "]", e );
throw new HibernateException( "Could not instantiate event listener '" + listenerImpl + "'", e );
}
}
@ -484,7 +495,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return fetchProfileMap;
}
public Map<Class, MappedSuperclass> getMappedSuperclassMap() {
public Map<Class<?>, MappedSuperclass> getMappedSuperclassMap() {
return mappedSuperclassMap;
}

View File

@ -57,24 +57,22 @@ import static org.hibernate.mapping.MappingHelper.injectParameters;
* @author Steve Ebersole
* @author John Verhaeg
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class TypeDefinition implements Serializable {
public static final AtomicInteger NAME_COUNTER = new AtomicInteger();
private final String name;
private final Class typeImplementorClass;
private final Class<?> typeImplementorClass;
private final String[] registrationKeys;
private final Properties parameters;
private final Map<String,String> parameters;
private BasicValue.Resolution<?> reusableResolution;
public TypeDefinition(
String name,
Class typeImplementorClass,
Class<?> typeImplementorClass,
String[] registrationKeys,
Properties parameters,
TypeConfiguration typeConfiguration) {
Map<String,String> parameters) {
this.name = name;
this.typeImplementorClass = typeImplementorClass;
this.registrationKeys= registrationKeys;
@ -85,7 +83,7 @@ public class TypeDefinition implements Serializable {
return name;
}
public Class getTypeImplementorClass() {
public Class<?> getTypeImplementorClass() {
return typeImplementorClass;
}
@ -93,13 +91,13 @@ public class TypeDefinition implements Serializable {
return registrationKeys;
}
public Properties getParameters() {
public Map<String,String> getParameters() {
return parameters;
}
public BasicValue.Resolution<?> resolve(
Map localConfigParameters,
MutabilityPlan explicitMutabilityPlan,
Map<?,?> localConfigParameters,
MutabilityPlan<?> explicitMutabilityPlan,
MetadataBuildingContext context,
JdbcTypeIndicators indicators) {
if ( CollectionHelper.isEmpty( localConfigParameters ) ) {
@ -107,7 +105,6 @@ public class TypeDefinition implements Serializable {
if ( reusableResolution == null ) {
reusableResolution = createResolution( name, Collections.emptyMap(), indicators, context );
}
return reusableResolution;
}
else {
@ -134,7 +131,7 @@ public class TypeDefinition implements Serializable {
private static BasicValue.Resolution<?> createResolution(
String name,
Class<?> typeImplementorClass,
Properties parameters,
Map<?,?> parameters,
Map<?,?> usageSiteProperties,
JdbcTypeIndicators indicators,
MetadataBuildingContext context) {
@ -153,34 +150,32 @@ public class TypeDefinition implements Serializable {
( (TypeConfigurationAware) typeInstance ).setTypeConfiguration( typeConfiguration );
}
final Properties combinedTypeParameters;
if ( CollectionHelper.isNotEmpty( usageSiteProperties ) ) {
combinedTypeParameters = new Properties( parameters );
combinedTypeParameters.putAll( usageSiteProperties );
final Properties combinedTypeParameters = new Properties();
if ( parameters!=null ) {
combinedTypeParameters.putAll( parameters );
}
else {
combinedTypeParameters = parameters;
if ( usageSiteProperties!=null ) {
combinedTypeParameters.putAll( usageSiteProperties );
}
injectParameters( typeInstance, combinedTypeParameters );
if ( typeInstance instanceof UserType ) {
final UserType<Object> userType = (UserType<Object>) typeInstance;
final CustomType<Object> customType = new CustomType<>( userType, typeConfiguration );
final UserType<?> userType = (UserType<?>) typeInstance;
final CustomType<?> customType = new CustomType<>( userType, typeConfiguration );
return new UserTypeResolution( customType, null, combinedTypeParameters );
}
if ( typeInstance instanceof BasicType ) {
final BasicType resolvedBasicType = (BasicType) typeInstance;
return new BasicValue.Resolution<Object>() {
final BasicType<?> resolvedBasicType = (BasicType<?>) typeInstance;
return new BasicValue.Resolution<>() {
@Override
public JdbcMapping getJdbcMapping() {
return resolvedBasicType;
}
@Override
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public BasicType getLegacyResolvedBasicType() {
return resolvedBasicType;
}
@ -190,8 +185,8 @@ public class TypeDefinition implements Serializable {
return combinedTypeParameters;
}
@Override
public JavaType<Object> getDomainJavaType() {
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public JavaType getDomainJavaType() {
return resolvedBasicType.getMappedJavaType();
}
@ -210,8 +205,8 @@ public class TypeDefinition implements Serializable {
return resolvedBasicType.getValueConverter();
}
@Override
public MutabilityPlan<Object> getMutabilityPlan() {
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public MutabilityPlan getMutabilityPlan() {
// a TypeDefinition does not explicitly provide a MutabilityPlan (yet?)
return resolvedBasicType.isMutable()
? getDomainJavaType().getMutabilityPlan()
@ -229,22 +224,23 @@ public class TypeDefinition implements Serializable {
.resolveDescriptor( typeImplementorClass );
final JdbcType jdbcType = typeConfiguration.getJdbcTypeRegistry().getDescriptor( Types.VARBINARY );
final BasicType<Serializable> resolved = typeConfiguration.getBasicTypeRegistry().resolve( jtd, jdbcType );
@SuppressWarnings({"rawtypes", "unchecked"})
final SerializableType legacyType = new SerializableType( typeImplementorClass );
return new BasicValue.Resolution<Object>() {
return new BasicValue.Resolution<>() {
@Override
public JdbcMapping getJdbcMapping() {
return resolved;
}
@Override
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public BasicType getLegacyResolvedBasicType() {
return legacyType;
}
@Override
public JavaType<Object> getDomainJavaType() {
return (JavaType) resolved.getMappedJavaType();
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public JavaType getDomainJavaType() {
return resolved.getMappedJavaType();
}
@Override
@ -262,8 +258,8 @@ public class TypeDefinition implements Serializable {
return resolved.getValueConverter();
}
@Override
public MutabilityPlan<Object> getMutabilityPlan() {
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public MutabilityPlan getMutabilityPlan() {
// a TypeDefinition does not explicitly provide a MutabilityPlan (yet?)
return resolved.isMutable()
? getDomainJavaType().getMutabilityPlan()
@ -281,47 +277,31 @@ public class TypeDefinition implements Serializable {
String name, Class<?> typeImplementorClass,
BeanInstanceProducer instanceProducer) {
if ( Helper.INSTANCE.shouldIgnoreBeanContainer( serviceRegistry ) ) {
if ( name != null ) {
return instanceProducer.produceBeanInstance( name, typeImplementorClass );
}
else {
return instanceProducer.produceBeanInstance( typeImplementorClass );
}
return name != null
? instanceProducer.produceBeanInstance( name, typeImplementorClass )
: instanceProducer.produceBeanInstance( typeImplementorClass );
}
else {
final ManagedBean typeBean;
if ( name != null ) {
typeBean = serviceRegistry.getService( ManagedBeanRegistry.class )
.getBean( name, typeImplementorClass, instanceProducer );
}
else {
typeBean = serviceRegistry.getService( ManagedBeanRegistry.class )
.getBean( typeImplementorClass, instanceProducer );
}
ManagedBeanRegistry beanRegistry = serviceRegistry.getService(ManagedBeanRegistry.class);
final ManagedBean<?> typeBean = name != null
? beanRegistry.getBean( name, typeImplementorClass, instanceProducer )
: beanRegistry.getBean( typeImplementorClass, instanceProducer );
return typeBean.getBeanInstance();
}
}
public static BasicValue.Resolution<?> createLocalResolution(
String name,
Class typeImplementorClass,
MutabilityPlan explicitMutabilityPlan,
Map localTypeParams,
Class<?> typeImplementorClass,
MutabilityPlan<?> explicitMutabilityPlan,
Map<?,?> localTypeParams,
MetadataBuildingContext buildingContext) {
name = name + ':' + NAME_COUNTER.getAndIncrement();
final Properties properties = new Properties();
properties.putAll( localTypeParams );
final TypeConfiguration typeConfiguration = buildingContext.getBootstrapContext().getTypeConfiguration();
return createResolution(
name,
name + ':' + NAME_COUNTER.getAndIncrement(),
typeImplementorClass,
properties,
localTypeParams,
null,
typeConfiguration.getCurrentBaseSqlTypeIndicators(),
buildingContext.getBootstrapContext().getTypeConfiguration().getCurrentBaseSqlTypeIndicators(),
buildingContext
);
}

View File

@ -30,7 +30,8 @@ import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
import com.fasterxml.classmate.ResolvedType;
import jakarta.persistence.AttributeConverter;
import static org.hibernate.boot.model.convert.internal.ConverterHelper.resolveConverterClassParamTypes;
/**
* @implNote It is important that all {@link RegisteredConversion} be registered
@ -95,22 +96,7 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler {
final Class<?> domainType;
if ( conversion.getExplicitDomainType().equals( void.class ) ) {
// the registration did not define an explicit domain-type, so inspect the converter
final ClassmateContext classmateContext = context.getClassmateContext();
final ResolvedType converterType = classmateContext.getTypeResolver().resolve( conversion.getConverterType() );
final List<ResolvedType> converterParamTypes = converterType.typeParametersFor( AttributeConverter.class );
if ( converterParamTypes == null ) {
throw new AnnotationException(
"Could not extract type parameter information from AttributeConverter implementation ["
+ conversion.getConverterType().getName() + "]"
);
}
else if ( converterParamTypes.size() != 2 ) {
throw new AnnotationException(
"Unexpected type parameter information for AttributeConverter implementation [" +
conversion.getConverterType().getName() + "]; expected 2 parameter types, but found " + converterParamTypes.size()
);
}
final List<ResolvedType> converterParamTypes = resolveConverterClassParamTypes( conversion.getConverterType(), context.getClassmateContext() );
domainType = converterParamTypes.get( 0 ).getErasedType();
}
else {
@ -122,13 +108,13 @@ public class AttributeConverterManager implements ConverterAutoApplyHandler {
if ( existingRegistration != null ) {
if ( !conversion.equals( existingRegistration ) ) {
throw new AnnotationException(
"Attempt to register non-matching `@ConverterRegistration` descriptors for `AttributeConverter` "
+ conversion.getConverterType().getName()
"Conflicting '@ConverterRegistration' descriptors for attribute converter '"
+ conversion.getConverterType().getName() + "'"
);
}
else {
if ( log.isDebugEnabled() ) {
log.debugf( "Skipping duplicate `@ConverterRegistration` for `%s`", conversion.getConverterType().getName() );
log.debugf( "Skipping duplicate '@ConverterRegistration' for '%s'", conversion.getConverterType().getName() );
}
}
}

View File

@ -97,14 +97,15 @@ public class ConverterHelper {
final List<ResolvedType> converterParamTypes = converterType.typeParametersFor( AttributeConverter.class );
if ( converterParamTypes == null ) {
throw new AnnotationException(
"Could not extract type parameter information from AttributeConverter implementation ["
+ converterClass.getName() + "]"
"Could not extract type argument from attribute converter class '"
+ converterClass.getName() + "'"
);
}
else if ( converterParamTypes.size() != 2 ) {
throw new AnnotationException(
"Unexpected type parameter information for AttributeConverter implementation [" +
converterClass.getName() + "]; expected 2 parameter types, but found " + converterParamTypes.size()
"Unexpected type argument for attribute converter class '"
+ converterClass.getName()
+ "' (expected 2 type arguments, but found " + converterParamTypes.size() + ")"
);
}
return converterParamTypes;

View File

@ -94,7 +94,7 @@ public class RegisteredConversion {
return explicitDomainType;
}
public Class<?> getConverterType() {
public Class<? extends AttributeConverter<?,?>> getConverterType() {
return converterType;
}

View File

@ -21,8 +21,8 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
* @author Steve Ebersole
*/
public class UserTypeResolution implements BasicValue.Resolution {
private final CustomType<Object> userTypeAdapter;
private final MutabilityPlan mutabilityPlan;
private final CustomType<?> userTypeAdapter;
private final MutabilityPlan<?> mutabilityPlan;
/**
* We need this for the way envers interprets the boot-model
@ -31,8 +31,8 @@ public class UserTypeResolution implements BasicValue.Resolution {
private final Properties combinedTypeParameters;
public UserTypeResolution(
CustomType<Object> userTypeAdapter,
MutabilityPlan explicitMutabilityPlan,
CustomType<?> userTypeAdapter,
MutabilityPlan<?> explicitMutabilityPlan,
Properties combinedTypeParameters) {
this.userTypeAdapter = userTypeAdapter;
this.combinedTypeParameters = combinedTypeParameters;

View File

@ -9,7 +9,6 @@ package org.hibernate.boot.model.source.internal.hbm;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -2383,7 +2382,7 @@ public class ModelBinder {
private BasicType<?> resolveExplicitlyNamedAnyDiscriminatorType(
String typeName,
Properties parameters,
Map<String,String> parameters,
Any.MetaValue discriminatorMapping) {
final BootstrapContext bootstrapContext = metadataBuildingContext.getBootstrapContext();
@ -2431,7 +2430,9 @@ public class ModelBinder {
if ( typeInstance instanceof ParameterizedType ) {
if ( parameters != null ) {
( (ParameterizedType) typeInstance ).setParameterValues( parameters );
Properties properties = new Properties();
properties.putAll( parameters );
( (ParameterizedType) typeInstance ).setParameterValues( properties );
}
}
@ -2807,9 +2808,9 @@ public class ModelBinder {
private static class TypeResolution {
private final String typeName;
private final Properties parameters;
private final Map<String,String> parameters;
public TypeResolution(String typeName, Properties parameters) {
public TypeResolution(String typeName, Map<String,String> parameters) {
this.typeName = typeName;
this.parameters = parameters;
}
@ -2823,7 +2824,7 @@ public class ModelBinder {
}
String typeName = typeSource.getName();
Properties typeParameters = new Properties();
Map<String,String> typeParameters = new HashMap<>();
final TypeDefinition typeDefinition = sourceDocument.getMetadataCollector().getTypeDefinition( typeName );
if ( typeDefinition != null ) {
@ -4245,12 +4246,11 @@ public class ModelBinder {
private String columns(Value value) {
final StringBuilder builder = new StringBuilder();
final Iterator<Selectable> selectableItr = value.getColumnIterator();
while ( selectableItr.hasNext() ) {
builder.append( selectableItr.next().getText() );
if ( selectableItr.hasNext() ) {
for ( Selectable selectable : value.getSelectables() ) {
if ( builder.length()>0) {
builder.append( ", " );
}
builder.append( selectable.getText() );
}
return builder.toString();
}

View File

@ -33,8 +33,7 @@ public class TypeDefinitionBinder {
typeDefinitionBinding.getName(),
cls.classForName( typeDefinitionBinding.getClazz() ),
null,
ConfigParameterHelper.extractConfigParametersAsProperties( typeDefinitionBinding ),
context.getMetadataCollector().getTypeConfiguration()
ConfigParameterHelper.extractConfigParameters( typeDefinitionBinding )
);
if ( log.isDebugEnabled() ) {

View File

@ -59,7 +59,7 @@ import org.hibernate.usertype.UserCollectionType;
import jakarta.persistence.AttributeConverter;
/**
* An in-flight representation of Metadata while Metadata is being built.
* An in-flight representation of {@link org.hibernate.boot.Metadata} while it is being built.
*
* @author Steve Ebersole
*

View File

@ -38,6 +38,7 @@ import org.hibernate.mapping.Table;
import org.jboss.logging.Logger;
import static org.hibernate.cfg.BinderHelper.getOverridableAnnotation;
import static org.hibernate.cfg.BinderHelper.getPath;
import static org.hibernate.cfg.BinderHelper.getRelativePath;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
@ -297,8 +298,9 @@ public class AnnotatedColumn {
final int numberOfJdbcParams = StringHelper.count( writeExpression, '?' );
if ( numberOfJdbcParams != 1 ) {
throw new AnnotationException(
"@WriteExpression must contain exactly one value placeholder ('?') character: property ["
+ propertyName + "] and column [" + logicalColumnName + "]"
"Write expression in '@ColumnTransformer' for property '" + propertyName
+ "' and column '" + logicalColumnName + "'"
+ " must contain exactly one placeholder character ('?')"
);
}
}
@ -512,8 +514,8 @@ public class AnnotatedColumn {
if ( join == null ) {
throw new AnnotationException(
"Cannot find the expected secondary table: no "
+ explicitTableName + " available for " + propertyHolder.getClassName()
"Secondary table '" + explicitTableName + "' for property '" + propertyHolder.getClassName()
+ "' is not declared (use '@SecondaryTable' to declare the secondary table)"
);
}
@ -710,7 +712,12 @@ public class AnnotatedColumn {
if ( overriddenCols != null ) {
//check for overridden first
if ( columnAnns != null && overriddenCols.length != columnAnns.length ) {
throw new AnnotationException( "AttributeOverride.column() should override all columns for now" );
//TODO: unfortunately, we never actually see this nice error message, since
// PersistentClass.validate() gets called first and produces a worse message
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
+ "' specifies " + columnAnns.length
+ " '@AttributeOverride's but the overridden property has " + overriddenCols.length
+ " columns (every column must have exactly one '@AttributeOverride')" );
}
LOG.debugf( "Column(s) overridden for property %s", inferredData.getPropertyName() );
return overriddenCols.length == 0 ? null : overriddenCols;
@ -959,24 +966,24 @@ public class AnnotatedColumn {
if ( nbrOfColumns > 1 ) {
for (int currentIndex = 1; currentIndex < nbrOfColumns; currentIndex++) {
if ( !columns[currentIndex].isFormula() && !columns[currentIndex - 1].isFormula() ) {
if ( columns[currentIndex].isInsertable() != columns[currentIndex - 1].isInsertable() ) {
throw new AnnotationException(
"Mixing insertable and non insertable columns in a property is not allowed: " + propertyName
);
}
if ( columns[currentIndex].isNullable() != columns[currentIndex - 1].isNullable() ) {
throw new AnnotationException(
"Mixing nullable and non nullable columns in a property is not allowed: " + propertyName
"Column mappings for property '" + propertyName + "' mix nullable with 'not null'"
);
}
if ( columns[currentIndex].isInsertable() != columns[currentIndex - 1].isInsertable() ) {
throw new AnnotationException(
"Column mappings for property '" + propertyName + "' mix insertable with 'insertable=false'"
);
}
if ( columns[currentIndex].isUpdatable() != columns[currentIndex - 1].isUpdatable() ) {
throw new AnnotationException(
"Mixing updatable and non updatable columns in a property is not allowed: " + propertyName
"Column mappings for property '" + propertyName + "' mix updatable with 'updatable=false'"
);
}
if ( !columns[currentIndex].getTable().equals( columns[currentIndex - 1].getTable() ) ) {
throw new AnnotationException(
"Mixing different tables in a property is not allowed: " + propertyName
"Column mappings for property '" + propertyName + "' mix distinct secondary tables"
);
}
}

View File

@ -258,8 +258,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
if ( ann != null ) {
if ( !BinderHelper.isEmptyOrNullAnnotationValue( mappedBy ) ) {
throw new AnnotationException(
"Illegal attempt to define a @JoinColumn with a mappedBy association: "
+ getRelativePath( propertyHolder, propertyName )
"Association '" + getRelativePath( propertyHolder, propertyName )
+ "' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'"
);
}
AnnotatedJoinColumn joinColumn = new AnnotatedJoinColumn();
@ -428,10 +428,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
public static void checkIfJoinColumn(Object columns, PropertyHolder holder, PropertyData property) {
if ( !( columns instanceof AnnotatedJoinColumn[] ) ) {
throw new AnnotationException(
"@Column cannot be used on an association property: "
+ holder.getEntityName()
+ "."
+ property.getPropertyName()
"Property '" + getRelativePath( holder, property.getPropertyName() )
+ "' is an association and may not use '@Column' to specify column mappings (use '@JoinColumn' instead)"
);
}
}
@ -559,9 +557,10 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
throw new AnnotationException(
String.format(
Locale.ENGLISH,
"mapped-by [%s] defined for attribute [%s] referenced an invalid property (no columns)",
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with no columns",
propertyHolder.getPath(),
mappedByPropertyName,
propertyHolder.getPath()
mappedByEntityName
)
);
}
@ -570,7 +569,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
throw new AnnotationException(
String.format(
Locale.ENGLISH,
"mapped-by [%s] defined for attribute [%s] referenced an invalid property (formula)",
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' which maps to a formula",
mappedByPropertyName,
propertyHolder.getPath()
)
@ -580,7 +579,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
throw new AnnotationException(
String.format(
Locale.ENGLISH,
"mapped-by [%s] defined for attribute [%s] referenced an invalid property (multiple columns)",
"Association '%s' is 'mappedBy' a property '%s' of entity '%s' with multiple columns",
mappedByPropertyName,
propertyHolder.getPath()
)
@ -604,7 +603,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
else if ( ownerSide ) {
final String logicalTableName = metadataCollector.getLogicalTableName( referencedEntity.getTable() );
columnIdentifier =implicitNamingStrategy.determineJoinColumnName(
columnIdentifier = implicitNamingStrategy.determineJoinColumnName(
new ImplicitJoinColumnNameSource() {
final ImplicitJoinColumnNameSource.Nature implicitNamingNature = getImplicitNature();
@ -794,10 +793,11 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
if ( columnOwner == null ) {
try {
throw new MappingException(
"Unable to find column with logical name: "
"No column with logical name '"
+ columns[0].getReferencedColumn()
+ " in " + referencedEntity.getTable()
+ " and its related supertables and secondary tables"
+ "' in table '" + referencedEntity.getTable().getName()
+ "' for entity '" + referencedEntity.getEntityName()
+ "', nor in its related superclass tables and secondary tables"
);
}
catch (MappingException e) {
@ -821,8 +821,8 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
catch (MappingException me) {
//rewrite the exception
throw new MappingException(
"Unable to find column with logical name: "
+ logicalReferencedColumnName + " in " + matchingTable.getName()
"No column with logical name '" + logicalReferencedColumnName
+ "' in table '" + matchingTable.getName() + "'"
);
}
noReferencedColumn = false;

View File

@ -560,8 +560,7 @@ public final class AnnotationBinder {
//@Entity and @MappedSuperclass on the same class leads to a NPE down the road
if ( clazzToProcess.isAnnotationPresent( Entity.class )
&& clazzToProcess.isAnnotationPresent( MappedSuperclass.class ) ) {
throw new AnnotationException( "An entity cannot be annotated with both @Entity and @MappedSuperclass: "
+ clazzToProcess.getName() );
throw new AnnotationException( "Type '"+ clazzToProcess.getName() + "' is annotated both '@Entity' and '@MappedSuperclass'");
}
if ( clazzToProcess.isAnnotationPresent( Inheritance.class )
@ -995,21 +994,17 @@ public final class AnnotationBinder {
final XAnnotatedElement element = propertyAnnotatedElement.getProperty();
if ( hasIdAnnotation(element) ) {
inFlightPropertyDataList.add( 0, propertyAnnotatedElement );
/*
* The property must be put in hibernate.properties as it's a system wide property. Fixable?
* TODO support true/false/default on the property instead of present / not present
* TODO is @Column mandatory?
* TODO add method support
*/
// The property must be put in hibernate.properties as it's a system wide property. Fixable?
//TODO support true/false/default on the property instead of present / not present
//TODO is @Column mandatory?
//TODO add method support
if ( context.getBuildingOptions().isSpecjProprietarySyntaxEnabled() ) {
if ( element.isAnnotationPresent( Id.class ) && element.isAnnotationPresent( Column.class ) ) {
String columnName = element.getAnnotation( Column.class ).name();
for ( XProperty prop : declaringClass.getDeclaredProperties( AccessType.FIELD.getType() ) ) {
if ( !prop.isAnnotationPresent( MapsId.class ) ) {
/*
* The detection of a configured individual JoinColumn differs between Annotation
* and XML configuration processing.
*/
//The detection of a configured individual JoinColumn differs between Annotation
//and XML configuration processing.
boolean isRequiredAnnotationPresent = false;
JoinColumns groupAnnotation = prop.getAnnotation( JoinColumns.class );
if ( (prop.isAnnotationPresent( JoinColumn.class )
@ -1106,8 +1101,9 @@ public final class AnnotationBinder {
}
else {
throw new AnnotationException(
"@Parent cannot be applied outside an embeddable object: "
+ getPath( propertyHolder, inferredData )
"Property '" + getPath( propertyHolder, inferredData )
+ "' is annotated '@Parent' but is not a member of an embeddable class"
);
}
}
@ -1292,19 +1288,20 @@ public final class AnnotationBinder {
PropertyBinder propertyBinder) {
if (isIdentifierMapper) {
throw new AnnotationException(
"@IdClass class should not have @Version property"
"Class '" + propertyHolder.getEntityName()
+ "' is annotated '@IdClass' and may not have a property annotated '@Version'"
);
}
if ( !( propertyHolder.getPersistentClass() instanceof RootClass ) ) {
throw new AnnotationException(
"Unable to define/override @Version on a subclass: "
+ propertyHolder.getEntityName()
"Entity '" + propertyHolder.getEntityName()
+ "' is a subclass in an entity class hierarchy and may not have a property annotated '@Version'"
);
}
if ( !propertyHolder.isEntity() ) {
throw new AnnotationException(
"Unable to define @Version on an embedded class: "
+ propertyHolder.getEntityName()
"Embedded class '" + propertyHolder.getEntityName()
+ "' may not have a property annotated '@Version'"
);
}
if ( LOG.isTraceEnabled() ) {
@ -1387,12 +1384,19 @@ public final class AnnotationBinder {
);
if ( isComponent || compositeUserType != null ) {
String referencedEntityName = null;
final String referencedEntityName;
final String propertyName;
if ( isOverridden ) {
// careful: not always a @MapsId property, sometimes it's from an @IdClass
PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
isId, propertyHolder, property.getName(), context
);
referencedEntityName = mapsIdProperty.getClassOrElementName();
propertyName = mapsIdProperty.getPropertyName();
}
else {
referencedEntityName = null;
propertyName = null;
}
propertyBinder = bindComponent(
@ -1406,6 +1410,7 @@ public final class AnnotationBinder {
isId,
inheritanceStatePerClass,
referencedEntityName,
propertyName,
determineCustomInstantiator( property, returnedClass, context ),
compositeUserType,
isOverridden ? (AnnotatedJoinColumn[]) columns : null
@ -1524,9 +1529,9 @@ public final class AnnotationBinder {
throw new AnnotationException(
String.format(
Locale.ROOT,
"@Columns not allowed on a @Any property [%s]; @Column or @Formula is used to map the discriminator" +
"and only one is allowed",
getPath(propertyHolder, inferredData)
"Property '%s' is annotated '@Any' and may not have a '@Columns' annotation "
+ "(a single '@Column' or '@Formula' must be used to map the discriminator, and '@JoinColumn's must be used to map the foreign key) ",
getPath( propertyHolder, inferredData )
)
);
}
@ -1561,8 +1566,8 @@ public final class AnnotationBinder {
if ( property.isAnnotationPresent( Column.class )
|| property.isAnnotationPresent( Columns.class ) ) {
throw new AnnotationException(
"@Column(s) not allowed on a @OneToOne property: "
+ getPath(propertyHolder, inferredData)
"Property '"+ getPath( propertyHolder, inferredData )
+ "' is a '@OneToOne' association and may not use '@Column' to specify column mappings (use '@PrimaryKeyJoinColumn' instead)"
);
}
@ -1631,8 +1636,8 @@ public final class AnnotationBinder {
if ( property.isAnnotationPresent( Column.class )
|| property.isAnnotationPresent( Columns.class ) ) {
throw new AnnotationException(
"@Column(s) not allowed on a @ManyToOne property: "
+ getPath(propertyHolder, inferredData)
"Property '"+ getPath( propertyHolder, inferredData )
+ "' is a '@ManyToOne' association and may not use '@Column' to specify column mappings (use '@JoinColumn' instead)"
);
}
@ -1830,8 +1835,9 @@ public final class AnnotationBinder {
MetadataBuildingContext buildingContext) {
if ( isIdentifierMapper ) {
throw new AnnotationException(
"@IdClass class should not have @Id nor @EmbeddedId properties: "
+ getPath( propertyHolder, inferredData )
"Property '"+ getPath( propertyHolder, inferredData )
+ "' belongs to an '@IdClass' and may not be annotated '@Id' or '@EmbeddedId'"
);
}
XClass entityXClass = inferredData.getClassOrElement();
@ -1931,6 +1937,7 @@ public final class AnnotationBinder {
boolean isId, //is an identifier
Map<XClass, InheritanceState> inheritanceStatePerClass,
String referencedEntityName, //is a component who is overridden by a @MapsId
String propertyName,
Class<? extends EmbeddableInstantiator> customInstantiatorImpl,
Class<? extends CompositeUserType<?>> compositeUserTypeClass,
AnnotatedJoinColumn[] columns) {
@ -1947,6 +1954,7 @@ public final class AnnotationBinder {
SecondPass sp = new CopyIdentifierComponentSecondPass(
comp,
referencedEntityName,
propertyName,
columns,
buildingContext
);
@ -1972,16 +1980,18 @@ public final class AnnotationBinder {
comp.setKey( true );
if ( propertyHolder.getPersistentClass().getIdentifier() != null ) {
throw new AnnotationException(
comp.getComponentClassName()
+ " must not have @Id properties when used as an @EmbeddedId: "
"Embeddable class '" + comp.getComponentClassName()
+ "' may not have a property annotated '@Id' since it is used by '"
+ getPath( propertyHolder, inferredData )
+ "' as an '@EmbeddedId'"
);
}
if ( referencedEntityName == null && comp.getPropertySpan() == 0 ) {
throw new AnnotationException(
comp.getComponentClassName()
+ " has no persistent id property: "
"Embeddable class '" + comp.getComponentClassName()
+ "' may not be used as an '@EmbeddedId' by '"
+ getPath( propertyHolder, inferredData )
+ "' because it has no properties"
);
}
}
@ -2136,9 +2146,10 @@ public final class AnnotationBinder {
if ( propertyHolder.isInIdClass() ) {
if ( entityPropertyData == null ) {
throw new AnnotationException(
"Property of @IdClass not found in entity "
+ baseInferredData.getPropertyClass().getName() + ": "
+ idClassPropertyData.getPropertyName()
"Property '" + getPath( propertyHolder, idClassPropertyData )
+ "' belongs to an '@IdClass' but has no matching property in entity class '"
+ baseInferredData.getPropertyClass().getName()
+ "' (every property of the '@IdClass' must have a corresponding persistent property in the '@Entity' class)"
);
}
final boolean hasXToOneAnnotation = hasToOneAnnotation( entityPropertyData.getProperty() );
@ -2439,8 +2450,8 @@ public final class AnnotationBinder {
toOne.setFetchMode( FetchMode.SELECT );
}
else if ( fetch.value() == org.hibernate.annotations.FetchMode.SUBSELECT ) {
throw new AnnotationException( "Use of FetchMode.SUBSELECT not allowed for to-one associations: "
+ property.getName() );
throw new AnnotationException( "Association '" + property.getName()
+ "' is annotated '@Fetch(SUBSELECT)' but is not many-valued");
}
else {
throw new AssertionFailure( "Unknown FetchMode: " + fetch.value() );

View File

@ -76,13 +76,14 @@ import jakarta.persistence.TableGenerator;
import jakarta.persistence.UniqueConstraint;
import static org.hibernate.cfg.AnnotatedColumn.buildColumnOrFormulaFromAnnotation;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.cfg.AnnotatedJoinColumn.NON_PK_REFERENCE;
import static org.hibernate.cfg.AnnotatedJoinColumn.checkReferencedColumnsType;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.EMBEDDED;
import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.NOOP;
import static org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies.interpret;
/**
* @author Emmanuel Bernard
*/
@ -749,7 +750,9 @@ public class BinderHelper {
buildingContext
);
if ( gen == null ) {
throw new AnnotationException( "Unknown named generator (@GeneratedValue#generatorName): " + generatorName );
throw new AnnotationException( "No id generator was declared with the name '" + generatorName
+ "' specified by '@GeneratedValue'"
+ " (define a named generator using '@SequenceGenerator', '@TableGenerator', or '@GenericGenerator')" );
}
//This is quite vague in the spec but a generator could override the generator choice
String identifierGeneratorStrategy = gen.getStrategy();
@ -1000,9 +1003,7 @@ public class BinderHelper {
}
public static String getAnnotationValueStringOrNull(String value) {
return isEmptyOrNullAnnotationValue( value )
? null
: value;
return isEmptyOrNullAnnotationValue( value ) ? null : value;
}
public static Any buildAnyValue(
@ -1159,7 +1160,7 @@ public class BinderHelper {
public static Map<String,String> toAliasTableMap(SqlFragmentAlias[] aliases){
Map<String,String> ret = new HashMap<>();
for ( SqlFragmentAlias aliase : aliases ) {
if ( StringHelper.isNotEmpty( aliase.table() ) ) {
if ( isNotEmpty( aliase.table() ) ) {
ret.put( aliase.alias(), aliase.table() );
}
}

View File

@ -140,8 +140,8 @@ class ColumnsBuilder {
);
}
else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
throw new AnnotationException( "@Any requires an explicit @JoinColumn(s): "
+ getPath( propertyHolder, inferredData ) );
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
+ "' is annotated '@Any' and must declare at least one '@JoinColumn'" );
}
if ( columns == null && !property.isAnnotationPresent( ManyToMany.class ) ) {
//useful for collection of embedded elements
@ -179,21 +179,19 @@ class ColumnsBuilder {
buildingContext
);
if ( StringHelper.isEmpty( joinTableAnn.name() ) ) {
//TODO: I don't see why this restriction makes sense (use the same defaulting rule as for many-valued)
throw new AnnotationException(
"JoinTable.name() on a @ToOne association has to be explicit: "
+ getPath( propertyHolder, inferredData )
"Single-valued association " + getPath( propertyHolder, inferredData )
+ " has a '@JoinTable' annotation with no explicit 'name'"
);
}
}
else {
OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class );
String mappedBy = oneToOneAnn != null
? oneToOneAnn.mappedBy()
: null;
joinColumns = AnnotatedJoinColumn.buildJoinColumns(
null,
comment,
mappedBy,
oneToOneAnn != null ? oneToOneAnn.mappedBy() : null,
entityBinder.getSecondaryTables(),
propertyHolder,
inferredData.getPropertyName(),
@ -215,7 +213,8 @@ class ColumnsBuilder {
joinColumnAnnotations = joinColumnAnnotation.value();
int length = joinColumnAnnotations.length;
if ( length == 0 ) {
throw new AnnotationException( "Cannot bind an empty @JoinColumns" );
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
+ "' has an empty '@JoinColumns' annotation" );
}
}
@ -243,7 +242,8 @@ class ColumnsBuilder {
joinColumnOrFormulaAnnotations = joinColumnsOrFormulasAnnotations.value();
int length = joinColumnOrFormulaAnnotations.length;
if ( length == 0 ) {
throw new AnnotationException( "Cannot bind an empty @JoinColumnsOrFormulas" );
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
+ "' has an empty '@JoinColumnsOrFormulas' annotation" );
}
}

View File

@ -270,11 +270,9 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier
/*
* Check table matches between the component and the columns
* if not, change the component table if no properties are set
* if a property is set already the core cannot support that
*/
// Check table matches between the component and the columns
// if not, change the component table if no properties are set
// if a property is set already the core cannot support that
if (columns != null) {
Table table = columns[0].getTable();
if ( !table.equals( component.getTable() ) ) {
@ -283,8 +281,9 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
}
else {
throw new AnnotationException(
"A component cannot hold properties split into 2 different tables: "
+ this.getPath()
"Embeddable class '" + component.getComponentClassName()
+ "' has properties mapped to two different tables"
+ " (all properties of the embeddable class must map to the same table)"
);
}
}

View File

@ -10,17 +10,16 @@ import java.util.Locale;
import java.util.Map;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.internal.util.MutableInteger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable;
@ -38,18 +37,20 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
private static final Logger log = Logger.getLogger( CopyIdentifierComponentSecondPass.class );
private final String referencedEntityName;
private final String propertyName;
private final Component component;
private final MetadataBuildingContext buildingContext;
private final AnnotatedJoinColumn[] joinColumns;
public CopyIdentifierComponentSecondPass(
Component comp,
String referencedEntityName,
String referencedEntityName, String propertyName,
AnnotatedJoinColumn[] joinColumns,
MetadataBuildingContext buildingContext) {
super( comp, joinColumns );
this.component = comp;
this.referencedEntityName = referencedEntityName;
this.propertyName = propertyName;
this.buildingContext = buildingContext;
this.joinColumns = joinColumns;
}
@ -68,17 +69,26 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
@Override
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
PersistentClass referencedPersistentClass = persistentClasses.get( referencedEntityName );
// TODO better error names
if ( referencedPersistentClass == null ) {
throw new AnnotationException( "Unknown entity name: " + referencedEntityName );
// TODO: much better error message if this is something that can really happen!
throw new AnnotationException( "Unknown entity name '" + referencedEntityName + "'");
}
if ( ! ( referencedPersistentClass.getIdentifier() instanceof Component ) ) {
throw new AssertionFailure(
"Unexpected identifier type on the referenced entity when mapping a @MapsId: "
+ referencedEntityName
KeyValue identifier = referencedPersistentClass.getIdentifier();
if ( !(identifier instanceof Component) ) {
// The entity with the @MapsId annotation has a composite
// id type, but the referenced entity has a basic-typed id.
// Therefore, the @MapsId annotation should have specified
// a property of the composite id that has the foreign key
throw new AnnotationException(
"Missing 'value' in '@MapsId' annotation of association '" + propertyName
+ "' of entity '" + component.getOwner().getEntityName()
+ "' with composite identifier type"
+ " ('@MapsId' must specify a property of the '@EmbeddedId' class which has the foreign key of '"
+ referencedEntityName + "')"
);
}
Component referencedComponent = (Component) referencedPersistentClass.getIdentifier();
Component referencedComponent = (Component) identifier;
//prepare column name structure
boolean isExplicitReference = true;
@ -184,22 +194,24 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
String logicalColumnName = null;
if ( isExplicitReference ) {
logicalColumnName = column.getName();
//JPA 2 requires referencedColumnNames to be case insensitive
//JPA 2 requires referencedColumnNames to be case-insensitive
joinColumn = columnByReferencedName.get( logicalColumnName.toLowerCase(Locale.ROOT ) );
}
else {
joinColumn = columnByReferencedName.get( String.valueOf( index.get() ) );
index.getAndIncrement();
}
if ( joinColumn == null && ! joinColumns[0].isNameDeferred() ) {
if ( joinColumn == null && !joinColumns[0].isNameDeferred() ) {
throw new AnnotationException(
isExplicitReference ?
"Unable to find column reference in the @MapsId mapping: " + logicalColumnName :
"Implicit column reference in the @MapsId mapping fails, try to use explicit referenceColumnNames: " + referencedEntityName
"Property '" + propertyName
+ "' of entity '" + component.getOwner().getEntityName()
+ "' must have a '@JoinColumn' which references the foreign key column '"
+ logicalColumnName + "'"
);
}
final String columnName = joinColumn == null || joinColumn.isNameDeferred() ? "tata_" + column.getName() : joinColumn
.getName();
final String columnName = joinColumn == null || joinColumn.isNameDeferred()
? "tata_" + column.getName()
: joinColumn.getName();
final Database database = buildingContext.getMetadataCollector().getDatabase();
final PhysicalNamingStrategy physicalNamingStrategy = buildingContext.getBuildingOptions().getPhysicalNamingStrategy();

View File

@ -103,7 +103,8 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
);
if ( column == null ) {
throw new AnnotationException(
"@Index references a unknown column: " + columnName
"Table '" + table.getName() + "' has no column named '" + columnName
+ "' matching the column specified in '@Index'"
);
}
if ( unique ) {

View File

@ -227,7 +227,8 @@ public class InheritanceState {
}
if ( idPropertyCount == 0 && !inheritanceState.hasParents() ) {
throw new AnnotationException( "No identifier specified for entity: " + clazz.getName() );
throw new AnnotationException( "Entity '" + clazz.getName() + "' has no identifier"
+ " (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)" );
}
elements.trimToSize();
elementsToProcess = new ElementsToProcess( elements, idPropertyCount );
@ -268,7 +269,8 @@ public class InheritanceState {
}
}
}
throw new AnnotationException( "No identifier specified for entity: " + clazz );
throw new AnnotationException( "Entity '" + clazz.getName() + "' has no identifier"
+ " (every '@Entity' class must declare or inherit at least one '@Id' or '@EmbeddedId' property)" );
}
private void getMappedSuperclassesTillNextEntityOrdered() {

View File

@ -18,7 +18,6 @@ import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.annotations.PropertyBinder;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.DependantValue;
@ -31,6 +30,7 @@ import org.hibernate.mapping.SortableValue;
import org.hibernate.type.ForeignKeyDirection;
import static org.hibernate.cfg.BinderHelper.findPropertyByName;
import static org.hibernate.cfg.BinderHelper.getPath;
import static org.hibernate.cfg.BinderHelper.isEmptyAnnotationValue;
import static org.hibernate.internal.util.StringHelper.qualify;
@ -125,12 +125,10 @@ public class OneToOneSecondPass implements SecondPass {
Property prop = binder.makeProperty();
prop.setOptional( optional );
if ( isEmptyAnnotationValue( mappedBy ) ) {
/*
* we need to check if the columns are in the right order
* if not, then we need to create a many to one and formula
* but actually, since entities linked by a one to one need
* to share the same composite id class, this cannot happen in hibernate
*/
// we need to check if the columns are in the right order
// if not, then we need to create a many to one and formula
// but actually, since entities linked by a one to one need
// to share the same composite id class, this cannot happen in hibernate
boolean rightOrder = true;
if ( rightOrder ) {
@ -154,26 +152,21 @@ public class OneToOneSecondPass implements SecondPass {
else {
value.setMappedByProperty( mappedBy );
PersistentClass otherSide = persistentClasses.get( value.getReferencedEntityName() );
if ( otherSide == null ) {
throw new MappingException( "Association '" + getPath( propertyHolder, inferredData )
+ "' targets unknown entity type '" + value.getReferencedEntityName() + "'" );
}
Property otherSideProperty;
try {
if ( otherSide == null ) {
throw new MappingException( "Unable to find entity: " + value.getReferencedEntityName() );
}
otherSideProperty = findPropertyByName( otherSide, mappedBy );
}
catch (MappingException e) {
throw new AnnotationException(
"Unknown mappedBy in: " + qualify( ownerEntity, ownerProperty )
+ ", referenced property unknown: "
+ qualify( value.getReferencedEntityName(), mappedBy )
);
otherSideProperty = null;
}
if ( otherSideProperty == null ) {
throw new AnnotationException(
"Unknown mappedBy in: " + qualify( ownerEntity, ownerProperty )
+ ", referenced property unknown: "
+ qualify( value.getReferencedEntityName(), mappedBy )
);
throw new AnnotationException( "Association '" + getPath( propertyHolder, inferredData )
+ "' is 'mappedBy' a property named '" + mappedBy
+ "' which does not exist in the target entity type '" + value.getReferencedEntityName() + "'" );
}
if ( otherSideProperty.getValue() instanceof OneToOne ) {
propertyHolder.addProperty( prop, inferredData.getDeclaringClass() );
@ -228,7 +221,9 @@ public class OneToOneSecondPass implements SecondPass {
// HHH-6813
// Foo: @Id long id, @OneToOne(mappedBy="foo") Bar bar
// Bar: @Id @OneToOne Foo foo
boolean referenceToPrimaryKey = ( mappedBy == null ) || otherSide.getIdentifier() instanceof Component && ! ( (Component) otherSide.getIdentifier() ).hasProperty( mappedBy ) ;
boolean referenceToPrimaryKey = mappedBy == null
|| otherSide.getIdentifier() instanceof Component
&& ! ( (Component) otherSide.getIdentifier() ).hasProperty( mappedBy );
value.setReferenceToPrimaryKey( referenceToPrimaryKey );
String propertyRef = value.getReferencedPropertyName();
@ -240,14 +235,10 @@ public class OneToOneSecondPass implements SecondPass {
}
}
else {
throw new AnnotationException(
"Referenced property not a (One|Many)ToOne: "
+ qualify(
otherSide.getEntityName(), mappedBy
)
+ " in mappedBy of "
+ qualify( ownerEntity, ownerProperty )
);
throw new AnnotationException( "Association '" + getPath( propertyHolder, inferredData )
+ "' is 'mappedBy' a property named '" + mappedBy
+ "' of the target entity type '" + value.getReferencedEntityName()
+ "' which is not a '@OneToOne' or '@ManyToOne' association" );
}
}
value.sortProperties();

View File

@ -44,9 +44,8 @@ public class PkDrivenByDefaultMapsIdSecondPass extends FkSecondPass {
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
PersistentClass referencedEntity = persistentClasses.get( referencedEntityName );
if ( referencedEntity == null ) {
throw new AnnotationException(
"Unknown entity name: " + referencedEntityName
);
// TODO: much better error message if this is something that can really happen!
throw new AnnotationException( "Unknown entity name '" + referencedEntityName + "'" );
}
TableBinder.linkJoinColumnWithValueOverridingNameIfImplicit(
referencedEntity,

View File

@ -100,6 +100,7 @@ class PropertyContainer {
if ( !recordComponents.isEmpty() && recordComponents.size() == fields.size() && getters.isEmpty() ) {
localAttributeMap = new LinkedHashMap<>();
}
//otherwise we sort them in alphabetical order, since this is at least deterministic
else {
localAttributeMap = new TreeMap<>();
}
@ -296,12 +297,12 @@ class PropertyContainer {
}
private static List<XProperty> verifyAndInitializePersistentAttributes(XClass xClass, Map<String, XProperty> localAttributeMap) {
ArrayList<XProperty> output = new ArrayList( localAttributeMap.size() );
ArrayList<XProperty> output = new ArrayList<>( localAttributeMap.size() );
for ( XProperty xProperty : localAttributeMap.values() ) {
if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xProperty ) ) {
String msg = "Property " + StringHelper.qualify( xClass.getName(), xProperty.getName() ) +
" has an unbound type and no explicit target entity. Resolve this Generic usage issue" +
" or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xClass, xProperty ) ) {
String msg = "Property '" + StringHelper.qualify( xClass.getName(), xProperty.getName() ) +
"' has an unbound type and no explicit target entity (resolve this generics usage issue" +
" or set an explicit target attribute with '@OneToMany(target=)' or use an explicit '@Type')";
throw new AnnotationException( msg );
}
output.add( xProperty );
@ -395,46 +396,47 @@ class PropertyContainer {
return classDefinedAccessType;
}
private static boolean discoverTypeWithoutReflection(XProperty p) {
if ( p.isAnnotationPresent( OneToOne.class ) && !p.getAnnotation( OneToOne.class )
private static boolean discoverTypeWithoutReflection(XClass clazz, XProperty property) {
if ( property.isAnnotationPresent( OneToOne.class ) && !property.getAnnotation( OneToOne.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( OneToMany.class ) && !p.getAnnotation( OneToMany.class )
else if ( property.isAnnotationPresent( OneToMany.class ) && !property.getAnnotation( OneToMany.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( ManyToOne.class ) && !p.getAnnotation( ManyToOne.class )
else if ( property.isAnnotationPresent( ManyToOne.class ) && !property.getAnnotation( ManyToOne.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( ManyToMany.class ) && !p.getAnnotation( ManyToMany.class )
else if ( property.isAnnotationPresent( ManyToMany.class ) && !property.getAnnotation( ManyToMany.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( ManyToAny.class ) ) {
if ( !p.isCollection() && !p.isArray() ) {
throw new AnnotationException( "@ManyToAny used on a non collection non array property: " + p.getName() );
else if ( property.isAnnotationPresent( ManyToAny.class ) ) {
if ( !property.isCollection() && !property.isArray() ) {
throw new AnnotationException( "Property '" + StringHelper.qualify( clazz.getName(), property.getName() )
+ "' annotated '@ManyToAny' is neither a collection nor an array" );
}
return true;
}
else if ( p.isAnnotationPresent( Basic.class ) ) {
else if ( property.isAnnotationPresent( Basic.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( Type.class ) ) {
else if ( property.isAnnotationPresent( Type.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( JavaType.class ) ) {
else if ( property.isAnnotationPresent( JavaType.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( Target.class ) ) {
else if ( property.isAnnotationPresent( Target.class ) ) {
return true;
}
return false;

View File

@ -93,12 +93,8 @@ public class ToOneFkSecondPass extends FkSecondPass {
ManyToOne manyToOne = (ManyToOne) value;
PersistentClass ref = persistentClasses.get( manyToOne.getReferencedEntityName() );
if ( ref == null ) {
throw new AnnotationException(
"@OneToOne or @ManyToOne on "
+ StringHelper.qualify( entityClassName, path )
+ " references an unknown entity: "
+ manyToOne.getReferencedEntityName()
);
throw new AnnotationException( "Association '" + StringHelper.qualify( entityClassName, path )
+ "' targets an unknown entity named '" + manyToOne.getReferencedEntityName() + "'" );
}
manyToOne.setPropertyName( path );
createSyntheticPropertyReference( columns, ref, null, manyToOne, false, buildingContext );

View File

@ -8,7 +8,6 @@ package org.hibernate.cfg.annotations;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -132,7 +131,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
private String explicitBasicTypeName;
private Class<? extends UserType<?>> explicitCustomType;
private Map explicitLocalTypeParams;
private Map<String,String> explicitLocalTypeParams;
private Function<TypeConfiguration, JdbcType> explicitJdbcTypeAccess;
private Function<TypeConfiguration, BasicJavaType> explicitJavaTypeAccess;
@ -302,9 +301,9 @@ public class BasicValueBinder implements JdbcTypeIndicators {
throw new AssertionFailure( "`BasicValueBinder#setColumns` should be called before `BasicValueBinder#setType`" );
}
if ( columns.length != 1 ) {
throw new AssertionFailure( "Expecting just one column, but found `" + Arrays.toString( columns ) + "`" );
}
// if ( columns.length != 1 ) {
// throw new AssertionFailure( "Expecting just one column, but found `" + Arrays.toString( columns ) + "`" );
// }
final XClass modelTypeXClass = isArray
? modelXProperty.getElementClass()
@ -377,8 +376,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
this.explicitLocalTypeParams = extractTypeParams( params );
}
@SuppressWarnings("unchecked")
private Map extractTypeParams(Parameter[] parameters) {
private Map<String,String> extractTypeParams(Parameter[] parameters) {
if ( parameters == null || parameters.length == 0 ) {
return Collections.emptyMap();
}
@ -387,7 +385,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
return Collections.singletonMap( parameters[0].name(), parameters[0].value() );
}
final Map map = new HashMap();
final Map<String,String> map = new HashMap<>();
for ( Parameter parameter: parameters ) {
map.put( parameter.name(), parameter.value() );
}
@ -740,7 +738,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
else {
throw new AnnotationException(
String.format(
"Attribute [%s.%s] was annotated as enumerated, but its java type is not an enum [%s]",
"Property '%s.%s' is annotated '@Enumerated' but its type '%s' is not an enum",
declaringClassName,
attributeDescriptor.getName(),
attributeType.getName()

View File

@ -199,7 +199,7 @@ public abstract class CollectionBinder {
PropertyHolder propertyHolder;
private int batchSize;
private String mappedBy;
private XClass collectionType;
private XClass collectionElementType;
private XClass targetEntity;
private AnnotatedJoinColumn[] inverseJoinColumns;
private String cascadeStrategy;
@ -261,19 +261,16 @@ public abstract class CollectionBinder {
final ElementCollection elementCollectionAnn = property.getAnnotation( ElementCollection.class );
if ( ( oneToManyAnn != null || manyToManyAnn != null || elementCollectionAnn != null )
&& isToManyAssociationWithinEmbeddableCollection(propertyHolder) ) {
throw new AnnotationException(
"@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection: "
+ getPath(propertyHolder, inferredData)
);
&& isToManyAssociationWithinEmbeddableCollection( propertyHolder ) ) {
String ann = oneToManyAnn!=null ? "'@OneToMany'" : manyToManyAnn!=null ? "'@ManyToMany'" : "'@ElementCollection'";
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData ) +
"' belongs to an '@Embeddable' class that is contained in an '@ElementCollection' and may not be a " + ann );
}
if ( property.isAnnotationPresent( OrderColumn.class )
&& manyToManyAnn != null && !manyToManyAnn.mappedBy().isEmpty() ) {
throw new AnnotationException(
"Explicit @OrderColumn on inverse side of @ManyToMany is illegal: "
+ getPath(propertyHolder, inferredData)
);
throw new AnnotationException("Collection '" + getPath( propertyHolder, inferredData ) +
"' is the unowned side of a bidirectional '@ManyToMany' and may not have an '@OrderColumn'");
}
final IndexColumn indexColumn = IndexColumn.fromAnnotations(
@ -305,12 +302,12 @@ public abstract class CollectionBinder {
NotFound notFound = property.getAnnotation( NotFound.class );
if ( notFound != null ) {
if ( manyToManyAnn == null ) {
throw new AnnotationException("collection annotated @NotFound is not a @ManyToMany association: "
+ getPath(propertyHolder, inferredData) );
throw new AnnotationException( "Collection '" + getPath( propertyHolder, inferredData )
+ "' annotated '@NotFound' is not a '@ManyToMany' association" );
}
collectionBinder.setNotFoundAction( notFound.action() );
}
collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
collectionBinder.setElementType( inferredData.getProperty().getElementClass() );
collectionBinder.setAccessType( inferredData.getDefaultAccess() );
//do not use "element" if you are a JPA 2 @ElementCollection, only for legacy Hibernate mappings
@ -408,10 +405,8 @@ public abstract class CollectionBinder {
//TODO enhance exception with @ManyToAny and @CollectionOfElements
if ( oneToManyAnn != null && manyToManyAnn != null ) {
throw new AnnotationException(
"@OneToMany and @ManyToMany on the same property is not allowed: "
+ propertyHolder.getEntityName() + "." + inferredData.getPropertyName()
);
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
+ "' is annotated both '@OneToMany' and '@ManyToMany'" );
}
String mappedBy = null;
ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager();
@ -568,10 +563,8 @@ public abstract class CollectionBinder {
index++;
}
if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) {
throw new AnnotationException(
"@MapKeyJoinColumn and @MapKeyJoinColumns used on the same property: "
+ getPath(propertyHolder, inferredData)
);
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData )
+ "' is annotated both '@MapKeyJoinColumn' and '@MapKeyJoinColumns'" );
}
return joinKeyColumns;
}
@ -1054,7 +1047,7 @@ public abstract class CollectionBinder {
throw new AnnotationException(
String.format(
Locale.ROOT,
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: %s.%s",
"Property '%s.%s' is not a collection and may not be a '@OneToMany', '@ManyToMany', or '@ElementCollection'",
property.getDeclaringClass().getName(),
property.getName()
)
@ -1080,9 +1073,8 @@ public abstract class CollectionBinder {
this.tableBinder = tableBinder;
}
public void setCollectionType(XClass collectionType) {
// NOTE: really really badly named. This is actually NOT the collection-type, but rather the collection-element-type!
this.collectionType = collectionType;
public void setElementType(XClass collectionElementType) {
this.collectionElementType = collectionElementType;
}
public void setTargetEntity(XClass targetEntity) {
@ -1113,12 +1105,8 @@ public abstract class CollectionBinder {
if ( property.isAnnotationPresent( MapKeyColumn.class )
&& mapKeyPropertyName != null ) {
throw new AnnotationException(
"Cannot mix @jakarta.persistence.MapKey and @MapKeyColumn or @org.hibernate.annotations.MapKey "
+ "on the same collection: " + qualify(
propertyHolder.getPath(), propertyName
)
);
throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName )
+ "' is annotated both '@MapKey' and '@MapKeyColumn'" );
}
bindExplicitTypes();
@ -1159,7 +1147,7 @@ public abstract class CollectionBinder {
private void scheduleSecondPass(boolean isMappedBy, InFlightMetadataCollector metadataCollector) {
//many to many may need some second pass information
if ( !oneToMany && isMappedBy ) {
metadataCollector.addMappedBy( getCollectionType().getName(), mappedBy, propertyName );
metadataCollector.addMappedBy( getElementType().getName(), mappedBy, propertyName );
}
if ( inheritanceStatePerClass == null) {
@ -1175,7 +1163,7 @@ public abstract class CollectionBinder {
mapKeyManyToManyColumns,
isEmbedded,
property,
getCollectionType(),
getElementType(),
notFoundAction,
oneToMany,
tableBinder,
@ -1190,8 +1178,9 @@ public abstract class CollectionBinder {
Persister persisterAnn = property.getAnnotation( Persister.class );
if ( persisterAnn != null ) {
Class clazz = persisterAnn.impl();
if ( !CollectionPersister.class.isAssignableFrom(clazz) ) {
throw new AnnotationException( "persister class does not implement CollectionPersister: " + clazz.getName() );
if ( !CollectionPersister.class.isAssignableFrom( clazz ) ) {
throw new AnnotationException( "Persister class '" + clazz.getName()
+ "' does not implement 'CollectionPersister'" );
}
collection.setCollectionPersisterClass( clazz );
}
@ -1229,12 +1218,18 @@ public abstract class CollectionBinder {
private void detectMappedByProblem(boolean isMappedBy) {
if (isMappedBy
&& (property.isAnnotationPresent( JoinColumn.class )
|| property.isAnnotationPresent( JoinColumns.class )
|| propertyHolder.getJoinTable( property ) != null ) ) {
String message = "Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: ";
message += qualify( propertyHolder.getPath(), propertyName );
throw new AnnotationException( message );
&& ( property.isAnnotationPresent( JoinColumn.class )
|| property.isAnnotationPresent( JoinColumns.class ) ) ) {
throw new AnnotationException( "Association '"
+ qualify( propertyHolder.getPath(), propertyName )
+ "' is 'mappedBy' another entity and may not specify the '@JoinColumn'" );
}
if (isMappedBy
&& propertyHolder.getJoinTable( property ) != null ) {
throw new AnnotationException( "Association '"
+ qualify( propertyHolder.getPath(), propertyName )
+ "' is 'mappedBy' another entity and may not specify the '@JoinTable'" );
}
if (!isMappedBy
@ -1242,9 +1237,9 @@ public abstract class CollectionBinder {
&& property.isAnnotationPresent( OnDelete.class )
&& !property.isAnnotationPresent( JoinColumn.class )
&& !property.isAnnotationPresent( JoinColumns.class )) {
String message = "Unidirectional one-to-many associations annotated with @OnDelete must define @JoinColumn: ";
message += qualify( propertyHolder.getPath(), propertyName );
throw new AnnotationException( message );
throw new AnnotationException( "Unidirectional '@OneToMany' association '"
+ qualify( propertyHolder.getPath(), propertyName )
+ "' is annotated '@OnDelete' and must explicitly specify a '@JoinColumn'" );
}
}
@ -1363,10 +1358,11 @@ public abstract class CollectionBinder {
catch (Exception e) {
throw new AnnotationException(
String.format(
"Could not instantiate comparator class [%s] for %s",
"Could not instantiate comparator class '%s' for collection '%s'",
comparatorClass.getName(),
safeCollectionRole()
)
),
e
);
}
}
@ -1376,10 +1372,10 @@ public abstract class CollectionBinder {
return new AnnotationException(
String.format(
Locale.ROOT,
"Illegal combination of ordering and sorting annotations (`%s`) - only one of `@%s` and `@%s` may be used",
"Collection '%s' is annotated both '@%s' and '@%s'",
safeCollectionRole(),
jakarta.persistence.OrderBy.class.getName(),
OrderBy.class.getName(),
safeCollectionRole()
OrderBy.class.getName()
)
);
}
@ -1388,7 +1384,7 @@ public abstract class CollectionBinder {
throw new AnnotationException(
String.format(
Locale.ROOT,
"Illegal combination of ordering and sorting annotations (`%s`) - only one of `@%s`, `@%s`, `@%s` and `@%s` can be used",
"Collection '%s' is both sorted and ordered (only one of '@%s', '@%s', '@%s', and '@%s' may be used)",
safeCollectionRole(),
jakarta.persistence.OrderBy.class.getName(),
OrderBy.class.getName(),
@ -1401,7 +1397,7 @@ public abstract class CollectionBinder {
private AnnotationException buildIllegalSortCombination() {
return new AnnotationException(
String.format(
"Illegal combination of sorting annotations (`%s`) - only one of `@%s` and `@%s` can be used",
"Collection '%s' is annotated both '@%s' and '@%s'",
safeCollectionRole(),
SortNatural.class.getName(),
SortComparator.class.getName()
@ -1470,15 +1466,14 @@ public abstract class CollectionBinder {
}
}
private XClass getCollectionType() {
private XClass getElementType() {
if ( AnnotationBinder.isDefault( targetEntity, buildingContext ) ) {
if ( collectionType != null ) {
return collectionType;
if ( collectionElementType != null ) {
return collectionElementType;
}
else {
String errorMsg = "Collection has neither generic type or OneToMany.targetEntity() defined: "
+ safeCollectionRole();
throw new AnnotationException( errorMsg );
throw new AnnotationException( "Collection '" + safeCollectionRole()
+ "' is declared with a raw type and has an explicit 'targetEntity'" );
}
}
else {
@ -1495,7 +1490,7 @@ public abstract class CollectionBinder {
final AnnotatedJoinColumn[] mapKeyManyToManyColumns,
final boolean isEmbedded,
final XProperty property,
final XClass collType,
final XClass elementType,
final NotFoundAction notFoundAction,
final boolean unique,
final TableBinder assocTableBinder,
@ -1505,7 +1500,7 @@ public abstract class CollectionBinder {
public void secondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
bindStarToManySecondPass(
persistentClasses,
collType,
elementType,
fkJoinColumns,
keyColumns,
inverseColumns,
@ -1526,7 +1521,7 @@ public abstract class CollectionBinder {
*/
protected boolean bindStarToManySecondPass(
Map<String, PersistentClass> persistentClasses,
XClass collType,
XClass elementType,
AnnotatedJoinColumn[] fkJoinColumns,
AnnotatedJoinColumn[] keyColumns,
AnnotatedJoinColumn[] inverseColumns,
@ -1537,23 +1532,17 @@ public abstract class CollectionBinder {
TableBinder associationTableBinder,
NotFoundAction notFoundAction,
MetadataBuildingContext buildingContext) {
PersistentClass persistentClass = persistentClasses.get( collType.getName() );
PersistentClass persistentClass = persistentClasses.get( elementType.getName() );
boolean reversePropertyInJoin = false;
if ( persistentClass != null && isNotEmpty( mappedBy ) ) {
try {
reversePropertyInJoin = 0 != persistentClass.getJoinNumber(
persistentClass.getRecursiveProperty( mappedBy )
);
reversePropertyInJoin =
0 != persistentClass.getJoinNumber( persistentClass.getRecursiveProperty( mappedBy ) );
}
catch (MappingException e) {
throw new AnnotationException(
"mappedBy references an unknown target entity property: " +
collType + "." + this.mappedBy +
" in " +
collection.getOwnerEntityName() +
"." +
property.getName()
);
throw new AnnotationException( "Collection '" + safeCollectionRole()
+ "' is 'mappedBy' a property named '" + mappedBy
+ "' which does not exist in the target entity '" + elementType.getName() + "'" );
}
}
if ( persistentClass != null
@ -1568,7 +1557,7 @@ public abstract class CollectionBinder {
getCollection(),
persistentClasses,
fkJoinColumns,
collType,
elementType,
cascadeDeleteEnabled,
notFoundAction,
buildingContext,
@ -1585,7 +1574,7 @@ public abstract class CollectionBinder {
inverseColumns,
elementColumns,
isEmbedded,
collType,
elementType,
notFoundAction,
unique,
cascadeDeleteEnabled,
@ -1784,8 +1773,8 @@ public abstract class CollectionBinder {
}
else {
throw new AnnotationException(
"Illegal use of @WhereJoinTable on an association without join table: "
+ qualify( propertyHolder.getPath(), propertyName )
"Collection '" + qualify( propertyHolder.getPath(), propertyName )
+ "' is an association with no join table and may not have a 'WhereJoinTable'"
);
}
}
@ -1794,22 +1783,25 @@ public abstract class CollectionBinder {
private void addFilter(boolean hasAssociationTable, FilterJoinTable filter) {
if ( hasAssociationTable ) {
final String condition;
final String name = filter.name();
if ( isEmpty( filter.condition() ) ) {
final FilterDefinition filterDefinition = buildingContext.getMetadataCollector()
.getFilterDefinition( filter.name() );
if ( filterDefinition == null ) {
throw new AnnotationException(
"@FilterJoinTable on an association without condition attribute and without an any @FilterDef with a default condition"
+ qualify( propertyHolder.getPath(), propertyName )
);
final FilterDefinition definition = buildingContext.getMetadataCollector().getFilterDefinition( name );
if ( definition == null ) {
throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName )
+ "' has a '@FilterJoinTable' for an undefined filter named '" + name + "'" );
}
condition = definition.getDefaultFilterCondition();
if ( isEmpty( condition ) ) {
throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName )
+ "' has a '@FilterJoinTable' with no 'condition' and no default condition was given by the '@FilterDef' named '"
+ name + "'");
}
condition = filterDefinition.getDefaultFilterCondition();
}
else {
condition = filter.condition();
}
collection.addFilter(
filter.name(),
name,
condition,
filter.deduceAliasInjectionPoints(),
toAliasTableMap( filter.aliases() ),
@ -1817,31 +1809,32 @@ public abstract class CollectionBinder {
);
}
else {
throw new AnnotationException(
"Illegal use of @FilterJoinTable on an association without join table: "
+ qualify( propertyHolder.getPath(), propertyName )
);
throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName )
+ "' is an association with no join table and may not have a '@FilterJoinTable'" );
}
}
private String getCondition(Filter filter) {
//set filtering
String name = filter.name();
String cond = filter.condition();
return getCondition( cond, name );
}
private String getCondition(String cond, String name) {
if ( isEmptyAnnotationValue( cond ) ) {
cond = buildingContext.getMetadataCollector().getFilterDefinition( name ).getDefaultFilterCondition();
if ( isEmpty( cond ) ) {
throw new AnnotationException(
"no filter condition found for filter " + name + " in "
+ qualify( propertyHolder.getPath(), propertyName )
);
final String condition = filter.condition();
if ( isEmptyAnnotationValue( condition ) ) {
final String name = filter.name();
final FilterDefinition definition = buildingContext.getMetadataCollector().getFilterDefinition( name );
if ( definition == null ) {
throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName )
+ "' has a '@Filter' for an undefined filter named '" + name + "'" );
}
final String defaultCondition = definition.getDefaultFilterCondition();
if ( isEmpty( defaultCondition ) ) {
throw new AnnotationException( "Collection '" + qualify( propertyHolder.getPath(), propertyName ) +
"' has a '@Filter' with no 'condition' and no default condition was given by the '@FilterDef' named '"
+ name + "'" );
}
return defaultCondition;
}
else {
return condition;
}
return cond;
}
public void setCache(Cache cacheAnn) {
@ -2057,7 +2050,7 @@ public abstract class CollectionBinder {
AnnotatedJoinColumn[] inverseJoinColumns,
AnnotatedColumn[] elementColumns,
boolean isEmbedded,
XClass collType,
XClass elementType,
NotFoundAction notFoundAction,
boolean unique,
boolean cascadeDeleteEnabled,
@ -2070,7 +2063,7 @@ public abstract class CollectionBinder {
throw new IllegalArgumentException( "null was passed for argument property" );
}
final PersistentClass collectionEntity = persistentClasses.get( collType.getName() );
final PersistentClass collectionEntity = persistentClasses.get( elementType.getName() );
final String hqlOrderBy = extractHqlOrderBy( jpaOrderBy );
boolean isCollectionOfEntities = collectionEntity != null;
@ -2081,7 +2074,7 @@ public abstract class CollectionBinder {
detectManyToManyProblems(
collValue,
joinColumns,
collType,
elementType,
property,
parentPropertyHolder,
isCollectionOfEntities,
@ -2092,7 +2085,7 @@ public abstract class CollectionBinder {
handleUnownedManyToMany(
collValue,
joinColumns,
collType,
elementType,
collectionEntity,
isCollectionOfEntities
);
@ -2125,7 +2118,7 @@ public abstract class CollectionBinder {
if ( isCollectionOfEntities ) {
element = handleCollectionOfEntities(
collValue,
collType,
elementType,
notFoundAction,
property,
buildingContext,
@ -2147,7 +2140,7 @@ public abstract class CollectionBinder {
collValue,
elementColumns,
isEmbedded,
collType,
elementType,
property,
parentPropertyHolder,
buildingContext,
@ -2164,12 +2157,19 @@ public abstract class CollectionBinder {
}
private void handleElementCollection(Collection collValue, AnnotatedColumn[] elementColumns, boolean isEmbedded, XClass collType, XProperty property, PropertyHolder parentPropertyHolder, MetadataBuildingContext buildingContext, String hqlOrderBy) {
private void handleElementCollection(
Collection collValue,
AnnotatedColumn[] elementColumns,
boolean isEmbedded,
XClass elementType,
XProperty property,
PropertyHolder parentPropertyHolder,
MetadataBuildingContext buildingContext,
String hqlOrderBy) {
XClass elementClass;
AnnotatedClassType classType;
CollectionPropertyHolder holder;
if ( PRIMITIVE_NAMES.contains( collType.getName() ) ) {
if ( PRIMITIVE_NAMES.contains( elementType.getName() ) ) {
classType = AnnotatedClassType.NONE;
elementClass = null;
@ -2183,7 +2183,7 @@ public abstract class CollectionBinder {
);
}
else {
elementClass = collType;
elementClass = elementType;
classType = buildingContext.getMetadataCollector().getClassType( elementClass );
holder = PropertyHolderBuilder.buildPropertyHolder(
@ -2276,7 +2276,7 @@ public abstract class CollectionBinder {
final BasicValueBinder elementBinder =
new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext);
elementBinder.setReturnedClassName( collType.getName() );
elementBinder.setReturnedClassName( elementType.getName() );
if ( elementColumns == null || elementColumns.length == 0 ) {
elementColumns = new AnnotatedColumn[1];
AnnotatedColumn column = new AnnotatedColumn();
@ -2313,16 +2313,15 @@ public abstract class CollectionBinder {
private ManyToOne handleCollectionOfEntities(
Collection collValue,
XClass collType,
XClass elementType,
NotFoundAction notFoundAction,
XProperty property,
MetadataBuildingContext buildingContext,
PersistentClass collectionEntity,
String hqlOrderBy) {
ManyToOne element;
element = new ManyToOne(buildingContext, collValue.getCollectionTable() );
ManyToOne element = new ManyToOne( buildingContext, collValue.getCollectionTable() );
collValue.setElement( element );
element.setReferencedEntityName( collType.getName() );
element.setReferencedEntityName( elementType.getName() );
//element.setFetchMode( fetchMode );
//element.setLazy( fetchMode != FetchMode.JOIN );
//make the second join non lazy
@ -2331,9 +2330,7 @@ public abstract class CollectionBinder {
element.setNotFoundAction( notFoundAction );
// as per 11.1.38 of JPA 2.0 spec, default to primary key if no column is specified by @OrderBy.
if ( hqlOrderBy != null ) {
collValue.setManyToManyOrdering(
buildOrderByClauseFromHql(hqlOrderBy, collectionEntity)
);
collValue.setManyToManyOrdering( buildOrderByClauseFromHql( hqlOrderBy, collectionEntity ) );
}
final ForeignKey fk = property.getAnnotation( ForeignKey.class );
@ -2366,7 +2363,12 @@ public abstract class CollectionBinder {
return element;
}
private void handleManyToAny(Collection collValue, AnnotatedJoinColumn[] inverseJoinColumns, boolean cascadeDeleteEnabled, XProperty property, MetadataBuildingContext buildingContext) {
private void handleManyToAny(
Collection collValue,
AnnotatedJoinColumn[] inverseJoinColumns,
boolean cascadeDeleteEnabled,
XProperty property,
MetadataBuildingContext buildingContext) {
//@ManyToAny
//Make sure that collTyp is never used during the @ManyToAny branch: it will be set to void.class
final PropertyData inferredData = new PropertyInferredData(
@ -2473,17 +2475,13 @@ public abstract class CollectionBinder {
private void handleUnownedManyToMany(
Collection collValue,
AnnotatedJoinColumn[] joinColumns,
XClass collType,
XClass elementType,
PersistentClass collectionEntity,
boolean isCollectionOfEntities) {
if ( !isCollectionOfEntities) {
throw new AnnotationException(
"Collection of elements must not have mappedBy or association reference an unmapped entity: " +
collValue.getOwnerEntityName() +
"." +
joinColumns[0].getPropertyName()
);
throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
}
Property otherSideProperty;
@ -2491,14 +2489,12 @@ public abstract class CollectionBinder {
otherSideProperty = collectionEntity.getRecursiveProperty( joinColumns[0].getMappedBy() );
}
catch (MappingException e) {
throw new AnnotationException(
"mappedBy references an unknown target entity property: "
+ collType + "." + joinColumns[0].getMappedBy() + " in "
+ collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName()
);
throw new AnnotationException( "Association '" + safeCollectionRole() +
"is 'mappedBy' a property named '" + mappedBy
+ "' which does not exist in the target entity '" + elementType.getName() + "'" );
}
Table table = otherSideProperty.getValue() instanceof Collection
? ((Collection) otherSideProperty.getValue()).getCollectionTable()
? ( (Collection) otherSideProperty.getValue() ).getCollectionTable()
: otherSideProperty.getValue().getTable();
//this is a collection on the other side
//This is a ToOne with a @JoinTable or a regular property
@ -2513,7 +2509,7 @@ public abstract class CollectionBinder {
private void detectManyToManyProblems(
Collection collValue,
AnnotatedJoinColumn[] joinColumns,
XClass collType,
XClass elementType,
XProperty property,
PropertyHolder parentPropertyHolder,
boolean isCollectionOfEntities,
@ -2521,26 +2517,21 @@ public abstract class CollectionBinder {
if ( !isCollectionOfEntities) {
if ( property.isAnnotationPresent( ManyToMany.class ) || property.isAnnotationPresent( OneToMany.class ) ) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
throw new AnnotationException(
"Use of @OneToMany or @ManyToMany targeting an unmapped class: " + path + "[" + collType + "]"
);
throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
}
else if (isManyToAny) {
if ( parentPropertyHolder.getJoinTable(property) == null ) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
throw new AnnotationException(
"@JoinTable is mandatory when @ManyToAny is used: " + path
);
if ( parentPropertyHolder.getJoinTable( property ) == null ) {
throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' is a '@ManyToAny' and must specify a '@JoinTable'" );
}
}
else {
JoinTable joinTableAnn = parentPropertyHolder.getJoinTable(property);
JoinTable joinTableAnn = parentPropertyHolder.getJoinTable( property );
if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0 ) {
String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
throw new AnnotationException(
"Use of @JoinTable.inverseJoinColumns targeting an unmapped class: " + path + "[" + collType + "]"
);
throw new AnnotationException( "Association '" + safeCollectionRole()
+ " has a '@JoinTable' with 'inverseJoinColumns' and targets the type '"
+ elementType.getName() + "' which is not an '@Entity' type" );
}
}
}
@ -2654,7 +2645,8 @@ public abstract class CollectionBinder {
);
}
catch (AnnotationException ex) {
throw new AnnotationException( "Unable to map collection " + collValue.getOwner().getClassName() + "." + property.getName(), ex );
throw new AnnotationException( "Unable to map collection "
+ collValue.getOwner().getClassName() + "." + property.getName(), ex );
}
DependantValue key = buildCollectionKey( collValue, joinColumns, cascadeDeleteEnabled,
buildingContext.getBuildingOptions().isNoConstraintByDefault(), property, propertyHolder, buildingContext );
@ -2669,7 +2661,7 @@ public abstract class CollectionBinder {
this.cascadeDeleteEnabled = onDeleteCascade;
}
private String safeCollectionRole() {
String safeCollectionRole() {
return propertyHolder != null ? propertyHolder.getEntityName() + "." + propertyName : "";
}

View File

@ -261,7 +261,7 @@ public class EntityBinder {
final InheritanceState.ElementsToProcess elementsToProcess = inheritanceState.getElementsToProcess();
inheritanceState.postProcess( persistentClass, entityBinder );
Set<String> idPropertiesIfIdClass = handleIdClass(
final Set<String> idPropertiesIfIdClass = handleIdClass(
persistentClass,
inheritanceState,
context,
@ -361,7 +361,7 @@ public class EntityBinder {
final XClass classWithIdClass = inheritanceState.getClassWithIdClass( false );
if ( classWithIdClass != null ) {
final IdClass idClass = classWithIdClass.getAnnotation( IdClass.class );
//noinspection unchecked
@SuppressWarnings("unchecked")
final XClass compositeClass = context.getBootstrapContext().getReflectionManager().toXClass( idClass.value() );
final PropertyData inferredData = new PropertyPreloadedData(
entityBinder.getPropertyAccessType(), "id", compositeClass
@ -502,18 +502,14 @@ public class EntityBinder {
MetadataBuildingContext buildingContext,
Map<XClass, InheritanceState> inheritanceStatePerClass) {
/*
* Fill simple value and property since and Id is a property
*/
PersistentClass persistentClass = propertyHolder.getPersistentClass();
// Fill simple value and property since and Id is a property
final PersistentClass persistentClass = propertyHolder.getPersistentClass();
if ( !(persistentClass instanceof RootClass) ) {
throw new AnnotationException(
"Unable to define/override @Id(s) on a subclass: "
+ propertyHolder.getEntityName()
);
throw new AnnotationException( "Entity '" + persistentClass.getEntityName()
+ "' is a subclass in an entity inheritance hierarchy and may not redefine the identifier of the root entity" );
}
RootClass rootClass = (RootClass) persistentClass;
Component id = AnnotationBinder.fillComponent(
final RootClass rootClass = (RootClass) persistentClass;
final Component id = AnnotationBinder.fillComponent(
propertyHolder,
inferredData,
baseInferredData,
@ -530,10 +526,13 @@ public class EntityBinder {
);
id.setKey( true );
if ( rootClass.getIdentifier() != null ) {
throw new AnnotationException( id.getComponentClassName() + " must not have @Id properties when used as an @EmbeddedId" );
throw new AssertionFailure( "Entity '" + persistentClass.getEntityName()
+ "' has an '@IdClass' and may not have an identifier property" );
}
if ( id.getPropertySpan() == 0 ) {
throw new AnnotationException( id.getComponentClassName() + " has no persistent id property" );
throw new AnnotationException( "Class '" + id.getComponentClassName()
+ " is the '@IdClass' for the entity '" + persistentClass.getEntityName()
+ "' but has no persistent properties" );
}
rootClass.setIdentifier( id );
@ -927,19 +926,18 @@ public class EntityBinder {
InheritanceState.ElementsToProcess elementsToProcess,
Map<XClass, InheritanceState> inheritanceStatePerClass) {
Set<String> missingIdProperties = new HashSet<>( idPropertiesIfIdClass );
final Set<String> missingIdProperties = new HashSet<>( idPropertiesIfIdClass );
for ( PropertyData propertyAnnotatedElement : elementsToProcess.getElements() ) {
String propertyName = propertyAnnotatedElement.getPropertyName();
if ( !idPropertiesIfIdClass.contains( propertyName ) ) {
boolean subclassAndSingleTableStrategy =
inheritanceState.getType() == InheritanceType.SINGLE_TABLE
&& inheritanceState.hasParents();
Nullability nullability = subclassAndSingleTableStrategy
? Nullability.FORCED_NULL
: Nullability.NO_CONSTRAINT;
AnnotationBinder.processElementAnnotations(
propertyHolder,
nullability,
subclassAndSingleTableStrategy
? Nullability.FORCED_NULL
: Nullability.NO_CONSTRAINT,
propertyAnnotatedElement,
classGenerators,
entityBinder,
@ -956,15 +954,16 @@ public class EntityBinder {
}
if ( missingIdProperties.size() != 0 ) {
StringBuilder missings = new StringBuilder();
final StringBuilder missings = new StringBuilder();
for ( String property : missingIdProperties ) {
missings.append( property ).append( ", " );
if ( missings.length() > 0 ) {
missings.append(", ");
}
missings.append("'").append( property ).append( "'" );
}
throw new AnnotationException(
"Unable to find properties ("
+ missings.substring( 0, missings.length() - 2 )
+ ") in entity annotated with @IdClass:" + persistentClass.getEntityName()
);
throw new AnnotationException( "Entity '" + persistentClass.getEntityName()
+ "' has an '@IdClass' with properties " + missings
+ " which do not match properties of the entity class" );
}
}
@ -1293,10 +1292,15 @@ public class EntityBinder {
String condition = filter.condition();
if ( isEmptyAnnotationValue( condition ) ) {
final FilterDefinition definition = context.getMetadataCollector().getFilterDefinition( filterName );
condition = definition == null ? null : definition.getDefaultFilterCondition();
if ( definition == null ) {
throw new AnnotationException( "Entity '" + name
+ "' has a '@Filter' for an undefined filter named '" + filterName + "'" );
}
condition = definition.getDefaultFilterCondition();
if ( isEmpty( condition ) ) {
throw new AnnotationException( "no filter condition found for filter "
+ filterName + " in " + this.name );
throw new AnnotationException( "Entity '" + name +
"' has a '@Filter' with no 'condition' and no default condition was given by the '@FilterDef' named '"
+ filterName + "'" );
}
}
persistentClass.addFilter(
@ -1330,7 +1334,8 @@ public class EntityBinder {
if ( persisterAnn != null ) {
Class clazz = persisterAnn.impl();
if ( !EntityPersister.class.isAssignableFrom(clazz) ) {
throw new AnnotationException( "persister class does not implement EntityPersister: " + clazz.getName() );
throw new AnnotationException( "Persister class '" + clazz.getName()
+ "' does not implement EntityPersister" );
}
persistentClass.setEntityPersisterClass( clazz );
}
@ -1366,9 +1371,8 @@ public class EntityBinder {
persistentClass.setDiscriminatorValue( name );
}
else if ( "character".equals( discriminator.getType().getName() ) ) {
throw new AnnotationException(
"Using default @DiscriminatorValue for a discriminator of type CHAR is not safe"
);
throw new AnnotationException( "Entity '" + name
+ "' has a discriminator of character type and must specify its '@DiscriminatorValue'" );
}
else if ( "integer".equals( discriminator.getType().getName() ) ) {
persistentClass.setDiscriminatorValue( String.valueOf( name.hashCode() ) );
@ -1528,9 +1532,8 @@ public class EntityBinder {
case "non-lazy":
return false;
default:
throw new AnnotationException( "Unknown @Cache.include value [" + effectiveCache.include() + "] : "
+ annotatedClass.getName()
);
throw new AnnotationException( "Class '" + annotatedClass.getName()
+ "' has a '@Cache' with undefined option 'include=\"" + effectiveCache.include() + "\"'" );
}
}
@ -2070,7 +2073,7 @@ public class EntityBinder {
public void processComplementaryTableDefinitions(org.hibernate.annotations.Table table) {
//comment and index are processed here
if ( table == null ) return;
String appliedTable = table.appliesTo();
final String appliedTable = table.appliesTo();
Table hibTable = null;
for ( Table pcTable : persistentClass.getTableClosure() ) {
if ( pcTable.getQuotedName().equals( appliedTable ) ) {
@ -2089,9 +2092,9 @@ public class EntityBinder {
}
}
if ( hibTable == null ) {
throw new AnnotationException(
"@org.hibernate.annotations.Table references an unknown table: " + appliedTable
);
throw new AnnotationException( "Entity '" + name
+ "' has a '@org.hibernate.annotations.Table' annotation which 'appliesTo' an unknown table named '"
+ appliedTable + "'" );
}
if ( !isEmptyAnnotationValue( table.comment() ) ) {
hibTable.setComment( table.comment() );

View File

@ -16,7 +16,6 @@ import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.IdGeneratorResolverSecondPass;

View File

@ -22,7 +22,6 @@ import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.PropertyHolderBuilder;
import org.hibernate.cfg.SecondPass;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IndexBackref;
import org.hibernate.mapping.List;
@ -73,7 +72,7 @@ public class ListBinder extends CollectionBinder {
final AnnotatedJoinColumn[] mapKeyManyToManyColumns,
final boolean isEmbedded,
final XProperty property,
final XClass collType,
final XClass elementType,
final NotFoundAction notFoundAction,
final boolean unique,
final TableBinder assocTableBinder,
@ -84,7 +83,7 @@ public class ListBinder extends CollectionBinder {
throws MappingException {
bindStarToManySecondPass(
persistentClasses,
collType,
elementType,
fkJoinColumns,
keyColumns,
inverseColumns,
@ -96,12 +95,12 @@ public class ListBinder extends CollectionBinder {
notFoundAction,
buildingContext
);
bindIndex( property, collType, buildingContext );
bindIndex( property, elementType, buildingContext );
}
};
}
private void bindIndex(XProperty property, XClass collType, final MetadataBuildingContext buildingContext) {
private void bindIndex(XProperty property, XClass elementType, final MetadataBuildingContext buildingContext) {
final PropertyHolder valueHolder = PropertyHolderBuilder.buildPropertyHolder(
collection,
qualify( collection.getRole(), "key" ),
@ -120,7 +119,7 @@ public class ListBinder extends CollectionBinder {
final BasicValueBinder valueBinder = new BasicValueBinder( BasicValueBinder.Kind.LIST_INDEX, buildingContext );
valueBinder.setColumns( new AnnotatedColumn[] { indexColumn } );
valueBinder.setReturnedClassName( Integer.class.getName() );
valueBinder.setType( property, collType, null, null );
valueBinder.setType( property, elementType, null, null );
// valueBinder.setExplicitType( "integer" );
SimpleValue indexValue = valueBinder.make();
indexColumn.linkWithValue( indexValue );

View File

@ -24,7 +24,6 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.CollectionPropertyHolder;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.AnnotatedColumn;
@ -34,7 +33,6 @@ import org.hibernate.cfg.PropertyData;
import org.hibernate.cfg.PropertyPreloadedData;
import org.hibernate.cfg.SecondPass;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
@ -165,7 +163,7 @@ public class MapBinder extends CollectionBinder {
}
private void bindKeyFromAssociationTable(
XClass collType,
XClass elementType,
Map<String, PersistentClass> persistentClasses,
String mapKeyPropertyName,
XProperty property,
@ -176,17 +174,19 @@ public class MapBinder extends CollectionBinder {
String targetPropertyName) {
if ( mapKeyPropertyName != null ) {
//this is an EJB3 @MapKey
PersistentClass associatedClass = persistentClasses.get( collType.getName() );
if ( associatedClass == null ) throw new AnnotationException( "Associated class not found: " + collType );
PersistentClass associatedClass = persistentClasses.get( elementType.getName() );
if ( associatedClass == null ) {
throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
}
Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName );
if ( mapProperty == null ) {
throw new AnnotationException(
"Map key property not found: " + collType + "." + mapKeyPropertyName
);
throw new AnnotationException( "Map key property '" + mapKeyPropertyName
+ "' not found in target entity '" + associatedClass.getEntityName() + "'" );
}
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
// HHH-11005 - if InheritanceType.JOINED then need to find class defining the column
InheritanceState inheritanceState = inheritanceStatePerClass.get( collType );
InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType );
PersistentClass targetPropertyPersistentClass = InheritanceType.JOINED.equals( inheritanceState.getType() ) ?
mapProperty.getPersistentClass() :
associatedClass;

View File

@ -24,13 +24,11 @@ import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.PropertyPreloadedData;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.KeyValue;
@ -166,10 +164,9 @@ public class PropertyBinder {
private void validateBind() {
if ( property.isAnnotationPresent( Immutable.class ) ) {
throw new AnnotationException(
"@Immutable on property not allowed. " +
"Only allowed on entity level or on a collection."
);
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
+ "' may not be '@Immutable'"
+ " ('@Immutable' may only be applied to entities and collections)" );
}
if ( !declaringClassSet ) {
throw new AssertionFailure( "declaringClass has not been set before a bind" );
@ -292,12 +289,14 @@ public class PropertyBinder {
}
private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(XProperty property, XClass embeddableClass) {
final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation = property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class );
final org.hibernate.annotations.EmbeddableInstantiator propertyAnnotation =
property.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class );
if ( propertyAnnotation != null ) {
return propertyAnnotation.value();
}
final org.hibernate.annotations.EmbeddableInstantiator classAnnotation = embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class );
final org.hibernate.annotations.EmbeddableInstantiator classAnnotation =
embeddableClass.getAnnotation( org.hibernate.annotations.EmbeddableInstantiator.class );
if ( classAnnotation != null ) {
return classAnnotation.value();
}
@ -341,7 +340,9 @@ public class PropertyBinder {
NaturalId naturalId = property.getAnnotation(NaturalId.class);
if ( naturalId != null ) {
if ( !entityBinder.isRootEntity() ) {
throw new AnnotationException( "@NaturalId only valid on root entity (or its @MappedSuperclasses)" );
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
+ "' belongs to an entity subclass and may not be annotated '@NaturalId'" +
" (only a property of a root '@Entity' or a '@MappedSuperclass' may be a '@NaturalId')" );
}
if ( !naturalId.mutable() ) {
updatable = false;
@ -368,22 +369,16 @@ public class PropertyBinder {
private void validateOptimisticLock(OptimisticLock lockAnn) {
if ( lockAnn.excluded() ) {
if ( property.isAnnotationPresent(Version.class) ) {
throw new AnnotationException(
"@OptimisticLock(excluded=true) incompatible with @Version: "
+ qualify( holder.getPath(), name )
);
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@Version'" );
}
if ( property.isAnnotationPresent(Id.class) ) {
throw new AnnotationException(
"@OptimisticLock(excluded=true) incompatible with @Id: "
+ qualify( holder.getPath(), name )
);
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@Id'" );
}
if ( property.isAnnotationPresent(EmbeddedId.class) ) {
throw new AnnotationException(
"@OptimisticLock(excluded=true) incompatible with @EmbeddedId: "
+ qualify( holder.getPath(), name )
);
throw new AnnotationException("Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@OptimisticLock(excluded=true)' and '@EmbeddedId'" );
}
}
}
@ -409,25 +404,18 @@ public class PropertyBinder {
*/
private ValueGeneration getValueGenerationFromAnnotations(XProperty property) {
AnnotationValueGeneration<?> valueGeneration = null;
for ( Annotation annotation : property.getAnnotations() ) {
AnnotationValueGeneration<?> candidate = getValueGenerationFromAnnotation( property, annotation );
if ( candidate != null ) {
if ( valueGeneration != null ) {
throw new AnnotationException(
"Only one generator annotation is allowed: " + qualify(
holder.getPath(),
name
)
);
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
+ "' has multiple 'ValueGenerationType' annotations" );
}
else {
valueGeneration = candidate;
}
}
}
return valueGeneration;
}
@ -439,7 +427,6 @@ public class PropertyBinder {
XProperty property,
A annotation) {
final ValueGenerationType generatorAnnotation = annotation.annotationType().getAnnotation( ValueGenerationType.class );
if ( generatorAnnotation == null ) {
return null;
}
@ -451,9 +438,9 @@ public class PropertyBinder {
&& property.isAnnotationPresent(Version.class)
&& valueGeneration.getGenerationTiming() == GenerationTiming.INSERT ) {
throw new AnnotationException(
"@Generated(INSERT) on a @Version property not allowed, use ALWAYS (or NEVER): "
+ qualify( holder.getPath(), name )
throw new AnnotationException( "Property '" + qualify( holder.getPath(), name )
+ "' is annotated '@Generated(INSERT)' and '@Version' (use '@Generated(ALWAYS)' instead)"
);
}

View File

@ -25,10 +25,8 @@ import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinitionBuilder;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateHints;
import org.hibernate.query.sql.internal.ParameterParser;
import org.hibernate.query.sql.spi.ParameterRecognizer;
@ -68,7 +66,7 @@ public abstract class QueryBinder {
}
if ( isEmptyAnnotationValue( queryAnn.name() ) ) {
throw new AnnotationException( "A named query must have a name when used in class or package level" );
throw new AnnotationException( "Class or package level '@NamedQuery' annotation must specify a 'name'" );
}
final String queryName = queryAnn.name();
@ -111,7 +109,7 @@ public abstract class QueryBinder {
}
if ( isEmptyAnnotationValue( queryAnn.name() ) ) {
throw new AnnotationException( "A named query must have a name when used in class or package level" );
throw new AnnotationException( "Class or package level '@NamedNativeQuery' annotation must specify a 'name'" );
}
final String registrationName = queryAnn.name();
@ -165,7 +163,7 @@ public abstract class QueryBinder {
//ResultSetMappingDefinition mappingDefinition = mappings.getJdbcValuesMappingProducer( queryAnn.resultSetMapping() );
if ( isEmptyAnnotationValue( registrationName ) ) {
throw new AnnotationException( "A named query must have a name when used in class or package level" );
throw new AnnotationException( "Class or package level '@NamedNativeQuery' annotation must specify a 'name'" );
}
final String resultSetMappingName = queryAnn.resultSetMapping();
@ -189,16 +187,11 @@ public abstract class QueryBinder {
.setComment( getAnnotationValueStringOrNull( queryAnn.comment() ) );
if ( queryAnn.callable() ) {
final NamedProcedureCallDefinition definition = createStoredProcedure(
builder, context,
() -> illegalCallSyntax(
queryAnn,
queryAnn.query()
)
);
final NamedProcedureCallDefinition definition =
createStoredProcedure( builder, context, () -> illegalCallSyntax( queryAnn ) );
context.getMetadataCollector().addNamedProcedureCallDefinition( definition );
DeprecationLogger.DEPRECATION_LOGGER.warn(
"Marking named native queries as callable is no longer supported; use `@jakarta.persistence.NamedStoredProcedureQuery` instead. Ignoring."
"Marking named native queries as callable is no longer supported; use '@jakarta.persistence.NamedStoredProcedureQuery' instead. Ignoring."
);
}
else {
@ -343,7 +336,7 @@ public abstract class QueryBinder {
//ResultSetMappingDefinition mappingDefinition = mappings.getJdbcValuesMappingProducer( queryAnn.resultSetMapping() );
if ( isEmptyAnnotationValue( registrationName ) ) {
throw new AnnotationException( "A named query must have a name when used in class or package level" );
throw new AnnotationException( "Class or package level '@NamedQuery' annotation must specify a 'name'" );
}
@ -432,7 +425,7 @@ public abstract class QueryBinder {
final String registrationName = annotation.name();
if ( isEmptyAnnotationValue( registrationName ) ) {
throw new AnnotationException( "A named query must have a name when used in class or package level" );
throw new AnnotationException( "Class or package level '@NamedStoredProcedureQuery' annotation must specify a 'name'" );
}
final NamedProcedureCallDefinitionImpl def = new NamedProcedureCallDefinitionImpl( annotation );
@ -537,15 +530,8 @@ public abstract class QueryBinder {
return i;
}
private static AnnotationException illegalCallSyntax(
org.hibernate.annotations.NamedNativeQuery queryAnn,
String sqlString) {
return new AnnotationException(
String.format(
"Callable named native query [%s] doesn't use the JDBC call syntax: %s",
queryAnn.name(),
sqlString
)
);
private static AnnotationException illegalCallSyntax(org.hibernate.annotations.NamedNativeQuery queryAnn) {
return new AnnotationException( "Callable 'NamedNativeQuery' named '" + queryAnn.name()
+ "' does not use the JDBC call syntax" );
}
}

View File

@ -22,7 +22,6 @@ import org.hibernate.boot.model.naming.NamingStrategyHelper;
import org.hibernate.boot.model.source.spi.AttributePath;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.IndexOrUniqueKeySecondPass;
import org.hibernate.cfg.JPAIndexHolder;
@ -30,7 +29,6 @@ import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
@ -546,10 +544,8 @@ public class TableBinder {
}
final String mappedByProperty = columns[0].getMappedBy();
if ( isNotEmpty( mappedByProperty ) ) {
/*
* Get the columns of the mapped-by property
* copy them and link the copy to the actual value
*/
// Get the columns of the mapped-by property
// copy them and link the copy to the actual value
LOG.debugf( "Retrieving property %s.%s", associatedClass.getEntityName(), mappedByProperty );
final Value propertyVal = associatedClass.getRecursiveProperty( columns[0].getMappedBy() ).getValue();
@ -558,8 +554,9 @@ public class TableBinder {
Value element = ((Collection) propertyVal).getElement();
if ( element == null ) {
throw new AnnotationException(
"Illegal use of mappedBy on both sides of the relationship: "
"Both sides of the bidirectional association '"
+ associatedClass.getEntityName() + "." + mappedByProperty
+ "' specify 'mappedBy'"
);
}
mappedByColumns = element.getColumns();
@ -573,10 +570,8 @@ public class TableBinder {
}
}
else if ( columns[0].isImplicit() ) {
/*
* if columns are implicit, then create the columns based on the
* referenced entity id columns
*/
// if columns are implicit, then create the columns based on the
// referenced entity id columns
List<Column> idColumns = referencedEntity instanceof JoinedSubclass
? referencedEntity.getKey().getColumns()
: referencedEntity.getIdentifier().getColumns();
@ -600,7 +595,7 @@ public class TableBinder {
referencedPropertyName = collection.getReferencedPropertyName();
}
else {
throw new AnnotationException( "SecondaryTable JoinColumn cannot reference a non primary key" );
throw new AnnotationException( "The '@JoinColumn' for a secondary table must reference the primary key" );
}
}
@ -621,9 +616,7 @@ public class TableBinder {
"Cannot find synthProp: " + referencedEntity.getEntityName() + "." + referencedPropertyName
);
}
linkJoinColumnWithValueOverridingNameIfImplicit(
referencedEntity, synthProp.getValue(), columns, value
);
linkJoinColumnWithValueOverridingNameIfImplicit( referencedEntity, synthProp.getValue(), columns, value );
if ( value instanceof SortableValue ) {
( (SortableValue) value ).sortProperties();
}
@ -633,10 +626,10 @@ public class TableBinder {
//implicit case, we hope PK and FK columns are in the same order
if ( columns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
throw new AnnotationException(
"A Foreign key referring " + referencedEntity.getEntityName()
+ " from " + associatedClass.getEntityName()
+ " has the wrong number of column. should be " + referencedEntity.getIdentifier()
.getColumnSpan()
"A foreign key that references '" + referencedEntity.getEntityName()
+ "' from entity '" + associatedClass.getEntityName()
+ "' has " + columns.length + " columns but the primary key has "
+ referencedEntity.getIdentifier().getColumnSpan() + " columns"
);
}
linkJoinColumnWithValueOverridingNameIfImplicit(
@ -667,7 +660,7 @@ public class TableBinder {
boolean match = false;
//for each PK column, find the associated FK column.
final String colName = col.getQuotedName(dialect);
for (AnnotatedJoinColumn joinCol : columns) {
for ( AnnotatedJoinColumn joinCol : columns ) {
String referencedColumn = joinCol.getReferencedColumn();
referencedColumn = buildingContext.getMetadataCollector().getPhysicalColumnName(
referencedEntity.getTable(),

View File

@ -119,12 +119,11 @@ public final class EventType<T> {
*
* @throws HibernateException If eventName is null, or if eventName does not correlate to any known event type.
*/
@SuppressWarnings("rawtypes")
public static EventType resolveEventTypeByName(final String eventName) {
public static EventType<?> resolveEventTypeByName(final String eventName) {
if ( eventName == null ) {
throw new HibernateException( "event name to resolve cannot be null" );
}
final EventType eventType = STANDARD_TYPE_BY_NAME_MAP.get( eventName );
final EventType<?> eventType = STANDARD_TYPE_BY_NAME_MAP.get( eventName );
if ( eventType == null ) {
throw new HibernateException( "Unable to locate proper event type for event name [" + eventName + "]" );
}

View File

@ -78,7 +78,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
// incoming "configuration" values
private String explicitTypeName;
private Map<Object,Object> explicitLocalTypeParams;
private Map<String,String> explicitLocalTypeParams;
private Function<TypeConfiguration, BasicJavaType> explicitJavaTypeAccess;
private Function<TypeConfiguration, JdbcType> explicitJdbcTypeAccess;
@ -117,7 +117,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
this.explicitTypeName = original.explicitTypeName;
this.explicitLocalTypeParams = original.explicitLocalTypeParams == null
? null
: new HashMap(original.explicitLocalTypeParams);
: new HashMap<>(original.explicitLocalTypeParams);
this.explicitJavaTypeAccess = original.explicitJavaTypeAccess;
this.explicitJdbcTypeAccess = original.explicitJdbcTypeAccess;
this.explicitMutabilityPlanAccess = original.explicitMutabilityPlanAccess;
@ -264,11 +264,11 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
return;
}
throw new IllegalStateException(
"BasicValue [" + ownerName + "." + propertyName +
"] already had column associated: `" + column.getText() +
"` -> `" + incomingColumn.getText() + "`"
);
// throw new IllegalStateException(
// "BasicValue [" + ownerName + "." + propertyName +
// "] already had column associated: `" + column.getText() +
// "` -> `" + incomingColumn.getText() + "`"
// );
}
@Override
@ -665,8 +665,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
name,
typeNamedClass,
null,
null,
typeConfiguration
null
);
context.getTypeDefinitionRegistry().register( implicitDefinition );
return implicitDefinition.resolve(
@ -754,7 +753,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
return typeConfiguration;
}
public void setExplicitTypeParams(Map<Object,Object> explicitLocalTypeParams) {
public void setExplicitTypeParams(Map<String,String> explicitLocalTypeParams) {
this.explicitLocalTypeParams = explicitLocalTypeParams;
}
@ -772,7 +771,6 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
.getServiceRegistry()
.getService( ClassLoaderService.class );
try {
//noinspection rawtypes
final Class<AttributeConverter<?,?>> converterClass = cls.classForName( converterClassName );
setAttributeConverterDescriptor( new ClassBasedConverterDescriptor(
converterClass,

View File

@ -196,18 +196,10 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn
return object instanceof Column && equals( (Column) object );
}
@SuppressWarnings("SimplifiableIfStatement")
public boolean equals(Column column) {
if ( null == column ) {
return false;
}
if ( this == column ) {
return true;
}
return isQuoted() ?
name.equals( column.name ) :
name.equalsIgnoreCase( column.name );
return column != null && (
this == column || isQuoted() ? name.equals( column.name ) : name.equalsIgnoreCase( column.name )
);
}
public int getSqlTypeCode(Mapping mapping) throws MappingException {

View File

@ -33,6 +33,7 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.jpa.event.spi.CallbackDefinition;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.Alias;
import org.hibernate.type.Type;
/**
* Mapping for an entity.
@ -704,11 +705,14 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
public void validate(Mapping mapping) throws MappingException {
for ( Property prop : getProperties() ) {
if ( !prop.isValid( mapping ) ) {
Type type = prop.getType();
int actualColumns = prop.getColumnSpan();
int requiredColumns = type.getColumnSpan(mapping);
throw new MappingException(
"property mapping has wrong number of columns: " +
StringHelper.qualify( getEntityName(), prop.getName() ) +
" type: " +
prop.getType().getName()
"Property '" + StringHelper.qualify( getEntityName(), prop.getName() )
+ "' maps to " + actualColumns + " columns but " + requiredColumns
+ " columns are required (type '" + type.getName()
+ "' spans " + requiredColumns + " columns)"
);
}
}
@ -1001,11 +1005,9 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
Column col = (Column) columnOrFormula;
if ( !distinctColumns.add( col.getName() ) ) {
throw new MappingException(
"Repeated column in mapping for entity: " +
getEntityName() +
" column: " +
col.getName() +
" (should be mapped with insert=\"false\" update=\"false\")"
"Column '" + col.getName()
+ "' is duplicated in mapping for entity '" + getEntityName()
+ "' (use '@Column(insertable=false, updatable=false)' when mapping multiple properties to the same column)"
);
}
}
@ -1014,14 +1016,15 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl
protected void checkPropertyColumnDuplication(Set<String> distinctColumns, List<Property> properties)
throws MappingException {
for (Property prop : properties) {
if ( prop.getValue() instanceof Component ) { //TODO: remove use of instanceof!
Component component = (Component) prop.getValue();
for ( Property prop : properties ) {
Value value = prop.getValue();
if ( value instanceof Component ) {
Component component = (Component) value;
checkPropertyColumnDuplication( distinctColumns, component.getProperties() );
}
else {
if ( prop.isUpdateable() || prop.isInsertable() ) {
checkColumnDuplication( distinctColumns, prop.getValue() );
checkColumnDuplication( distinctColumns, value);
}
}
}

View File

@ -14,7 +14,7 @@ import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl;
import org.hibernate.property.access.internal.PropertyAccessStrategyNoopImpl;
/**
* Describes the built-in externally-nameable PropertyAccessStrategy implementations.
* Describes the built-in externally-nameable {@link PropertyAccessStrategy} implementations.
*
* @author Steve Ebersole
*/
@ -24,8 +24,7 @@ public enum BuiltInPropertyAccessStrategies {
MIXED( "mixed", PropertyAccessStrategyMixedImpl.INSTANCE ),
MAP( "map", PropertyAccessStrategyMapImpl.INSTANCE ),
EMBEDDED( "embedded", PropertyAccessStrategyEmbeddedImpl.INSTANCE ),
NOOP( "noop", PropertyAccessStrategyNoopImpl.INSTANCE )
;
NOOP( "noop", PropertyAccessStrategyNoopImpl.INSTANCE );
private final String externalName;
private final PropertyAccessStrategy strategy;
@ -44,22 +43,11 @@ public enum BuiltInPropertyAccessStrategies {
}
public static BuiltInPropertyAccessStrategies interpret(String name) {
if ( BASIC.externalName.equals( name ) ) {
return BASIC;
for ( BuiltInPropertyAccessStrategies strategy : values() ) {
if ( strategy.externalName.equals( name ) ) {
return strategy;
}
}
else if ( FIELD.externalName.equals( name ) ) {
return FIELD;
}
else if ( MAP.externalName.equals( name ) ) {
return MAP;
}
else if ( EMBEDDED.externalName.equals( name ) ) {
return EMBEDDED;
}
else if ( NOOP.externalName.equals( name ) ) {
return NOOP;
}
return null;
}
}

View File

@ -34,7 +34,7 @@ public class AttributeAccessorBinder implements AttributeBinder<AttributeAccesso
property.setPropertyAccessorName( type.getName() );
}
else {
throw new AnnotationException("@AttributeAccessor must specify a PropertyAccessStrategy type");
throw new AnnotationException("'@AttributeAccessor' annotation must specify a 'strategy'");
}
}

View File

@ -7,15 +7,14 @@
package org.hibernate.usertype;
import java.lang.annotation.Annotation;
import java.util.Properties;
/**
* Types who implements this interface will have in the setParameterValues an
* instance of the class DynamicParameterizedType$ParameterType instead of
* the key PARAMETER_TYPE = "org.hibernate.type.ParameterType"
*
* The interface ParameterType provides some methods to read information
* dynamically for build the type
*
* Types which implement this interface will have
* {@link ParameterizedType#setParameterValues(Properties)} called with an
* instance of the class {@link DynamicParameterizedType.ParameterType}
* instead of the key {@value PARAMETER_TYPE}.
*
* @author Janario Oliveira
*/
public interface DynamicParameterizedType extends ParameterizedType {

View File

@ -9,10 +9,10 @@ package org.hibernate.usertype;
import java.util.Properties;
/**
* Support for parameterizable types. A UserType or CustomUserType may be
* made parameterizable by implementing this interface. Parameters for a
* type may be set by using a nested type element for the property element
* in the mapping file, or by defining a typedef.
* Support for parameterizable types. A {@link UserType} or {@link UserCollectionType}
* may be made parameterizable by implementing this interface. Parameters for a type
* may be set by using a nested type element for the property element in the mapping
* file, or by defining a typedef.
*
* @author Michael Gloegl
*/

View File

@ -16,8 +16,8 @@ import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware;
/**
* Convenience UserType implementation to mimic the legacy `@Type` annotation
* which based on the {@code hbm.xml} mapping's String-based type support
* Convenience {@link UserType} implementation which mimics the legacy <code>@Type</code>
* annotation which was based on the {@code hbm.xml} mapping's string-based type support.
*
* @see Type
*/

View File

@ -9,10 +9,8 @@ public class Dependent {
@EmbeddedId
DependentId id;
@JoinColumns({
@JoinColumn(name = "FIRSTNAME", referencedColumnName = "FIRSTNAME"),
@JoinColumn(name = "LASTNAME", referencedColumnName = "lastName")
})
@JoinColumn(name = "FIRSTNAME", referencedColumnName = "FIRSTNAME")
@JoinColumn(name = "LASTNAME", referencedColumnName = "lastName")
@MapsId("empPK")
@ManyToOne
Employee emp;

View File

@ -6,8 +6,8 @@ import java.io.Serializable;
@Embeddable
public class EmployeeId implements Serializable {
@Column(length = 32)
@Column(name="firstname", length = 32)
String firstName;
@Column(length = 32)
@Column(name="lastname", length = 32)
String lastName;
}

View File

@ -28,8 +28,8 @@ public abstract class AbstractEmbeddableWithManyToManyTest {
fail( "Should throw AnnotationException!" );
}
catch (AnnotationException expected) {
assertTrue( expected.getMessage().startsWith(
"@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection"
assertTrue( expected.getMessage().contains(
"belongs to an '@Embeddable' class that is contained in an '@ElementCollection' and may not be"
) );
}
}

View File

@ -16,7 +16,6 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@ -30,7 +29,8 @@ public class BasketItems implements Serializable {
@Id
@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
@JoinColumns({ @JoinColumn(name="basketDatetime", referencedColumnName="basketDatetime"), @JoinColumn(name="customerID", referencedColumnName="customerID") })
@JoinColumn(name="basketDatetime", referencedColumnName="basketDatetime")
@JoinColumn(name="customerID", referencedColumnName="customerID")
@Basic(fetch= FetchType.LAZY)
private ShoppingBaskets shoppingBaskets;

View File

@ -15,7 +15,6 @@ import jakarta.persistence.Embeddable;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
@Embeddable
@ -50,7 +49,8 @@ public class BasketItemsPK implements Serializable {
@Id
@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
@JoinColumns({ @JoinColumn(name="basketDatetime", referencedColumnName="basketDatetime"), @JoinColumn(name="customerID", referencedColumnName="customerID") })
@JoinColumn(name="basketDatetime", referencedColumnName="basketDatetime")
@JoinColumn(name="customerID", referencedColumnName="customerID")
@Basic(fetch= FetchType.LAZY)
private ShoppingBaskets shoppingBaskets;

View File

@ -16,7 +16,6 @@ import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@ -31,7 +30,7 @@ public class ShoppingBaskets implements Serializable {
@Id
@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
@JoinColumns({ @JoinColumn(name="customerID", referencedColumnName="customerID") })
@JoinColumn(name="customerID", referencedColumnName="customerID")
@Basic(fetch=FetchType.LAZY)
private Customers owner;

View File

@ -15,7 +15,6 @@ import jakarta.persistence.Embeddable;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
@Embeddable
@ -48,7 +47,7 @@ public class ShoppingBasketsPK implements Serializable {
@Id
@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
@JoinColumns({ @JoinColumn(name="customerID", referencedColumnName="customerID") })
@JoinColumn(name="customerID", referencedColumnName="customerID")
@Basic(fetch= FetchType.LAZY)
private Customers owner;

View File

@ -9,7 +9,6 @@ package org.hibernate.orm.test.annotations.index.jpa;
import java.util.List;
import java.util.Set;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.AttributeOverrides;
import jakarta.persistence.CascadeType;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.Column;
@ -28,8 +27,8 @@ import jakarta.persistence.Table;
*/
@Entity
@Table(indexes = {
@Index(unique = true, columnList = "brand, producer")
, @Index(name = "Car_idx", columnList = "since DESC")
@Index(unique = true, columnList = "brand, producer"),
@Index(name = "Car_idx", columnList = "since DESC")
})
@SecondaryTable(name = "T_DEALER", indexes = @Index(columnList = "dealer_name ASC, rate DESC"))
public class Car {
@ -38,10 +37,8 @@ public class Car {
private String brand;
private String producer;
private long since;
@AttributeOverrides({
@AttributeOverride(name = "name", column = @Column(name = "dealer_name", table = "T_DEALER")),
@AttributeOverride(name = "rate", column = @Column(table = "T_DEALER"))
})
@AttributeOverride(name = "name", column = @Column(name = "dealer_name", table = "T_DEALER"))
@AttributeOverride(name = "rate", column = @Column(table = "T_DEALER"))
@Embedded
private Dealer dealer;

View File

@ -397,7 +397,7 @@ public class OneToManyTest extends BaseNonConfigCoreFunctionalTestCase {
.build();
}
catch ( AnnotationException e ) {
assertTrue(e.getMessage().contains( "Unidirectional one-to-many associations annotated with @OnDelete must define @JoinColumn" ));
assertTrue(e.getMessage().contains( "is annotated '@OnDelete' and must explicitly specify a '@JoinColumn'" ));
}
finally {
StandardServiceRegistryBuilder.destroy( serviceRegistry );

View File

@ -73,7 +73,7 @@ public class OverrideOneToOneJoinColumnTest {
);
assertTrue(
ex.getMessage().startsWith( "Illegal attempt to define a @JoinColumn with a mappedBy association:" ),
ex.getMessage().contains( "is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'" ),
"Should disallow exactly because of @JoinColumn override on side with mappedBy"
);
}

View File

@ -23,7 +23,6 @@ import jakarta.persistence.Basic;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;
import jakarta.persistence.Table;
@ -47,7 +46,7 @@ public class SortAndOrderTests {
fail( "Expecting to fail" );
}
catch (AnnotationException expected) {
assertThat( expected ).hasMessageStartingWith( "Illegal combination of ordering and sorting annotations" );
assertThat( expected ).hasMessageContaining( "both sorted and ordered" );
}
}

View File

@ -63,8 +63,8 @@ public class UserWithUnimplementedCollectionTest extends BaseCoreFunctionalTestC
}
catch (Exception e) {
assertThat( e ).isInstanceOf( AnnotationException.class );
assertThat( e ).hasMessageStartingWith( "Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements:" );
assertThat( e ).hasMessageEndingWith( ".emailAddresses" );
assertThat( e ).hasMessageEndingWith( "is not a collection and may not be a '@OneToMany', '@ManyToMany', or '@ElementCollection'" );
assertThat( e ).hasMessageContaining( ".emailAddresses" );
}
}

View File

@ -16,7 +16,6 @@ import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MapsId;
import jakarta.persistence.Table;
@ -122,10 +121,8 @@ public class ColumnLengthTest extends BaseUnitTestCase {
@EmbeddedId
DependentId id;
@MapsId("empPK")
@JoinColumns({
@JoinColumn(name = "FK1", referencedColumnName = "first_name"),
@JoinColumn(name = "FK2", referencedColumnName = "last_name")
})
@JoinColumn(name = "FK1", referencedColumnName = "first_name")
@JoinColumn(name = "FK2", referencedColumnName = "last_name")
@ManyToOne
Employee emp;
}