6 - SQM based on JPA type system
This commit is contained in:
parent
fa754a77e2
commit
84a481a3c2
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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() };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue