/*
*
* SchemaCrawler
* http://sourceforge.net/projects/schemacrawler
* Copyright (c) 2000-2013, Sualeh Fatehi.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
package schemacrawler.utility;
import java.sql.Connection;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import sf.util.Utility;
public final class TypeMap
implements Map<String, Class<?>>
{
private static final Logger LOGGER = Logger
.getLogger(TypeMap.class.getName());
private static Map<String, Class<?>> createDefaultTypeMap()
{
final Map<String, Class<?>> sqlTypeMap = new HashMap<>();
// From the JDBC Specification 4.1,
// Appendix B (Data Type Conversion Tables)
sqlTypeMap.put("ARRAY", java.sql.Array.class);
sqlTypeMap.put("BIGINT", Long.class);
sqlTypeMap.put("BINARY", byte[].class);
sqlTypeMap.put("BIT", Boolean.class);
sqlTypeMap.put("BLOB", java.sql.Blob.class);
sqlTypeMap.put("BOOLEAN", Boolean.class);
sqlTypeMap.put("CHAR", String.class);
sqlTypeMap.put("CLOB", java.sql.Clob.class);
sqlTypeMap.put("DATALINK", java.net.URL.class);
sqlTypeMap.put("DATE", java.sql.Date.class);
sqlTypeMap.put("DECIMAL", java.math.BigDecimal.class);
sqlTypeMap.put("DISTINCT", Object.class);
sqlTypeMap.put("DOUBLE", Double.class);
sqlTypeMap.put("FLOAT", Double.class);
sqlTypeMap.put("INTEGER", Integer.class);
sqlTypeMap.put("JAVA_OBJECT", Object.class);
sqlTypeMap.put("LONGNVARCHAR", String.class);
sqlTypeMap.put("LONGVARBINARY", byte[].class);
sqlTypeMap.put("LONGVARCHAR", String.class);
sqlTypeMap.put("NCHAR", String.class);
sqlTypeMap.put("NCLOB", java.sql.NClob.class);
sqlTypeMap.put("NULL", Void.class);
sqlTypeMap.put("NUMERIC", java.math.BigDecimal.class);
sqlTypeMap.put("NVARCHAR", String.class);
sqlTypeMap.put("OTHER", Object.class);
sqlTypeMap.put("REAL", Float.class);
sqlTypeMap.put("REF", java.sql.Ref.class);
sqlTypeMap.put("ROWID", java.sql.RowId.class);
sqlTypeMap.put("SMALLINT", Short.class);
sqlTypeMap.put("SQLXML", java.sql.SQLXML.class);
sqlTypeMap.put("STRUCT", java.sql.Struct.class);
sqlTypeMap.put("TIME", java.sql.Time.class);
sqlTypeMap.put("TIMESTAMP", java.sql.Timestamp.class);
sqlTypeMap.put("TINYINT", byte.class);
sqlTypeMap.put("VARBINARY", byte[].class);
sqlTypeMap.put("VARCHAR", String.class);
return sqlTypeMap;
}
private final Map<String, Class<?>> sqlTypeMap;
public TypeMap()
{
this(null);
}
public TypeMap(final Connection connection)
{
final Map<String, Class<?>> sqlTypeMap = createDefaultTypeMap();
if (connection != null)
{
// Override and add mappings from the connection
try
{
final Map<String, Class<?>> typeMap = connection.getTypeMap();
if (typeMap != null && !typeMap.isEmpty())
{
sqlTypeMap.putAll(typeMap);
}
}
catch (final Exception e)
{
// (Some drivers would throw SQLException, Sybase Adaptive
// Server throws UnimplementedOperationException)
LOGGER.log(Level.WARNING,
"Could not obtain data type map from connection",
e);
}
}
this.sqlTypeMap = sqlTypeMap;
}
@Override
public void clear()
{
throw new UnsupportedOperationException();
}
@Override
public boolean containsKey(final Object key)
{
return sqlTypeMap.containsKey(key);
}
@Override
public boolean containsValue(final Object value)
{
return sqlTypeMap.containsValue(value);
}
@Override
public Set<Entry<String, Class<?>>> entrySet()
{
return new HashSet<>(sqlTypeMap.entrySet());
}
@Override
public boolean equals(final Object o)
{
return sqlTypeMap.equals(o);
}
@Override
public Class<?> get(final Object key)
{
if (containsKey(key))
{
return sqlTypeMap.get(key);
}
else
{
return Object.class;
}
}
/**
* Gets the Java type mapping for a data type. If no mapping exists,
* returns null. If a class name is passed in, it overrides the
* mapping in the type map.
*
* @param typeName
* Type name to find a mapping for.
* @param className
* Overridden class name
* @return Mapped class
*/
public Class<?> get(final String typeName, final String className)
{
if (Utility.isBlank(className))
{
return sqlTypeMap.get(typeName);
}
else
{
try
{
return Class.forName(className);
}
catch (final ClassNotFoundException e)
{
LOGGER.log(Level.WARNING,
"Could not obtain class mapping for data type " + typeName,
e);
return null;
}
}
}
@Override
public int hashCode()
{
return sqlTypeMap.hashCode();
}
@Override
public boolean isEmpty()
{
return sqlTypeMap.isEmpty();
}
@Override
public Set<String> keySet()
{
return new HashSet<>(sqlTypeMap.keySet());
}
@Override
public Class<?> put(final String key, final Class<?> value)
{
throw new UnsupportedOperationException();
}
@Override
public void putAll(final Map<? extends String, ? extends Class<?>> m)
{
throw new UnsupportedOperationException();
}
@Override
public Class<?> remove(final Object key)
{
throw new UnsupportedOperationException();
}
@Override
public int size()
{
return sqlTypeMap.size();
}
@Override
public String toString()
{
return sqlTypeMap.toString();
}
@Override
public Collection<Class<?>> values()
{
return new HashSet<>(sqlTypeMap.values());
}
}