/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.type.impl;
import static org.hibernate.ogm.util.impl.CollectionHelper.newHashMap;
import java.util.Collections;
import java.util.Map;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.mapping.SimpleValue;
import org.hibernate.ogm.dialect.spi.GridDialect;
import org.hibernate.ogm.type.descriptor.impl.AttributeConverterGridTypeDescriptorAdaptor;
import org.hibernate.ogm.type.descriptor.impl.GridTypeDescriptor;
import org.hibernate.ogm.type.spi.GridType;
import org.hibernate.ogm.type.spi.TypeTranslator;
import org.hibernate.ogm.util.impl.Log;
import org.hibernate.ogm.util.impl.LoggerFactory;
import org.hibernate.type.AbstractStandardBasicType;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.SerializableToBlobType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry;
import org.hibernate.usertype.UserType;
/**
* @author Emmanuel Bernard
* @author Nicolas Helleringer
*/
public class TypeTranslatorImpl implements TypeTranslator {
private static final Log log = LoggerFactory.make();
// ORM Type to OGM GridType relation
private final Map<Type, GridType> typeConverter;
private final GridDialect dialect;
// ORM type resolver
private final TypeResolver typeResolver;
public TypeTranslatorImpl(GridDialect dialect, TypeResolver typeResolver) {
this.dialect = dialect;
this.typeResolver = typeResolver;
Map<Type, GridType> tmpMap = newHashMap( 20 );
tmpMap.put( org.hibernate.type.ClassType.INSTANCE, ClassType.INSTANCE );
tmpMap.put( org.hibernate.type.LongType.INSTANCE, LongType.INSTANCE );
tmpMap.put( org.hibernate.type.IntegerType.INSTANCE, IntegerType.INSTANCE );
tmpMap.put( org.hibernate.type.DoubleType.INSTANCE, DoubleType.INSTANCE );
tmpMap.put( org.hibernate.type.FloatType.INSTANCE, FloatType.INSTANCE );
tmpMap.put( org.hibernate.type.ShortType.INSTANCE, ShortType.INSTANCE );
tmpMap.put( org.hibernate.type.CharacterType.INSTANCE, CharacterType.INSTANCE );
tmpMap.put( org.hibernate.type.StringType.INSTANCE, StringType.INSTANCE );
tmpMap.put( org.hibernate.type.UrlType.INSTANCE, UrlType.INSTANCE );
tmpMap.put( org.hibernate.type.BigDecimalType.INSTANCE, BigDecimalType.INSTANCE );
tmpMap.put( org.hibernate.type.BigIntegerType.INSTANCE, BigIntegerType.INSTANCE );
tmpMap.put( org.hibernate.type.BooleanType.INSTANCE, BooleanType.INSTANCE );
tmpMap.put( org.hibernate.type.TrueFalseType.INSTANCE, TrueFalseType.INSTANCE );
tmpMap.put( org.hibernate.type.YesNoType.INSTANCE, YesNoType.INSTANCE );
tmpMap.put( org.hibernate.type.NumericBooleanType.INSTANCE, NumericBooleanType.INSTANCE );
tmpMap.put( org.hibernate.type.ByteType.INSTANCE, ByteType.INSTANCE );
tmpMap.put( org.hibernate.type.DateType.INSTANCE, DateType.INSTANCE );
tmpMap.put( org.hibernate.type.TimestampType.INSTANCE, TimestampType.INSTANCE );
tmpMap.put( org.hibernate.type.TimeType.INSTANCE, TimeType.INSTANCE );
tmpMap.put( org.hibernate.type.CalendarDateType.INSTANCE, CalendarDateType.INSTANCE );
tmpMap.put( org.hibernate.type.CalendarType.INSTANCE, CalendarType.INSTANCE );
tmpMap.put( org.hibernate.type.BinaryType.INSTANCE, PrimitiveByteArrayType.INSTANCE );
tmpMap.put( org.hibernate.type.MaterializedBlobType.INSTANCE, PrimitiveByteArrayType.INSTANCE );
tmpMap.put( org.hibernate.type.MaterializedClobType.INSTANCE, StringType.INSTANCE );
tmpMap.put( org.hibernate.type.ImageType.INSTANCE, PrimitiveByteArrayType.INSTANCE );
tmpMap.put( org.hibernate.type.UUIDBinaryType.INSTANCE, UUIDType.INSTANCE );
tmpMap.put( org.hibernate.type.UUIDCharType.INSTANCE, UUIDType.INSTANCE );
typeConverter = Collections.unmodifiableMap( tmpMap );
}
@Override
public GridType getType(Type type) {
if ( type == null ) {
return null;
}
//TODO should we cache results? It seems an actual HashMap might be slower but it makes it more robust
// against badly written dialects
GridType dialectType = dialect.overrideType( type );
if ( dialectType != null ) {
return dialectType;
}
else if ( type instanceof SerializableToBlobType ) {
SerializableToBlobType<?> exposedType = (SerializableToBlobType<?>) type;
return new SerializableAsByteArrayType<>( exposedType.getJavaTypeDescriptor() );
}
else if ( type instanceof AttributeConverterTypeAdapter<?> ) {
// Handles JPA AttributeConverter integration logic
return buildAttributeConverterGridTypeAdaptor( (AttributeConverterTypeAdapter<?>) type );
}
else if ( type instanceof AbstractStandardBasicType ) {
AbstractStandardBasicType<?> exposedType = (AbstractStandardBasicType<?>) type;
final GridType gridType = typeConverter.get( exposedType );
if ( gridType == null ) {
throw log.unableToFindGridType( exposedType.getName() );
}
return gridType;
}
else if ( type instanceof CustomType ) {
CustomType cType = (CustomType) type;
final UserType userType = cType.getUserType();
if ( userType instanceof EnumType ) {
EnumType enumType = (EnumType) userType;
//should we cache that (the key must be enumClass / isOrdinal
return new org.hibernate.ogm.type.impl.EnumType( cType, enumType );
}
//let it go it will eventually fail
}
else if ( type instanceof org.hibernate.type.ComponentType ) {
org.hibernate.type.ComponentType componentType = (org.hibernate.type.ComponentType) type;
return new ComponentType( componentType, this );
}
else if ( type instanceof org.hibernate.type.ManyToOneType ) {
//do some stuff
org.hibernate.type.ManyToOneType manyToOneType = (org.hibernate.type.ManyToOneType) type;
return new ManyToOneType( manyToOneType, this );
}
else if ( type instanceof org.hibernate.type.OneToOneType ) {
//do some stuff
org.hibernate.type.OneToOneType oneToOneType = (org.hibernate.type.OneToOneType) type;
return new OneToOneType( oneToOneType, this );
}
else if ( type instanceof org.hibernate.type.CollectionType ) {
return new CollectionType( (org.hibernate.type.CollectionType) type );
}
throw log.unableToFindGridType( type.getClass().getName() );
}
/**
* Logic modeled after {@link SimpleValue#buildAttributeConverterTypeAdapter}
* <p>
* Adapt AttributeConverter to GridType. Most of the logic is done by the
* AttributeConverterGridTypeDescriptorAdaptor class which will call the attribute converter and then call the
* GridType compliant with the intermediary type
*/
private <T> AttributeConverterGridTypeAdaptor<T> buildAttributeConverterGridTypeAdaptor(AttributeConverterTypeAdapter<T> specificType) {
// Rebuild the definition as we need some generic type extraction logic from it
AttributeConverterDefinition attributeConverterDefinition = new AttributeConverterDefinition( specificType.getAttributeConverter(), false );
final Class<?> databaseColumnJavaType = attributeConverterDefinition.getDatabaseColumnType();
// Find the GridType for the intermediary datastore Java type (from the attribute converter
Type intermediaryORMType = typeResolver.basic( databaseColumnJavaType.getName() );
if ( intermediaryORMType == null ) {
throw log.cannotFindTypeForAttributeConverter( specificType.getAttributeConverter().getClass(), databaseColumnJavaType );
}
GridType intermediaryOGMGridType = this.getType( intermediaryORMType );
// find the JavaTypeDescriptor representing the "intermediate database type representation".
final JavaTypeDescriptor<?> intermediateJavaTypeDescriptor = JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( databaseColumnJavaType );
// and finally construct the adapter, which injects the AttributeConverter calls into the binding/extraction
// process...
final GridTypeDescriptor gridTypeDescriptorAdapter = new AttributeConverterGridTypeDescriptorAdaptor(
attributeConverterDefinition.getAttributeConverter(),
intermediaryOGMGridType,
intermediateJavaTypeDescriptor
);
return new AttributeConverterGridTypeAdaptor<T>( specificType, gridTypeDescriptorAdapter );
}
}