6 - SQM based on JPA type system

This commit is contained in:
Steve Ebersole 2019-05-23 11:01:56 -05:00 committed by Andrea Boriero
parent fa754a77e2
commit 84a481a3c2
13 changed files with 433 additions and 292 deletions

View File

@ -10,23 +10,48 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.InvalidGraphException;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphImplementor;
import org.hibernate.graph.spi.SubGraphImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.internal.util.io.CharSequenceReader;
import org.jboss.logging.Logger;
import antlr.RecognitionException;
import antlr.Token;
import antlr.TokenStreamException;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
/**
* @author Steve Ebersole
*/
public class GraphParser extends GeneratedGraphParser {
public class GraphParser extends GraphLanguageParserBaseVisitor {
public static final Logger PARSING_LOGGER = Logger.getLogger( "org.hibernate.orm.graph.parsing" );
/**
* Parse the passed graph textual representation into the passed Graph.
*/
public static void parseInto(
GraphImplementor<?> targetGraph,
String graphString,
SessionFactoryImplementor sessionFactory) {
// Build the lexer
final GraphLanguageLexer lexer = new GraphLanguageLexer( CharStreams.fromString( graphString ) );
// Build the parser...
final GraphLanguageParser parser = new GraphLanguageParser( new CommonTokenStream( lexer ) );
// Build an instance of this class as a visitor
final GraphParser visitor = new GraphParser( sessionFactory );
visitor.graphStack.push( targetGraph );
try {
visitor.visitGraph( parser.graph() );
}
finally {
visitor.graphStack.pop();
assert visitor.graphStack.isEmpty();
}
}
/**
* Parse the passed graph textual representation into the passed Graph.
*/
@ -34,14 +59,7 @@ public class GraphParser extends GeneratedGraphParser {
GraphImplementor<?> targetGraph,
CharSequence graphString,
SessionFactoryImplementor sessionFactory) {
final GraphParser instance = new GraphParser( graphString, sessionFactory );
instance.graphStack.push( targetGraph );
try {
instance.graph();
}
catch (RecognitionException | TokenStreamException e) {
throw new InvalidGraphException( "Error parsing graph string" );
}
parseInto( targetGraph, graphString.toString(), sessionFactory );
}
private final SessionFactoryImplementor sessionFactory;
@ -50,30 +68,71 @@ public class GraphParser extends GeneratedGraphParser {
private final Stack<AttributeNodeImplementor<?>> attributeNodeStack = new StandardStack<>();
private final Stack<SubGraphGenerator> graphSourceStack = new StandardStack<>();
private GraphParser(CharSequence charSequence, SessionFactoryImplementor sessionFactory) {
super( new GraphLexer( new CharSequenceReader( charSequence ) ) );
public GraphParser(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
protected void startAttribute(Token attributeNameToken) {
final String attributeName = attributeNameToken.getText();
public AttributeNodeImplementor visitAttributeNode(GraphLanguageParser.AttributeNodeContext ctx) {
final String attributeName = ctx.attributePath().NAME().getText();
final SubGraphGenerator subGraphCreator;
if ( ctx.attributePath().attributeQualifier() == null ) {
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Start attribute : %s",
StringHelper.repeat( ">>", attributeNodeStack.depth() + 1 ),
attributeName
);
}
subGraphCreator = PathQualifierType.VALUE.getSubGraphCreator();
}
else {
final String qualifierName = ctx.attributePath().attributeQualifier().NAME().getText();
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Start qualified attribute : %s.%s",
StringHelper.repeat( ">>", attributeNodeStack.depth() + 1 ),
attributeName,
qualifierName
);
}
final PathQualifierType pathQualifierType = resolvePathQualifier( qualifierName );
subGraphCreator = pathQualifierType.getSubGraphCreator();
}
final AttributeNodeImplementor attributeNode = resolveAttributeNode( attributeName );
if ( ctx.subGraph() != null ) {
attributeNodeStack.push( attributeNode );
graphSourceStack.push( subGraphCreator );
try {
visitSubGraph( ctx.subGraph() );
}
finally {
graphSourceStack.pop();
attributeNodeStack.pop();
}
}
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Start attribute : %s",
StringHelper.repeat( ">>", attributeNodeStack.depth() + 1 ),
"%s Finished attribute : %s",
StringHelper.repeat( "<<", attributeNodeStack.depth() + 1 ),
attributeName
);
}
final AttributeNodeImplementor attributeNode = resolveAttributeNode( attributeName );
attributeNodeStack.push( attributeNode );
graphSourceStack.push( PathQualifierType.VALUE.getSubGraphCreator() );
return attributeNode;
}
private AttributeNodeImplementor resolveAttributeNode(String attributeName) {
final GraphImplementor<?> currentGraph = graphStack.getCurrent();
assert currentGraph != null;
@ -84,28 +143,6 @@ public class GraphParser extends GeneratedGraphParser {
return attributeNode;
}
@Override
protected void startQualifiedAttribute(Token attributeNameToken, Token qualifierToken) {
final String attributeName = attributeNameToken.getText();
final String qualifierName = qualifierToken.getText();
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Start qualified attribute : %s.%s",
StringHelper.repeat( ">>", attributeNodeStack.depth() + 1 ),
attributeName,
qualifierName
);
}
final AttributeNodeImplementor<?> attributeNode = resolveAttributeNode( attributeName );
attributeNodeStack.push( attributeNode );
final PathQualifierType pathQualifierType = resolvePathQualifier( qualifierName );
graphSourceStack.push( pathQualifierType.getSubGraphCreator() );
}
private PathQualifierType resolvePathQualifier(String qualifier) {
if ( "key".equalsIgnoreCase( qualifier ) ) {
return PathQualifierType.KEY;
@ -119,23 +156,8 @@ public class GraphParser extends GeneratedGraphParser {
}
@Override
protected void finishAttribute() {
graphSourceStack.pop();
final AttributeNodeImplementor<?> popped = attributeNodeStack.pop();
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Finished attribute : %s",
StringHelper.repeat( "<<", attributeNodeStack.depth() + 1 ),
popped.getAttributeDescriptor().getName()
);
}
}
@Override
protected void startSubGraph(Token subTypeToken) {
final String subTypeName = subTypeToken == null ? null : subTypeToken.getText();
public SubGraphImplementor visitSubGraph(GraphLanguageParser.SubGraphContext ctx) {
final String subTypeName = ctx.subType() == null ? null : ctx.subType().getText();
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
@ -146,22 +168,31 @@ public class GraphParser extends GeneratedGraphParser {
}
final AttributeNodeImplementor<?> attributeNode = attributeNodeStack.getCurrent();
graphStack.push(
graphSourceStack.getCurrent()
.createSubGraph( attributeNode, subTypeName, sessionFactory )
);
}
final SubGraphGenerator subGraphCreator = graphSourceStack.getCurrent();
@Override
protected void finishSubGraph() {
final GraphImplementor<?> popped = graphStack.pop();
final SubGraphImplementor<?> subGraph = subGraphCreator.createSubGraph(
attributeNode,
subTypeName,
sessionFactory
);
graphStack.push( subGraph );
try {
ctx.attributeList().accept( this );
}
finally {
graphStack.pop();
}
if ( PARSING_LOGGER.isDebugEnabled() ) {
PARSING_LOGGER.debugf(
"%s Finished graph : %s",
StringHelper.repeat( "<<", attributeNodeStack.depth() + 2 ),
popped.getGraphedType().getName()
subGraph.getGraphedType().getTypeName()
);
}
return subGraph;
}
}

View File

@ -11,6 +11,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.type.StandardBasicTypes;
/**
* Base support for {@link JpaTupleElement} impls
@ -38,7 +39,7 @@ public abstract class AbstractJpaTupleElement<T>
setJavaType( javaType );
}
else {
setExpressableType( StandardSpiBasicTypes.OBJECT_TYPE );
setExpressableType( StandardBasicTypes.OBJECT_TYPE );
}
}

View File

@ -52,6 +52,16 @@ public abstract class AbstractStandardBasicType<T>
this.javaTypeDescriptor = javaTypeDescriptor;
}
@Override
public JavaTypeDescriptor getExpressableJavaTypeDescriptor() {
return getJavaTypeDescriptor();
}
@Override
public Class getJavaType() {
return getExpressableJavaTypeDescriptor().getJavaType();
}
public T fromString(String string) {
return javaTypeDescriptor.fromString( string );
}
@ -172,18 +182,12 @@ public abstract class AbstractStandardBasicType<T>
return false;
}
public final boolean isXMLElement() {
return false;
}
@Override
@SuppressWarnings({ "unchecked" })
public final boolean isSame(Object x, Object y) {
return isEqual( x, y );
}
@Override
@SuppressWarnings({ "unchecked" })
public final boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) {
return isEqual( x, y );
}
@ -262,7 +266,6 @@ public abstract class AbstractStandardBasicType<T>
}
@Override
@SuppressWarnings({ "unchecked" })
public final void nullSafeSet(
PreparedStatement st,
Object value,

View File

@ -6,12 +6,14 @@
*/
package org.hibernate.type;
import org.hibernate.metamodel.model.domain.BasicDomainType;
/**
* Marker interface for basic types.
*
* @author Steve Ebersole
*/
public interface BasicType extends Type {
public interface BasicType extends Type, BasicDomainType {
/**
* Get the names under which this type should be registered in the type registry.
*

View File

@ -0,0 +1,29 @@
/*
* 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.type;
import org.hibernate.type.descriptor.java.JavaObjectTypeDescriptor;
import org.hibernate.type.descriptor.sql.ObjectSqlTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class JavaObjectType extends AbstractSingleColumnStandardBasicType<Object> {
/**
* Singleton access
*/
public static final JavaObjectType INSTANCE = new JavaObjectType();
public JavaObjectType() {
super( ObjectSqlTypeDescriptor.INSTANCE, JavaObjectTypeDescriptor.INSTANCE );
}
@Override
public String getName() {
return "JAVA_OBJECT";
}
}

View File

@ -7,6 +7,9 @@
package org.hibernate.type;
import org.hibernate.type.descriptor.java.JavaObjectTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Specific adaptation of the "any" type to the old deprecated "object" type
*
@ -28,6 +31,16 @@ public class ObjectType extends AnyType implements BasicType {
return "object";
}
@Override
public JavaTypeDescriptor getExpressableJavaTypeDescriptor() {
return JavaObjectTypeDescriptor.INSTANCE;
}
@Override
public Class getJavaType() {
return Object.class;
}
@Override
public String[] getRegistrationKeys() {
return new String[] { getName(), Object.class.getName() };

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.type;
import org.hibernate.type.descriptor.sql.ObjectSqlTypeDescriptor;
/**
* Centralizes access to the standard set of basic {@link Type types}.
* <p/>
@ -19,7 +21,6 @@ package org.hibernate.type;
* @author Gavin King
* @author Steve Ebersole
*/
@SuppressWarnings( {"UnusedDeclaration"})
public final class StandardBasicTypes {
private StandardBasicTypes() {
}
@ -336,4 +337,6 @@ public final class StandardBasicTypes {
* @see SerializableType
*/
public static final SerializableType SERIALIZABLE = SerializableType.INSTANCE;
public static final JavaObjectType OBJECT_TYPE = JavaObjectType.INSTANCE;
}

View File

@ -0,0 +1,33 @@
/*
* 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.type.descriptor.java;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* @author Steve Ebersole
*/
public class JavaObjectTypeDescriptor extends AbstractTypeDescriptor<Object> {
/**
* Singleton access
*/
public static final JavaObjectTypeDescriptor INSTANCE = new JavaObjectTypeDescriptor();
public JavaObjectTypeDescriptor() {
super( Object.class );
}
@Override
public <X> X unwrap(Object value, Class<X> type, SharedSessionContractImplementor options) {
return (X) value;
}
@Override
public <X> Object wrap(X value, SharedSessionContractImplementor options) {
return value;
}
}

View File

@ -12,6 +12,7 @@ import java.util.Objects;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.compare.ComparableComparator;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
@ -116,7 +117,7 @@ public interface JavaTypeDescriptor<T> extends Serializable {
*
* @return The unwrapped value.
*/
<X> X unwrap(T value, Class<X> type, SharedSessionContractImplementor options);
<X> X unwrap(T value, Class<X> type, WrapperOptions options);
/**
* Wrap a value as our handled Java type.
@ -129,7 +130,7 @@ public interface JavaTypeDescriptor<T> extends Serializable {
*
* @return The wrapped value.
*/
<X> T wrap(X value, SharedSessionContractImplementor options);
<X> T wrap(X value, WrapperOptions options);
/**
* Retrieve the Java type handled here.

View File

@ -0,0 +1,92 @@
/*
* 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.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.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
* @author Steve Ebersole
*/
public class ObjectSqlTypeDescriptor implements SqlTypeDescriptor {
/**
* Singleton access
*/
public static final ObjectSqlTypeDescriptor INSTANCE = new ObjectSqlTypeDescriptor( Types.JAVA_OBJECT );
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.getJavaType() ) ) {
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
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, jdbcTypeCode );
}
};
}
@Override
@SuppressWarnings("unchecked")
public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaType() ) ) {
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 );
}
@Override
protected Object doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return statement.getObject( name );
}
};
}
}

View File

@ -1,198 +0,0 @@
/*
* 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.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.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;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
/**
* Basically a map from JDBC type code (int) -> {@link SqlTypeDescriptor}
*
* @author Steve Ebersole
*
* @deprecated (5.3) Use {@link org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry} instead.
*/
@Deprecated
public class SqlTypeDescriptorRegistry implements Serializable {
/**
* @deprecated (5.3) Use {@link TypeConfiguration#getSqlTypeDescriptorRegistry()} instead.
*/
@Deprecated
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>();
protected SqlTypeDescriptorRegistry() {
addDescriptorInternal( BooleanTypeDescriptor.INSTANCE );
addDescriptorInternal( BitTypeDescriptor.INSTANCE );
addDescriptorInternal( BigIntTypeDescriptor.INSTANCE );
addDescriptorInternal( DecimalTypeDescriptor.INSTANCE );
addDescriptorInternal( DoubleTypeDescriptor.INSTANCE );
addDescriptorInternal( FloatTypeDescriptor.INSTANCE );
addDescriptorInternal( IntegerTypeDescriptor.INSTANCE );
addDescriptorInternal( NumericTypeDescriptor.INSTANCE );
addDescriptorInternal( RealTypeDescriptor.INSTANCE );
addDescriptorInternal( SmallIntTypeDescriptor.INSTANCE );
addDescriptorInternal( TinyIntTypeDescriptor.INSTANCE );
addDescriptorInternal( DateTypeDescriptor.INSTANCE );
addDescriptorInternal( TimestampTypeDescriptor.INSTANCE );
addDescriptorInternal( TimeTypeDescriptor.INSTANCE );
addDescriptorInternal( BinaryTypeDescriptor.INSTANCE );
addDescriptorInternal( VarbinaryTypeDescriptor.INSTANCE );
addDescriptorInternal( LongVarbinaryTypeDescriptor.INSTANCE );
addDescriptorInternal( BlobTypeDescriptor.DEFAULT );
addDescriptorInternal( CharTypeDescriptor.INSTANCE );
addDescriptorInternal( VarcharTypeDescriptor.INSTANCE );
addDescriptorInternal( LongVarcharTypeDescriptor.INSTANCE );
addDescriptorInternal( ClobTypeDescriptor.DEFAULT );
addDescriptorInternal( NCharTypeDescriptor.INSTANCE );
addDescriptorInternal( NVarcharTypeDescriptor.INSTANCE );
addDescriptorInternal( LongNVarcharTypeDescriptor.INSTANCE );
addDescriptorInternal( NClobTypeDescriptor.DEFAULT );
}
/**
* @deprecated (5.3) Use {@link org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry#addDescriptor(SqlTypeDescriptor)} instead.
*/
@Deprecated
public void addDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
descriptorMap.put( sqlTypeDescriptor.getSqlType(), sqlTypeDescriptor );
}
private void addDescriptorInternal(SqlTypeDescriptor sqlTypeDescriptor){
descriptorMap.put( sqlTypeDescriptor.getSqlType(), sqlTypeDescriptor );
}
/**
* @deprecated (5.3) Use {@link org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry#getDescriptor(int)} instead.
*/
@Deprecated
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.getJavaType() ) ) {
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
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
st.setObject( name, value, jdbcTypeCode );
}
};
}
@Override
@SuppressWarnings("unchecked")
public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaType() ) ) {
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 );
}
@Override
protected Object doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return statement.getObject( name );
}
};
}
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.type.descriptor.sql.internal;
import org.hibernate.type.descriptor.sql.BigIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.BinaryTypeDescriptor;
import org.hibernate.type.descriptor.sql.BitTypeDescriptor;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.BooleanTypeDescriptor;
import org.hibernate.type.descriptor.sql.CharTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.DateTypeDescriptor;
import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor;
import org.hibernate.type.descriptor.sql.DoubleTypeDescriptor;
import org.hibernate.type.descriptor.sql.FloatTypeDescriptor;
import org.hibernate.type.descriptor.sql.IntegerTypeDescriptor;
import org.hibernate.type.descriptor.sql.LongNVarcharTypeDescriptor;
import org.hibernate.type.descriptor.sql.LongVarbinaryTypeDescriptor;
import org.hibernate.type.descriptor.sql.LongVarcharTypeDescriptor;
import org.hibernate.type.descriptor.sql.NCharTypeDescriptor;
import org.hibernate.type.descriptor.sql.NClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.NVarcharTypeDescriptor;
import org.hibernate.type.descriptor.sql.NumericTypeDescriptor;
import org.hibernate.type.descriptor.sql.RealTypeDescriptor;
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimeTypeDescriptor;
import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor;
import org.hibernate.type.descriptor.sql.TinyIntTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
/**
* Registers the base {@link SqlTypeDescriptor} instances.
*
* @author Chris Cranford
*/
public class SqlTypeDescriptorBaseline {
public interface BaselineTarget {
void addDescriptor(SqlTypeDescriptor descriptor);
}
public static void prime(BaselineTarget target) {
target.addDescriptor( BooleanTypeDescriptor .INSTANCE );
target.addDescriptor( BitTypeDescriptor.INSTANCE );
target.addDescriptor( BigIntTypeDescriptor.INSTANCE );
target.addDescriptor( DecimalTypeDescriptor.INSTANCE );
target.addDescriptor( DoubleTypeDescriptor.INSTANCE );
target.addDescriptor( FloatTypeDescriptor.INSTANCE );
target.addDescriptor( IntegerTypeDescriptor.INSTANCE );
target.addDescriptor( NumericTypeDescriptor.INSTANCE );
target.addDescriptor( RealTypeDescriptor.INSTANCE );
target.addDescriptor( SmallIntTypeDescriptor.INSTANCE );
target.addDescriptor( TinyIntTypeDescriptor.INSTANCE );
target.addDescriptor( DateTypeDescriptor.INSTANCE );
target.addDescriptor( TimestampTypeDescriptor.INSTANCE );
target.addDescriptor( TimeTypeDescriptor.INSTANCE );
target.addDescriptor( BinaryTypeDescriptor.INSTANCE );
target.addDescriptor( VarbinaryTypeDescriptor.INSTANCE );
target.addDescriptor( LongVarbinaryTypeDescriptor.INSTANCE );
target.addDescriptor( CharTypeDescriptor.INSTANCE );
target.addDescriptor( VarcharTypeDescriptor.INSTANCE );
target.addDescriptor( LongVarcharTypeDescriptor.INSTANCE );
target.addDescriptor( NCharTypeDescriptor.INSTANCE );
target.addDescriptor( NVarcharTypeDescriptor.INSTANCE );
target.addDescriptor( LongNVarcharTypeDescriptor.INSTANCE );
// Use the default LOB mappings by default
target.addDescriptor( BlobTypeDescriptor.DEFAULT );
target.addDescriptor( ClobTypeDescriptor.DEFAULT );
target.addDescriptor( NClobTypeDescriptor.DEFAULT );
}
}

View File

@ -7,10 +7,17 @@
package org.hibernate.type.descriptor.sql.spi;
import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.sql.JdbcTypeFamilyInformation;
import org.hibernate.type.descriptor.sql.ObjectSqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.internal.SqlTypeDescriptorBaseline;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
/**
* Basically a map from JDBC type code (int) -> {@link SqlTypeDescriptor}
*
@ -19,25 +26,67 @@ import org.hibernate.type.spi.TypeConfiguration;
*
* @since 5.3
*/
public class SqlTypeDescriptorRegistry
extends org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry
implements Serializable {
public class SqlTypeDescriptorRegistry implements SqlTypeDescriptorBaseline.BaselineTarget, Serializable {
private static final Logger log = Logger.getLogger( SqlTypeDescriptorRegistry.class );
private final TypeConfiguration typeConfiguration;
private final org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry sqlTypeDescriptorRegistry;
private ConcurrentHashMap<Integer, SqlTypeDescriptor> descriptorMap = new ConcurrentHashMap<>();
public SqlTypeDescriptorRegistry(TypeConfiguration typeConfiguration) {
this.typeConfiguration = typeConfiguration;
sqlTypeDescriptorRegistry = org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry.INSTANCE;
// this.typeConfiguration = typeConfiguration;
SqlTypeDescriptorBaseline.prime( this );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// baseline descriptors
@Override
public void addDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
sqlTypeDescriptorRegistry.addDescriptor( sqlTypeDescriptor );
descriptorMap.put( sqlTypeDescriptor.getSqlType(), sqlTypeDescriptor );
}
@Override
public SqlTypeDescriptor getDescriptor(int jdbcTypeCode) {
return sqlTypeDescriptorRegistry.getDescriptor( jdbcTypeCode );
SqlTypeDescriptor descriptor = descriptorMap.get( 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( potentialAlternateTypeCode );
if ( potentialAlternateDescriptor != null ) {
// todo (6.0) : 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 boolean hasRegisteredDescriptor(int jdbcTypeCode) {
return descriptorMap.containsKey( jdbcTypeCode )
|| JdbcTypeNameMapper.isStandardTypeCode( jdbcTypeCode )
|| JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode ) != null;
}
}