HHH-7108 HHH-6608

This commit is contained in:
Strong Liu 2012-08-07 15:08:23 +08:00
parent 45118e729d
commit d0e13b664a
18 changed files with 994 additions and 103 deletions

View File

@ -2496,6 +2496,7 @@ public final class AnnotationBinder {
value.setPersistentClassName( persistentClassName );
value.setMappings( mappings );
value.setType( inferredData.getProperty(), inferredData.getClassOrElement() );
value.setAccessType( propertyAccessor );
id = value.make();
}
rootClass.setIdentifier( id );

View File

@ -268,15 +268,15 @@ public class BinderHelper {
*/
StringBuilder propertyNameBuffer = new StringBuilder( "_" );
propertyNameBuffer.append( associatedClass.getEntityName().replace( '.', '_' ) );
propertyNameBuffer.append( "_" ).append( columns[0].getPropertyName() );
propertyNameBuffer.append( "_" ).append( columns[0].getPropertyName().replace( '.', '_' ) );
String syntheticPropertyName = propertyNameBuffer.toString();
//find properties associated to a certain column
Object columnOwner = findColumnOwner( ownerEntity, columns[0].getReferencedColumn(), mappings );
List<Property> properties = findPropertiesByColumns( columnOwner, columns, mappings );
//create an embeddable component
Property synthProp = null;
Property synthProp = null;
if ( properties != null ) {
//todo how about properties.size() == 1, this should be much simpler
//todo how about properties.size() == 1, this should be much simpler
Component embeddedComp = columnOwner instanceof PersistentClass ?
new Component( mappings, (PersistentClass) columnOwner ) :
new Component( mappings, (Join) columnOwner );
@ -290,8 +290,8 @@ public class BinderHelper {
clone.setNaturalIdentifier( false );
clone.setGeneration( property.getGeneration() );
embeddedComp.addProperty( clone );
}
synthProp = new SyntheticProperty();
}
synthProp = new SyntheticProperty();
synthProp.setName( syntheticPropertyName );
synthProp.setNodeName( syntheticPropertyName );
synthProp.setPersistentClass( ownerEntity );
@ -300,9 +300,9 @@ public class BinderHelper {
synthProp.setValue( embeddedComp );
synthProp.setPropertyAccessorName( "embedded" );
ownerEntity.addProperty( synthProp );
//make it unique
//make it unique
TableBinder.createUniqueConstraint( embeddedComp );
}
}
else {
//TODO use a ToOne type doing a second select
StringBuilder columnsList = new StringBuilder();
@ -830,7 +830,7 @@ public class BinderHelper {
for (int i = 0; i < aliases.length; i++){
if (StringHelper.isNotEmpty(aliases[i].table())){
ret.put(aliases[i].alias(), aliases[i].table());
}
}
}
return ret;
}

View File

@ -1289,6 +1289,8 @@ public abstract class CollectionBinder {
}
elementBinder.setColumns( elementColumns );
elementBinder.setType( property, elementClass );
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );
collValue.setElement( elementBinder.make() );
String orderBy = adjustUserSuppliedValueCollectionOrderingFragment( hqlOrderBy );
if ( orderBy != null ) {
@ -1439,4 +1441,4 @@ public abstract class CollectionBinder {
public void setLocalGenerators(HashMap<String, IdGenerator> localGenerators) {
this.localGenerators = localGenerators;
}
}
}

View File

@ -210,26 +210,25 @@ public class MapBinder extends CollectionBinder {
}
}
PersistentClass owner = mapValue.getOwner();
AccessType accessType;
// FIXME support @Access for collection of elements
// String accessType = access != null ? access.value() : null;
if ( owner.getIdentifierProperty() != null ) {
accessType = owner.getIdentifierProperty().getPropertyAccessorName().equals( "property" ) ? AccessType.PROPERTY
: AccessType.FIELD;
}
else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) {
Property prop = (Property) owner.getIdentifierMapper().getPropertyIterator().next();
accessType = prop.getPropertyAccessorName().equals( "property" ) ? AccessType.PROPERTY
: AccessType.FIELD;
}
else {
throw new AssertionFailure( "Unable to guess collection property accessor name" );
}
if ( AnnotatedClassType.EMBEDDABLE.equals( classType ) ) {
EntityBinder entityBinder = new EntityBinder();
PersistentClass owner = mapValue.getOwner();
boolean isPropertyAnnotated;
//FIXME support @Access for collection of elements
//String accessType = access != null ? access.value() : null;
if ( owner.getIdentifierProperty() != null ) {
isPropertyAnnotated = owner.getIdentifierProperty()
.getPropertyAccessorName()
.equals( "property" );
}
else
if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) {
Property prop = (Property) owner.getIdentifierMapper().getPropertyIterator().next();
isPropertyAnnotated = prop.getPropertyAccessorName().equals( "property" );
}
else {
throw new AssertionFailure( "Unable to guess collection property accessor name" );
}
PropertyData inferredData;
if ( isHibernateExtensionMapping() ) {
@ -242,7 +241,7 @@ public class MapBinder extends CollectionBinder {
//TODO be smart with isNullable
Component component = AnnotationBinder.fillComponent(
holder, inferredData, isPropertyAnnotated ? AccessType.PROPERTY : AccessType.FIELD, true,
holder, inferredData, accessType, true,
entityBinder, false, false,
true, mappings, inheritanceStatePerClass
);
@ -285,6 +284,8 @@ public class MapBinder extends CollectionBinder {
else {
elementBinder.setType( property, elementClass );
}
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );
mapValue.setIndex( elementBinder.make() );
}
}

View File

@ -188,6 +188,7 @@ public class PropertyBinder {
simpleValueBinder.setType( property, returnedClass );
simpleValueBinder.setMappings( mappings );
simpleValueBinder.setReferencedEntityName( referencedEntityName );
simpleValueBinder.setAccessType( accessType );
SimpleValue propertyValue = simpleValueBinder.make();
setValue( propertyValue );
return makeProperty();

View File

@ -24,6 +24,7 @@
package org.hibernate.cfg.annotations;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.TypeVariable;
import java.sql.Types;
import java.util.Calendar;
@ -40,15 +41,15 @@ import javax.persistence.MapKeyTemporal;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
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.AccessType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3Column;
@ -67,6 +68,8 @@ import org.hibernate.type.PrimitiveCharacterArrayClobType;
import org.hibernate.type.SerializableToBlobType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.WrappedMaterializedBlobType;
import org.hibernate.usertype.DynamicParameterizedType;
import org.jboss.logging.Logger;
/**
* @author Emmanuel Bernard
@ -79,6 +82,7 @@ public class SimpleValueBinder {
private Ejb3Column[] columns;
private String persistentClassName;
private String explicitType = "";
private String defaultType = "";
private Properties typeParameters = new Properties();
private Mappings mappings;
private Table table;
@ -88,6 +92,8 @@ public class SimpleValueBinder {
//is a Map key
private boolean key;
private String referencedEntityName;
private XProperty xproperty;
private AccessType accessType;
private AttributeConverterDefinition attributeConverterDefinition;
@ -113,6 +119,10 @@ public class SimpleValueBinder {
public void setReturnedClassName(String returnedClassName) {
this.returnedClassName = returnedClassName;
if ( defaultType.length() == 0 ) {
defaultType = returnedClassName;
}
}
public void setTable(Table table) {
@ -135,15 +145,22 @@ public class SimpleValueBinder {
return;
} //we cannot guess anything
XClass returnedClassOrElement = returnedClass;
boolean isArray = false;
boolean isArray = false;
if ( property.isArray() ) {
returnedClassOrElement = property.getElementClass();
isArray = true;
}
this.xproperty = property;
Properties typeParameters = this.typeParameters;
typeParameters.clear();
String type = BinderHelper.ANNOTATION_STRING_DEFAULT;
if ( ( !key && property.isAnnotationPresent( Temporal.class ) )
Type annType = property.getAnnotation( Type.class );
if ( annType != null ) {
setExplicitType( annType );
type = explicitType;
}
else if ( ( !key && property.isAnnotationPresent( Temporal.class ) )
|| ( key && property.isAnnotationPresent( MapKeyTemporal.class ) ) ) {
boolean isDate;
@ -179,6 +196,7 @@ public class SimpleValueBinder {
default:
throw new AssertionFailure( "Unknown temporal type: " + temporalType );
}
explicitType = type;
}
else if ( property.isAnnotationPresent( Lob.class ) ) {
if ( mappings.getReflectionManager().equals( returnedClassOrElement, java.sql.Clob.class ) ) {
@ -215,42 +233,27 @@ public class SimpleValueBinder {
else {
type = "blob";
}
explicitType = type;
}
//implicit type will check basic types and Serializable classes
else if ( ( !key && property.isAnnotationPresent( Enumerated.class ) )
|| ( key && property.isAnnotationPresent( MapKeyEnumerated.class ) ) ) {
type = EnumType.class.getName();
explicitType = type;
}
// implicit type will check basic types and Serializable classes
if ( columns == null ) {
throw new AssertionFailure( "SimpleValueBinder.setColumns should be set before SimpleValueBinder.setType" );
}
if ( BinderHelper.ANNOTATION_STRING_DEFAULT.equals( type ) ) {
if ( returnedClassOrElement.isEnum() ) {
type = EnumType.class.getName();
typeParameters = new Properties();
typeParameters.setProperty( EnumType.ENUM, returnedClassOrElement.getName() );
String schema = columns[0].getTable().getSchema();
schema = schema == null ? "" : schema;
String catalog = columns[0].getTable().getCatalog();
catalog = catalog == null ? "" : catalog;
typeParameters.setProperty( EnumType.SCHEMA, schema );
typeParameters.setProperty( EnumType.CATALOG, catalog );
typeParameters.setProperty( EnumType.TABLE, columns[0].getTable().getName() );
typeParameters.setProperty( EnumType.COLUMN, columns[0].getName() );
javax.persistence.EnumType enumType = getEnumType( property );
if ( enumType != null ) {
if ( javax.persistence.EnumType.ORDINAL.equals( enumType ) ) {
typeParameters.setProperty( EnumType.TYPE, String.valueOf( Types.INTEGER ) );
}
else if ( javax.persistence.EnumType.STRING.equals( enumType ) ) {
typeParameters.setProperty( EnumType.TYPE, String.valueOf( Types.VARCHAR ) );
}
else {
throw new AssertionFailure( "Unknown EnumType: " + enumType );
}
}
}
}
explicitType = type;
defaultType = BinderHelper.isEmptyAnnotationValue( type ) ? returnedClassName : type;
this.typeParameters = typeParameters;
Type annType = property.getAnnotation( Type.class );
setExplicitType( annType );
applyAttributeConverter( property );
}
@ -447,24 +450,7 @@ public class SimpleValueBinder {
throw new AssertionFailure( "Unexpected primitive type (VOID most likely) passed to getWrapperEquivalent" );
}
private javax.persistence.EnumType getEnumType(XProperty property) {
javax.persistence.EnumType enumType = null;
if ( key ) {
MapKeyEnumerated enumAnn = property.getAnnotation( MapKeyEnumerated.class );
if ( enumAnn != null ) {
enumType = enumAnn.value();
}
}
else {
Enumerated enumAnn = property.getAnnotation( Enumerated.class );
if ( enumAnn != null ) {
enumType = enumAnn.value();
}
}
return enumType;
}
private TemporalType getTemporalType(XProperty property) {
if ( key ) {
MapKeyTemporal ann = property.getAnnotation( MapKeyTemporal.class );
@ -542,7 +528,7 @@ public class SimpleValueBinder {
public void fillSimpleValue() {
LOG.debugf( "Setting SimpleValue typeName for %s", propertyName );
if ( attributeConverterDefinition != null ) {
if ( ! BinderHelper.isEmptyAnnotationValue( explicitType ) ) {
throw new AnnotationException(
@ -557,8 +543,26 @@ public class SimpleValueBinder {
simpleValue.setJpaAttributeConverterDefinition( attributeConverterDefinition );
}
else {
String type = BinderHelper.isEmptyAnnotationValue( explicitType ) ? returnedClassName : explicitType;
org.hibernate.mapping.TypeDef typeDef = mappings.getTypeDef( type );
String type;
org.hibernate.mapping.TypeDef typeDef;
if ( !BinderHelper.isEmptyAnnotationValue( explicitType ) ) {
type = explicitType;
typeDef = mappings.getTypeDef( type );
}
else {
// try implicit type
org.hibernate.mapping.TypeDef implicitTypeDef = mappings.getTypeDef( returnedClassName );
if ( implicitTypeDef != null ) {
typeDef = implicitTypeDef;
type = returnedClassName;
}
else {
typeDef = mappings.getTypeDef( defaultType );
type = defaultType;
}
}
if ( typeDef != null ) {
type = typeDef.getTypeClass();
simpleValue.setTypeParameters( typeDef.getParameters() );
@ -582,10 +586,43 @@ public class SimpleValueBinder {
if ( timeStampVersionType != null ) {
simpleValue.setTypeName( timeStampVersionType );
}
if ( simpleValue.getTypeName() != null && simpleValue.getTypeName().length() > 0
&& simpleValue.getMappings().getTypeResolver().basic( simpleValue.getTypeName() ) == null ) {
try {
Class typeClass = ReflectHelper.classForName( simpleValue.getTypeName() );
if ( typeClass != null && DynamicParameterizedType.class.isAssignableFrom( typeClass ) ) {
Properties parameters = simpleValue.getTypeParameters();
if ( parameters == null ) {
parameters = new Properties();
}
parameters.put( DynamicParameterizedType.IS_DYNAMIC, Boolean.toString( true ) );
parameters.put( DynamicParameterizedType.RETURNED_CLASS, returnedClassName );
parameters.put( DynamicParameterizedType.IS_PRIMARY_KEY, Boolean.toString( key ) );
parameters.put( DynamicParameterizedType.ENTITY, persistentClassName );
parameters.put( DynamicParameterizedType.PROPERTY, xproperty.getName() );
parameters.put( DynamicParameterizedType.ACCESS_TYPE, accessType.getType() );
simpleValue.setTypeParameters( parameters );
}
}
catch ( ClassNotFoundException cnfe ) {
throw new MappingException( "Could not determine type for: " + simpleValue.getTypeName(), cnfe );
}
}
}
public void setKey(boolean key) {
this.key = key;
}
}
public AccessType getAccessType() {
return accessType;
}
public void setAccessType(AccessType accessType) {
this.accessType = accessType;
}
}

View File

@ -23,6 +23,8 @@
*/
package org.hibernate.mapping;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import javax.persistence.AttributeConverter;
import java.lang.reflect.TypeVariable;
import java.sql.CallableStatement;
@ -36,9 +38,9 @@ import java.util.Properties;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.FetchMode;
import org.hibernate.MappingException;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Mappings;
@ -49,6 +51,7 @@ import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.property.DirectPropertyAccessor;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.ValueBinder;
@ -61,6 +64,7 @@ import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.JdbcTypeJavaClassMappings;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry;
import org.hibernate.usertype.DynamicParameterizedType;
/**
* Any value that maps to columns.
@ -324,6 +328,11 @@ public class SimpleValue implements KeyValue {
if ( typeName == null ) {
throw new MappingException( "No type name" );
}
if ( typeParameters != null
&& Boolean.valueOf( typeParameters.getProperty( DynamicParameterizedType.IS_DYNAMIC ) )
&& typeParameters.get( DynamicParameterizedType.PARAMETER_TYPE ) == null ) {
createParameterImpl();
}
Type result = mappings.getTypeResolver().heuristicType( typeName, typeParameters );
if ( result == null ) {
@ -331,7 +340,7 @@ public class SimpleValue implements KeyValue {
if ( table != null ) {
msg += ", at table: " + table.getName();
}
if ( columns!=null && columns.size()>0 ) {
if ( columns != null && columns.size() > 0 ) {
msg += ", for columns: " + columns;
}
throw new MappingException( msg );
@ -510,4 +519,97 @@ public class SimpleValue implements KeyValue {
};
}
}
}
private void createParameterImpl() {
try {
String[] columnsNames = new String[columns.size()];
for ( int i = 0; i < columns.size(); i++ ) {
columnsNames[i] = ( (Column) columns.get( i ) ).getName();
}
AccessType accessType = AccessType.getAccessStrategy( typeParameters
.getProperty( DynamicParameterizedType.ACCESS_TYPE ) );
final Class classEntity = ReflectHelper.classForName( typeParameters
.getProperty( DynamicParameterizedType.ENTITY ) );
final String propertyName = typeParameters.getProperty( DynamicParameterizedType.PROPERTY );
Annotation[] annotations;
if ( accessType == AccessType.FIELD ) {
annotations = ( (Field) new DirectPropertyAccessor().getGetter( classEntity, propertyName ).getMember() )
.getAnnotations();
}
else {
annotations = ReflectHelper.getGetter( classEntity, propertyName ).getMethod().getAnnotations();
}
typeParameters.put(
DynamicParameterizedType.PARAMETER_TYPE,
new ParameterTypeImpl( ReflectHelper.classForName( typeParameters
.getProperty( DynamicParameterizedType.RETURNED_CLASS ) ), annotations, table.getCatalog(),
table.getSchema(), table.getName(), Boolean.valueOf( typeParameters
.getProperty( DynamicParameterizedType.IS_PRIMARY_KEY ) ), columnsNames ) );
}
catch ( ClassNotFoundException cnfe ) {
throw new MappingException( "Could not create DynamicParameterizedType for type: " + typeName, cnfe );
}
}
private final class ParameterTypeImpl implements DynamicParameterizedType.ParameterType {
private final Class returnedClass;
private final Annotation[] annotationsMethod;
private final String catalog;
private final String schema;
private final String table;
private final boolean primaryKey;
private final String[] columns;
private ParameterTypeImpl(Class returnedClass, Annotation[] annotationsMethod, String catalog, String schema,
String table, boolean primaryKey, String[] columns) {
this.returnedClass = returnedClass;
this.annotationsMethod = annotationsMethod;
this.catalog = catalog;
this.schema = schema;
this.table = table;
this.primaryKey = primaryKey;
this.columns = columns;
}
@Override
public Class getReturnedClass() {
return returnedClass;
}
@Override
public Annotation[] getAnnotationsMethod() {
return annotationsMethod;
}
@Override
public String getCatalog() {
return catalog;
}
@Override
public String getSchema() {
return schema;
}
@Override
public String getTable() {
return table;
}
@Override
public boolean isPrimaryKey() {
return primaryKey;
}
@Override
public String[] getColumns() {
return columns;
}
}
}

View File

@ -24,20 +24,22 @@
package org.hibernate.type;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
import org.jboss.logging.Logger;
import javax.persistence.Enumerated;
import javax.persistence.MapKeyEnumerated;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.EnhancedUserType;
import org.hibernate.usertype.ParameterizedType;
import org.jboss.logging.Logger;
/**
* Enum type mapper
@ -49,7 +51,7 @@ import org.hibernate.usertype.ParameterizedType;
* @author Hardy Ferentschik
*/
@SuppressWarnings("unchecked")
public class EnumType implements EnhancedUserType, ParameterizedType, Serializable {
public class EnumType implements EnhancedUserType, DynamicParameterizedType, Serializable {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, EnumType.class.getName());
@ -168,17 +170,37 @@ public class EnumType implements EnhancedUserType, ParameterizedType, Serializab
}
public void setParameterValues(Properties parameters) {
String enumClassName = parameters.getProperty( ENUM );
try {
enumClass = ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass( Enum.class );
}
catch ( ClassNotFoundException exception ) {
throw new HibernateException( "Enum class not found", exception );
}
ParameterType reader = (ParameterType) parameters.get( PARAMETER_TYPE );
String type = parameters.getProperty( TYPE );
if ( type != null ) {
sqlType = Integer.decode( type );
if ( reader != null ) {
enumClass = reader.getReturnedClass().asSubclass( Enum.class );
javax.persistence.EnumType enumType = getEnumType( reader );
if ( enumType != null ) {
if ( javax.persistence.EnumType.ORDINAL.equals( enumType ) ) {
sqlType = Types.INTEGER;
}
else if ( javax.persistence.EnumType.STRING.equals( enumType ) ) {
sqlType = Types.VARCHAR;
}
else {
throw new AssertionFailure( "Unknown EnumType: " + enumType );
}
}
}
else {
String enumClassName = (String) parameters.get( ENUM );
try {
enumClass = ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass( Enum.class );
}
catch ( ClassNotFoundException exception ) {
throw new HibernateException( "Enum class not found", exception );
}
String type = (String) parameters.get( TYPE );
if ( type != null ) {
sqlType = Integer.decode( type );
}
}
}
@ -234,4 +256,30 @@ public class EnumType implements EnhancedUserType, ParameterizedType, Serializab
}
}
}
private javax.persistence.EnumType getEnumType(ParameterType reader) {
javax.persistence.EnumType enumType = null;
if ( reader.isPrimaryKey() ) {
MapKeyEnumerated enumAnn = getAnnotation( reader.getAnnotationsMethod(), MapKeyEnumerated.class );
if ( enumAnn != null ) {
enumType = enumAnn.value();
}
}
else {
Enumerated enumAnn = getAnnotation( reader.getAnnotationsMethod(), Enumerated.class );
if ( enumAnn != null ) {
enumType = enumAnn.value();
}
}
return enumType;
}
private <T extends Annotation> T getAnnotation(Annotation[] annotations, Class<T> anClass) {
for ( Annotation annotation : annotations ) {
if ( anClass.isInstance( annotation ) ) {
return (T) annotation;
}
}
return null;
}
}

View File

@ -0,0 +1,45 @@
package org.hibernate.usertype;
import java.lang.annotation.Annotation;
/**
* {@inheritDoc}
*
* 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
*
* @author Janario Oliveira
*/
public interface DynamicParameterizedType extends ParameterizedType {
public static final String PARAMETER_TYPE = "org.hibernate.type.ParameterType";
public static final String IS_DYNAMIC = "org.hibernate.type.ParameterType.dynamic";
public static final String RETURNED_CLASS = "org.hibernate.type.ParameterType.returnedClass";
public static final String IS_PRIMARY_KEY = "org.hibernate.type.ParameterType.primaryKey";
public static final String ENTITY = "org.hibernate.type.ParameterType.entityClass";
public static final String PROPERTY = "org.hibernate.type.ParameterType.propertyName";
public static final String ACCESS_TYPE = "org.hibernate.type.ParameterType.accessType";
public static interface ParameterType {
public Class getReturnedClass();
public Annotation[] getAnnotationsMethod();
public String getCatalog();
public String getSchema();
public String getTable();
public boolean isPrimaryKey();
public String[] getColumns();
}
}

View File

@ -0,0 +1,93 @@
package org.hibernate.test.annotations.enumerated;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;
/**
* @author Janario Oliveira
*/
@Entity
@TypeDefs({ @TypeDef(typeClass = LastNumberType.class, defaultForType = EntityEnum.LastNumber.class) })
public class EntityEnum {
enum Common {
A1, A2, B1, B2
}
enum FirstLetter {
A_LETTER, B_LETTER, C_LETTER
}
enum LastNumber {
NUMBER_1, NUMBER_2, NUMBER_3
}
@Id
@GeneratedValue
private long id;
private Common ordinal;
@Enumerated(EnumType.STRING)
private Common string;
@Type(type = "org.hibernate.test.annotations.enumerated.FirstLetterType")
private FirstLetter firstLetter;
private LastNumber lastNumber;
@Enumerated(EnumType.STRING)
private LastNumber explicitOverridingImplicit;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Common getOrdinal() {
return ordinal;
}
public void setOrdinal(Common ordinal) {
this.ordinal = ordinal;
}
public Common getString() {
return string;
}
public void setString(Common string) {
this.string = string;
}
public FirstLetter getFirstLetter() {
return firstLetter;
}
public void setFirstLetter(FirstLetter firstLetter) {
this.firstLetter = firstLetter;
}
public LastNumber getLastNumber() {
return lastNumber;
}
public void setLastNumber(LastNumber lastNumber) {
this.lastNumber = lastNumber;
}
public LastNumber getExplicitOverridingImplicit() {
return explicitOverridingImplicit;
}
public void setExplicitOverridingImplicit(LastNumber explicitOverridingImplicit) {
this.explicitOverridingImplicit = explicitOverridingImplicit;
}
}

View File

@ -0,0 +1,335 @@
package org.hibernate.test.annotations.enumerated;
import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.type.EnumType;
import org.hibernate.type.Type;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.hibernate.test.annotations.enumerated.EntityEnum.*;
/**
* Test type definition for enum
*
* @author Janario Oliveira
*/
public class EnumeratedTypeTest extends BaseCoreFunctionalTestCase {
@Test
public void testTypeDefinition() {
Configuration cfg = configuration();
PersistentClass pc = cfg.getClassMapping( EntityEnum.class.getName() );
// ordinal default of EnumType
Type ordinalEnum = pc.getProperty( "ordinal" ).getType();
assertEquals( Common.class, ordinalEnum.getReturnedClass() );
assertEquals( EnumType.class.getName(), ordinalEnum.getName() );
// string defined by Enumerated(STRING)
Type stringEnum = pc.getProperty( "string" ).getType();
assertEquals( Common.class, stringEnum.getReturnedClass() );
assertEquals( EnumType.class.getName(), stringEnum.getName() );
// explicit defined by @Type
Type first = pc.getProperty( "firstLetter" ).getType();
assertEquals( FirstLetter.class, first.getReturnedClass() );
assertEquals( FirstLetterType.class.getName(), first.getName() );
// implicit defined by @TypeDef in somewhere
Type last = pc.getProperty( "lastNumber" ).getType();
assertEquals( LastNumber.class, last.getReturnedClass() );
assertEquals( LastNumberType.class.getName(), last.getName() );
// implicit defined by @TypeDef in anywhere, but overrided by Enumerated(STRING)
Type implicitOverrideExplicit = pc.getProperty( "explicitOverridingImplicit" ).getType();
assertEquals( LastNumber.class, implicitOverrideExplicit.getReturnedClass() );
assertEquals( EnumType.class.getName(), implicitOverrideExplicit.getName() );
}
@Test
public void testTypeQuery() {
Session session = openSession();
session.getTransaction().begin();
// persist
EntityEnum entityEnum = new EntityEnum();
entityEnum.setOrdinal( Common.A2 );
Serializable id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.ordinal=1" ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( Common.A2, entityEnum.getOrdinal() );
// find parameter
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.ordinal=:ordinal" )
.setParameter( "ordinal", Common.A2 ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( Common.A2, entityEnum.getOrdinal() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where ordinal=1" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setString( Common.B1 );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.string='B1'" ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( Common.B1, entityEnum.getString() );
// find parameter
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.string=:string" )
.setParameter( "string", Common.B1 ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( Common.B1, entityEnum.getString() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where string='B1'" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setFirstLetter( FirstLetter.C_LETTER );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.firstLetter='C'" ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( FirstLetter.C_LETTER, entityEnum.getFirstLetter() );
// find parameter
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.firstLetter=:firstLetter" )
.setParameter( "firstLetter", FirstLetter.C_LETTER ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( FirstLetter.C_LETTER, entityEnum.getFirstLetter() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where firstLetter='C'" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setLastNumber( LastNumber.NUMBER_1 );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.lastNumber='1'" ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( LastNumber.NUMBER_1, entityEnum.getLastNumber() );
// find parameter
entityEnum = (EntityEnum) session.createQuery( "from EntityEnum ee where ee.lastNumber=:lastNumber" )
.setParameter( "lastNumber", LastNumber.NUMBER_1 ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( LastNumber.NUMBER_1, entityEnum.getLastNumber() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where lastNumber='1'" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setExplicitOverridingImplicit( LastNumber.NUMBER_2 );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createQuery(
"from EntityEnum ee where ee.explicitOverridingImplicit='NUMBER_2'" ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( LastNumber.NUMBER_2, entityEnum.getExplicitOverridingImplicit() );
// find parameter
entityEnum = (EntityEnum) session
.createQuery( "from EntityEnum ee where ee.explicitOverridingImplicit=:override" )
.setParameter( "override", LastNumber.NUMBER_2 ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( LastNumber.NUMBER_2, entityEnum.getExplicitOverridingImplicit() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where explicitOverridingImplicit='NUMBER_2'" )
.executeUpdate() );
session.getTransaction().commit();
session.close();
}
@Test
public void testTypeCriteria() {
Session session = openSession();
session.getTransaction().begin();
// persist
EntityEnum entityEnum = new EntityEnum();
entityEnum.setOrdinal( Common.A1 );
Serializable id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createCriteria( EntityEnum.class )
.add( Restrictions.eq( "ordinal", Common.A1 ) ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( Common.A1, entityEnum.getOrdinal() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where ordinal=0" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setString( Common.B2 );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createCriteria( EntityEnum.class )
.add( Restrictions.eq( "string", Common.B2 ) ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( Common.B2, entityEnum.getString() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where string='B2'" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setFirstLetter( FirstLetter.A_LETTER );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createCriteria( EntityEnum.class )
.add( Restrictions.eq( "firstLetter", FirstLetter.A_LETTER ) ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( FirstLetter.A_LETTER, entityEnum.getFirstLetter() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where firstLetter='A'" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setLastNumber( LastNumber.NUMBER_3 );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createCriteria( EntityEnum.class )
.add( Restrictions.eq( "lastNumber", LastNumber.NUMBER_3 ) ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( LastNumber.NUMBER_3, entityEnum.getLastNumber() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where lastNumber='3'" ).executeUpdate() );
session.getTransaction().commit();
session.close();
// **************
session = openSession();
session.getTransaction().begin();
// persist
entityEnum = new EntityEnum();
entityEnum.setExplicitOverridingImplicit( LastNumber.NUMBER_2 );
id = session.save( entityEnum );
session.getTransaction().commit();
session.close();
session = openSession();
session.getTransaction().begin();
// find
entityEnum = (EntityEnum) session.createCriteria( EntityEnum.class )
.add( Restrictions.eq( "explicitOverridingImplicit", LastNumber.NUMBER_2 ) ).uniqueResult();
assertEquals( id, entityEnum.getId() );
assertEquals( LastNumber.NUMBER_2, entityEnum.getExplicitOverridingImplicit() );
// delete
assertEquals( 1, session.createSQLQuery( "DELETE FROM EntityEnum where explicitOverridingImplicit='NUMBER_2'" )
.executeUpdate() );
session.getTransaction().commit();
session.close();
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { EntityEnum.class };
}
}

View File

@ -0,0 +1,41 @@
package org.hibernate.test.annotations.enumerated;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
/**
* @author Janario Oliveira
*/
public class FirstLetterType extends org.hibernate.type.EnumType {
@Override
public int[] sqlTypes() {
return new int[] { Types.VARCHAR };
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
String persistValue = (String) rs.getObject( names[0] );
if ( rs.wasNull() ) {
return null;
}
return Enum.valueOf( returnedClass(), persistValue + "_LETTER" );
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if ( value == null ) {
st.setNull( index, sqlTypes()[0] );
}
else {
String enumString = ( (Enum<?>) value ).name();
st.setObject( index, enumString.charAt( 0 ), sqlTypes()[0] );
}
}
}

View File

@ -0,0 +1,42 @@
package org.hibernate.test.annotations.enumerated;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
/**
* @author Janario Oliveira
*/
public class LastNumberType extends org.hibernate.type.EnumType {
@Override
public int[] sqlTypes() {
return new int[] { Types.VARCHAR };
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
String persistValue = (String) rs.getObject( names[0] );
if ( rs.wasNull() ) {
return null;
}
return Enum.valueOf( returnedClass(), "NUMBER_" + persistValue );
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if ( value == null ) {
st.setNull( index, sqlTypes()[0] );
}
else {
String enumString = ( (Enum<?>) value ).name();
st.setObject( index, enumString.charAt( enumString.length() - 1 ), sqlTypes()[0] );
}
}
}

View File

@ -0,0 +1,29 @@
package org.hibernate.test.annotations.referencedcolumnname;
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
/**
* @author Janario Oliveira
*/
@Entity
public class HousePlaces {
@Id
@GeneratedValue
int id;
@Embedded
Places places;
@Embedded
@AssociationOverrides({
@AssociationOverride(name = "livingRoom", joinColumns = {
@JoinColumn(name = "NEIGHBOUR_LIVINGROOM", referencedColumnName = "NAME"),
@JoinColumn(name = "NEIGHBOUR_LIVINGROOM_OWNER", referencedColumnName = "OWNER") }),
@AssociationOverride(name = "kitchen", joinColumns = @JoinColumn(name = "NEIGHBOUR_KITCHEN", referencedColumnName = "NAME")) })
Places neighbourPlaces;
}

View File

@ -0,0 +1,21 @@
package org.hibernate.test.annotations.referencedcolumnname;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @author Janario Oliveira
*/
@Entity
public class Place {
@Id
@GeneratedValue
int id;
@Column(name = "NAME")
String name;
@Column(name = "OWNER")
String owner;
}

View File

@ -0,0 +1,22 @@
package org.hibernate.test.annotations.referencedcolumnname;
import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
/**
* @author Janario Oliveira
*/
@Embeddable
public class Places {
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumns({ @JoinColumn(name = "LIVING_ROOM", referencedColumnName = "NAME"),
@JoinColumn(name = "LIVING_ROOM_OWNER", referencedColumnName = "OWNER") })
Place livingRoom;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "KITCHEN", referencedColumnName = "NAME")
Place kitchen;
}

View File

@ -30,6 +30,7 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -206,6 +207,68 @@ public class ReferencedColumnNameTest extends BaseCoreFunctionalTestCase {
s.close();
}
@Test
public void testManyToOneInsideComponentReferencedColumn() {
HousePlaces house = new HousePlaces();
house.places = new Places();
house.places.livingRoom = new Place();
house.places.livingRoom.name = "First";
house.places.livingRoom.owner = "mine";
house.places.kitchen = new Place();
house.places.kitchen.name = "Kitchen 1";
house.neighbourPlaces = new Places();
house.neighbourPlaces.livingRoom = new Place();
house.neighbourPlaces.livingRoom.name = "Neighbour";
house.neighbourPlaces.livingRoom.owner = "his";
house.neighbourPlaces.kitchen = new Place();
house.neighbourPlaces.kitchen.name = "His Kitchen";
Session s = openSession();
Transaction tx = s.beginTransaction();
s.save( house );
s.flush();
HousePlaces get = (HousePlaces) s.get( HousePlaces.class, house.id );
assertEquals( house.id, get.id );
HousePlaces uniqueResult = (HousePlaces) s.createQuery( "from HousePlaces h where h.places.livingRoom.name='First'" )
.uniqueResult();
assertNotNull( uniqueResult );
assertEquals( uniqueResult.places.livingRoom.name, "First" );
assertEquals( uniqueResult.places.livingRoom.owner, "mine" );
uniqueResult = (HousePlaces) s.createQuery( "from HousePlaces h where h.places.livingRoom.owner=:owner" )
.setParameter( "owner", "mine" ).uniqueResult();
assertNotNull( uniqueResult );
assertEquals( uniqueResult.places.livingRoom.name, "First" );
assertEquals( uniqueResult.places.livingRoom.owner, "mine" );
assertNotNull( s.createCriteria( HousePlaces.class ).add( Restrictions.eq( "places.livingRoom.owner", "mine" ) )
.uniqueResult() );
// override
uniqueResult = (HousePlaces) s.createQuery( "from HousePlaces h where h.neighbourPlaces.livingRoom.owner='his'" )
.uniqueResult();
assertNotNull( uniqueResult );
assertEquals( uniqueResult.neighbourPlaces.livingRoom.name, "Neighbour" );
assertEquals( uniqueResult.neighbourPlaces.livingRoom.owner, "his" );
uniqueResult = (HousePlaces) s.createQuery( "from HousePlaces h where h.neighbourPlaces.livingRoom.name=:name" )
.setParameter( "name", "Neighbour" ).uniqueResult();
assertNotNull( uniqueResult );
assertEquals( uniqueResult.neighbourPlaces.livingRoom.name, "Neighbour" );
assertEquals( uniqueResult.neighbourPlaces.livingRoom.owner, "his" );
assertNotNull( s.createCriteria( HousePlaces.class )
.add( Restrictions.eq( "neighbourPlaces.livingRoom.owner", "his" ) ).uniqueResult() );
tx.rollback();
}
@Override
protected Class[] getAnnotatedClasses() {
return new Class[]{
@ -219,7 +282,9 @@ public class ReferencedColumnNameTest extends BaseCoreFunctionalTestCase {
Item.class,
ItemCost.class,
Vendor.class,
WarehouseItem.class
WarehouseItem.class,
Place.class,
HousePlaces.class
};
}
}

View File

@ -64,10 +64,16 @@ public final class BasicMetadataGenerator {
Element type_mapping = prop_mapping.addElement("type");
type_mapping.addAttribute("name", typeName);
for (java.util.Map.Entry paramKeyValue : typeParameters.entrySet()) {
Element type_param = type_mapping.addElement("param");
type_param.addAttribute("name", (String) paramKeyValue.getKey());
type_param.setText((String) paramKeyValue.getValue());
for (Object object : typeParameters.keySet()) {
String keyType = (String) object;
String property = typeParameters.getProperty(keyType);
if (property != null) {
Element type_param = type_mapping.addElement("param");
type_param.addAttribute("name", keyType);
type_param.setText(property);
}
}
}
}