fix the misleading documentation of the @Bag annotation

and improve error reporting when used in a nonsensical way
This commit is contained in:
Gavin 2022-12-31 17:06:07 +01:00
parent a1d52b0bb1
commit 60e5b75282
5 changed files with 34 additions and 12 deletions

View File

@ -9,21 +9,25 @@ package org.hibernate.annotations;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.hibernate.cfg.AvailableSettings;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* Can be used to map a {@link java.util.List}-valued attribute using * Specifies that an attribute of type {@link java.util.List} is semantically
* {@link org.hibernate.metamodel.CollectionClassification#BAG} semantics. * a {@linkplain org.hibernate.metamodel.CollectionClassification#BAG bag},
* that is, that the order of the list elements is not significant, and should
* not be persistent.
* <p> * <p>
* @apiNote Ignored if either {@link jakarta.persistence.OrderColumn} or * This annotation is not necessary, and has no effect, unless the configuration
* {@link ListIndexBase} is used. * property {@value org.hibernate.cfg.AvailableSettings#DEFAULT_LIST_SEMANTICS}
* is set to {@link org.hibernate.metamodel.CollectionClassification#LIST}.
* However, its use is still encouraged, since the explicit annotation serves
* as useful documentation.
* *
* @implSpec May also be specified SessionFactory-wide using {@value AvailableSettings#DEFAULT_LIST_SEMANTICS} * @apiNote This annotation causes an exception if the attribute is also annotated
* {@link jakarta.persistence.OrderColumn} or {@link ListIndexBase}.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */

View File

@ -60,7 +60,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface Type { public @interface Type {
/** /**
* The implementation class which implements {@link UserType}. * The class which implements {@link UserType}.
*/ */
Class<? extends UserType<?>> value(); Class<? extends UserType<?>> value();

View File

@ -987,16 +987,26 @@ public abstract class CollectionBinder {
return determineCollectionClassification( determineSemanticJavaType( property ), property, buildingContext ); return determineCollectionClassification( determineSemanticJavaType( property ), property, buildingContext );
} }
else { else {
if ( property.isAnnotationPresent( OrderColumn.class ) ) {
throw new AnnotationException( "Attribute '"
+ qualify( property.getDeclaringClass().getName(), property.getName() )
+ "' is annotated '@Bag' and may not also be annotated '@OrderColumn'" );
}
if ( property.isAnnotationPresent( ListIndexBase.class ) ) {
throw new AnnotationException( "Attribute '"
+ qualify( property.getDeclaringClass().getName(), property.getName() )
+ "' is annotated '@Bag' and may not also be annotated '@ListIndexBase'" );
}
final Class<?> collectionJavaType = property.getCollectionClass(); final Class<?> collectionJavaType = property.getCollectionClass();
if ( java.util.List.class.equals( collectionJavaType ) if ( java.util.List.class.equals( collectionJavaType )
|| java.util.Collection.class.equals( collectionJavaType ) ) { || java.util.Collection.class.equals( collectionJavaType ) ) {
return CollectionClassification.BAG; return CollectionClassification.BAG;
} }
else { else {
throw new MappingException( throw new AnnotationException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"@Bag annotation encountered on an attribute `%s#%s` of type `%s`; only `%s` and `%s` are supported", "Attribute '%s.%s' of type '%s' is annotated '@Bag' (bags are of type '%s' or '%s')",
property.getDeclaringClass().getName(), property.getDeclaringClass().getName(),
property.getName(), property.getName(),
collectionJavaType.getName(), collectionJavaType.getName(),

View File

@ -17,9 +17,9 @@ import org.hibernate.boot.MetadataSources;
*/ */
public interface MetadataSourcesContributor { public interface MetadataSourcesContributor {
/** /**
* Perform the process of contributing to MetadataSources. * Perform the process of contributing to the {@link MetadataSources}.
* *
* @param metadataSources The MetadataSources, to which to contribute. * @param metadataSources The {@code MetadataSource}s, to which to contribute.
*/ */
void contribute(MetadataSources metadataSources); void contribute(MetadataSources metadataSources);
} }

View File

@ -929,8 +929,16 @@ public interface AvailableSettings {
* <li>the (case insensitive) name of a {@code CollectionClassification} (list e.g.) * <li>the (case insensitive) name of a {@code CollectionClassification} (list e.g.)
* <li>a {@link Class} representing either {@link java.util.List} or {@link java.util.Collection} * <li>a {@link Class} representing either {@link java.util.List} or {@link java.util.Collection}
* </ul> * </ul>
* <p>
* By default, when this property is not set, an attribute of type {@code List}
* is taken to have the semantics of a
* {@linkplain org.hibernate.metamodel.CollectionClassification#BAG bag} unless
* it is annotated {@link jakarta.persistence.OrderColumn} or
* {@link org.hibernate.annotations.ListIndexBase}.
* *
* @since 6.0 * @since 6.0
*
* @see org.hibernate.annotations.Bag
*/ */
String DEFAULT_LIST_SEMANTICS = "hibernate.mapping.default_list_semantics"; String DEFAULT_LIST_SEMANTICS = "hibernate.mapping.default_list_semantics";