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 @@
/**
* 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.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.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 @@
@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.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 @@
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.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 @@ private void buildRecursiveOrderedFkSecondPasses(
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 Identifier getUserProvidedIdentifier() {
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 Identifier getUserProvidedIdentifier() {
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 MappingDefaultsImpl(StandardServiceRegistry serviceRegistry) {
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 MetadataImpl(
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 void initSessionFactory(SessionFactoryImplementor sessionFactory) {
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 Map<String, FetchProfile> getFetchProfileMap() {
return fetchProfileMap;
}
public Map<Class, MappedSuperclass> getMappedSuperclassMap() {
public Map<Class<?>, MappedSuperclass> getMappedSuperclassMap() {
return mappedSuperclassMap;
}

View File

@ -57,24 +57,22 @@
* @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 String getName() {
return name;
}
public Class getTypeImplementorClass() {
public Class<?> getTypeImplementorClass() {
return typeImplementorClass;
}
@ -93,13 +91,13 @@ public String[] getRegistrationKeys() {
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 BasicValue.Resolution<?> resolve(
if ( reusableResolution == null ) {
reusableResolution = createResolution( name, Collections.emptyMap(), indicators, context );
}
return reusableResolution;
}
else {
@ -134,7 +131,7 @@ private BasicValue.Resolution<?> createResolution(
private static BasicValue.Resolution<?> createResolution(
String name,
Class<?> typeImplementorClass,
Properties parameters,
Map<?,?> parameters,
Map<?,?> usageSiteProperties,
JdbcTypeIndicators indicators,
MetadataBuildingContext context) {
@ -153,34 +150,32 @@ private static BasicValue.Resolution<?> createResolution(
( (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 Properties getCombinedTypeParameters() {
return combinedTypeParameters;
}
@Override
public JavaType<Object> getDomainJavaType() {
@Override @SuppressWarnings({"rawtypes", "unchecked"})
public JavaType getDomainJavaType() {
return resolvedBasicType.getMappedJavaType();
}
@ -210,8 +205,8 @@ public BasicValueConverter getValueConverter() {
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 MutabilityPlan<Object> getMutabilityPlan() {
.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 BasicValueConverter getValueConverter() {
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 @@ private static Object instantiateType(StandardServiceRegistry serviceRegistry,
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.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 void addRegistration(RegisteredConversion conversion, BootstrapContext co
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 @@ else if ( converterParamTypes.size() != 2 ) {
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 static List<ResolvedType> resolveConverterClassParamTypes(
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<?> getExplicitDomainType() {
return explicitDomainType;
}
public Class<?> getConverterType() {
public Class<? extends AttributeConverter<?,?>> getConverterType() {
return converterType;
}

View File

@ -21,8 +21,8 @@
* @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 @@
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 @@ private void bindAny(
private BasicType<?> resolveExplicitlyNamedAnyDiscriminatorType(
String typeName,
Properties parameters,
Map<String,String> parameters,
Any.MetaValue discriminatorMapping) {
final BootstrapContext bootstrapContext = metadataBuildingContext.getBootstrapContext();
@ -2431,7 +2430,9 @@ private BasicType<?> resolveExplicitlyNamedAnyDiscriminatorType(
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 @@ private static void bindSimpleValueType(
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 @@ private static TypeResolution resolveType(
}
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 Identifier getUserProvidedIdentifier() {
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 static void processTypeDefinition(
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 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.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 @@ protected void initMappingColumn(
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 Join getJoin() {
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 @@ private static jakarta.persistence.Column[] overrideColumns(
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 static void checkPropertyConsistency(AnnotatedColumn[] columns, String pr
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 @@ private static AnnotatedJoinColumn buildJoinColumn(
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 void setPersistentClass(
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 Identifier getReferencedColumnName() {
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 Identifier getReferencedColumnName() {
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 Identifier getReferencedColumnName() {
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 MetadataBuildingContext getBuildingContext() {
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 static int checkReferencedColumnsType(
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 static int checkReferencedColumnsType(
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 @@ private static void detectMappedSuperclassProblems(XClass clazzToProcess) {
//@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 @@ private static int addProperty(
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 static void processElementAnnotations(
}
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 @@ private static void bindVersionProperty(
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 @@ private static AnnotatedColumn[] bindBasic(
);
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 @@ private static AnnotatedColumn[] bindBasic(
isId,
inheritanceStatePerClass,
referencedEntityName,
propertyName,
determineCustomInstantiator( property, returnedClass, context ),
compositeUserType,
isOverridden ? (AnnotatedJoinColumn[]) columns : null
@ -1524,9 +1529,9 @@ private static void bindAny(
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 @@ private static void bindOneToOne(PropertyHolder propertyHolder, PropertyData inf
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 @@ private static void bindManyToOne(
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 @@ private static void processId(
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 @@ private static PropertyBinder bindComponent(
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 @@ private static PropertyBinder bindComponent(
SecondPass sp = new CopyIdentifierComponentSecondPass(
comp,
referencedEntityName,
propertyName,
columns,
buildingContext
);
@ -1972,16 +1980,18 @@ private static PropertyBinder bindComponent(
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 static Component fillComponent(
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 @@ else if ( fetch.value() == org.hibernate.annotations.FetchMode.SELECT ) {
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.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 static void makeIdGenerator(
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 static boolean isEmptyOrNullAnnotationValue(String annotationString) {
}
public static String getAnnotationValueStringOrNull(String value) {
return isEmptyOrNullAnnotationValue( value )
? null
: value;
return isEmptyOrNullAnnotationValue( value ) ? null : value;
}
public static Any buildAnyValue(
@ -1159,7 +1160,7 @@ static PropertyData getPropertyOverriddenByMapperOrMapsId(
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 @@ else if ( joinColumns == null &&
);
}
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 @@ AnnotatedJoinColumn[] buildDefaultJoinColumnsForXToOne(XProperty property, Prope
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 @@ else if ( property.isAnnotationPresent( JoinColumns.class ) ) {
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 @@ else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) {
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 String getEntityName() {
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 void addProperty(Property prop, AnnotatedColumn[] columns, XClass declari
}
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.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 boolean isInPrimaryKey() {
@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 @@ private Property createSimpleProperty(
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 @@ private void addConstraintToColumn(final String columnName ) {
);
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 ElementsToProcess getElementsToProcess() {
}
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 @@ private AccessType determineDefaultAccessType() {
}
}
}
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.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.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 void doSecondPass(Map<String, PersistentClass> persistentClasses) throws
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 void doSecondPass(Map<String, PersistentClass> persistentClasses) throws
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 @@ else if ( otherSideProperty.getValue() instanceof ManyToOne ) {
// 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 @@ else if ( otherSideProperty.getValue() instanceof ManyToOne ) {
}
}
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 boolean isInPrimaryKey() {
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 @@ public Iterable<XProperty> propertyIterator() {
}
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 @@ private AccessType determineLocalClassDefinedAccessStrategy() {
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 void doSecondPass(java.util.Map<String, PersistentClass> persistentClasse
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 @@
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 enum Kind {
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 void setType(
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 @@ private void applyExplicitType(Class<? extends UserType<?>> impl, Parameter[] pa
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 @@ private Map extractTypeParams(Parameter[] parameters) {
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 @@ private void prepareBasicAttribute(String declaringClassName, XProperty attribut
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 static void bindCollection(
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 @@ && isToManyAssociationWithinEmbeddableCollection(propertyHolder) ) {
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 @@ private static String handleTargetEntity(
//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 @@ private static JoinColumn[] mapKeyColumns(
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 @@ private static Class<?> determineSemanticJavaType(XProperty property) {
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 void setTableBinder(TableBinder tableBinder) {
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 void bind() {
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 void bind() {
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 @@ private void scheduleSecondPass(boolean isMappedBy, InFlightMetadataCollector me
mapKeyManyToManyColumns,
isEmbedded,
property,
getCollectionType(),
getElementType(),
notFoundAction,
oneToMany,
tableBinder,
@ -1190,8 +1178,9 @@ private void bindCustomPersister() {
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 @@ private void bindExplicitTypes() {
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 @@ private void detectMappedByProblem(boolean isMappedBy) {
&& 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 @@ private void instantiateComparator(Collection collection, Class<? extends Compar
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 @@ private AnnotationException buildIllegalOrderCombination() {
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 @@ private AnnotationException buildIllegalOrderAndSortCombination() {
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 @@ private AnnotationException buildIllegalOrderAndSortCombination() {
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 @@ else if ( manyToAny != null ) {
}
}
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 SecondPass getSecondPass(
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 SecondPass getSecondPass(
public void secondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
bindStarToManySecondPass(
persistentClasses,
collType,
elementType,
fkJoinColumns,
keyColumns,
inverseColumns,
@ -1526,7 +1521,7 @@ public void secondPass(Map<String, PersistentClass> persistentClasses) throws Ma
*/
protected boolean bindStarToManySecondPass(
Map<String, PersistentClass> persistentClasses,
XClass collType,
XClass elementType,
AnnotatedJoinColumn[] fkJoinColumns,
AnnotatedJoinColumn[] keyColumns,
AnnotatedJoinColumn[] inverseColumns,
@ -1537,23 +1532,17 @@ protected boolean bindStarToManySecondPass(
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 @@ protected boolean bindStarToManySecondPass(
getCollection(),
persistentClasses,
fkJoinColumns,
collType,
elementType,
cascadeDeleteEnabled,
notFoundAction,
buildingContext,
@ -1585,7 +1574,7 @@ protected boolean bindStarToManySecondPass(
inverseColumns,
elementColumns,
isEmbedded,
collType,
elementType,
notFoundAction,
unique,
cascadeDeleteEnabled,
@ -1784,8 +1773,8 @@ private void handleWhere(boolean hasAssociationTable) {
}
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 @@ private void handleWhere(boolean hasAssociationTable) {
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 @@ private void addFilter(boolean hasAssociationTable, FilterJoinTable filter) {
);
}
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 @@ private void bindManyToManySecondPass(
AnnotatedJoinColumn[] inverseJoinColumns,
AnnotatedColumn[] elementColumns,
boolean isEmbedded,
XClass collType,
XClass elementType,
NotFoundAction notFoundAction,
boolean unique,
boolean cascadeDeleteEnabled,
@ -2070,7 +2063,7 @@ private void bindManyToManySecondPass(
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 @@ private void bindManyToManySecondPass(
detectManyToManyProblems(
collValue,
joinColumns,
collType,
elementType,
property,
parentPropertyHolder,
isCollectionOfEntities,
@ -2092,7 +2085,7 @@ private void bindManyToManySecondPass(
handleUnownedManyToMany(
collValue,
joinColumns,
collType,
elementType,
collectionEntity,
isCollectionOfEntities
);
@ -2125,7 +2118,7 @@ private void bindManyToManySecondPass(
if ( isCollectionOfEntities ) {
element = handleCollectionOfEntities(
collValue,
collType,
elementType,
notFoundAction,
property,
buildingContext,
@ -2147,7 +2140,7 @@ else if ( isManyToAny ) {
collValue,
elementColumns,
isEmbedded,
collType,
elementType,
property,
parentPropertyHolder,
buildingContext,
@ -2164,12 +2157,19 @@ else if ( isManyToAny ) {
}
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 @@ private void handleElementCollection(Collection collValue, AnnotatedColumn[] ele
);
}
else {
elementClass = collType;
elementClass = elementType;
classType = buildingContext.getMetadataCollector().getClassType( elementClass );
holder = PropertyHolderBuilder.buildPropertyHolder(
@ -2276,7 +2276,7 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
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 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
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 @@ private ManyToOne handleCollectionOfEntities(
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 @@ private ManyToOne handleCollectionOfEntities(
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 @@ private void handleOwnedManyToMany(
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 @@ private void handleUnownedManyToMany(
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 @@ private void handleUnownedManyToMany(
private void detectManyToManyProblems(
Collection collValue,
AnnotatedJoinColumn[] joinColumns,
XClass collType,
XClass elementType,
XProperty property,
PropertyHolder parentPropertyHolder,
boolean isCollectionOfEntities,
@ -2521,26 +2517,21 @@ private void detectManyToManyProblems(
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 @@ private static void bindCollectionSecondPass(
);
}
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 void setCascadeDeleteEnabled(boolean onDeleteCascade) {
this.cascadeDeleteEnabled = onDeleteCascade;
}
private String safeCollectionRole() {
String safeCollectionRole() {
return propertyHolder != null ? propertyHolder.getEntityName() + "." + propertyName : "";
}

View File

@ -261,7 +261,7 @@ public static void bindEntityClass(
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 @@ private static boolean mapAsIdClass(
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 @@ private static void bindIdClass(
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 @@ private static void bindIdClass(
);
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 @@ private static void processIdPropertiesIfNotAlready(
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 @@ private static void processIdPropertiesIfNotAlready(
}
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 @@ private void bindhandleFilters() {
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 @@ private void bindCustomPersister() {
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 void bindDiscriminatorValue() {
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 @@ private static boolean isCacheLazy(Cache effectiveCache, XClass annotatedClass)
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 void processComplementaryTableDefinitions(jakarta.persistence.Table table
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 void processComplementaryTableDefinitions(org.hibernate.annotations.Table
}
}
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.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.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 SecondPass getSecondPass(
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 void secondPass(Map<String, PersistentClass> persistentClasses)
throws MappingException {
bindStarToManySecondPass(
persistentClasses,
collType,
elementType,
fkJoinColumns,
keyColumns,
inverseColumns,
@ -96,12 +95,12 @@ public void secondPass(Map<String, PersistentClass> persistentClasses)
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 @@ private void bindIndex(XProperty property, XClass collType, final MetadataBuildi
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.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.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 @@ private boolean propertiesContainColumn(List<Property> properties, Column column
}
private void bindKeyFromAssociationTable(
XClass collType,
XClass elementType,
Map<String, PersistentClass> persistentClasses,
String mapKeyPropertyName,
XProperty property,
@ -176,17 +174,19 @@ private void bindKeyFromAssociationTable(
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.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 void setDeclaringClass(XClass declaringClass) {
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 @@ private Property bind(Property prop) {
}
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 @@ private void handleNaturalId(Property prop) {
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 @@ else if ( property != null && property.isAnnotationPresent(OptimisticLock.class)
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 @@ private ValueGeneration determineValueGenerationStrategy(XProperty property) {
*/
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 @@ private <A extends Annotation> AnnotationValueGeneration<A> getValueGenerationFr
XProperty property,
A annotation) {
final ValueGenerationType generatorAnnotation = annotation.annotationType().getAnnotation( ValueGenerationType.class );
if ( generatorAnnotation == null ) {
return null;
}
@ -451,9 +438,9 @@ private <A extends Annotation> AnnotationValueGeneration<A> getValueGenerationFr
&& 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.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 static void bindQuery(
}
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 static void bindNativeQuery(
}
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 static void bindNativeQuery(
//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 static void bindNativeQuery(
.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 static void bindQuery(
//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 static void bindNamedStoredProcedureQuery(
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 @@ private static int skipWhitespace(String sqlString, int i) {
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.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.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 static void bindFk(
}
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 static void bindFk(
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 static void bindFk(
}
}
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 @@ else if ( value instanceof DependantValue ) {
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 @@ else if ( value instanceof DependantValue ) {
"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 @@ else if ( value instanceof DependantValue ) {
//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 @@ else if ( value instanceof DependantValue ) {
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 static <T> EventType<T> create(String name, Class<T> listenerRole, int or
*
* @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 BasicValue(BasicValue original) {
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 @@ private void checkSelectable(Selectable incomingColumn) {
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 TypeConfiguration getTypeConfiguration() {
name,
typeNamedClass,
null,
null,
typeConfiguration
null
);
context.getTypeDefinitionRegistry().register( implicitDefinition );
return implicitDefinition.resolve(
@ -754,7 +753,7 @@ public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;
}
public void setExplicitTypeParams(Map<Object,Object> explicitLocalTypeParams) {
public void setExplicitTypeParams(Map<String,String> explicitLocalTypeParams) {
this.explicitLocalTypeParams = explicitLocalTypeParams;
}
@ -772,7 +771,6 @@ public void setTypeName(String typeName) {
.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 boolean equals(Object object) {
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.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 void setOptimisticLockStyle(OptimisticLockStyle optimisticLockStyle) {
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 @@ protected void checkColumnDuplication(Set<String> distinctColumns, Value value)
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 @@ protected void checkColumnDuplication(Set<String> distinctColumns, Value value)
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.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 PropertyAccessStrategy getStrategy() {
}
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 @@ else if ( !PropertyAccessStrategy.class.equals(type) ) {
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 @@
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.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 @@
@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 void test() {
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.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.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
@Embeddable
@ -50,7 +49,8 @@ public int hashCode() {
@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.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.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinColumns;
import jakarta.persistence.ManyToOne;
@Embeddable
@ -48,7 +47,7 @@ public int hashCode() {
@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 @@
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 @@
*/
@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 void testOnDeleteWithoutJoinColumn() throws Exception {
.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 void disallowOnSideWithMappedBy() {
);
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.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 @@ void test(ServiceRegistryScope scope) {
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 @@ protected void buildSessionFactory() {
}
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.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 static class Dependent {
@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;
}