HHH-8469 - Application of JPA 2.1 AttributeConverters

This commit is contained in:
Steve Ebersole 2013-09-05 22:30:52 -05:00
parent cf7bb0dcec
commit 1f6daa6785
18 changed files with 1009 additions and 336 deletions

View File

@ -22,8 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.AttributeOverride;
@ -34,11 +33,17 @@ import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.MappedSuperclass;
import java.util.HashMap;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.StringHelper;
/**
@ -47,6 +52,8 @@ import org.hibernate.internal.util.StringHelper;
* @author Emmanuel Bernard
*/
public abstract class AbstractPropertyHolder implements PropertyHolder {
private static final Logger log = CoreLogging.logger( AbstractPropertyHolder.class );
protected AbstractPropertyHolder parent;
private Map<String, Column[]> holderColumnOverride;
private Map<String, Column[]> currentPropertyColumnOverride;
@ -58,7 +65,6 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
private Mappings mappings;
private Boolean isInIdClass;
AbstractPropertyHolder(
String path,
PropertyHolder parent,
@ -70,6 +76,122 @@ public abstract class AbstractPropertyHolder implements PropertyHolder {
buildHierarchyColumnOverride( clazzToProcess );
}
protected abstract String normalizeCompositePathForLogging(String attributeName);
protected abstract String normalizeCompositePath(String attributeName);
protected abstract AttributeConversionInfo locateAttributeConversionInfo(XProperty property);
protected abstract AttributeConversionInfo locateAttributeConversionInfo(String path);
@Override
public AttributeConverterDefinition resolveAttributeConverterDefinition(XProperty property) {
AttributeConversionInfo info = locateAttributeConversionInfo( property );
if ( info != null ) {
if ( info.isConversionDisabled() ) {
return null;
}
else {
try {
return makeAttributeConverterDefinition( info );
}
catch (Exception e) {
throw new IllegalStateException(
String.format( "Unable to instantiate AttributeConverter [%s", info.getConverterClass().getName() ),
e
);
}
}
}
// look for auto applied converters
// todo : hook in the orm.xml local entity work brett did
// for now, just look in global converters
log.debugf( "Attempting to locate auto-apply AttributeConverter for property [%s:%s]", path, property.getName() );
final Class propertyType = mappings.getReflectionManager().toClass( property.getType() );
for ( AttributeConverterDefinition attributeConverterDefinition : mappings.getAttributeConverters() ) {
if ( ! attributeConverterDefinition.isAutoApply() ) {
continue;
}
log.debugf(
"Checking auto-apply AttributeConverter [%s] type [%s] for match [%s]",
attributeConverterDefinition.toString(),
attributeConverterDefinition.getEntityAttributeType().getSimpleName(),
propertyType.getSimpleName()
);
if ( areTypeMatch( attributeConverterDefinition.getEntityAttributeType(), propertyType ) ) {
return attributeConverterDefinition;
}
}
return null;
}
private AttributeConverterDefinition makeAttributeConverterDefinition(AttributeConversionInfo conversion) {
try {
return new AttributeConverterDefinition( conversion.getConverterClass().newInstance(), false );
}
catch (Exception e) {
throw new AnnotationException( "Unable to create AttributeConverter instance", e );
}
}
private boolean areTypeMatch(Class converterDefinedType, Class propertyType) {
if ( converterDefinedType == null ) {
throw new AnnotationException( "AttributeConverter defined java type cannot be null" );
}
if ( propertyType == null ) {
throw new AnnotationException( "Property defined java type cannot be null" );
}
return converterDefinedType.equals( propertyType )
|| arePrimitiveWrapperEquivalents( converterDefinedType, propertyType );
}
private boolean arePrimitiveWrapperEquivalents(Class converterDefinedType, Class propertyType) {
if ( converterDefinedType.isPrimitive() ) {
return getWrapperEquivalent( converterDefinedType ).equals( propertyType );
}
else if ( propertyType.isPrimitive() ) {
return getWrapperEquivalent( propertyType ).equals( converterDefinedType );
}
return false;
}
private static Class getWrapperEquivalent(Class primitive) {
if ( ! primitive.isPrimitive() ) {
throw new AssertionFailure( "Passed type for which to locate wrapper equivalent was not a primitive" );
}
if ( boolean.class.equals( primitive ) ) {
return Boolean.class;
}
else if ( char.class.equals( primitive ) ) {
return Character.class;
}
else if ( byte.class.equals( primitive ) ) {
return Byte.class;
}
else if ( short.class.equals( primitive ) ) {
return Short.class;
}
else if ( int.class.equals( primitive ) ) {
return Integer.class;
}
else if ( long.class.equals( primitive ) ) {
return Long.class;
}
else if ( float.class.equals( primitive ) ) {
return Float.class;
}
else if ( double.class.equals( primitive ) ) {
return Double.class;
}
throw new AssertionFailure( "Unexpected primitive type (VOID most likely) passed to getWrapperEquivalent" );
}
@Override
public boolean isInIdClass() {
return isInIdClass != null ? isInIdClass : parent != null ? parent.isInIdClass() : false;

View File

@ -135,6 +135,8 @@ import org.hibernate.annotations.Tuplizers;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
import org.hibernate.annotations.Where;
import org.hibernate.annotations.common.reflection.ClassLoaderDelegate;
import org.hibernate.annotations.common.reflection.ClassLoadingException;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
@ -292,6 +294,10 @@ public final class AnnotationBinder {
try {
pckg = mappings.getReflectionManager().packageForName( packageName );
}
catch (ClassLoadingException e) {
LOG.packageNotFound( packageName );
return;
}
catch ( ClassNotFoundException cnf ) {
LOG.packageNotFound( packageName );
return;
@ -2415,10 +2421,18 @@ public final class AnnotationBinder {
String subpath = BinderHelper.getPath( propertyHolder, inferredData );
LOG.tracev( "Binding component with path: {0}", subpath );
PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder(
comp, subpath,
inferredData, propertyHolder, mappings
comp,
subpath,
inferredData,
propertyHolder,
mappings
);
// propertyHolder here is the owner of the component property. Tell it we are about to start the component...
propertyHolder.startingProperty( inferredData.getProperty() );
final XClass xClassProcessed = inferredData.getPropertyClass();
List<PropertyData> classElements = new ArrayList<PropertyData>();
XClass returnedClassOrElement = inferredData.getClassOrElement();
@ -2599,7 +2613,7 @@ public final class AnnotationBinder {
value.setColumns( columns );
value.setPersistentClassName( persistentClassName );
value.setMappings( mappings );
value.setType( inferredData.getProperty(), inferredData.getClassOrElement(), persistentClassName );
value.setType( inferredData.getProperty(), inferredData.getClassOrElement(), persistentClassName, null );
value.setAccessType( propertyAccessor );
id = value.make();
}

View File

@ -0,0 +1,80 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
/**
* Describes a {@link javax.persistence.Convert} conversion
*
* @author Steve Ebersole
*/
public class AttributeConversionInfo {
private final Class<? extends AttributeConverter> converterClass;
private final boolean conversionDisabled;
private final String attributeName;
private final XAnnotatedElement source;
public AttributeConversionInfo(
Class<? extends AttributeConverter> converterClass,
boolean conversionDisabled,
String attributeName,
XAnnotatedElement source) {
this.converterClass = converterClass;
this.conversionDisabled = conversionDisabled;
this.attributeName = attributeName;
this.source = source;
}
@SuppressWarnings("unchecked")
public AttributeConversionInfo(Convert convertAnnotation, XAnnotatedElement xAnnotatedElement) {
this(
convertAnnotation.converter(),
convertAnnotation.disableConversion(),
convertAnnotation.attributeName(),
xAnnotatedElement
);
}
public Class<? extends AttributeConverter> getConverterClass() {
return converterClass;
}
public boolean isConversionDisabled() {
return conversionDisabled;
}
public String getAttributeName() {
return attributeName;
}
public XAnnotatedElement getSource() {
return source;
}
}

View File

@ -22,21 +22,21 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.Convert;
import javax.persistence.Converts;
import javax.persistence.JoinTable;
import java.util.HashMap;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.annotations.common.util.ReflectHelper;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.KeyValue;
@ -49,36 +49,145 @@ import org.hibernate.mapping.Table;
* @author Emmanuel Bernard
*/
public class ClassPropertyHolder extends AbstractPropertyHolder {
private static final Logger log = CoreLogging.logger( ClassPropertyHolder.class );
private PersistentClass persistentClass;
private Map<String, Join> joins;
private transient Map<String, Join> joinsPerRealTableName;
private EntityBinder entityBinder;
private final Map<XClass, InheritanceState> inheritanceStatePerClass;
private Map<String,AttributeConversionInfo> attributeConversionInfoMap;
public ClassPropertyHolder(
PersistentClass persistentClass,
XClass clazzToProcess,
XClass entityXClass,
Map<String, Join> joins,
Mappings mappings,
Map<XClass, InheritanceState> inheritanceStatePerClass) {
super( persistentClass.getEntityName(), null, clazzToProcess, mappings );
super( persistentClass.getEntityName(), null, entityXClass, mappings );
this.persistentClass = persistentClass;
this.joins = joins;
this.inheritanceStatePerClass = inheritanceStatePerClass;
this.attributeConversionInfoMap = buildAttributeConversionInfoMap( entityXClass );
}
public ClassPropertyHolder(
PersistentClass persistentClass,
XClass clazzToProcess,
XClass entityXClass,
EntityBinder entityBinder,
Mappings mappings,
Map<XClass, InheritanceState> inheritanceStatePerClass) {
this( persistentClass, clazzToProcess, entityBinder.getSecondaryTables(), mappings, inheritanceStatePerClass );
this( persistentClass, entityXClass, entityBinder.getSecondaryTables(), mappings, inheritanceStatePerClass );
this.entityBinder = entityBinder;
}
@Override
protected String normalizeCompositePath(String attributeName) {
return attributeName;
}
@Override
protected String normalizeCompositePathForLogging(String attributeName) {
return getEntityName() + '.' + attributeName;
}
protected Map<String, AttributeConversionInfo> buildAttributeConversionInfoMap(XClass entityXClass) {
final HashMap<String, AttributeConversionInfo> map = new HashMap<String, AttributeConversionInfo>();
collectAttributeConversionInfo( map, entityXClass );
return map;
}
private void collectAttributeConversionInfo(Map<String, AttributeConversionInfo> infoMap, XClass xClass) {
if ( xClass == null ) {
// typically indicates we have reached the end of the inheritance hierarchy
return;
}
// collect superclass info first
collectAttributeConversionInfo( infoMap, xClass.getSuperclass() );
final boolean canContainConvert = xClass.isAnnotationPresent( javax.persistence.Entity.class )
|| xClass.isAnnotationPresent( javax.persistence.MappedSuperclass.class )
|| xClass.isAnnotationPresent( javax.persistence.Embeddable.class );
if ( ! canContainConvert ) {
return;
}
{
final Convert convertAnnotation = xClass.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, xClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "@Convert placed on @Entity/@MappedSuperclass must define attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
{
final Converts convertsAnnotation = xClass.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, xClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "@Converts placed on @Entity/@MappedSuperclass must define attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
}
}
@Override
public void startingProperty(XProperty property) {
if ( property == null ) {
return;
}
final String propertyName = property.getName();
if ( attributeConversionInfoMap.containsKey( propertyName ) ) {
return;
}
{
// @Convert annotation on the Embeddable attribute
final Convert convertAnnotation = property.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
attributeConversionInfoMap.put( propertyName, info );
}
else {
attributeConversionInfoMap.put( propertyName + '.' + info.getAttributeName(), info );
}
}
}
{
// @Converts annotation on the Embeddable attribute
final Converts convertsAnnotation = property.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
attributeConversionInfoMap.put( propertyName, info );
}
else {
attributeConversionInfoMap.put( propertyName + '.' + info.getAttributeName(), info );
}
}
}
}
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) {
return locateAttributeConversionInfo( property.getName() );
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(String path) {
return attributeConversionInfoMap.get( path );
}
public String getEntityName() {
return persistentClass.getEntityName();
}
@ -286,4 +395,10 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
//
// return lookForEntityDefinedConvertAnnotation( property, owner );
// }
@Override
public String toString() {
return super.toString() + "(" + getEntityName() + ")";
}
}

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import javax.persistence.JoinTable;
import org.hibernate.AssertionFailure;
@ -52,6 +53,33 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder {
setCurrentProperty( property );
}
@Override
protected String normalizeCompositePath(String attributeName) {
return attributeName;
}
@Override
protected String normalizeCompositePathForLogging(String attributeName) {
return collection.getRole() + '.' + attributeName;
}
@Override
public void startingProperty(XProperty property) {
// todo : implement
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) {
// todo : implement
return null;
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(String path) {
// todo : implement
return null;
}
public String getClassName() {
throw new AssertionFailure( "Collection property holder does not have a class name" );
}
@ -100,4 +128,9 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder {
public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
throw new AssertionFailure( "Add a <join> in a second pass" );
}
@Override
public String toString() {
return super.toString() + "(" + collection.getRole() + ")";
}
}

View File

@ -23,14 +23,21 @@
*/
package org.hibernate.cfg;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Converts;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.KeyValue;
@ -39,8 +46,31 @@ import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
/**
* Component implementation of property holder
* PropertyHolder for composites (Embeddable/Embedded).
* <p/>
* To facilitate code comments, I'll often refer to this example:
* <pre>
* &#064;Embeddable
* &#064;Convert( attributeName="city", ... )
* class Address {
* ...
* &#064;Convert(...)
* public String city;
* }
*
* &#064;Entity
* &#064;Convert( attributeName="homeAddress.city", ... )
* class Person {
* ...
* &#064;Embedded
* &#064;Convert( attributeName="city", ... )
* public Address homeAddress;
* }
* </pre>
*
* As you can see, lots of ways to specify the conversion for embeddable attributes :(
*
* @author Steve Ebersole
* @author Emmanuel Bernard
*/
public class ComponentPropertyHolder extends AbstractPropertyHolder {
@ -49,6 +79,201 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
private Component component;
private boolean isOrWithinEmbeddedId;
private boolean virtual;
private String embeddedAttributeName;
private Map<String,AttributeConversionInfo> attributeConversionInfoMap;
public ComponentPropertyHolder(
Component component,
String path,
PropertyData inferredData,
PropertyHolder parent,
Mappings mappings) {
super( path, parent, inferredData.getPropertyClass(), mappings );
final XProperty embeddedXProperty = inferredData.getProperty();
setCurrentProperty( embeddedXProperty );
this.component = component;
this.isOrWithinEmbeddedId =
parent.isOrWithinEmbeddedId()
|| ( embeddedXProperty != null &&
( embeddedXProperty.isAnnotationPresent( Id.class )
|| embeddedXProperty.isAnnotationPresent( EmbeddedId.class ) ) );
this.virtual = embeddedXProperty == null;
if ( !virtual ) {
this.embeddedAttributeName = embeddedXProperty.getName();
this.attributeConversionInfoMap = processAttributeConversions( embeddedXProperty );
}
else {
embeddedAttributeName = "";
this.attributeConversionInfoMap = Collections.emptyMap();
}
}
/**
* This is called from our constructor and handles (in order):<ol>
* <li>@Convert annotation at the Embeddable class level</li>
* <li>@Converts annotation at the Embeddable class level</li>
* <li>@Convert annotation at the Embedded attribute level</li>
* <li>@Converts annotation at the Embedded attribute level</li>
* </ol>
* <p/>
* The order is important to ensure proper precedence.
* <p/>
* {@literal @Convert/@Converts} annotations at the Embeddable attribute level are handled in the calls to
* {@link #startingProperty}. Duplicates are simply ignored there.
*
* @param embeddedXProperty The property that is the composite being described by this ComponentPropertyHolder
*/
private Map<String,AttributeConversionInfo> processAttributeConversions(XProperty embeddedXProperty) {
final Map<String,AttributeConversionInfo> infoMap = new HashMap<String, AttributeConversionInfo>();
final XClass embeddableXClass = embeddedXProperty.getType();
// as a baseline, we want to apply conversions from the Embeddable and then overlay conversions
// from the Embedded
// first apply conversions from the Embeddable...
{
// @Convert annotation on the Embeddable class level
final Convert convertAnnotation = embeddableXClass.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "@Convert placed on @Embeddable must define attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
{
// @Converts annotation on the Embeddable class level
final Converts convertsAnnotation = embeddableXClass.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "@Converts placed on @Embeddable must define attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
}
// then we can overlay any conversions from the Embedded attribute
{
// @Convert annotation on the Embedded attribute
final Convert convertAnnotation = embeddedXProperty.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
{
// @Converts annotation on the Embedded attribute
final Converts convertsAnnotation = embeddedXProperty.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, embeddableXClass );
if ( StringHelper.isEmpty( info.getAttributeName() ) ) {
throw new IllegalStateException( "Convert placed on Embedded attribute must define (sub)attributeName" );
}
infoMap.put( info.getAttributeName(), info );
}
}
}
return infoMap;
}
@Override
protected String normalizeCompositePath(String attributeName) {
return embeddedAttributeName + '.' + attributeName;
}
@Override
protected String normalizeCompositePathForLogging(String attributeName) {
return normalizeCompositePath( attributeName );
}
@Override
public void startingProperty(XProperty property) {
if ( property == null ) {
return;
}
if ( virtual ) {
return;
}
// again : the property coming in here *should* be the property on the embeddable (Address#city in the example),
// so we just ignore it if there is already an existing conversion info for that path since they would have
// precedence
// technically we should only do this for properties of "basic type"
final String path = embeddedAttributeName + '.' + property.getName();
if ( attributeConversionInfoMap.containsKey( path ) ) {
return;
}
{
// @Convert annotation on the Embeddable attribute
final Convert convertAnnotation = property.getAnnotation( Convert.class );
if ( convertAnnotation != null ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property );
attributeConversionInfoMap.put( property.getName(), info );
}
}
{
// @Converts annotation on the Embeddable attribute
final Converts convertsAnnotation = property.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
final AttributeConversionInfo info = new AttributeConversionInfo( convertAnnotation, property );
attributeConversionInfoMap.put( property.getName(), info );
}
}
}
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(XProperty property) {
final String propertyName = property.getName();
// conversions on parent would have precedence
AttributeConversionInfo conversion = locateAttributeConversionInfo( propertyName );
if ( conversion != null ) {
return conversion;
}
Convert localConvert = property.getAnnotation( Convert.class );
if ( localConvert != null ) {
return new AttributeConversionInfo( localConvert, property );
}
return null;
}
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(String path) {
final String embeddedPath = embeddedAttributeName + '.' + path;
AttributeConversionInfo fromParent = parent.locateAttributeConversionInfo( embeddedPath );
if ( fromParent != null ) {
return fromParent;
}
AttributeConversionInfo fromEmbedded = attributeConversionInfoMap.get( embeddedPath );
if ( fromEmbedded != null ) {
return fromEmbedded;
}
return attributeConversionInfoMap.get( path );
}
public String getEntityName() {
return component.getComponentClassName();
}
@ -82,23 +307,6 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
}
public ComponentPropertyHolder(
Component component,
String path,
PropertyData inferredData,
PropertyHolder parent,
Mappings mappings) {
super( path, parent, inferredData.getPropertyClass(), mappings );
final XProperty property = inferredData.getProperty();
setCurrentProperty( property );
this.component = component;
this.isOrWithinEmbeddedId =
parent.isOrWithinEmbeddedId()
|| ( property != null &&
( property.isAnnotationPresent( Id.class )
|| property.isAnnotationPresent( EmbeddedId.class ) ) );
}
public String getClassName() {
return component.getComponentClassName();
}
@ -173,4 +381,9 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
public JoinColumn[] getOverriddenJoinColumn(String propertyName) {
return super.getOverriddenJoinColumn( propertyName );
}
@Override
public String toString() {
return super.toString() + "(" + parent.normalizeCompositePathForLogging( embeddedAttributeName ) + ")";
}
}

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg;
import javax.persistence.AttributeConverter;
import javax.persistence.Column;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
@ -67,8 +68,6 @@ public interface PropertyHolder {
String getPath();
// public AttributeConverterDefinition resolveAttributeConverter(String attributeName);
/**
* return null if the column is not overridden, or an array of column if true
*/
@ -94,4 +93,20 @@ public interface PropertyHolder {
boolean isInIdClass();
void setInIdClass(Boolean isInIdClass);
/**
* Called during binding to allow the PropertyHolder to inspect its discovered properties. Mainly
* this is used in collecting attribute conversion declarations (via @Convert/@Converts).
*
* @param property The property
*/
void startingProperty(XProperty property);
/**
* Determine the AttributeConverter to use for the given property.
*
* @param property
* @return
*/
AttributeConverterDefinition resolveAttributeConverterDefinition(XProperty property);
}

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg.annotations;
import javax.persistence.AttributeConverter;
/**
* @author Steve Ebersole
*/
public interface AttributeConverterResolver {
/**
* Resolve the AttributeConverter to use for an attribute during binding. The assumption of the API
* is that the path information is encoded into the AttributeConverterResolver instance itself to account
* for all the different paths converters can be defined on.
*
* @return The AttributeConverter to use, or {@code null} if none.
*/
public AttributeConverter resolveAttributeConverter();
}

View File

@ -0,0 +1,184 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg.annotations;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.Mappings;
/**
* Manages the resolution of the AttributeConverter, if one, for a property (path).
*
* @author Steve Ebersole
*/
public class AttributeConverterResolverContext {
private final Mappings mappings;
public AttributeConverterResolverContext(Mappings mappings) {
this.mappings = mappings;
}
private Map<String,EntityPropertyPathSource> entityPropertyPathSourceMap;
public EntityPropertyPathSource resolveEntityPropertyPathSource(XClass entityClass) {
EntityPropertyPathSource found = null;
if ( entityPropertyPathSourceMap == null ) {
entityPropertyPathSourceMap = new HashMap<String, EntityPropertyPathSource>();
}
else {
found = entityPropertyPathSourceMap.get( entityClass.getName() );
}
if ( found == null ) {
found = new EntityPropertyPathSource( entityClass );
entityPropertyPathSourceMap.put( entityClass.getName(), found );
}
return found;
}
private Map<String,CollectionPropertyPathSource> collectionPropertyPathSourceMap;
public CollectionPropertyPathSource resolveRootCollectionPropertyPathSource(XClass owner, XProperty property) {
CollectionPropertyPathSource found = null;
if ( collectionPropertyPathSourceMap == null ) {
collectionPropertyPathSourceMap = new HashMap<String, CollectionPropertyPathSource>();
}
else {
found = collectionPropertyPathSourceMap.get( owner.getName() );
}
if ( found == null ) {
final EntityPropertyPathSource ownerSource = resolveEntityPropertyPathSource( owner );
found = new CollectionPropertyPathSource( ownerSource, property.getName() );
collectionPropertyPathSourceMap.put( owner.getName(), found );
}
return found;
}
public static interface PropertyPathSource {
public CompositePropertyPathSource makeComposite(String propertyName);
public CollectionPropertyPathSource makeCollection(String propertyName);
}
public static abstract class AbstractPropertyPathSource implements PropertyPathSource {
protected abstract String normalize(String path);
private Map<String,CompositePropertyPathSource> compositePropertyPathSourceMap;
@Override
public CompositePropertyPathSource makeComposite(String propertyName) {
CompositePropertyPathSource found = null;
if ( compositePropertyPathSourceMap == null ) {
compositePropertyPathSourceMap = new HashMap<String, CompositePropertyPathSource>();
}
else {
found = compositePropertyPathSourceMap.get( propertyName );
}
if ( found == null ) {
found = new CompositePropertyPathSource( this, propertyName );
compositePropertyPathSourceMap.put( propertyName, found );
}
return found;
}
private Map<String,CollectionPropertyPathSource> collectionPropertyPathSourceMap;
@Override
public CollectionPropertyPathSource makeCollection(String propertyName) {
CollectionPropertyPathSource found = null;
if ( collectionPropertyPathSourceMap == null ) {
collectionPropertyPathSourceMap = new HashMap<String, CollectionPropertyPathSource>();
}
else {
found = collectionPropertyPathSourceMap.get( propertyName );
}
if ( found == null ) {
found = new CollectionPropertyPathSource( this, propertyName );
collectionPropertyPathSourceMap.put( propertyName, found );
}
return found;
}
}
public static class EntityPropertyPathSource extends AbstractPropertyPathSource implements PropertyPathSource {
private final XClass entityClass;
private EntityPropertyPathSource(XClass entityClass) {
this.entityClass = entityClass;
}
@Override
protected String normalize(String path) {
return path;
}
}
public static class CompositePropertyPathSource extends AbstractPropertyPathSource implements PropertyPathSource {
private final AbstractPropertyPathSource sourceOfComposite;
private final String compositeName;
public CompositePropertyPathSource(AbstractPropertyPathSource sourceOfComposite, String compositeName) {
this.sourceOfComposite = sourceOfComposite;
this.compositeName = compositeName;
}
@Override
protected String normalize(String path) {
return getSourceOfComposite().normalize( compositeName ) + "." + path;
}
public AbstractPropertyPathSource getSourceOfComposite() {
return sourceOfComposite;
}
public String getCompositeName() {
return compositeName;
}
}
public static class CollectionPropertyPathSource extends AbstractPropertyPathSource implements PropertyPathSource {
private final AbstractPropertyPathSource collectionSource;
private final String collectionName;
private CollectionPropertyPathSource(AbstractPropertyPathSource collectionSource, String collectionName) {
this.collectionSource = collectionSource;
this.collectionName = collectionName;
}
@Override
protected String normalize(String path) {
return path;
}
}
}

View File

@ -1367,7 +1367,7 @@ public abstract class CollectionBinder {
column.setTable( collValue.getCollectionTable() );
}
elementBinder.setColumns( elementColumns );
elementBinder.setType( property, elementClass, collValue.getOwnerEntityName() );
elementBinder.setType( property, elementClass, collValue.getOwnerEntityName(), null );
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );
collValue.setElement( elementBinder.make() );

View File

@ -278,7 +278,7 @@ public class MapBinder extends CollectionBinder {
elementBinder.setExplicitType( mapKeyTypeAnnotation.value() );
}
else {
elementBinder.setType( property, elementClass, this.collection.getOwnerEntityName() );
elementBinder.setType( property, elementClass, this.collection.getOwnerEntityName(), null );
}
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );

View File

@ -176,17 +176,23 @@ public class PropertyBinder {
private Property makePropertyAndValue() {
validateBind();
LOG.debugf( "MetadataSourceProcessor property %s with lazy=%s", name, lazy );
String containerClassName = holder == null ?
null :
holder.getClassName();
final String containerClassName = holder.getClassName();
holder.startingProperty( property );
simpleValueBinder = new SimpleValueBinder();
simpleValueBinder.setMappings( mappings );
simpleValueBinder.setPropertyName( name );
simpleValueBinder.setReturnedClassName( returnedClassName );
simpleValueBinder.setColumns( columns );
simpleValueBinder.setPersistentClassName( containerClassName );
simpleValueBinder.setType( property, returnedClass, containerClassName );
simpleValueBinder.setType(
property,
returnedClass,
containerClassName,
holder.resolveAttributeConverterDefinition( property )
);
simpleValueBinder.setMappings( mappings );
simpleValueBinder.setReferencedEntityName( referencedEntityName );
simpleValueBinder.setAccessType( accessType );

View File

@ -23,15 +23,6 @@
*/
package org.hibernate.cfg.annotations;
import java.io.Serializable;
import java.lang.reflect.TypeVariable;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import javax.persistence.Converts;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Lob;
@ -39,6 +30,12 @@ import javax.persistence.MapKeyEnumerated;
import javax.persistence.MapKeyTemporal;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
@ -46,9 +43,10 @@ import org.hibernate.MappingException;
import org.hibernate.annotations.Nationalized;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.common.reflection.ClassLoadingException;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.annotations.common.util.ReflectHelper;
import org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.BinderHelper;
@ -73,7 +71,6 @@ import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.StringNVarcharType;
import org.hibernate.type.WrappedMaterializedBlobType;
import org.hibernate.usertype.DynamicParameterizedType;
import org.jboss.logging.Logger;
/**
* @author Emmanuel Bernard
@ -144,7 +141,7 @@ public class SimpleValueBinder {
//TODO execute it lazily to be order safe
public void setType(XProperty property, XClass returnedClass, String declaringClassName) {
public void setType(XProperty property, XClass returnedClass, String declaringClassName, AttributeConverterDefinition attributeConverterDefinition) {
if ( returnedClass == null ) {
// we cannot guess anything
return;
@ -302,11 +299,11 @@ public class SimpleValueBinder {
defaultType = BinderHelper.isEmptyAnnotationValue( type ) ? returnedClassName : type;
this.typeParameters = typeParameters;
applyAttributeConverter( property );
applyAttributeConverter( property, attributeConverterDefinition );
}
private void applyAttributeConverter(XProperty property) {
if ( attributeConverterDefinition != null ) {
private void applyAttributeConverter(XProperty property, AttributeConverterDefinition attributeConverterDefinition) {
if ( attributeConverterDefinition == null ) {
return;
}
@ -337,58 +334,7 @@ public class SimpleValueBinder {
return;
}
// @Convert annotations take precedence if present
final Convert convertAnnotation = locateConvertAnnotation( property );
if ( convertAnnotation != null ) {
LOG.debugf(
"Applying located @Convert AttributeConverter [%s] to attribute [%]",
convertAnnotation.converter().getName(),
property.getName()
);
attributeConverterDefinition = mappings.locateAttributeConverter( convertAnnotation.converter() );
if ( attributeConverterDefinition == null ) {
attributeConverterDefinition = makeAttributeConverterDefinition( convertAnnotation );
}
}
else {
attributeConverterDefinition = locateAutoApplyAttributeConverter( property );
}
}
private AttributeConverterDefinition makeAttributeConverterDefinition(Convert convertAnnotation) {
try {
return new AttributeConverterDefinition(
(AttributeConverter) convertAnnotation.converter().newInstance(),
false
);
}
catch (Exception e) {
throw new AnnotationException( "Unable to create AttributeConverter instance", e );
}
}
private AttributeConverterDefinition locateAutoApplyAttributeConverter(XProperty property) {
LOG.debugf(
"Attempting to locate auto-apply AttributeConverter for property [%s:%s]",
persistentClassName,
property.getName()
);
final Class propertyType = mappings.getReflectionManager().toClass( property.getType() );
for ( AttributeConverterDefinition attributeConverterDefinition : mappings.getAttributeConverters() ) {
if ( ! attributeConverterDefinition.isAutoApply() ) {
continue;
}
LOG.debugf(
"Checking auto-apply AttributeConverter [%s] type [%s] for match [%s]",
attributeConverterDefinition.toString(),
attributeConverterDefinition.getEntityAttributeType().getSimpleName(),
propertyType.getSimpleName()
);
if ( areTypeMatch( attributeConverterDefinition.getEntityAttributeType(), propertyType ) ) {
return attributeConverterDefinition;
}
}
return null;
this.attributeConverterDefinition = attributeConverterDefinition;
}
private boolean isAssociation() {
@ -397,218 +343,6 @@ public class SimpleValueBinder {
return referencedEntityName != null;
}
@SuppressWarnings("unchecked")
private Convert locateConvertAnnotation(XProperty property) {
LOG.debugf(
"Attempting to locate Convert annotation for property [%s:%s]",
persistentClassName,
property.getName()
);
// first look locally on the property for @Convert/@Converts
{
Convert localConvertAnnotation = property.getAnnotation( Convert.class );
if ( localConvertAnnotation != null ) {
LOG.debugf(
"Found matching local @Convert annotation [disableConversion=%s]",
localConvertAnnotation.disableConversion()
);
return localConvertAnnotation.disableConversion()
? null
: localConvertAnnotation;
}
}
{
Converts localConvertsAnnotation = property.getAnnotation( Converts.class );
if ( localConvertsAnnotation != null ) {
for ( Convert localConvertAnnotation : localConvertsAnnotation.value() ) {
if ( isLocalMatch( localConvertAnnotation, property ) ) {
LOG.debugf(
"Found matching @Convert annotation as part local @Converts [disableConversion=%s]",
localConvertAnnotation.disableConversion()
);
return localConvertAnnotation.disableConversion()
? null
: localConvertAnnotation;
}
}
}
}
if ( persistentClassName == null ) {
LOG.debug( "Persistent Class name not known during attempt to locate @Convert annotations" );
return null;
}
final XClass owner;
try {
final Class ownerClass = ReflectHelper.classForName( persistentClassName );
owner = mappings.getReflectionManager().classForName( persistentClassName, ownerClass );
}
catch (ClassNotFoundException e) {
throw new AnnotationException( "Unable to resolve Class reference during attempt to locate @Convert annotations" );
}
return lookForEntityDefinedConvertAnnotation( property, owner );
}
private Convert lookForEntityDefinedConvertAnnotation(XProperty property, XClass owner) {
if ( owner == null ) {
// we have hit the root of the entity hierarchy
return null;
}
LOG.debugf(
"Attempting to locate any AttributeConverter defined via @Convert/@Converts on type-hierarchy [%s] to apply to attribute [%s]",
owner.getName(),
property.getName()
);
{
Convert convertAnnotation = owner.getAnnotation( Convert.class );
if ( convertAnnotation != null && isMatch( convertAnnotation, property ) ) {
LOG.debugf(
"Found matching @Convert annotation [disableConversion=%s]",
convertAnnotation.disableConversion()
);
return convertAnnotation.disableConversion() ? null : convertAnnotation;
}
}
{
Converts convertsAnnotation = owner.getAnnotation( Converts.class );
if ( convertsAnnotation != null ) {
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
if ( isMatch( convertAnnotation, property ) ) {
LOG.debugf(
"Found matching @Convert annotation as part @Converts [disableConversion=%s]",
convertAnnotation.disableConversion()
);
return convertAnnotation.disableConversion() ? null : convertAnnotation;
}
}
}
}
// finally, look on superclass
return lookForEntityDefinedConvertAnnotation( property, owner.getSuperclass() );
}
@SuppressWarnings("unchecked")
private boolean isLocalMatch(Convert convertAnnotation, XProperty property) {
if ( StringHelper.isEmpty( convertAnnotation.attributeName() ) ) {
return isTypeMatch( convertAnnotation.converter(), property );
}
return property.getName().equals( convertAnnotation.attributeName() )
&& isTypeMatch( convertAnnotation.converter(), property );
}
@SuppressWarnings("unchecked")
private boolean isMatch(Convert convertAnnotation, XProperty property) {
return property.getName().equals( convertAnnotation.attributeName() );
// return property.getName().equals( convertAnnotation.attributeName() )
// && isTypeMatch( convertAnnotation.converter(), property );
}
private boolean isTypeMatch(Class<? extends AttributeConverter> attributeConverterClass, XProperty property) {
return areTypeMatch(
extractEntityAttributeType( attributeConverterClass ),
mappings.getReflectionManager().toClass( property.getType() )
);
}
private Class extractEntityAttributeType(Class<? extends AttributeConverter> attributeConverterClass) {
// this is duplicated in SimpleValue...
final TypeVariable[] attributeConverterTypeInformation = attributeConverterClass.getTypeParameters();
if ( attributeConverterTypeInformation == null || attributeConverterTypeInformation.length < 2 ) {
throw new AnnotationException(
"AttributeConverter [" + attributeConverterClass.getName()
+ "] did not retain parameterized type information"
);
}
if ( attributeConverterTypeInformation.length > 2 ) {
LOG.debug(
"AttributeConverter [" + attributeConverterClass.getName()
+ "] specified more than 2 parameterized types"
);
}
final Class entityAttributeJavaType = extractType( attributeConverterTypeInformation[0] );
if ( entityAttributeJavaType == null ) {
throw new AnnotationException(
"Could not determine 'entity attribute' type from given AttributeConverter [" +
attributeConverterClass.getName() + "]"
);
}
return entityAttributeJavaType;
}
private Class extractType(TypeVariable typeVariable) {
java.lang.reflect.Type[] boundTypes = typeVariable.getBounds();
if ( boundTypes == null || boundTypes.length != 1 ) {
return null;
}
return (Class) boundTypes[0];
}
private boolean areTypeMatch(Class converterDefinedType, Class propertyType) {
if ( converterDefinedType == null ) {
throw new AnnotationException( "AttributeConverter defined java type cannot be null" );
}
if ( propertyType == null ) {
throw new AnnotationException( "Property defined java type cannot be null" );
}
return converterDefinedType.equals( propertyType )
|| arePrimitiveWrapperEquivalents( converterDefinedType, propertyType );
}
private boolean arePrimitiveWrapperEquivalents(Class converterDefinedType, Class propertyType) {
if ( converterDefinedType.isPrimitive() ) {
return getWrapperEquivalent( converterDefinedType ).equals( propertyType );
}
else if ( propertyType.isPrimitive() ) {
return getWrapperEquivalent( propertyType ).equals( converterDefinedType );
}
return false;
}
private static Class getWrapperEquivalent(Class primitive) {
if ( ! primitive.isPrimitive() ) {
throw new AssertionFailure( "Passed type for which to locate wrapper equivalent was not a primitive" );
}
if ( boolean.class.equals( primitive ) ) {
return Boolean.class;
}
else if ( char.class.equals( primitive ) ) {
return Character.class;
}
else if ( byte.class.equals( primitive ) ) {
return Byte.class;
}
else if ( short.class.equals( primitive ) ) {
return Short.class;
}
else if ( int.class.equals( primitive ) ) {
return Integer.class;
}
else if ( long.class.equals( primitive ) ) {
return Long.class;
}
else if ( float.class.equals( primitive ) ) {
return Float.class;
}
else if ( double.class.equals( primitive ) ) {
return Double.class;
}
throw new AssertionFailure( "Unexpected primitive type (VOID most likely) passed to getWrapperEquivalent" );
}
private TemporalType getTemporalType(XProperty property) {
if ( key ) {
MapKeyTemporal ann = property.getAnnotation( MapKeyTemporal.class );
@ -754,7 +488,7 @@ public class SimpleValueBinder {
if ( simpleValue.getTypeName() != null && simpleValue.getTypeName().length() > 0
&& simpleValue.getMappings().getTypeResolver().basic( simpleValue.getTypeName() ) == null ) {
try {
Class typeClass = ReflectHelper.classForName( simpleValue.getTypeName() );
Class typeClass = StandardClassLoaderDelegateImpl.INSTANCE.classForName( simpleValue.getTypeName() );
if ( typeClass != null && DynamicParameterizedType.class.isAssignableFrom( typeClass ) ) {
Properties parameters = simpleValue.getTypeParameters();
@ -772,8 +506,8 @@ public class SimpleValueBinder {
simpleValue.setTypeParameters( parameters );
}
}
catch ( ClassNotFoundException cnfe ) {
throw new MappingException( "Could not determine type for: " + simpleValue.getTypeName(), cnfe );
catch (ClassLoadingException e) {
throw new MappingException( "Could not determine type for: " + simpleValue.getTypeName(), e );
}
}

View File

@ -80,7 +80,7 @@ public class SimpleValue implements KeyValue {
private Properties typeParameters;
private boolean cascadeDeleteEnabled;
private AttributeConverterDefinition jpaAttributeConverterDefinition;
private AttributeConverterDefinition attributeConverterDefinition;
private Type type;
public SimpleValue(Mappings mappings) {
@ -354,7 +354,7 @@ public class SimpleValue implements KeyValue {
return;
}
if ( jpaAttributeConverterDefinition == null ) {
if ( attributeConverterDefinition == null ) {
// this is here to work like legacy. This should change when we integrate with metamodel to
// look for SqlTypeDescriptor and JavaTypeDescriptor individually and create the BasicType (well, really
// keep a registry of [SqlTypeDescriptor,JavaTypeDescriptor] -> BasicType...)
@ -405,8 +405,8 @@ public class SimpleValue implements KeyValue {
private Type buildAttributeConverterTypeAdapter() {
// todo : validate the number of columns present here?
final Class entityAttributeJavaType = jpaAttributeConverterDefinition.getEntityAttributeType();
final Class databaseColumnJavaType = jpaAttributeConverterDefinition.getDatabaseColumnType();
final Class entityAttributeJavaType = attributeConverterDefinition.getEntityAttributeType();
final Class databaseColumnJavaType = attributeConverterDefinition.getDatabaseColumnType();
// resolve the JavaTypeDescriptor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -430,7 +430,7 @@ public class SimpleValue implements KeyValue {
// and finally construct the adapter, which injects the AttributeConverter calls into the binding/extraction
// process...
final SqlTypeDescriptor sqlTypeDescriptorAdapter = new AttributeConverterSqlTypeDescriptorAdapter(
jpaAttributeConverterDefinition.getAttributeConverter(),
attributeConverterDefinition.getAttributeConverter(),
sqlTypeDescriptor,
intermediateJavaTypeDescriptor
);
@ -444,7 +444,7 @@ public class SimpleValue implements KeyValue {
);
return new AttributeConverterTypeAdapter(
name,
jpaAttributeConverterDefinition.getAttributeConverter(),
attributeConverterDefinition.getAttributeConverter(),
sqlTypeDescriptorAdapter,
entityAttributeJavaTypeDescriptor
);
@ -486,8 +486,8 @@ public class SimpleValue implements KeyValue {
return getColumnInsertability();
}
public void setJpaAttributeConverterDefinition(AttributeConverterDefinition jpaAttributeConverterDefinition) {
this.jpaAttributeConverterDefinition = jpaAttributeConverterDefinition;
public void setJpaAttributeConverterDefinition(AttributeConverterDefinition attributeConverterDefinition) {
this.attributeConverterDefinition = attributeConverterDefinition;
}
private void createParameterImpl() {

View File

@ -142,7 +142,6 @@ public class AttributeConverterTest extends BaseUnitTestCase {
}
@Test
@FailureExpected( jiraKey = "HHH-8449" )
public void testBasicConverterDisableApplication() {
Configuration cfg = new Configuration();
cfg.addAttributeConverter( StringClobConverter.class, true );

View File

@ -0,0 +1,120 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.convert;
import javax.persistence.Convert;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.CompositeType;
import org.hibernate.type.StringType;
import org.hibernate.type.Type;
import org.junit.Test;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
/**
* Tests MappedSuperclass/Entity overriding of Convert definitions
*
* @author Steve Ebersole
*/
public class SimpleEmbeddableOverriddenConverterTest extends BaseUnitTestCase {
/**
* Test outcome of annotations exclusively.
*/
@Test
public void testSimpleConvertOverrides() {
final PersistenceUnitDescriptorAdapter pu = new PersistenceUnitDescriptorAdapter() {
@Override
public List<String> getManagedClassNames() {
return Arrays.asList( Person.class.getName() );
}
};
final Map settings = new HashMap();
// settings.put( AvailableSettings.HBM2DDL_AUTO, "create-drop" );
EntityManagerFactory emf = Bootstrap.getEntityManagerFactoryBuilder( pu, settings ).build();
final SessionFactoryImplementor sfi = emf.unwrap( SessionFactoryImplementor.class );
try {
final EntityPersister ep = sfi.getEntityPersister( Person.class.getName() );
CompositeType homeAddressType = assertTyping( CompositeType.class, ep.getPropertyType( "homeAddress" ) );
Type homeAddressCityType = findCompositeAttributeType( homeAddressType, "city" );
assertTyping( StringType.class, homeAddressCityType );
}
finally {
emf.close();
}
}
public Type findCompositeAttributeType(CompositeType compositeType, String attributeName) {
int pos = 0;
for ( String name : compositeType.getPropertyNames() ) {
if ( name.equals( attributeName ) ) {
break;
}
pos++;
}
if ( pos >= compositeType.getPropertyNames().length ) {
throw new IllegalStateException( "Could not locate attribute index for [" + attributeName + "] in composite" );
}
return compositeType.getSubtypes()[pos];
}
@Embeddable
public static class Address {
public String street;
@Convert(converter = SillyStringConverter.class)
public String city;
}
@Entity( name="Person" )
public static class Person {
@Id
public Integer id;
@Embedded
@Convert( attributeName = "city", disableConversion = true )
public Address homeAddress;
}
}

View File

@ -43,7 +43,6 @@ import org.hibernate.type.Type;
import org.junit.Test;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
@ -58,7 +57,6 @@ public class SimpleOverriddenConverterTest extends BaseUnitTestCase {
* Test outcome of annotations exclusively.
*/
@Test
@FailureExpected( jiraKey = "HHH-8449" )
public void testSimpleConvertOverrides() {
final PersistenceUnitDescriptorAdapter pu = new PersistenceUnitDescriptorAdapter() {
@Override

View File

@ -43,7 +43,7 @@ ext {
// Annotations
commons_annotations:
'org.hibernate.common:hibernate-commons-annotations:4.0.2.Final@jar',
'org.hibernate.common:hibernate-commons-annotations:4.0.3.Final@jar',
jandex: 'org.jboss:jandex:1.1.0.Alpha1',
classmate: 'com.fasterxml:classmate:0.8.0',