/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2012, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.type.descriptor.sql;

import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;

import org.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.jboss.logging.Logger;

Basically a map from JDBC type code (int) -> SqlTypeDescriptor
Author:Steve Ebersole
/** * Basically a map from JDBC type code (int) -> {@link SqlTypeDescriptor} * * @author Steve Ebersole */
public class SqlTypeDescriptorRegistry { public static final SqlTypeDescriptorRegistry INSTANCE = new SqlTypeDescriptorRegistry(); private static final Logger log = Logger.getLogger( SqlTypeDescriptorRegistry.class ); private ConcurrentHashMap<Integer,SqlTypeDescriptor> descriptorMap = new ConcurrentHashMap<Integer, SqlTypeDescriptor>(); private SqlTypeDescriptorRegistry() { addDescriptor( BooleanTypeDescriptor.INSTANCE ); addDescriptor( BitTypeDescriptor.INSTANCE ); addDescriptor( BigIntTypeDescriptor.INSTANCE ); addDescriptor( DecimalTypeDescriptor.INSTANCE ); addDescriptor( DoubleTypeDescriptor.INSTANCE ); addDescriptor( FloatTypeDescriptor.INSTANCE ); addDescriptor( IntegerTypeDescriptor.INSTANCE ); addDescriptor( NumericTypeDescriptor.INSTANCE ); addDescriptor( RealTypeDescriptor.INSTANCE ); addDescriptor( SmallIntTypeDescriptor.INSTANCE ); addDescriptor( TinyIntTypeDescriptor.INSTANCE ); addDescriptor( DateTypeDescriptor.INSTANCE ); addDescriptor( TimestampTypeDescriptor.INSTANCE ); addDescriptor( TimeTypeDescriptor.INSTANCE ); addDescriptor( BinaryTypeDescriptor.INSTANCE ); addDescriptor( VarbinaryTypeDescriptor.INSTANCE ); addDescriptor( LongVarbinaryTypeDescriptor.INSTANCE ); addDescriptor( BlobTypeDescriptor.DEFAULT ); addDescriptor( CharTypeDescriptor.INSTANCE ); addDescriptor( VarcharTypeDescriptor.INSTANCE ); addDescriptor( LongVarcharTypeDescriptor.INSTANCE ); addDescriptor( ClobTypeDescriptor.DEFAULT ); addDescriptor( NCharTypeDescriptor.INSTANCE ); addDescriptor( NVarcharTypeDescriptor.INSTANCE ); addDescriptor( LongNVarcharTypeDescriptor.INSTANCE ); addDescriptor( NClobTypeDescriptor.DEFAULT ); } public void addDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { descriptorMap.put( sqlTypeDescriptor.getSqlType(), sqlTypeDescriptor ); } public SqlTypeDescriptor getDescriptor(int jdbcTypeCode) { SqlTypeDescriptor descriptor = descriptorMap.get( Integer.valueOf( jdbcTypeCode ) ); if ( descriptor != null ) { return descriptor; } if ( JdbcTypeNameMapper.isStandardTypeCode( jdbcTypeCode ) ) { log.debugf( "A standard JDBC type code [%s] was not defined in SqlTypeDescriptorRegistry", jdbcTypeCode ); } // see if the typecode is part of a known type family... JdbcTypeFamilyInformation.Family family = JdbcTypeFamilyInformation.INSTANCE.locateJdbcTypeFamilyByTypeCode( jdbcTypeCode ); if ( family != null ) { for ( int potentialAlternateTypeCode : family.getTypeCodes() ) { if ( potentialAlternateTypeCode != jdbcTypeCode ) { final SqlTypeDescriptor potentialAlternateDescriptor = descriptorMap.get( Integer.valueOf( potentialAlternateTypeCode ) ); if ( potentialAlternateDescriptor != null ) { // todo : add a SqlTypeDescriptor.canBeAssignedFrom method... return potentialAlternateDescriptor; } if ( JdbcTypeNameMapper.isStandardTypeCode( potentialAlternateTypeCode ) ) { log.debugf( "A standard JDBC type code [%s] was not defined in SqlTypeDescriptorRegistry", potentialAlternateTypeCode ); } } } } // finally, create a new descriptor mapping to getObject/setObject for this type code... final ObjectSqlTypeDescriptor fallBackDescriptor = new ObjectSqlTypeDescriptor( jdbcTypeCode ); addDescriptor( fallBackDescriptor ); return fallBackDescriptor; } public static class ObjectSqlTypeDescriptor implements SqlTypeDescriptor { private final int jdbcTypeCode; public ObjectSqlTypeDescriptor(int jdbcTypeCode) { this.jdbcTypeCode = jdbcTypeCode; } @Override public int getSqlType() { return jdbcTypeCode; } @Override public boolean canBeRemapped() { return true; } @Override public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) { if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) { return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor ); } return new BasicBinder<X>( javaTypeDescriptor, this ) { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { st.setObject( index, value, jdbcTypeCode ); } }; } @Override @SuppressWarnings("unchecked") public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) { return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor ); } return new BasicExtractor( javaTypeDescriptor, this ) { @Override protected Object doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { return rs.getObject( name ); } @Override protected Object doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { return statement.getObject( index ); } @Override protected Object doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { return statement.getObject( name ); } }; } } }