Skip to content

Commit

Permalink
HHH-15733 Change convert logic to default to value for Map collection…
Browse files Browse the repository at this point in the history
…s of basic types
  • Loading branch information
mbladel authored and beikov committed Feb 6, 2023
1 parent dfedde8 commit 7f53dc8
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public Collection getCollectionBinding() {

private void buildAttributeConversionInfoMaps(
XProperty collectionProperty,
boolean isComposite,
Map<String,AttributeConversionInfo> elementAttributeConversionInfoMap,
Map<String,AttributeConversionInfo> keyAttributeConversionInfoMap) {
if ( collectionProperty == null ) {
Expand All @@ -86,7 +87,13 @@ private void buildAttributeConversionInfoMaps(
{
final Convert convertAnnotation = collectionProperty.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
applyLocalConvert( convertAnnotation, collectionProperty, elementAttributeConversionInfoMap, keyAttributeConversionInfoMap );
applyLocalConvert(
convertAnnotation,
collectionProperty,
isComposite,
elementAttributeConversionInfoMap,
keyAttributeConversionInfoMap
);
}
}

Expand All @@ -97,6 +104,7 @@ private void buildAttributeConversionInfoMaps(
applyLocalConvert(
convertAnnotation,
collectionProperty,
isComposite,
elementAttributeConversionInfoMap,
keyAttributeConversionInfoMap
);
Expand All @@ -108,14 +116,15 @@ private void buildAttributeConversionInfoMaps(
private void applyLocalConvert(
Convert convertAnnotation,
XProperty collectionProperty,
boolean isComposite,
Map<String,AttributeConversionInfo> elementAttributeConversionInfoMap,
Map<String,AttributeConversionInfo> keyAttributeConversionInfoMap) {

// IMPL NOTE : the rules here are quite more lenient than what JPA says. For example, JPA says
// that @Convert on a Map always needs to specify attributeName of key/value (or prefixed with
// key./value. for embedded paths). However, we try to see if conversion of either is disabled
// for whatever reason. For example, if the Map is annotated with @Enumerated the elements cannot
// be converted so any @Convert likely meant the key, so we apply it to the key
// IMPL NOTE : the rules here are quite more lenient than what JPA says. For example, JPA says that @Convert
// on a Map of basic types should default to "value" but it should explicitly specify attributeName of "key"
// (or prefixed with "key." for embedded paths) to be applied on the key. However, we try to see if conversion
// of either is disabled for whatever reason. For example, if the Map is annotated with @Enumerated the
// elements cannot be converted so any @Convert likely meant the key, so we apply it to the key

final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, collectionProperty );
if ( collection.isMap() ) {
Expand All @@ -130,10 +139,15 @@ private void applyLocalConvert(
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
// the @Convert did not name an attribute...
if ( canElementBeConverted && canKeyBeConverted ) {
throw new IllegalStateException(
"@Convert placed on Map attribute [" + collection.getRole()
+ "] must define attributeName of 'key' or 'value'"
);
if ( !isComposite ) {
// if element is of basic type default to "value"
elementAttributeConversionInfoMap.put( "", info );
}
else {
throw new IllegalStateException(
"@Convert placed on Map attribute [" + collection.getRole()
+ "] of non-basic types must define attributeName of 'key' or 'value'" );
}
}
else if ( canKeyBeConverted ) {
keyAttributeConversionInfoMap.put( "", info );
Expand Down Expand Up @@ -325,7 +339,7 @@ public String toString() {

boolean prepared;

public void prepare(XProperty collectionProperty) {
public void prepare(XProperty collectionProperty, boolean isComposite) {
// fugly
if ( prepared ) {
return;
Expand Down Expand Up @@ -377,7 +391,12 @@ else if ( collectionProperty.isAnnotationPresent( CollectionType.class ) ) {
// Is it valid to reference a collection attribute in a @Convert attached to the owner (entity) by path?
// if so we should pass in 'clazzToProcess' also
if ( canKeyBeConverted || canElementBeConverted ) {
buildAttributeConversionInfoMaps( collectionProperty, elementAttributeConversionInfoMap, keyAttributeConversionInfoMap );
buildAttributeConversionInfoMaps(
collectionProperty,
isComposite,
elementAttributeConversionInfoMap,
keyAttributeConversionInfoMap
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2238,7 +2238,7 @@ private void handleElementCollection(
buildingContext
);
if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) {
holder.prepare(property);
holder.prepare( property, true );

EntityBinder entityBinder = new EntityBinder();
PersistentClass owner = collValue.getOwner();
Expand Down Expand Up @@ -2295,7 +2295,7 @@ else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().get
}
}
else {
holder.prepare(property);
holder.prepare( property, false );

final BasicValueBinder elementBinder =
new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.type.BasicType;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserCollectionType;

Expand Down Expand Up @@ -262,7 +263,7 @@ private void bindKeyFromAssociationTable(
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
propertyHolder.startingProperty( property );
holder.prepare( property );
holder.prepare( property, !( collection.getKey().getType() instanceof BasicType ) );

PersistentClass owner = mapValue.getOwner();
AccessType accessType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,9 @@ public static class Customer {
private Integer id;

@ElementCollection(fetch = FetchType.EAGER)
@Convert(converter = MyStringConverter.class)
@Convert(converter = MyStringConverter.class) // note omitted attributeName
private final Map<String, String> colors = new HashMap<>();

public Customer() {
}

public Customer(Integer id) {
this.id = id;
}

public Map<String, String> getColors() {
return colors;
}
Expand Down

0 comments on commit 7f53dc8

Please sign in to comment.