HHH-7387 - Integrate Draft 6 of the JPA 2.1 spec : AttributeConverter
This commit is contained in:
parent
153eb4a913
commit
ad2a9ef651
|
@ -279,6 +279,7 @@ public final class AnnotationBinder {
|
|||
bindTypeDefs( pckg, mappings );
|
||||
bindFetchProfiles( pckg, mappings );
|
||||
BinderHelper.bindAnyMetaDefs( pckg, mappings );
|
||||
|
||||
}
|
||||
|
||||
private static void bindGenericGenerators(XAnnotatedElement annotatedElement, Mappings mappings) {
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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 java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AttributeConverterDefinition {
|
||||
private static final Logger log = Logger.getLogger( AttributeConverterDefinition.class );
|
||||
|
||||
private final AttributeConverter attributeConverter;
|
||||
private final boolean autoApply;
|
||||
private final Class entityAttributeType;
|
||||
private final Class databaseColumnType;
|
||||
|
||||
public AttributeConverterDefinition(AttributeConverter attributeConverter, boolean autoApply) {
|
||||
this.attributeConverter = attributeConverter;
|
||||
this.autoApply = autoApply;
|
||||
|
||||
final Class attributeConverterClass = attributeConverter.getClass();
|
||||
final ParameterizedType attributeConverterSignature = extractAttributeConverterParameterizedType( attributeConverterClass );
|
||||
|
||||
if ( attributeConverterSignature.getActualTypeArguments().length < 2 ) {
|
||||
throw new AnnotationException(
|
||||
"AttributeConverter [" + attributeConverterClass.getName()
|
||||
+ "] did not retain parameterized type information"
|
||||
);
|
||||
}
|
||||
|
||||
if ( attributeConverterSignature.getActualTypeArguments().length > 2 ) {
|
||||
throw new AnnotationException(
|
||||
"AttributeConverter [" + attributeConverterClass.getName()
|
||||
+ "] specified more than 2 parameterized types"
|
||||
);
|
||||
}
|
||||
entityAttributeType = (Class) attributeConverterSignature.getActualTypeArguments()[0];
|
||||
if ( entityAttributeType == null ) {
|
||||
throw new AnnotationException(
|
||||
"Could not determine 'entity attribute' type from given AttributeConverter [" +
|
||||
attributeConverterClass.getName() + "]"
|
||||
);
|
||||
}
|
||||
|
||||
databaseColumnType = (Class) attributeConverterSignature.getActualTypeArguments()[1];
|
||||
if ( databaseColumnType == null ) {
|
||||
throw new AnnotationException(
|
||||
"Could not determine 'database column' type from given AttributeConverter [" +
|
||||
attributeConverterClass.getName() + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ParameterizedType extractAttributeConverterParameterizedType(Class attributeConverterClass) {
|
||||
for ( Type type : attributeConverterClass.getGenericInterfaces() ) {
|
||||
if ( ParameterizedType.class.isInstance( type ) ) {
|
||||
final ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
if ( AttributeConverter.class.equals( parameterizedType.getRawType() ) ) {
|
||||
return parameterizedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionFailure(
|
||||
"Could not extract ParameterizedType representation of AttributeConverter definition " +
|
||||
"from AttributeConverter implementation class [" + attributeConverterClass.getName() + "]"
|
||||
);
|
||||
}
|
||||
|
||||
public AttributeConverter getAttributeConverter() {
|
||||
return attributeConverter;
|
||||
}
|
||||
|
||||
public boolean isAutoApply() {
|
||||
return autoApply;
|
||||
}
|
||||
|
||||
public Class getEntityAttributeType() {
|
||||
return entityAttributeType;
|
||||
}
|
||||
|
||||
public Class getDatabaseColumnType() {
|
||||
return databaseColumnType;
|
||||
}
|
||||
|
||||
private static Class extractType(TypeVariable typeVariable) {
|
||||
java.lang.reflect.Type[] boundTypes = typeVariable.getBounds();
|
||||
if ( boundTypes == null || boundTypes.length != 1 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (Class) boundTypes[0];
|
||||
}
|
||||
}
|
|
@ -48,8 +48,10 @@ import java.util.Properties;
|
|||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.MapsId;
|
||||
|
@ -63,6 +65,7 @@ import org.xml.sax.EntityResolver;
|
|||
import org.xml.sax.InputSource;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.DuplicateMappingException;
|
||||
import org.hibernate.EmptyInterceptor;
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -259,6 +262,7 @@ public class Configuration implements Serializable {
|
|||
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
|
||||
private boolean specjProprietarySyntaxEnabled;
|
||||
|
||||
private ConcurrentHashMap<Class,AttributeConverterDefinition> attributeConverterDefinitionsByClass;
|
||||
|
||||
protected Configuration(SettingsFactory settingsFactory) {
|
||||
this.settingsFactory = settingsFactory;
|
||||
|
@ -2450,6 +2454,52 @@ public class Configuration implements Serializable {
|
|||
this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the AttributeConverter Class to this Configuration.
|
||||
*
|
||||
* @param attributeConverterClass The AttributeConverter class.
|
||||
* @param autoApply Should the AttributeConverter be auto applied to property types as specified
|
||||
* by its "entity attribute" parameterized type?
|
||||
*/
|
||||
public void addAttributeConverter(Class<? extends AttributeConverter> attributeConverterClass, boolean autoApply) {
|
||||
final AttributeConverter attributeConverter;
|
||||
try {
|
||||
attributeConverter = attributeConverterClass.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AnnotationException(
|
||||
"Unable to instantiate AttributeConverter [" + attributeConverterClass.getName() + "]"
|
||||
);
|
||||
}
|
||||
addAttributeConverter( attributeConverter, autoApply );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the AttributeConverter instance to this Configuration. This form is mainly intended for developers
|
||||
* to programatically add their own AttributeConverter instance. HEM, instead, uses the
|
||||
* {@link #addAttributeConverter(Class, boolean)} form
|
||||
*
|
||||
* @param attributeConverter The AttributeConverter instance.
|
||||
* @param autoApply Should the AttributeConverter be auto applied to property types as specified
|
||||
* by its "entity attribute" parameterized type?
|
||||
*/
|
||||
public void addAttributeConverter(AttributeConverter attributeConverter, boolean autoApply) {
|
||||
if ( attributeConverterDefinitionsByClass == null ) {
|
||||
attributeConverterDefinitionsByClass = new ConcurrentHashMap<Class, AttributeConverterDefinition>();
|
||||
}
|
||||
|
||||
final Object old = attributeConverterDefinitionsByClass.put(
|
||||
attributeConverter.getClass(),
|
||||
new AttributeConverterDefinition( attributeConverter, autoApply )
|
||||
);
|
||||
|
||||
if ( old != null ) {
|
||||
throw new AssertionFailure(
|
||||
"AttributeConverter class [" + attributeConverter.getClass() + "] registered multiple times"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Mappings impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -2984,6 +3034,22 @@ public class Configuration implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeConverterDefinition locateAttributeConverter(Class converterClass) {
|
||||
if ( attributeConverterDefinitionsByClass == null ) {
|
||||
return null;
|
||||
}
|
||||
return attributeConverterDefinitionsByClass.get( converterClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.Collection<AttributeConverterDefinition> getAttributeConverters() {
|
||||
if ( attributeConverterDefinitionsByClass == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return attributeConverterDefinitionsByClass.values();
|
||||
}
|
||||
|
||||
public void addPropertyReference(String referencedClass, String propertyName) {
|
||||
propertyReferences.add( new PropertyReference( referencedClass, propertyName, false ) );
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.cfg;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -509,6 +510,23 @@ public interface Mappings {
|
|||
*/
|
||||
public void addSecondPass(SecondPass sp, boolean onTopOfTheQueue);
|
||||
|
||||
/**
|
||||
* Locate the AttributeConverterDefinition corresponding to the given AttributeConverter Class.
|
||||
*
|
||||
* @param attributeConverterClass The AttributeConverter Class for which to get the definition
|
||||
*
|
||||
* @return The corresponding AttributeConverter definition; will return {@code null} if no corresponding
|
||||
* definition found.
|
||||
*/
|
||||
public AttributeConverterDefinition locateAttributeConverter(Class attributeConverterClass);
|
||||
|
||||
/**
|
||||
* All all AttributeConverter definitions
|
||||
*
|
||||
* @return The collection of all AttributeConverter definitions.
|
||||
*/
|
||||
public java.util.Collection<AttributeConverterDefinition> getAttributeConverters();
|
||||
|
||||
/**
|
||||
* Represents a property-ref mapping.
|
||||
* <p/>
|
||||
|
|
|
@ -24,11 +24,16 @@
|
|||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.sql.Types;
|
||||
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;
|
||||
import javax.persistence.MapKeyEnumerated;
|
||||
import javax.persistence.MapKeyTemporal;
|
||||
|
@ -43,6 +48,8 @@ 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.AttributeConverterDefinition;
|
||||
import org.hibernate.cfg.BinderHelper;
|
||||
import org.hibernate.cfg.Ejb3Column;
|
||||
import org.hibernate.cfg.Ejb3JoinColumn;
|
||||
|
@ -82,6 +89,8 @@ public class SimpleValueBinder {
|
|||
private boolean key;
|
||||
private String referencedEntityName;
|
||||
|
||||
private AttributeConverterDefinition attributeConverterDefinition;
|
||||
|
||||
public void setReferencedEntityName(String referencedEntityName) {
|
||||
this.referencedEntityName = referencedEntityName;
|
||||
}
|
||||
|
@ -172,7 +181,6 @@ public class SimpleValueBinder {
|
|||
}
|
||||
}
|
||||
else if ( property.isAnnotationPresent( Lob.class ) ) {
|
||||
|
||||
if ( mappings.getReflectionManager().equals( returnedClassOrElement, java.sql.Clob.class ) ) {
|
||||
type = "clob";
|
||||
}
|
||||
|
@ -243,6 +251,201 @@ public class SimpleValueBinder {
|
|||
this.typeParameters = typeParameters;
|
||||
Type annType = property.getAnnotation( Type.class );
|
||||
setExplicitType( annType );
|
||||
|
||||
applyAttributeConverter( property );
|
||||
}
|
||||
|
||||
private void applyAttributeConverter(XProperty property) {
|
||||
final boolean canBeConverted = ! property.isAnnotationPresent( Id.class )
|
||||
&& ! isVersion
|
||||
&& ! isAssociation()
|
||||
&& ! property.isAnnotationPresent( Temporal.class )
|
||||
&& ! property.isAnnotationPresent( Enumerated.class );
|
||||
|
||||
if ( canBeConverted ) {
|
||||
// @Convert annotations take precedence
|
||||
final Convert convertAnnotation = locateConvertAnnotation( property );
|
||||
if ( convertAnnotation != null ) {
|
||||
if ( ! convertAnnotation.disableConversion() ) {
|
||||
attributeConverterDefinition = mappings.locateAttributeConverter( convertAnnotation.converter() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
attributeConverterDefinition = locateAutoApplyAttributeConverter( property );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AttributeConverterDefinition locateAutoApplyAttributeConverter(XProperty property) {
|
||||
final Class propertyType = mappings.getReflectionManager().toClass( property.getType() );
|
||||
for ( AttributeConverterDefinition attributeConverterDefinition : mappings.getAttributeConverters() ) {
|
||||
if ( areTypeMatch( attributeConverterDefinition.getEntityAttributeType(), propertyType ) ) {
|
||||
return attributeConverterDefinition;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isAssociation() {
|
||||
// todo : this information is only known to caller(s), need to pass that information in somehow.
|
||||
// or, is this enough?
|
||||
return referencedEntityName != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Convert locateConvertAnnotation(XProperty property) {
|
||||
// first look locally on the property for @Convert
|
||||
Convert localConvertAnnotation = property.getAnnotation( Convert.class );
|
||||
if ( localConvertAnnotation != null ) {
|
||||
return 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;
|
||||
}
|
||||
|
||||
{
|
||||
Convert convertAnnotation = owner.getAnnotation( Convert.class );
|
||||
if ( convertAnnotation != null && isMatch( convertAnnotation, property ) ) {
|
||||
return convertAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Converts convertsAnnotation = owner.getAnnotation( Converts.class );
|
||||
if ( convertsAnnotation != null ) {
|
||||
for ( Convert convertAnnotation : convertsAnnotation.value() ) {
|
||||
if ( isMatch( convertAnnotation, property ) ) {
|
||||
return convertAnnotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally, look on superclass
|
||||
return lookForEntityDefinedConvertAnnotation( property, owner.getSuperclass() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isMatch(Convert convertAnnotation, XProperty property) {
|
||||
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 javax.persistence.EnumType getEnumType(XProperty property) {
|
||||
|
@ -338,21 +541,36 @@ public class SimpleValueBinder {
|
|||
}
|
||||
|
||||
public void fillSimpleValue() {
|
||||
|
||||
LOG.debugf( "Setting SimpleValue typeName for %s", propertyName );
|
||||
|
||||
String type = BinderHelper.isEmptyAnnotationValue( explicitType ) ? returnedClassName : explicitType;
|
||||
org.hibernate.mapping.TypeDef typeDef = mappings.getTypeDef( type );
|
||||
if ( typeDef != null ) {
|
||||
type = typeDef.getTypeClass();
|
||||
simpleValue.setTypeParameters( typeDef.getParameters() );
|
||||
if ( attributeConverterDefinition != null ) {
|
||||
if ( ! BinderHelper.isEmptyAnnotationValue( explicitType ) ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
"AttributeConverter and explicit Type cannot be applied to same attribute [%s.%s];" +
|
||||
"remove @Type or specify @Convert(disableConversion = true)",
|
||||
persistentClassName,
|
||||
propertyName
|
||||
)
|
||||
);
|
||||
}
|
||||
simpleValue.setJpaAttributeConverterDefinition( attributeConverterDefinition );
|
||||
}
|
||||
if ( typeParameters != null && typeParameters.size() != 0 ) {
|
||||
//explicit type params takes precedence over type def params
|
||||
simpleValue.setTypeParameters( typeParameters );
|
||||
else {
|
||||
String type = BinderHelper.isEmptyAnnotationValue( explicitType ) ? returnedClassName : explicitType;
|
||||
org.hibernate.mapping.TypeDef typeDef = mappings.getTypeDef( type );
|
||||
if ( typeDef != null ) {
|
||||
type = typeDef.getTypeClass();
|
||||
simpleValue.setTypeParameters( typeDef.getParameters() );
|
||||
}
|
||||
if ( typeParameters != null && typeParameters.size() != 0 ) {
|
||||
//explicit type params takes precedence over type def params
|
||||
simpleValue.setTypeParameters( typeParameters );
|
||||
}
|
||||
simpleValue.setTypeName( type );
|
||||
}
|
||||
simpleValue.setTypeName( type );
|
||||
if ( persistentClassName != null ) {
|
||||
|
||||
if ( persistentClassName != null || attributeConverterDefinition != null ) {
|
||||
simpleValue.setTypeUsingReflection( persistentClassName, propertyName );
|
||||
}
|
||||
|
||||
|
@ -369,4 +587,5 @@ public class SimpleValueBinder {
|
|||
public void setKey(boolean key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,13 +22,24 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
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.AttributeConverterDefinition;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.cfg.Mappings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
|
@ -38,13 +49,26 @@ 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.type.AbstractSingleColumnStandardBasicType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry;
|
||||
import org.hibernate.type.descriptor.sql.BasicBinder;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Any value that maps to columns.
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class SimpleValue implements KeyValue {
|
||||
private static final Logger log = Logger.getLogger( SimpleValue.class );
|
||||
|
||||
public static final String DEFAULT_ID_GEN_STRATEGY = "assigned";
|
||||
|
||||
private final Mappings mappings;
|
||||
|
@ -60,6 +84,9 @@ public class SimpleValue implements KeyValue {
|
|||
private Properties typeParameters;
|
||||
private boolean cascadeDeleteEnabled;
|
||||
|
||||
private AttributeConverterDefinition jpaAttributeConverterDefinition;
|
||||
private Type type;
|
||||
|
||||
public SimpleValue(Mappings mappings) {
|
||||
this.mappings = mappings;
|
||||
}
|
||||
|
@ -290,30 +317,100 @@ public class SimpleValue implements KeyValue {
|
|||
}
|
||||
|
||||
public Type getType() throws MappingException {
|
||||
if (typeName==null) {
|
||||
throw new MappingException("No type name");
|
||||
if ( type != null ) {
|
||||
return type;
|
||||
}
|
||||
Type result = mappings.getTypeResolver().heuristicType(typeName, typeParameters);
|
||||
if (result==null) {
|
||||
|
||||
if ( typeName == null ) {
|
||||
throw new MappingException( "No type name" );
|
||||
}
|
||||
|
||||
Type result = mappings.getTypeResolver().heuristicType( typeName, typeParameters );
|
||||
if ( result == null ) {
|
||||
String msg = "Could not determine type for: " + typeName;
|
||||
if(table != null){
|
||||
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);
|
||||
throw new MappingException( msg );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTypeUsingReflection(String className, String propertyName) throws MappingException {
|
||||
if (typeName==null) {
|
||||
if (className==null) {
|
||||
throw new MappingException("you must specify types for a dynamic entity: " + propertyName);
|
||||
}
|
||||
typeName = ReflectHelper.reflectedPropertyClass(className, propertyName).getName();
|
||||
// NOTE : this is called as the last piece in setting SimpleValue type information, and implementations
|
||||
// rely on that fact, using it as a signal that all information it is going to get is defined at this point...
|
||||
|
||||
if ( typeName != null ) {
|
||||
// assume either (a) explicit type was specified or (b) determine was already performed
|
||||
return;
|
||||
}
|
||||
|
||||
if ( type != null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( jpaAttributeConverterDefinition == 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...)
|
||||
if ( className == null ) {
|
||||
throw new MappingException( "you must specify types for a dynamic entity: " + propertyName );
|
||||
}
|
||||
typeName = ReflectHelper.reflectedPropertyClass( className, propertyName ).getName();
|
||||
return;
|
||||
}
|
||||
|
||||
// we had an AttributeConverter...
|
||||
|
||||
// todo : we should validate the number of columns present
|
||||
// todo : ultimately I want to see attributeConverterJavaType and attributeConverterJdbcTypeCode specify-able separately
|
||||
// then we can "play them against each other" in terms of determining proper typing
|
||||
// todo : see if we already have previously built a custom on-the-fly BasicType for this AttributeConverter; see note below about caching
|
||||
|
||||
// AttributeConverter works totally in memory, meaning it converts between one Java representation (the entity
|
||||
// attribute representation) and another (the value bound into JDBC statements or extracted from results).
|
||||
// However, the Hibernate Type system operates at the lower level of actually dealing with those JDBC objects.
|
||||
// So even though we have an AttributeConverter, we still need to "fill out" the rest of the BasicType
|
||||
// data. For the JavaTypeDescriptor portion we simply resolve the "entity attribute representation" part of
|
||||
// the AttributeConverter to resolve the corresponding descriptor. For the SqlTypeDescriptor portion we use the
|
||||
// "database column representation" part of the AttributeConverter to resolve the "recommended" JDBC type-code
|
||||
// and use that type-code to resolve the SqlTypeDescriptor to use.
|
||||
final Class entityAttributeJavaType = jpaAttributeConverterDefinition.getEntityAttributeType();
|
||||
final Class databaseColumnJavaType = jpaAttributeConverterDefinition.getDatabaseColumnType();
|
||||
final int jdbcTypeCode = JdbcTypeJavaClassMappings.INSTANCE.determineJdbcTypeCodeForJavaClass( databaseColumnJavaType );
|
||||
|
||||
final JavaTypeDescriptor javaTypeDescriptor = JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( entityAttributeJavaType );
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = SqlTypeDescriptorRegistry.INSTANCE.getDescriptor( jdbcTypeCode );
|
||||
// the adapter here injects the AttributeConverter calls into the binding/extraction process...
|
||||
final SqlTypeDescriptor sqlTypeDescriptorAdapter = new AttributeConverterSqlTypeDescriptorAdapter(
|
||||
jpaAttributeConverterDefinition.getAttributeConverter(),
|
||||
sqlTypeDescriptor
|
||||
);
|
||||
|
||||
final String name = "BasicType adapter for AttributeConverter<" + entityAttributeJavaType + "," + databaseColumnJavaType + ">";
|
||||
type = new AbstractSingleColumnStandardBasicType( sqlTypeDescriptorAdapter, javaTypeDescriptor ) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
log.debug( "Created : " + name );
|
||||
|
||||
// todo : cache the BasicType we just created in case that AttributeConverter is applied multiple times.
|
||||
}
|
||||
|
||||
private Class extractType(TypeVariable typeVariable) {
|
||||
java.lang.reflect.Type[] boundTypes = typeVariable.getBounds();
|
||||
if ( boundTypes == null || boundTypes.length != 1 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (Class) boundTypes[0];
|
||||
}
|
||||
|
||||
public boolean isTypeSpecified() {
|
||||
|
@ -351,4 +448,60 @@ public class SimpleValue implements KeyValue {
|
|||
public boolean[] getColumnUpdateability() {
|
||||
return getColumnInsertability();
|
||||
}
|
||||
|
||||
public void setJpaAttributeConverterDefinition(AttributeConverterDefinition jpaAttributeConverterDefinition) {
|
||||
this.jpaAttributeConverterDefinition = jpaAttributeConverterDefinition;
|
||||
}
|
||||
|
||||
public static class AttributeConverterSqlTypeDescriptorAdapter implements SqlTypeDescriptor {
|
||||
private final AttributeConverter converter;
|
||||
private final SqlTypeDescriptor delegate;
|
||||
|
||||
public AttributeConverterSqlTypeDescriptorAdapter(AttributeConverter converter, SqlTypeDescriptor delegate) {
|
||||
this.converter = converter;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return delegate.getSqlType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return delegate.canBeRemapped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
final ValueBinder realBinder = delegate.getBinder( javaTypeDescriptor );
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
realBinder.bind( st, converter.convertToDatabaseColumn( value ), index, options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
final ValueExtractor realExtractor = delegate.getExtractor( javaTypeDescriptor );
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return (X) converter.convertToEntityAttribute( realExtractor.extract( rs, name, options ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return (X) converter.convertToEntityAttribute( realExtractor.extract( statement, index, options ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,13 +44,12 @@ public abstract class AbstractSingleColumnStandardBasicType<T>
|
|||
super( sqlTypeDescriptor, javaTypeDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int sqlType() {
|
||||
return getSqlTypeDescriptor().getSqlType();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor session)
|
||||
throws HibernateException, SQLException {
|
||||
if ( settable[0] ) {
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
package org.hibernate.type.descriptor;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Types;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -35,7 +34,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* (Badly named) helper for dealing with standard JDBC types as defined by {@link java.sql.Types}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -46,7 +45,7 @@ public class JdbcTypeNameMapper {
|
|||
|
||||
private static Map<Integer, String> buildJdbcTypeMap() {
|
||||
HashMap<Integer, String> map = new HashMap<Integer, String>();
|
||||
Field[] fields = Types.class.getFields();
|
||||
Field[] fields = java.sql.Types.class.getFields();
|
||||
if ( fields == null ) {
|
||||
throw new HibernateException( "Unexpected problem extracting JDBC type mapping codes from java.sql.Types" );
|
||||
}
|
||||
|
@ -54,7 +53,9 @@ public class JdbcTypeNameMapper {
|
|||
try {
|
||||
final int code = field.getInt( null );
|
||||
String old = map.put( code, field.getName() );
|
||||
if (old != null) LOG.JavaSqlTypesMappedSameCodeMultipleTimes(code, old, field.getName());
|
||||
if ( old != null ) {
|
||||
LOG.JavaSqlTypesMappedSameCodeMultipleTimes( code, old, field.getName() );
|
||||
}
|
||||
}
|
||||
catch ( IllegalAccessException e ) {
|
||||
throw new HibernateException( "Unable to access JDBC type mapping [" + field.getName() + "]", e );
|
||||
|
@ -63,10 +64,43 @@ public class JdbcTypeNameMapper {
|
|||
return Collections.unmodifiableMap( map );
|
||||
}
|
||||
|
||||
public static String getTypeName(Integer code) {
|
||||
String name = JDBC_TYPE_MAP.get( code );
|
||||
/**
|
||||
* Determine whether the given JDBC type code represents a standard JDBC type ("standard" being those defined on
|
||||
* {@link java.sql.Types}).
|
||||
*
|
||||
* NOTE : {@link java.sql.Types#OTHER} is also "filtered out" as being non-standard.
|
||||
*
|
||||
* @param typeCode The JDBC type code to check
|
||||
*
|
||||
* @return {@code true} to indicate the type code is a standard type code; {@code false} otherwise.
|
||||
*/
|
||||
public static boolean isStandardTypeCode(int typeCode) {
|
||||
return isStandardTypeCode( Integer.valueOf( typeCode ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as call to {@link #isStandardTypeCode(int)}
|
||||
*
|
||||
* @see #isStandardTypeCode(int)
|
||||
*/
|
||||
public static boolean isStandardTypeCode(Integer typeCode) {
|
||||
return JDBC_TYPE_MAP.containsKey( typeCode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type name as in the static field names defined on {@link java.sql.Types}. If a type code is not
|
||||
* recognized, it is reported as {@code UNKNOWN(?)} where '?' is replace with the given type code.
|
||||
*
|
||||
* Intended as useful for logging purposes...
|
||||
*
|
||||
* @param typeCode The type code to find the name for.
|
||||
*
|
||||
* @return The type name.
|
||||
*/
|
||||
public static String getTypeName(Integer typeCode) {
|
||||
String name = JDBC_TYPE_MAP.get( typeCode );
|
||||
if ( name == null ) {
|
||||
return "UNKNOWN(" + code + ")";
|
||||
return "UNKNOWN(" + typeCode + ")";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -65,46 +65,36 @@ public abstract class AbstractTypeDescriptor<T> implements JavaTypeDescriptor<T>
|
|||
this.comparator = Comparable.class.isAssignableFrom( type )
|
||||
? (Comparator<T>) ComparableComparator.INSTANCE
|
||||
: null;
|
||||
|
||||
JavaTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MutabilityPlan<T> getMutabilityPlan() {
|
||||
return mutabilityPlan;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Class<T> getJavaTypeClass() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int extractHashCode(T value) {
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean areEqual(T one, T another) {
|
||||
return EqualsHelper.equals( one, another );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Comparator<T> getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String extractLoggableRepresentation(T value) {
|
||||
return (value == null) ? "null" : value.toString();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.hibernate.type.descriptor.BinaryStream;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@code Byte[]} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.hibernate.type.descriptor.CharacterStream;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@code Character[]} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link Class} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -28,7 +28,7 @@ import java.util.Currency;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link Currency} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -39,10 +39,12 @@ public class CurrencyTypeDescriptor extends AbstractTypeDescriptor<Currency> {
|
|||
super( Currency.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Currency value) {
|
||||
return value.getCurrencyCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Currency fromString(String string) {
|
||||
return Currency.getInstance( string );
|
||||
}
|
||||
|
@ -58,6 +60,7 @@ public class CurrencyTypeDescriptor extends AbstractTypeDescriptor<Currency> {
|
|||
throw unknownUnwrap( type );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> Currency wrap(X value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link Date} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
|
@ -32,30 +33,22 @@ import java.io.Serializable;
|
|||
public class ImmutableMutabilityPlan<T> implements MutabilityPlan<T> {
|
||||
public static final ImmutableMutabilityPlan INSTANCE = new ImmutableMutabilityPlan();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public T deepCopy(T value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Serializable disassemble(T value) {
|
||||
return (Serializable) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public T assemble(Serializable cached) {
|
||||
return (T) cached;
|
||||
|
|
|
@ -22,16 +22,19 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Comparator for things that cannot be compared (in a way we know about).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IncomparableComparator implements Comparator {
|
||||
public static final IncomparableComparator INSTANCE = new IncomparableComparator();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("ComparatorMethodParameterNotUsed")
|
||||
public int compare(Object o1, Object o2) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.java;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* Basically a map from {@link Class} -> {@link JavaTypeDescriptor}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JavaTypeDescriptorRegistry {
|
||||
public static final JavaTypeDescriptorRegistry INSTANCE = new JavaTypeDescriptorRegistry();
|
||||
|
||||
private ConcurrentHashMap<Class,JavaTypeDescriptor> descriptorsByClass = new ConcurrentHashMap<Class, JavaTypeDescriptor>();
|
||||
|
||||
/**
|
||||
* Adds the given descriptor to this registry
|
||||
*
|
||||
* @param descriptor The descriptor to add.
|
||||
*/
|
||||
public void addDescriptor(JavaTypeDescriptor descriptor) {
|
||||
descriptorsByClass.put( descriptor.getJavaTypeClass(), descriptor );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> cls) {
|
||||
if ( cls == null ) {
|
||||
throw new IllegalArgumentException( "Class passed to locate Java type descriptor cannot be null" );
|
||||
}
|
||||
|
||||
JavaTypeDescriptor<T> descriptor = descriptorsByClass.get( cls );
|
||||
if ( descriptor != null ) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
// find the first "assignable" match
|
||||
for ( Map.Entry<Class,JavaTypeDescriptor> entry : descriptorsByClass.entrySet() ) {
|
||||
if ( cls.isAssignableFrom( entry.getKey() ) ) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
// we could not find one; warn the user (as stuff is likely to break later) and create a fallback instance...
|
||||
if ( Serializable.class.isAssignableFrom( cls ) ) {
|
||||
return new SerializableTypeDescriptor( cls );
|
||||
}
|
||||
else {
|
||||
return new FallbackJavaTypeDescriptor<T>( cls );
|
||||
}
|
||||
}
|
||||
|
||||
public static class FallbackJavaTypeDescriptor<T> extends AbstractTypeDescriptor<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected FallbackJavaTypeDescriptor(Class<T> type) {
|
||||
// MutableMutabilityPlan would be the "safest" option, but we do not necessarily know how to deepCopy etc...
|
||||
super( type, ImmutableMutabilityPlan.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(T value) {
|
||||
return value == null ? "<null>" : value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T fromString(String string) {
|
||||
throw new HibernateException(
|
||||
"Not known how to convert String to given type [" + getJavaTypeClass().getName() + "]"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X> X unwrap(T value, Class<X> type, WrapperOptions options) {
|
||||
return (X) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X> T wrap(X value, WrapperOptions options) {
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link java.sql.Date} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link Time} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link Timestamp} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -53,8 +53,7 @@ public class JdbcTimestampTypeDescriptor extends AbstractTypeDescriptor<Date> {
|
|||
return ts;
|
||||
}
|
||||
else {
|
||||
Date orig = value;
|
||||
return new Date( orig.getTime() );
|
||||
return new Date( value.getTime() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.util.StringTokenizer;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@link Locale} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Describes the mutability aspects of a Java type. The term mutability refers to the fact that generally speaking
|
||||
* the aspects described by this contract are defined by whether the Java type's internal state is mutable or not.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
|
@ -30,29 +31,23 @@ import java.io.Serializable;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class MutableMutabilityPlan<T> implements MutabilityPlan<T> {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Serializable disassemble(T value) {
|
||||
return (Serializable) deepCopy( value );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public T assemble(Serializable cached) {
|
||||
return (T) deepCopy( (T) cached );
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T deepCopy(T value) {
|
||||
return value == null ? null : deepCopyNotNull( value );
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.hibernate.type.descriptor.CharacterStream;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for {@code char[]} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.hibernate.type.descriptor.BinaryStream;
|
|||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
* Descriptor for general {@link Serializable} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class BigIntTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final BigIntTypeDescriptor INSTANCE = new BigIntTypeDescriptor();
|
||||
|
||||
public BigIntTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.BIGINT;
|
||||
}
|
||||
|
@ -51,6 +56,7 @@ public class BigIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -60,6 +66,7 @@ public class BigIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -32,6 +32,10 @@ import java.sql.Types;
|
|||
public class BinaryTypeDescriptor extends VarbinaryTypeDescriptor {
|
||||
public static final BinaryTypeDescriptor INSTANCE = new BinaryTypeDescriptor();
|
||||
|
||||
public BinaryTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.BINARY;
|
||||
|
|
|
@ -45,6 +45,10 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class BitTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final BitTypeDescriptor INSTANCE = new BitTypeDescriptor();
|
||||
|
||||
public BitTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
public int getSqlType() {
|
||||
return Types.BIT;
|
||||
}
|
||||
|
@ -54,6 +58,7 @@ public class BitTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -63,6 +68,7 @@ public class BitTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.sql.SQLException;
|
|||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
@ -40,13 +39,50 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
* Descriptor for {@link Types#BLOB BLOB} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
|
||||
|
||||
private BlobTypeDescriptor() {}
|
||||
private BlobTypeDescriptor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.BLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getBlob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBlob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract <X> BasicBinder<X> getBlobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
public <X> BasicBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return getBlobBinder( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
public static final BlobTypeDescriptor DEFAULT =
|
||||
new BlobTypeDescriptor() {
|
||||
{
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> BasicBinder<X> getBlobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
@ -110,32 +146,4 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
|
|||
}
|
||||
};
|
||||
|
||||
protected abstract <X> BasicBinder<X> getBlobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getBlob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getBlob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int getSqlType() {
|
||||
return Types.BLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return getBlobBinder( javaTypeDescriptor );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class BooleanTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final BooleanTypeDescriptor INSTANCE = new BooleanTypeDescriptor();
|
||||
|
||||
public BooleanTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
public int getSqlType() {
|
||||
return Types.BOOLEAN;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,10 @@ import java.sql.Types;
|
|||
public class CharTypeDescriptor extends VarcharTypeDescriptor {
|
||||
public static final CharTypeDescriptor INSTANCE = new CharTypeDescriptor();
|
||||
|
||||
public CharTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.CHAR;
|
||||
|
|
|
@ -40,11 +40,47 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
* Descriptor for {@link Types#CLOB CLOB} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public abstract class ClobTypeDescriptor implements SqlTypeDescriptor {
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.CLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getClob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getClob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected abstract <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return getClobBinder( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
public static final ClobTypeDescriptor DEFAULT =
|
||||
new ClobTypeDescriptor() {
|
||||
{
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
public <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -87,32 +123,4 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor {
|
|||
}
|
||||
};
|
||||
|
||||
protected abstract <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return getClobBinder( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
public int getSqlType() {
|
||||
return Types.CLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getClob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getClob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class DateTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final DateTypeDescriptor INSTANCE = new DateTypeDescriptor();
|
||||
|
||||
public DateTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.DATE;
|
||||
}
|
||||
|
@ -52,6 +57,7 @@ public class DateTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -61,6 +67,7 @@ public class DateTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -43,6 +43,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class DecimalTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final DecimalTypeDescriptor INSTANCE = new DecimalTypeDescriptor();
|
||||
|
||||
public DecimalTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.DECIMAL;
|
||||
}
|
||||
|
@ -52,6 +57,7 @@ public class DecimalTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -61,6 +67,7 @@ public class DecimalTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -42,6 +42,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class DoubleTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final DoubleTypeDescriptor INSTANCE = new DoubleTypeDescriptor();
|
||||
|
||||
public DoubleTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.DOUBLE;
|
||||
}
|
||||
|
@ -51,6 +56,7 @@ public class DoubleTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -60,6 +66,7 @@ public class DoubleTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
|
@ -32,6 +33,11 @@ import java.sql.Types;
|
|||
public class FloatTypeDescriptor extends RealTypeDescriptor {
|
||||
public static final FloatTypeDescriptor INSTANCE = new FloatTypeDescriptor();
|
||||
|
||||
public FloatTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.FLOAT;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class IntegerTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final IntegerTypeDescriptor INSTANCE = new IntegerTypeDescriptor();
|
||||
|
||||
public IntegerTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.INTEGER;
|
||||
}
|
||||
|
@ -51,6 +56,7 @@ public class IntegerTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -60,6 +66,7 @@ public class IntegerTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Information pertaining to JDBC type families.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcTypeFamilyInformation {
|
||||
public static final JdbcTypeFamilyInformation INSTANCE = new JdbcTypeFamilyInformation();
|
||||
|
||||
// todo : make Family non-enum so it can be expanded by Dialects?
|
||||
|
||||
public static enum Family {
|
||||
BINARY( Types.BINARY, Types.VARBINARY, Types.LONGVARBINARY ),
|
||||
NUMERIC( Types.BIGINT, Types.DECIMAL, Types.DOUBLE, Types.FLOAT, Types.INTEGER, Types.NUMERIC, Types.REAL, Types.SMALLINT, Types.TINYINT ),
|
||||
CHARACTER( Types.CHAR, Types.LONGNVARCHAR, Types.LONGVARCHAR, Types.NCHAR, Types.NVARCHAR, Types.VARCHAR ),
|
||||
DATETIME( Types.DATE, Types.TIME, Types.TIMESTAMP ),
|
||||
CLOB( Types.CLOB, Types.NCLOB );
|
||||
|
||||
private final int[] typeCodes;
|
||||
|
||||
@SuppressWarnings("UnnecessaryBoxing")
|
||||
private Family(int... typeCodes) {
|
||||
this.typeCodes = typeCodes;
|
||||
|
||||
for ( int typeCode : typeCodes ) {
|
||||
JdbcTypeFamilyInformation.INSTANCE.typeCodeToFamilyMap.put( Integer.valueOf( typeCode ), this );
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getTypeCodes() {
|
||||
return typeCodes;
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentHashMap<Integer,Family> typeCodeToFamilyMap = new ConcurrentHashMap<Integer, Family>();
|
||||
|
||||
/**
|
||||
* Will return {@code null} if no match is found.
|
||||
*
|
||||
* @param typeCode The JDBC type code.
|
||||
*
|
||||
* @return The family of datatypes the type code belongs to, or {@code null} if it belongs to no known families.
|
||||
*/
|
||||
@SuppressWarnings("UnnecessaryBoxing")
|
||||
public Family locateJdbcTypeFamilyByTypeCode(int typeCode) {
|
||||
return typeCodeToFamilyMap.get( Integer.valueOf( typeCode ) );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Date;
|
||||
import java.sql.Ref;
|
||||
import java.sql.Struct;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.mapping.Array;
|
||||
|
||||
/**
|
||||
* Presents recommended {@literal JDCB typecode <-> Java Class} mappings. Currently the recommendations
|
||||
* contained here come from the JDBC spec itself, as outlined at <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/jdbc/getstart/mapping.html#1034737"/>
|
||||
* Eventually, the plan is to have {@link org.hibernate.dialect.Dialect} contribute this information.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcTypeJavaClassMappings {
|
||||
private static final Logger log = Logger.getLogger( JdbcTypeJavaClassMappings.class );
|
||||
|
||||
private static final ConcurrentHashMap<Class, Integer> javaClassToJdbcTypeCodeMap = buildJdbcJavaClassMappings();
|
||||
private static final ConcurrentHashMap<Integer, Class> jdbcTypeCodeToJavaClassMap = transpose( javaClassToJdbcTypeCodeMap );
|
||||
|
||||
public static final JdbcTypeJavaClassMappings INSTANCE = new JdbcTypeJavaClassMappings();
|
||||
|
||||
private JdbcTypeJavaClassMappings() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnboxing")
|
||||
public int determineJdbcTypeCodeForJavaClass(Class cls) {
|
||||
Integer typeCode = JdbcTypeJavaClassMappings.javaClassToJdbcTypeCodeMap.get( cls );
|
||||
if ( typeCode != null ) {
|
||||
return typeCode.intValue();
|
||||
}
|
||||
|
||||
int specialCode = cls.hashCode();
|
||||
log.debug(
|
||||
"JDBC type code mapping not known for class [" + cls.getName() + "]; using custom code [" + specialCode + "]"
|
||||
);
|
||||
return specialCode;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryUnboxing")
|
||||
public Class determineJavaClassForJdbcTypeCode(int typeCode) {
|
||||
Class cls = jdbcTypeCodeToJavaClassMap.get( Integer.valueOf( typeCode ) );
|
||||
if ( cls != null ) {
|
||||
return cls;
|
||||
}
|
||||
|
||||
log.debugf(
|
||||
"Java Class mapping not known for JDBC type code [%s]; using java.lang.Object",
|
||||
typeCode
|
||||
);
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private static ConcurrentHashMap<Class, Integer> buildJdbcJavaClassMappings() {
|
||||
ConcurrentHashMap<Class, Integer> jdbcJavaClassMappings = new ConcurrentHashMap<Class, Integer>();
|
||||
|
||||
// these mappings are the ones outlined specifically in the spec
|
||||
jdbcJavaClassMappings.put( String.class, Types.VARCHAR );
|
||||
jdbcJavaClassMappings.put( BigDecimal.class, Types.NUMERIC );
|
||||
jdbcJavaClassMappings.put( Boolean.class, Types.BIT );
|
||||
jdbcJavaClassMappings.put( Integer.class, Types.INTEGER );
|
||||
jdbcJavaClassMappings.put( Long.class, Types.BIGINT );
|
||||
jdbcJavaClassMappings.put( Float.class, Types.REAL );
|
||||
jdbcJavaClassMappings.put( Double.class, Types.DOUBLE );
|
||||
jdbcJavaClassMappings.put( byte[].class, Types.LONGVARBINARY );
|
||||
jdbcJavaClassMappings.put( Date.class, Types.DATE );
|
||||
jdbcJavaClassMappings.put( Time.class, Types.TIME );
|
||||
jdbcJavaClassMappings.put( Timestamp.class, Types.TIMESTAMP );
|
||||
jdbcJavaClassMappings.put( Blob.class, Types.BLOB );
|
||||
jdbcJavaClassMappings.put( Clob.class, Types.CLOB );
|
||||
jdbcJavaClassMappings.put( Array.class, Types.ARRAY );
|
||||
jdbcJavaClassMappings.put( Struct.class, Types.STRUCT );
|
||||
jdbcJavaClassMappings.put( Ref.class, Types.REF );
|
||||
jdbcJavaClassMappings.put( Class.class, Types.JAVA_OBJECT );
|
||||
|
||||
// additional "common sense" registrations
|
||||
jdbcJavaClassMappings.put( Character.class, Types.CHAR );
|
||||
jdbcJavaClassMappings.put( char[].class, Types.VARCHAR );
|
||||
jdbcJavaClassMappings.put( Character[].class, Types.VARCHAR );
|
||||
jdbcJavaClassMappings.put( Byte[].class, Types.LONGVARBINARY );
|
||||
jdbcJavaClassMappings.put( Date.class, Types.TIMESTAMP );
|
||||
jdbcJavaClassMappings.put( Calendar.class, Types.TIMESTAMP );
|
||||
|
||||
return jdbcJavaClassMappings;
|
||||
}
|
||||
|
||||
private static ConcurrentHashMap<Integer, Class> transpose(ConcurrentHashMap<Class, Integer> javaClassToJdbcTypeCodeMap) {
|
||||
final ConcurrentHashMap<Integer, Class> transposed = new ConcurrentHashMap<Integer, Class>();
|
||||
|
||||
for ( Map.Entry<Class,Integer> entry : javaClassToJdbcTypeCodeMap.entrySet() ) {
|
||||
transposed.put( entry.getValue(), entry.getKey() );
|
||||
}
|
||||
|
||||
return transposed;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#LONGNVARCHAR LONGNVARCHAR} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LongNVarcharTypeDescriptor extends NVarcharTypeDescriptor {
|
||||
public static final LongNVarcharTypeDescriptor INSTANCE = new LongNVarcharTypeDescriptor();
|
||||
|
||||
public LongNVarcharTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.LONGNVARCHAR;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
|
@ -32,6 +33,10 @@ import java.sql.Types;
|
|||
public class LongVarbinaryTypeDescriptor extends VarbinaryTypeDescriptor {
|
||||
public static final LongVarbinaryTypeDescriptor INSTANCE = new LongVarbinaryTypeDescriptor();
|
||||
|
||||
public LongVarbinaryTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.LONGVARBINARY;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
|
@ -32,6 +33,10 @@ import java.sql.Types;
|
|||
public class LongVarcharTypeDescriptor extends VarcharTypeDescriptor {
|
||||
public static final LongVarcharTypeDescriptor INSTANCE = new LongVarcharTypeDescriptor();
|
||||
|
||||
public LongVarcharTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.LONGVARCHAR;
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#NCHAR NCHAR} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NCharTypeDescriptor extends NVarcharTypeDescriptor {
|
||||
public static final NCharTypeDescriptor INSTANCE = new NCharTypeDescriptor();
|
||||
|
||||
public NCharTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.NCHAR;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#NCLOB NCLOB} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public abstract class NClobTypeDescriptor implements SqlTypeDescriptor {
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.NCLOB;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getNClob( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getNClob( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected abstract <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return getClobBinder( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
public static final ClobTypeDescriptor DEFAULT =
|
||||
new ClobTypeDescriptor() {
|
||||
{
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
public <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
|
||||
if ( options.useStreamForLobBinding() ) {
|
||||
STREAM_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options );
|
||||
}
|
||||
else {
|
||||
CLOB_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
public static final ClobTypeDescriptor CLOB_BINDING =
|
||||
new ClobTypeDescriptor() {
|
||||
public <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
st.setNClob( index, javaTypeDescriptor.unwrap( value, NClob.class, options ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
public static final ClobTypeDescriptor STREAM_BINDING =
|
||||
new ClobTypeDescriptor() {
|
||||
public <X> BasicBinder<X> getClobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options );
|
||||
st.setCharacterStream( index, characterStream.getReader(), characterStream.getLength() );
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#NVARCHAR NVARCHAR} handling.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NVarcharTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final NVarcharTypeDescriptor INSTANCE = new NVarcharTypeDescriptor();
|
||||
|
||||
public NVarcharTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.NVARCHAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
|
||||
st.setNString( index, javaTypeDescriptor.unwrap( value, String.class, options ) );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getNString( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getNString( index ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
|
@ -32,6 +33,10 @@ import java.sql.Types;
|
|||
public class NumericTypeDescriptor extends DecimalTypeDescriptor {
|
||||
public static final NumericTypeDescriptor INSTANCE = new NumericTypeDescriptor();
|
||||
|
||||
public NumericTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.NUMERIC;
|
||||
|
|
|
@ -42,6 +42,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class RealTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final RealTypeDescriptor INSTANCE = new RealTypeDescriptor();
|
||||
|
||||
public RealTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.REAL;
|
||||
}
|
||||
|
@ -51,6 +56,7 @@ public class RealTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -60,6 +66,7 @@ public class RealTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -42,6 +42,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class SmallIntTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final SmallIntTypeDescriptor INSTANCE = new SmallIntTypeDescriptor();
|
||||
|
||||
public SmallIntTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.SMALLINT;
|
||||
}
|
||||
|
@ -51,6 +56,7 @@ public class SmallIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -60,6 +66,7 @@ public class SmallIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -31,6 +31,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
|
||||
/**
|
||||
* Descriptor for the <tt>SQL</tt>/<tt>JDBC</tt> side of a value mapping.
|
||||
* <p/>
|
||||
* NOTE : Implementations should be registered with the {@link SqlTypeDescriptor}. The built-in Hibernate
|
||||
* implementations register themselves on construction.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -52,7 +55,23 @@ public interface SqlTypeDescriptor extends Serializable {
|
|||
*/
|
||||
public boolean canBeRemapped();
|
||||
|
||||
/**
|
||||
* Get the binder (setting JDBC in-going parameter values) capable of handling values of the type described by the
|
||||
* passed descriptor.
|
||||
*
|
||||
* @param javaTypeDescriptor The descriptor describing the types of Java values to be bound
|
||||
*
|
||||
* @return The appropriate binder.
|
||||
*/
|
||||
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
|
||||
/**
|
||||
* Get the extractor (pulling out-going values from JDBC objects) capable of handling values of the type described
|
||||
* by the passed descriptor.
|
||||
*
|
||||
* @param javaTypeDescriptor The descriptor describing the types of Java values to be extracted
|
||||
*
|
||||
* @return The appropriate extractor
|
||||
*/
|
||||
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type.descriptor.sql;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* Basically a map from JDBC type code (int) -> {@link SqlTypeDescriptor}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqlTypeDescriptorRegistry {
|
||||
public static final SqlTypeDescriptorRegistry INSTANCE = new SqlTypeDescriptorRegistry();
|
||||
|
||||
private static final Logger log = Logger.getLogger( SqlTypeDescriptorRegistry.class );
|
||||
|
||||
private ConcurrentHashMap<Integer,SqlTypeDescriptor> descriptorMap = new ConcurrentHashMap<Integer, SqlTypeDescriptor>();
|
||||
|
||||
@SuppressWarnings("UnnecessaryBoxing")
|
||||
public void addDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
|
||||
descriptorMap.put( Integer.valueOf( sqlTypeDescriptor.getSqlType() ), sqlTypeDescriptor );
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryBoxing")
|
||||
public SqlTypeDescriptor getDescriptor(int jdbcTypeCode) {
|
||||
SqlTypeDescriptor descriptor = descriptorMap.get( Integer.valueOf( jdbcTypeCode ) );
|
||||
if ( descriptor != null ) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
if ( JdbcTypeNameMapper.isStandardTypeCode( jdbcTypeCode ) ) {
|
||||
log.debugf(
|
||||
"A standard JDBC type code [%s] was not defined in SqlTypeDescriptorRegistry",
|
||||
jdbcTypeCode
|
||||
);
|
||||
}
|
||||
|
||||
// see if the typecode is part of a known type family...
|
||||
JdbcTypeFamilyInformation.Family family = JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode );
|
||||
if ( family != null ) {
|
||||
for ( int potentialAlternateTypeCode : family.getTypeCodes() ) {
|
||||
if ( potentialAlternateTypeCode != jdbcTypeCode ) {
|
||||
final SqlTypeDescriptor potentialAlternateDescriptor = descriptorMap.get( Integer.valueOf( potentialAlternateTypeCode ) );
|
||||
if ( potentialAlternateDescriptor != null ) {
|
||||
// todo : add a SqlTypeDescriptor.canBeAssignedFrom method...
|
||||
return potentialAlternateDescriptor;
|
||||
}
|
||||
|
||||
if ( JdbcTypeNameMapper.isStandardTypeCode( potentialAlternateTypeCode ) ) {
|
||||
log.debugf(
|
||||
"A standard JDBC type code [%s] was not defined in SqlTypeDescriptorRegistry",
|
||||
potentialAlternateTypeCode
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally, create a new descriptor mapping to getObject/setObject for this type code...
|
||||
final ObjectSqlTypeDescriptor fallBackDescriptor = new ObjectSqlTypeDescriptor( jdbcTypeCode );
|
||||
addDescriptor( fallBackDescriptor );
|
||||
return fallBackDescriptor;
|
||||
}
|
||||
|
||||
public static class ObjectSqlTypeDescriptor implements SqlTypeDescriptor {
|
||||
private final int jdbcTypeCode;
|
||||
|
||||
public ObjectSqlTypeDescriptor(int jdbcTypeCode) {
|
||||
this.jdbcTypeCode = jdbcTypeCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return jdbcTypeCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
|
||||
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
st.setObject( index, value, jdbcTypeCode );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) {
|
||||
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) {
|
||||
return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
return new BasicExtractor( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected Object doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return rs.getObject( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doExtract(CallableStatement statement, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return statement.getObject( index );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,6 +43,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final TimeTypeDescriptor INSTANCE = new TimeTypeDescriptor();
|
||||
|
||||
public TimeTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.TIME;
|
||||
}
|
||||
|
@ -52,6 +57,7 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -61,6 +67,7 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -43,6 +43,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final TimestampTypeDescriptor INSTANCE = new TimestampTypeDescriptor();
|
||||
|
||||
public TimestampTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.TIMESTAMP;
|
||||
}
|
||||
|
@ -52,6 +57,7 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -61,6 +67,7 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -45,6 +45,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class TinyIntTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final TinyIntTypeDescriptor INSTANCE = new TinyIntTypeDescriptor();
|
||||
|
||||
public TinyIntTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.TINYINT;
|
||||
}
|
||||
|
@ -54,6 +59,7 @@ public class TinyIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -63,6 +69,7 @@ public class TinyIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -42,6 +42,10 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class VarbinaryTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final VarbinaryTypeDescriptor INSTANCE = new VarbinaryTypeDescriptor();
|
||||
|
||||
public VarbinaryTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
public int getSqlType() {
|
||||
return Types.VARBINARY;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
public class VarcharTypeDescriptor implements SqlTypeDescriptor {
|
||||
public static final VarcharTypeDescriptor INSTANCE = new VarcharTypeDescriptor();
|
||||
|
||||
public VarcharTypeDescriptor() {
|
||||
SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.VARCHAR;
|
||||
}
|
||||
|
@ -51,6 +56,7 @@ public class VarcharTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
@ -60,6 +66,7 @@ public class VarcharTypeDescriptor implements SqlTypeDescriptor {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.type;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Converter;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.IrrelevantEntity;
|
||||
import org.hibernate.cfg.AttributeConverterDefinition;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.type.descriptor.java.StringTypeDescriptor;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
/**
|
||||
* Tests the principle of adding "AttributeConverter" to the mix of {@link Type} resolution
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AttributeConverterTest extends BaseUnitTestCase {
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
Configuration cfg = new Configuration();
|
||||
SimpleValue simpleValue = new SimpleValue( cfg.createMappings() );
|
||||
simpleValue.setJpaAttributeConverterDefinition(
|
||||
new AttributeConverterDefinition( new StringClobConverter(), true )
|
||||
);
|
||||
simpleValue.setTypeUsingReflection( IrrelevantEntity.class.getName(), "name" );
|
||||
|
||||
Type type = simpleValue.getType();
|
||||
assertNotNull( type );
|
||||
assertTyping( BasicType.class, type );
|
||||
AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type );
|
||||
assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() );
|
||||
assertEquals( Types.CLOB, basicType.getSqlTypeDescriptor().getSqlType() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalOperation() {
|
||||
Configuration cfg = new Configuration();
|
||||
cfg.addAttributeConverter( StringClobConverter.class, true );
|
||||
cfg.addAnnotatedClass( Tester.class );
|
||||
cfg.addAnnotatedClass( Tester2.class );
|
||||
cfg.buildMappings();
|
||||
|
||||
{
|
||||
PersistentClass tester = cfg.getClassMapping( Tester.class.getName() );
|
||||
Property nameProp = tester.getProperty( "name" );
|
||||
SimpleValue nameValue = (SimpleValue) nameProp.getValue();
|
||||
Type type = nameValue.getType();
|
||||
assertNotNull( type );
|
||||
assertTyping( BasicType.class, type );
|
||||
AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type );
|
||||
assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() );
|
||||
assertEquals( Types.CLOB, basicType.getSqlTypeDescriptor().getSqlType() );
|
||||
}
|
||||
|
||||
{
|
||||
PersistentClass tester = cfg.getClassMapping( Tester2.class.getName() );
|
||||
Property nameProp = tester.getProperty( "name" );
|
||||
SimpleValue nameValue = (SimpleValue) nameProp.getValue();
|
||||
Type type = nameValue.getType();
|
||||
assertNotNull( type );
|
||||
assertTyping( BasicType.class, type );
|
||||
AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type );
|
||||
assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() );
|
||||
assertEquals( Types.VARCHAR, basicType.getSqlTypeDescriptor().getSqlType() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
public static class Tester {
|
||||
@Id
|
||||
private Long id;
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Tester2 {
|
||||
@Id
|
||||
private Long id;
|
||||
@Convert(disableConversion = true)
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Tester3 {
|
||||
@Id
|
||||
private Long id;
|
||||
@org.hibernate.annotations.Type( type = "string" )
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Converter( autoApply = true )
|
||||
public static class StringClobConverter implements AttributeConverter<String,Clob> {
|
||||
@Override
|
||||
public Clob convertToDatabaseColumn(String attribute) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToEntityAttribute(Clob dbData) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,4 +37,18 @@ public class ExtraAssertions {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T assertTyping(Class<T> expectedType, Object value) {
|
||||
if ( ! expectedType.isInstance( value ) ) {
|
||||
Assert.fail(
|
||||
String.format(
|
||||
"Expecting value of type [%s], but found [%s]",
|
||||
expectedType.getName(),
|
||||
value == null ? "<null>" : value
|
||||
)
|
||||
);
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue