Created
December 16, 2011 09:41
-
-
Save simonetripodi/1485359 to your computer and use it in GitHub Desktop.
add advanced generic type handling in MyBatis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: src/test/java/org/apache/ibatis/type/TypeHandlerRegistryTest.java | |
=================================================================== | |
--- src/test/java/org/apache/ibatis/type/TypeHandlerRegistryTest.java (revision 4287) | |
+++ src/test/java/org/apache/ibatis/type/TypeHandlerRegistryTest.java (working copy) | |
@@ -15,6 +15,13 @@ | |
*/ | |
package org.apache.ibatis.type; | |
+import java.net.URI; | |
+import java.sql.CallableStatement; | |
+import java.sql.PreparedStatement; | |
+import java.sql.ResultSet; | |
+import java.sql.SQLException; | |
+import java.util.List; | |
+ | |
import domain.misc.RichType; | |
import static org.junit.Assert.*; | |
import org.junit.Test; | |
@@ -25,7 +32,7 @@ | |
@Test | |
public void shouldRegisterAndRetrieveTypeHandler() { | |
- TypeHandler stringTypeHandler = typeHandlerRegistry.getTypeHandler(String.class); | |
+ TypeHandler<String> stringTypeHandler = typeHandlerRegistry.getTypeHandler(String.class); | |
typeHandlerRegistry.register(String.class, JdbcType.LONGVARCHAR, stringTypeHandler); | |
assertEquals(stringTypeHandler, typeHandlerRegistry.getTypeHandler(String.class, JdbcType.LONGVARCHAR)); | |
@@ -36,4 +43,39 @@ | |
assertTrue(typeHandlerRegistry.getUnknownTypeHandler() instanceof UnknownTypeHandler); | |
} | |
+ @Test | |
+ public void shouldRegisterAndRetrieveComplexTypeHandler() { | |
+ TypeHandler<List<URI>> fakeHandler = new TypeHandler<List<URI>>() { | |
+ | |
+ public void setParameter( PreparedStatement ps, int i, List<URI> parameter, JdbcType jdbcType ) | |
+ throws SQLException { | |
+ // do nothing, fake method | |
+ } | |
+ | |
+ public List<URI> getResult( CallableStatement cs, int columnIndex ) | |
+ throws SQLException { | |
+ // do nothing, fake method | |
+ return null; | |
+ } | |
+ | |
+ public List<URI> getResult( ResultSet rs, int columnIndex ) | |
+ throws SQLException { | |
+ // do nothing, fake method | |
+ return null; | |
+ } | |
+ | |
+ public List<URI> getResult( ResultSet rs, String columnName ) | |
+ throws SQLException { | |
+ // do nothing, fake method | |
+ return null; | |
+ } | |
+ | |
+ }; | |
+ | |
+ TypeReference<List<URI>> type = new TypeReference<List<URI>>(){}; | |
+ | |
+ typeHandlerRegistry.register(type, fakeHandler); | |
+ assertSame(fakeHandler, typeHandlerRegistry.getTypeHandler(type)); | |
+ } | |
+ | |
} | |
Index: src/main/java/org/apache/ibatis/type/TypeReference.java | |
=================================================================== | |
--- src/main/java/org/apache/ibatis/type/TypeReference.java (revision 0) | |
+++ src/main/java/org/apache/ibatis/type/TypeReference.java (revision 0) | |
@@ -0,0 +1,43 @@ | |
+/* | |
+ * Copyright 2009-2011 The MyBatis Team | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+package org.apache.ibatis.type; | |
+ | |
+import java.lang.reflect.ParameterizedType; | |
+import java.lang.reflect.Type; | |
+ | |
+/** | |
+ * References a generic type. | |
+ * | |
+ * @param <T> the referenced type | |
+ * @since 3.1.0 | |
+ */ | |
+public abstract class TypeReference<T> { | |
+ | |
+ private final Type rawType; | |
+ | |
+ protected TypeReference() { | |
+ Type superclass = getClass().getGenericSuperclass(); | |
+ if ( superclass instanceof Class ) { | |
+ throw new RuntimeException( "Missing type parameter." ); | |
+ } | |
+ rawType = ( (ParameterizedType) superclass ).getActualTypeArguments()[0]; | |
+ } | |
+ | |
+ public final Type getRawType() { | |
+ return rawType; | |
+ } | |
+ | |
+} | |
Property changes on: src/main/java/org/apache/ibatis/type/TypeReference.java | |
___________________________________________________________________ | |
Added: svn:mime-type | |
+ text/plain | |
Added: svn:keywords | |
+ Date Author Id Revision HeadURL | |
Added: svn:eol-style | |
+ native | |
Index: src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java | |
=================================================================== | |
--- src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java (revision 4287) | |
+++ src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java (working copy) | |
@@ -18,6 +18,7 @@ | |
import org.apache.ibatis.io.ResolverUtil; | |
import java.lang.reflect.Modifier; | |
+import java.lang.reflect.Type; | |
import java.math.BigDecimal; | |
import java.math.BigInteger; | |
import java.util.Date; | |
@@ -41,7 +42,7 @@ | |
}; | |
private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class); | |
- private final Map<Class<?>, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Class<?>, Map<JdbcType, TypeHandler<?>>>(); | |
+ private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>(); | |
private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this); | |
public TypeHandlerRegistry() { | |
@@ -126,19 +127,39 @@ | |
return hasTypeHandler(javaType, null); | |
} | |
+ public boolean hasTypeHandler(TypeReference<?> javaTypeReference) { | |
+ return hasTypeHandler(javaTypeReference, null); | |
+ } | |
+ | |
public boolean hasTypeHandler(Class<?> javaType, JdbcType jdbcType) { | |
- return javaType != null && getTypeHandler(javaType, jdbcType) != null; | |
+ return javaType != null && getTypeHandler((Type) javaType, jdbcType) != null; | |
} | |
- public TypeHandler<?> getTypeHandler(Class<?> type) { | |
- return getTypeHandler(type, null); | |
+ public boolean hasTypeHandler(TypeReference<?> javaTypeReference, JdbcType jdbcType) { | |
+ return javaTypeReference != null && getTypeHandler(javaTypeReference, jdbcType) != null; | |
} | |
+ public <T> TypeHandler<T> getTypeHandler(Class<T> type) { | |
+ return getTypeHandler((Type) type, null); | |
+ } | |
+ | |
+ public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference) { | |
+ return getTypeHandler(javaTypeReference, null); | |
+ } | |
+ | |
public TypeHandler<?> getTypeHandler(JdbcType jdbcType) { | |
return JDBC_TYPE_HANDLER_MAP.get(jdbcType); | |
} | |
- public TypeHandler<?> getTypeHandler(Class<?> type, JdbcType jdbcType) { | |
+ public <T> TypeHandler<T> getTypeHandler(Class<?> type, JdbcType jdbcType) { | |
+ return getTypeHandler( (Type) type, jdbcType ); | |
+ } | |
+ | |
+ public <T> TypeHandler<T> getTypeHandler(TypeReference<T> javaTypeReference, JdbcType jdbcType) { | |
+ return getTypeHandler( javaTypeReference.getRawType(), jdbcType ); | |
+ } | |
+ | |
+ private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) { | |
Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type); | |
TypeHandler<?> handler = null; | |
if (jdbcHandlerMap != null) { | |
@@ -147,10 +168,12 @@ | |
handler = jdbcHandlerMap.get(null); | |
} | |
} | |
- if (handler == null && type != null && Enum.class.isAssignableFrom(type)) { | |
- handler = new EnumTypeHandler(type); | |
+ if (handler == null && type != null && type instanceof Class && Enum.class.isAssignableFrom((Class<?>) type)) { | |
+ handler = new EnumTypeHandler((Class<?>) type); | |
} | |
- return handler; | |
+ @SuppressWarnings( "unchecked" ) // type drives generics here | |
+ TypeHandler<T> returned = (TypeHandler<T>) handler; | |
+ return returned; | |
} | |
public TypeHandler<Object> getUnknownTypeHandler() { | |
@@ -162,6 +185,14 @@ | |
} | |
public <T> void register(Class<T> type, TypeHandler<? extends T> handler) { | |
+ register((Type) type, handler); | |
+ } | |
+ | |
+ public <T> void register(TypeReference<T> javaTypeReference, TypeHandler<? extends T> handler) { | |
+ register(javaTypeReference.getRawType(), handler); | |
+ } | |
+ | |
+ public void register(Type type, TypeHandler<?> handler) { | |
MappedJdbcTypes mappedJdbcTypes = handler.getClass().getAnnotation(MappedJdbcTypes.class); | |
if (mappedJdbcTypes != null) { | |
for (JdbcType handledJdbcType : mappedJdbcTypes.value()) { | |
@@ -172,8 +203,9 @@ | |
} | |
} | |
- public <T> void register(TypeHandler<? extends T> handler) { | |
+ public <T> void register(TypeHandler<T> handler) { | |
boolean mappedTypeFound = false; | |
+ | |
MappedTypes mappedTypes = handler.getClass().getAnnotation(MappedTypes.class); | |
if (mappedTypes != null) { | |
for (Class<?> handledType : mappedTypes.value()) { | |
@@ -182,12 +214,37 @@ | |
mappedTypeFound = true; | |
} | |
} | |
+ | |
+ // @since 3.1.0 - try to auto-discover the mapped type | |
+ if (!mappedTypeFound && handler instanceof TypeReference) | |
+ { | |
+ try | |
+ { | |
+ @SuppressWarnings( "unchecked" ) | |
+ TypeReference<T> typeReference = (TypeReference<T>) handler; | |
+ register( typeReference, handler ); | |
+ mappedTypeFound = true; | |
+ } catch (Throwable t) { | |
+ // maybe users define the TypeReference with a different type and are not assignable, so just ignore it | |
+ } | |
+ } | |
+ | |
if (!mappedTypeFound) { | |
- throw new RuntimeException("Unable to get mapped types, check @MappedTypes annotation for type handler " + handler); | |
+ throw new RuntimeException("Unable to get mapped types, check @MappedTypes annotation for type handler " | |
+ + handler | |
+ + " or TypeReference<T> raw type"); | |
} | |
} | |
- public void register(Class<?> type, JdbcType jdbcType, TypeHandler<?> handler) { | |
+ public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) { | |
+ register((Type) type, jdbcType, handler); | |
+ } | |
+ | |
+ public <T> void register(TypeReference<T> javaTypeReference, JdbcType jdbcType, TypeHandler<? extends T> handler) { | |
+ register(javaTypeReference.getRawType(), jdbcType, handler); | |
+ } | |
+ | |
+ public void register(Type type, JdbcType jdbcType, TypeHandler<?> handler) { | |
Map<JdbcType, TypeHandler<?>> map = TYPE_HANDLER_MAP.get(type); | |
if (map == null) { | |
map = new HashMap<JdbcType, TypeHandler<?>>(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment