Verified and fixed BasicValue resolutions based on type-defs and UserTypes
This commit is contained in:
parent
41093ae66c
commit
e38a4de536
|
@ -33,11 +33,12 @@ import org.hibernate.MappingException;
|
|||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.annotations.AnyMetaDef;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.util.StringHelper;
|
||||
import org.hibernate.boot.CacheRegionDefinition;
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistryStandardImpl;
|
||||
import org.hibernate.boot.model.convert.internal.AttributeConverterManager;
|
||||
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
||||
import org.hibernate.boot.model.convert.spi.ConverterAutoApplyHandler;
|
||||
|
@ -131,10 +132,11 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
private final Map<String,PersistentClass> entityBindingMap = new HashMap<>();
|
||||
private final Map<String,Collection> collectionBindingMap = new HashMap<>();
|
||||
|
||||
private final Map<String, TypeDefinition> typeDefinitionMap = new HashMap<>();
|
||||
private final Map<String, FilterDefinition> filterDefinitionMap = new HashMap<>();
|
||||
private final Map<String, String> imports = new HashMap<>();
|
||||
|
||||
private final TypeDefinitionRegistry typeDefRegistry = new TypeDefinitionRegistryStandardImpl();
|
||||
|
||||
private Database database;
|
||||
|
||||
private final Map<String, NamedHqlQueryDefinition> namedQueryMap = new HashMap<>();
|
||||
|
@ -340,39 +342,20 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Hibernate Type handling
|
||||
|
||||
|
||||
@Override
|
||||
public TypeDefinitionRegistry getTypeDefinitionRegistry() {
|
||||
return typeDefRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinition getTypeDefinition(String registrationKey) {
|
||||
return typeDefinitionMap.get( registrationKey );
|
||||
return typeDefRegistry.resolve( registrationKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTypeDefinition(TypeDefinition typeDefinition) {
|
||||
if ( typeDefinition == null ) {
|
||||
throw new IllegalArgumentException( "Type definition is null" );
|
||||
}
|
||||
|
||||
// Need to register both by name and registration keys.
|
||||
if ( !StringHelper.isEmpty( typeDefinition.getName() ) ) {
|
||||
addTypeDefinition( typeDefinition.getName(), typeDefinition );
|
||||
}
|
||||
|
||||
if ( typeDefinition.getRegistrationKeys() != null ) {
|
||||
for ( String registrationKey : typeDefinition.getRegistrationKeys() ) {
|
||||
addTypeDefinition( registrationKey, typeDefinition );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addTypeDefinition(String registrationKey, TypeDefinition typeDefinition) {
|
||||
final TypeDefinition previous = typeDefinitionMap.put(
|
||||
registrationKey, typeDefinition );
|
||||
if ( previous != null ) {
|
||||
log.debugf(
|
||||
"Duplicate typedef name [%s] now -> %s",
|
||||
registrationKey,
|
||||
typeDefinition.getTypeImplementorClass().getName()
|
||||
);
|
||||
}
|
||||
typeDefRegistry.register( typeDefinition );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2259,7 +2242,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
entityBindingMap,
|
||||
mappedSuperClasses,
|
||||
collectionBindingMap,
|
||||
typeDefinitionMap,
|
||||
typeDefRegistry.copyRegistrationMap(),
|
||||
filterDefinitionMap,
|
||||
fetchProfileMap,
|
||||
imports,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.boot.internal;
|
||||
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistryStandardImpl;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
import org.hibernate.boot.spi.ClassLoaderAccess;
|
||||
|
@ -24,7 +24,7 @@ public class MetadataBuildingContextRootImpl implements MetadataBuildingContext
|
|||
private final MappingDefaults mappingDefaults;
|
||||
private final InFlightMetadataCollector metadataCollector;
|
||||
private final ObjectNameNormalizer objectNameNormalizer;
|
||||
private final TypeDefinitionRegistry typeDefinitionRegistry;
|
||||
private final TypeDefinitionRegistryStandardImpl typeDefinitionRegistry;
|
||||
|
||||
public MetadataBuildingContextRootImpl(
|
||||
BootstrapContext bootstrapContext,
|
||||
|
@ -40,7 +40,7 @@ public class MetadataBuildingContextRootImpl implements MetadataBuildingContext
|
|||
return MetadataBuildingContextRootImpl.this;
|
||||
}
|
||||
};
|
||||
this.typeDefinitionRegistry = new TypeDefinitionRegistry();
|
||||
this.typeDefinitionRegistry = new TypeDefinitionRegistryStandardImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,7 +74,7 @@ public class MetadataBuildingContextRootImpl implements MetadataBuildingContext
|
|||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinitionRegistry getTypeDefinitionRegistry() {
|
||||
public TypeDefinitionRegistryStandardImpl getTypeDefinitionRegistry() {
|
||||
return typeDefinitionRegistry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.SessionFactory;
|
|||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.boot.model.relational.Namespace;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.hibernate.resource.beans.spi.ManagedBean;
|
|||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CustomType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
@ -48,6 +48,7 @@ import org.hibernate.usertype.UserType;
|
|||
* @author Steve Ebersole
|
||||
* @author John Verhaeg
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class TypeDefinition implements Serializable {
|
||||
private static final AtomicInteger nameCounter = new AtomicInteger();
|
||||
|
||||
|
@ -96,8 +97,6 @@ public class TypeDefinition implements Serializable {
|
|||
}
|
||||
|
||||
public BasicValue.Resolution<?> resolve(
|
||||
JavaTypeDescriptor<?> explicitJtd,
|
||||
SqlTypeDescriptor explicitStd,
|
||||
Map localConfigParameters,
|
||||
MutabilityPlan explicitMutabilityPlan,
|
||||
MetadataBuildingContext context) {
|
||||
|
@ -137,8 +136,6 @@ public class TypeDefinition implements Serializable {
|
|||
return createResolution(
|
||||
name,
|
||||
typeInstance,
|
||||
explicitJtd,
|
||||
explicitStd,
|
||||
explicitMutabilityPlan,
|
||||
context
|
||||
);
|
||||
|
@ -213,7 +210,10 @@ public class TypeDefinition implements Serializable {
|
|||
|
||||
@Override
|
||||
public MutabilityPlan<Object> getMutabilityPlan() {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
// a TypeDefinition does not explicitly provide a MutabilityPlan (yet?)
|
||||
return resolvedBasicType.isMutable()
|
||||
? getDomainJavaDescriptor().getMutabilityPlan()
|
||||
: ImmutableMutabilityPlan.instance();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -226,8 +226,6 @@ public class TypeDefinition implements Serializable {
|
|||
public static BasicValue.Resolution<?> createLocalResolution(
|
||||
String name,
|
||||
Class typeImplementorClass,
|
||||
JavaTypeDescriptor<?> explicitJtd,
|
||||
SqlTypeDescriptor explicitStd,
|
||||
MutabilityPlan explicitMutabilityPlan,
|
||||
Map localTypeParams,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
|
@ -245,8 +243,6 @@ public class TypeDefinition implements Serializable {
|
|||
return createResolution(
|
||||
name,
|
||||
typeInstance,
|
||||
explicitJtd,
|
||||
explicitStd,
|
||||
explicitMutabilityPlan,
|
||||
buildingContext
|
||||
);
|
||||
|
@ -255,8 +251,6 @@ public class TypeDefinition implements Serializable {
|
|||
private static BasicValue.Resolution<?> createResolution(
|
||||
String name,
|
||||
Object namedTypeInstance,
|
||||
JavaTypeDescriptor<?> explicitJtd,
|
||||
SqlTypeDescriptor explicitStd,
|
||||
MutabilityPlan explicitMutabilityPlan,
|
||||
MetadataBuildingContext metadataBuildingContext) {
|
||||
if ( namedTypeInstance instanceof UserType ) {
|
||||
|
|
|
@ -6,98 +6,27 @@
|
|||
*/
|
||||
package org.hibernate.boot.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TypeDefinitionRegistry {
|
||||
private static final Logger log = Logger.getLogger( TypeDefinitionRegistry.class );
|
||||
private final TypeDefinitionRegistry parent;
|
||||
public interface TypeDefinitionRegistry {
|
||||
|
||||
public enum DuplicationStrategy {
|
||||
enum DuplicationStrategy {
|
||||
KEEP,
|
||||
OVERWRITE,
|
||||
DISALLOW
|
||||
}
|
||||
|
||||
private final Map<String, TypeDefinition> typeDefinitionMap = new HashMap<>();
|
||||
TypeDefinition resolve(String typeName);
|
||||
TypeDefinition resolveAutoApplied(BasicJavaDescriptor<?> jtd);
|
||||
|
||||
public TypeDefinitionRegistry() {
|
||||
this( null );
|
||||
}
|
||||
TypeDefinitionRegistry register(TypeDefinition typeDefinition);
|
||||
TypeDefinitionRegistry register(TypeDefinition typeDefinition, DuplicationStrategy duplicationStrategy);
|
||||
|
||||
public TypeDefinitionRegistry(TypeDefinitionRegistry parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public TypeDefinition resolve(String typeName) {
|
||||
final TypeDefinition localDefinition = typeDefinitionMap.get( typeName );
|
||||
if ( localDefinition != null ) {
|
||||
return localDefinition;
|
||||
}
|
||||
|
||||
if ( parent != null ) {
|
||||
return parent.resolve( typeName );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeDefinitionRegistry register(TypeDefinition typeDefinition) {
|
||||
return register( typeDefinition, DuplicationStrategy.OVERWRITE );
|
||||
}
|
||||
|
||||
public TypeDefinitionRegistry register(TypeDefinition typeDefinition, DuplicationStrategy duplicationStrategy) {
|
||||
if ( typeDefinition == null ) {
|
||||
throw new IllegalArgumentException( "TypeDefinition to register cannot be null" );
|
||||
}
|
||||
|
||||
if ( typeDefinition.getTypeImplementorClass() == null ) {
|
||||
throw new IllegalArgumentException( "TypeDefinition to register cannot define null #typeImplementorClass" );
|
||||
}
|
||||
|
||||
if ( !StringHelper.isEmpty( typeDefinition.getName() ) ) {
|
||||
register( typeDefinition.getName(), typeDefinition, duplicationStrategy );
|
||||
}
|
||||
|
||||
if ( typeDefinition.getRegistrationKeys() != null ) {
|
||||
for ( String registrationKey : typeDefinition.getRegistrationKeys() ) {
|
||||
register( registrationKey, typeDefinition, duplicationStrategy );
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void register(String name, TypeDefinition typeDefinition, DuplicationStrategy duplicationStrategy) {
|
||||
if ( duplicationStrategy == DuplicationStrategy.KEEP ) {
|
||||
if ( !typeDefinitionMap.containsKey( name ) ) {
|
||||
typeDefinitionMap.put( name, typeDefinition );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final TypeDefinition existing = typeDefinitionMap.put( name, typeDefinition );
|
||||
if ( existing != null && existing != typeDefinition ) {
|
||||
if ( duplicationStrategy == DuplicationStrategy.OVERWRITE ) {
|
||||
log.debugf( "Overwrote existing registration [%s] for type definition.", name );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Attempted to overwrite registration [%s] for type definition.",
|
||||
name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<String, TypeDefinition> copyRegistrationMap();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.boot.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public class TypeDefinitionRegistryStandardImpl implements TypeDefinitionRegistry {
|
||||
private static final Logger log = Logger.getLogger( TypeDefinitionRegistryStandardImpl.class );
|
||||
|
||||
private final TypeDefinitionRegistry parent;
|
||||
private final Map<String, TypeDefinition> typeDefinitionMap = new HashMap<>();
|
||||
|
||||
public TypeDefinitionRegistryStandardImpl() {
|
||||
this( null );
|
||||
}
|
||||
|
||||
public TypeDefinitionRegistryStandardImpl(TypeDefinitionRegistry parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinition resolve(String typeName) {
|
||||
final TypeDefinition localDefinition = typeDefinitionMap.get( typeName );
|
||||
if ( localDefinition != null ) {
|
||||
return localDefinition;
|
||||
}
|
||||
|
||||
if ( parent != null ) {
|
||||
return parent.resolve( typeName );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinition resolveAutoApplied(BasicJavaDescriptor<?> jtd) {
|
||||
// For now, check the definition map for a entry keyed by the JTD name.
|
||||
// Ultimately should maybe have TypeDefinition or the registry keep explicit track of
|
||||
// auto-applied defs
|
||||
if ( jtd.getJavaType() == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return typeDefinitionMap.get( jtd.getJavaType().getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinitionRegistry register(TypeDefinition typeDefinition) {
|
||||
return register( typeDefinition, DuplicationStrategy.OVERWRITE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinitionRegistry register(TypeDefinition typeDefinition, DuplicationStrategy duplicationStrategy) {
|
||||
if ( typeDefinition == null ) {
|
||||
throw new IllegalArgumentException( "TypeDefinition to register cannot be null" );
|
||||
}
|
||||
|
||||
if ( typeDefinition.getTypeImplementorClass() == null ) {
|
||||
throw new IllegalArgumentException( "TypeDefinition to register cannot define null #typeImplementorClass" );
|
||||
}
|
||||
|
||||
if ( !StringHelper.isEmpty( typeDefinition.getName() ) ) {
|
||||
register( typeDefinition.getName(), typeDefinition, duplicationStrategy );
|
||||
}
|
||||
|
||||
if ( typeDefinition.getRegistrationKeys() != null ) {
|
||||
for ( String registrationKey : typeDefinition.getRegistrationKeys() ) {
|
||||
register( registrationKey, typeDefinition, duplicationStrategy );
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void register(String name, TypeDefinition typeDefinition, DuplicationStrategy duplicationStrategy) {
|
||||
if ( duplicationStrategy == DuplicationStrategy.KEEP ) {
|
||||
if ( !typeDefinitionMap.containsKey( name ) ) {
|
||||
typeDefinitionMap.put( name, typeDefinition );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final TypeDefinition existing = typeDefinitionMap.put( name, typeDefinition );
|
||||
if ( existing != null && existing != typeDefinition ) {
|
||||
if ( duplicationStrategy == DuplicationStrategy.OVERWRITE ) {
|
||||
log.debugf( "Overwrote existing registration [%s] for type definition.", name );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Attempted to overwrite registration [%s] for type definition.",
|
||||
name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, TypeDefinition> copyRegistrationMap() {
|
||||
return new HashMap<>( typeDefinitionMap );
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNamedQueryType;
|
|||
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmTypeDefinitionType;
|
||||
import org.hibernate.boot.jaxb.hbm.spi.ResultSetMappingBindingDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistryStandardImpl;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.model.source.internal.OverriddenMappingDefaults;
|
||||
import org.hibernate.boot.model.source.spi.MetadataSourceProcessor;
|
||||
|
@ -52,7 +53,7 @@ public class MappingDocument implements HbmLocalMetadataBuildingContext, Metadat
|
|||
|
||||
private final ToolingHintContext toolingHintContext;
|
||||
|
||||
private final TypeDefinitionRegistry typeDefinitionRegistry;
|
||||
private final TypeDefinitionRegistryStandardImpl typeDefinitionRegistry;
|
||||
|
||||
|
||||
public MappingDocument(
|
||||
|
@ -78,7 +79,7 @@ public class MappingDocument implements HbmLocalMetadataBuildingContext, Metadat
|
|||
|
||||
this.toolingHintContext = Helper.collectToolingHints( null, documentRoot );
|
||||
|
||||
this.typeDefinitionRegistry = new TypeDefinitionRegistry( rootBuildingContext.getTypeDefinitionRegistry() );
|
||||
this.typeDefinitionRegistry = new TypeDefinitionRegistryStandardImpl( rootBuildingContext.getTypeDefinitionRegistry() );
|
||||
}
|
||||
|
||||
public JaxbHbmHibernateMapping getDocumentRoot() {
|
||||
|
|
|
@ -43,7 +43,7 @@ public class TypeDefinitionBinder {
|
|||
definition.getTypeImplementorClass().getName()
|
||||
);
|
||||
|
||||
context.getMetadataCollector().addTypeDefinition( definition );
|
||||
context.getTypeDefinitionRegistry().register( definition );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.boot.internal.ClassmateContext;
|
|||
import org.hibernate.boot.internal.NamedProcedureCallDefinitionImpl;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.convert.internal.InstanceBasedConverterDescriptor;
|
||||
import org.hibernate.boot.model.convert.spi.ConverterAutoApplyHandler;
|
||||
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
|
||||
|
@ -171,9 +172,16 @@ public interface InFlightMetadataCollector extends Mapping, MetadataImplementor
|
|||
* @param typeDefinition The named type definition to add.
|
||||
*
|
||||
* @throws DuplicateMappingException If a TypeDefinition already exists with that name.
|
||||
*
|
||||
* @deprecated Use {@link #getTypeDefinitionRegistry()} instead
|
||||
*
|
||||
* @see #getTypeDefinitionRegistry()
|
||||
*/
|
||||
@Deprecated
|
||||
void addTypeDefinition(TypeDefinition typeDefinition);
|
||||
|
||||
TypeDefinitionRegistry getTypeDefinitionRegistry();
|
||||
|
||||
/**
|
||||
* Adds a filter definition to this repository.
|
||||
*
|
||||
|
|
|
@ -1463,7 +1463,16 @@ public final class AnnotationBinder {
|
|||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( typeBindMessageF, defAnn.name() );
|
||||
}
|
||||
context.getMetadataCollector().addTypeDefinition(
|
||||
// context.getMetadataCollector().addTypeDefinition(
|
||||
// new TypeDefinition(
|
||||
// defAnn.name(),
|
||||
// defAnn.typeClass(),
|
||||
// null,
|
||||
// params,
|
||||
// context.getMetadataCollector().getTypeConfiguration()
|
||||
// )
|
||||
// );
|
||||
context.getTypeDefinitionRegistry().register(
|
||||
new TypeDefinition(
|
||||
defAnn.name(),
|
||||
defAnn.typeClass(),
|
||||
|
@ -1478,7 +1487,8 @@ public final class AnnotationBinder {
|
|||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( typeBindMessageF, defAnn.defaultForType().getName() );
|
||||
}
|
||||
context.getMetadataCollector().addTypeDefinition(
|
||||
|
||||
context.getTypeDefinitionRegistry().register(
|
||||
new TypeDefinition(
|
||||
defAnn.defaultForType().getName(),
|
||||
defAnn.typeClass(),
|
||||
|
|
|
@ -361,6 +361,13 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
|||
|
||||
// Use JTD if we know it to apply any specialized resolutions
|
||||
|
||||
final TypeDefinition autoAppliedTypeDef = getBuildingContext().getTypeDefinitionRegistry()
|
||||
.resolveAutoApplied( (BasicJavaDescriptor<?>) jtd );
|
||||
if ( autoAppliedTypeDef != null ) {
|
||||
log.debugf( "BasicValue resolution matched auto-applied type-definition" );
|
||||
return autoAppliedTypeDef.resolve( getTypeParameters(), null, getBuildingContext() );
|
||||
}
|
||||
|
||||
if ( jtd instanceof EnumJavaTypeDescriptor ) {
|
||||
return InferredBasicValueResolver.fromEnum(
|
||||
(EnumJavaTypeDescriptor) jtd,
|
||||
|
@ -499,8 +506,6 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
|||
final TypeDefinition typeDefinition = context.getTypeDefinitionRegistry().resolve( name );
|
||||
if ( typeDefinition != null ) {
|
||||
return typeDefinition.resolve(
|
||||
explicitJtdAccess.apply( typeConfiguration ),
|
||||
explicitStdAccess.apply( typeConfiguration ),
|
||||
localTypeParams,
|
||||
explicitMutabilityPlanAccess != null
|
||||
? explicitMutabilityPlanAccess.apply( typeConfiguration )
|
||||
|
@ -527,8 +532,6 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
|||
);
|
||||
context.getTypeDefinitionRegistry().register( implicitDefinition );
|
||||
return implicitDefinition.resolve(
|
||||
explicitJtdAccess != null ? explicitJtdAccess.apply( typeConfiguration ) : null,
|
||||
explicitStdAccess != null ? explicitStdAccess.apply( typeConfiguration ) : null,
|
||||
null,
|
||||
explicitMutabilityPlanAccess != null
|
||||
? explicitMutabilityPlanAccess.apply( typeConfiguration )
|
||||
|
@ -540,8 +543,6 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
|||
return TypeDefinition.createLocalResolution(
|
||||
name,
|
||||
typeNamedClass,
|
||||
explicitJtdAccess.apply( typeConfiguration ),
|
||||
explicitStdAccess.apply( typeConfiguration ),
|
||||
explicitMutabilityPlanAccess != null
|
||||
? explicitMutabilityPlanAccess.apply( typeConfiguration )
|
||||
: null,
|
||||
|
@ -549,8 +550,9 @@ public class BasicValue extends SimpleValue implements SqlTypeDescriptorIndicato
|
|||
context
|
||||
);
|
||||
}
|
||||
catch (ClassLoadingException ignore) {
|
||||
catch (ClassLoadingException e) {
|
||||
// allow the exception below to trigger
|
||||
log.debugf( "Could not resolve type-name [%s] as Java type : %s", name, e );
|
||||
}
|
||||
|
||||
throw new MappingException( "Could not resolve named type : " + name );
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.bootstrap.binding.annotations.basics;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.TypeDef;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
||||
import org.hibernate.type.CustomType;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.UrlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* Resolution for custom-types
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@ServiceRegistry(
|
||||
settings = @ServiceRegistry.Setting( name = AvailableSettings.HBM2DDL_AUTO, value = "create-drop" )
|
||||
)
|
||||
@DomainModel( annotatedClasses = CustomTypeResolutionTests.Person.class )
|
||||
public class CustomTypeResolutionTests {
|
||||
|
||||
@Test
|
||||
public void testMappings(DomainModelScope scope) {
|
||||
final PersistentClass entityBinding = scope.getDomainModel().getEntityBinding( Person.class.getName() );
|
||||
|
||||
final Property genderProperty = entityBinding.getProperty( "gender" );
|
||||
final BasicValue genderValue = (BasicValue) genderProperty.getValue();
|
||||
final BasicValue.Resolution<?> genderValueResolution = genderValue.resolve();
|
||||
assertThat( genderValueResolution.getLegacyResolvedBasicType(), instanceOf( GenderType.class ) );
|
||||
|
||||
final Property string1Property = entityBinding.getProperty( "string1" );
|
||||
final BasicValue string1Value = (BasicValue) string1Property.getValue();
|
||||
final BasicValue.Resolution<?> string1ValueResolution = string1Value.resolve();
|
||||
assertThat( string1ValueResolution.getLegacyResolvedBasicType(), instanceOf( CustomType.class ) );
|
||||
assertThat( string1ValueResolution.getJdbcMapping(), instanceOf( CustomType.class ) );
|
||||
assertThat( string1ValueResolution.getLegacyResolvedBasicType(), is( string1ValueResolution.getJdbcMapping() ) );
|
||||
final CustomType string1TypeWrapper = (CustomType) string1ValueResolution.getJdbcMapping();
|
||||
assertThat( string1TypeWrapper.getUserType(), instanceOf( UserTypeImpl.class ) );
|
||||
|
||||
final Property string2Property = entityBinding.getProperty( "string2" );
|
||||
final BasicValue string2Value = (BasicValue) string2Property.getValue();
|
||||
final BasicValue.Resolution<?> string2ValueResolution = string2Value.resolve();
|
||||
assertThat( string2ValueResolution.getLegacyResolvedBasicType(), instanceOf( CustomType.class ) );
|
||||
assertThat( string2ValueResolution.getJdbcMapping(), instanceOf( CustomType.class ) );
|
||||
assertThat( string2ValueResolution.getLegacyResolvedBasicType(), is( string2ValueResolution.getJdbcMapping() ) );
|
||||
final CustomType string2TypeWrapper = (CustomType) string2ValueResolution.getJdbcMapping();
|
||||
assertThat( string2TypeWrapper.getUserType(), instanceOf( UserTypeImpl.class ) );
|
||||
|
||||
final Property url1Property = entityBinding.getProperty( "url1" );
|
||||
final BasicValue url1Value = (BasicValue) url1Property.getValue();
|
||||
final BasicValue.Resolution<?> url1ValueResolution = url1Value.resolve();
|
||||
assertThat( url1ValueResolution.getLegacyResolvedBasicType(), instanceOf( CustomTypeImpl.class ) );
|
||||
|
||||
final Property url2Property = entityBinding.getProperty( "url2" );
|
||||
final BasicValue url2Value = (BasicValue) url2Property.getValue();
|
||||
final BasicValue.Resolution<?> url2ValueResolution = url2Value.resolve();
|
||||
assertThat( url2ValueResolution.getLegacyResolvedBasicType(), instanceOf( CustomTypeImpl.class ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleUsageSmokeTest(DomainModelScope scope) {
|
||||
try ( SessionFactory sessionFactory = scope.getDomainModel().buildSessionFactory()) {
|
||||
// set up test data
|
||||
sessionFactory.inTransaction(
|
||||
session -> {
|
||||
try {
|
||||
session.persist(
|
||||
new Person(
|
||||
1,
|
||||
Gender.MALE,
|
||||
"str1",
|
||||
"str2",
|
||||
new URL( "http://url1" ),
|
||||
new URL( "http://url2" )
|
||||
)
|
||||
);
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// try to read it back
|
||||
try {
|
||||
sessionFactory.inTransaction(
|
||||
session -> {
|
||||
final Person loaded = session.byId( Person.class ).load( 1 );
|
||||
assertThat( loaded, notNullValue() );
|
||||
assertThat( loaded.gender, is( Gender.MALE ) );
|
||||
assertThat( loaded.string1, is( "str1" ) );
|
||||
assertThat( loaded.string2, is( "str2" ) );
|
||||
assertThat( loaded.url1.getHost(), is( "url1" ) );
|
||||
assertThat( loaded.url2.getHost(), is( "url2" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
sessionFactory.inTransaction(
|
||||
session -> session.createQuery( "delete Person" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum Gender { MALE, FEMALE }
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Entity( name = "Person" )
|
||||
@Table( name = "persons" )
|
||||
@TypeDef( name = "user-type", typeClass = UserTypeImpl.class )
|
||||
@TypeDef( name = "custom-type", typeClass = CustomTypeImpl.class )
|
||||
@TypeDef( name = "gender-type", typeClass = GenderType.class, defaultForType = Gender.class )
|
||||
public static class Person {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private Gender gender;
|
||||
|
||||
@Type( type = "org.hibernate.orm.test.bootstrap.binding.annotations.basics.CustomTypeResolutionTests$UserTypeImpl" )
|
||||
private String string1;
|
||||
|
||||
@Type( type = "user-type" )
|
||||
private String string2;
|
||||
|
||||
@Type( type = "org.hibernate.orm.test.bootstrap.binding.annotations.basics.CustomTypeResolutionTests$CustomTypeImpl" )
|
||||
private URL url1;
|
||||
|
||||
@Type( type = "custom-type" )
|
||||
private URL url2;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Integer id, Gender gender, String string1, String string2, URL url1, URL url2) {
|
||||
this.id = id;
|
||||
this.gender = gender;
|
||||
this.string1 = string1;
|
||||
this.string2 = string2;
|
||||
this.url1 = url1;
|
||||
this.url2 = url2;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserTypeImpl implements UserType {
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] { Types.VARCHAR };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> returnedClass() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object x, Object y) throws HibernateException {
|
||||
return Objects.equals( x, y );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object x) throws HibernateException {
|
||||
return Objects.hashCode( x );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nullSafeGet(
|
||||
ResultSet rs,
|
||||
String[] names,
|
||||
SharedSessionContractImplementor session,
|
||||
Object owner) throws HibernateException, SQLException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(
|
||||
PreparedStatement st,
|
||||
Object value,
|
||||
int index,
|
||||
SharedSessionContractImplementor session) throws HibernateException, SQLException {
|
||||
if ( value == null ) {
|
||||
st.setNull( index, Types.VARCHAR );
|
||||
}
|
||||
else {
|
||||
st.setString( index, value.toString() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deepCopy(Object value) throws HibernateException {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(Object value) throws HibernateException {
|
||||
return (String) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||
return cached;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomTypeImpl extends AbstractSingleColumnStandardBasicType<URL> {
|
||||
|
||||
public CustomTypeImpl() {
|
||||
super( VarcharTypeDescriptor.INSTANCE, UrlTypeDescriptor.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Custom URL mapper";
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenderJtd implements JavaTypeDescriptor<Gender> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final GenderJtd INSTANCE = new GenderJtd();
|
||||
|
||||
@Override
|
||||
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
|
||||
return CharTypeDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Gender fromString(String string) {
|
||||
if ( StringHelper.isEmpty( string ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( "M".equalsIgnoreCase( string ) ) {
|
||||
return Gender.MALE;
|
||||
}
|
||||
else if ( "F".equalsIgnoreCase( string ) ) {
|
||||
return Gender.FEMALE;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException( "Unrecognized Gender code : " + string );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X> X unwrap(Gender value, Class<X> type, WrapperOptions options) {
|
||||
// only defines support for String conversion as part of unwrap
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( type.isInstance( value ) ) {
|
||||
return (X) value;
|
||||
}
|
||||
|
||||
if ( String.class.equals( type ) ) {
|
||||
return (X) (value == Gender.MALE ? "M" : "F");
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> Gender wrap(X value, WrapperOptions options) {
|
||||
if ( value == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( value instanceof String ) {
|
||||
if ( "F".equalsIgnoreCase( (String) value ) ) {
|
||||
return Gender.FEMALE;
|
||||
}
|
||||
|
||||
if ( "M".equalsIgnoreCase( (String) value ) ) {
|
||||
return Gender.MALE;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Gender> getJavaTypeClass() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenderType extends AbstractSingleColumnStandardBasicType<Gender> {
|
||||
|
||||
public GenderType() {
|
||||
super( VarcharTypeDescriptor.INSTANCE, GenderJtd.INSTANCE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Custom URL mapper";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,11 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.grammar.importsql;
|
||||
package org.hibernate.orm.test.bootstrap.schema;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Reader;
|
|
@ -9,7 +9,7 @@ package org.hibernate.testing.boot;
|
|||
import org.hibernate.boot.internal.BootstrapContextImpl;
|
||||
import org.hibernate.boot.internal.InFlightMetadataCollectorImpl;
|
||||
import org.hibernate.boot.internal.MetadataBuilderImpl;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistryStandardImpl;
|
||||
import org.hibernate.boot.model.naming.ObjectNameNormalizer;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
|
@ -29,7 +29,7 @@ public class MetadataBuildingContextTestingImpl implements MetadataBuildingConte
|
|||
private final InFlightMetadataCollector metadataCollector;
|
||||
private final BootstrapContext bootstrapContext;
|
||||
private final ObjectNameNormalizer objectNameNormalizer;
|
||||
private final TypeDefinitionRegistry typeDefinitionRegistry;
|
||||
private final TypeDefinitionRegistryStandardImpl typeDefinitionRegistry;
|
||||
|
||||
public MetadataBuildingContextTestingImpl() {
|
||||
this( new StandardServiceRegistryBuilder().build() );
|
||||
|
@ -48,7 +48,7 @@ public class MetadataBuildingContextTestingImpl implements MetadataBuildingConte
|
|||
}
|
||||
};
|
||||
|
||||
this.typeDefinitionRegistry = new TypeDefinitionRegistry();
|
||||
this.typeDefinitionRegistry = new TypeDefinitionRegistryStandardImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,7 +82,7 @@ public class MetadataBuildingContextTestingImpl implements MetadataBuildingConte
|
|||
}
|
||||
|
||||
@Override
|
||||
public TypeDefinitionRegistry getTypeDefinitionRegistry() {
|
||||
public TypeDefinitionRegistryStandardImpl getTypeDefinitionRegistry() {
|
||||
return typeDefinitionRegistry;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue