-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
395 additions
and
0 deletions.
There are no files selected for viewing
245 changes: 245 additions & 0 deletions
245
docs/spring/cs2b2a6db8-90df-11ef-a50a-acde48001122.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
/** | ||
* Copyright 2009-2018 the original author or authors. | ||
* <p> | ||
* 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 | ||
* <p> | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* 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.reflection; | ||
|
||
import org.apache.ibatis.reflection.invoker.GetFieldInvoker; | ||
import org.apache.ibatis.reflection.invoker.Invoker; | ||
import org.apache.ibatis.reflection.invoker.MethodInvoker; | ||
import org.apache.ibatis.reflection.property.PropertyTokenizer; | ||
|
||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import java.util.Collection; | ||
|
||
/** | ||
* 源类 | ||
* | ||
* @author Clinton Begin | ||
*/ | ||
public class MetaClass { | ||
|
||
/** | ||
* {@link DefaultReflectorFactory} | ||
*/ | ||
private final ReflectorFactory reflectorFactory; | ||
/** | ||
* 反射器 | ||
*/ | ||
private final Reflector reflector; | ||
|
||
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) { | ||
this.reflectorFactory = reflectorFactory; | ||
this.reflector = reflectorFactory.findForClass(type); | ||
} | ||
|
||
/** | ||
* 根据 type (java.class) 和 反射工厂{@link DefaultReflectorFactory} 创建 {@link MetaClass} | ||
* | ||
* @param type | ||
* @param reflectorFactory | ||
* @return | ||
*/ | ||
public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) { | ||
return new MetaClass(type, reflectorFactory); | ||
} | ||
|
||
public MetaClass metaClassForProperty(String name) { | ||
Class<?> propType = reflector.getGetterType(name); | ||
return MetaClass.forClass(propType, reflectorFactory); | ||
} | ||
|
||
/** | ||
* 根据 name 获取数据类型 | ||
* | ||
* @param name | ||
* @return | ||
*/ | ||
public String findProperty(String name) { | ||
StringBuilder prop = buildProperty(name, new StringBuilder()); | ||
return prop.length() > 0 ? prop.toString() : null; | ||
} | ||
|
||
public String findProperty(String name, boolean useCamelCaseMapping) { | ||
if (useCamelCaseMapping) { | ||
name = name.replace("_", ""); | ||
} | ||
return findProperty(name); | ||
} | ||
|
||
public String[] getGetterNames() { | ||
return reflector.getGetablePropertyNames(); | ||
} | ||
|
||
public String[] getSetterNames() { | ||
return reflector.getSetablePropertyNames(); | ||
} | ||
|
||
public Class<?> getSetterType(String name) { | ||
PropertyTokenizer prop = new PropertyTokenizer(name); | ||
if (prop.hasNext()) { | ||
MetaClass metaProp = metaClassForProperty(prop.getName()); | ||
return metaProp.getSetterType(prop.getChildren()); | ||
} else { | ||
return reflector.getSetterType(prop.getName()); | ||
} | ||
} | ||
|
||
/** | ||
* @param name | ||
* @return | ||
*/ | ||
public Class<?> getGetterType(String name) { | ||
PropertyTokenizer prop = new PropertyTokenizer(name); | ||
if (prop.hasNext()) { | ||
MetaClass metaProp = metaClassForProperty(prop); | ||
return metaProp.getGetterType(prop.getChildren()); | ||
} | ||
// issue #506. Resolve the type inside a Collection Object | ||
return getGetterType(prop); | ||
} | ||
|
||
/** | ||
* 根据属性获取 操作javaType | ||
* | ||
* @param prop | ||
* @return | ||
*/ | ||
private MetaClass metaClassForProperty(PropertyTokenizer prop) { | ||
Class<?> propType = getGetterType(prop); | ||
return MetaClass.forClass(propType, reflectorFactory); | ||
} | ||
|
||
/** | ||
* 获取数据类型 | ||
* | ||
* @param prop | ||
* @return | ||
*/ | ||
private Class<?> getGetterType(PropertyTokenizer prop) { | ||
// 在 Reflector 类中获取 | ||
Class<?> type = reflector.getGetterType(prop.getName()); | ||
if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) { | ||
Type returnType = getGenericGetterType(prop.getName()); | ||
if (returnType instanceof ParameterizedType) { | ||
Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments(); | ||
if (actualTypeArguments != null && actualTypeArguments.length == 1) { | ||
returnType = actualTypeArguments[0]; | ||
if (returnType instanceof Class) { | ||
type = (Class<?>) returnType; | ||
} else if (returnType instanceof ParameterizedType) { | ||
type = (Class<?>) ((ParameterizedType) returnType).getRawType(); | ||
} | ||
} | ||
} | ||
} | ||
return type; | ||
} | ||
|
||
private Type getGenericGetterType(String propertyName) { | ||
try { | ||
Invoker invoker = reflector.getGetInvoker(propertyName); | ||
if (invoker instanceof MethodInvoker) { | ||
Field _method = MethodInvoker.class.getDeclaredField("method"); | ||
_method.setAccessible(true); | ||
Method method = (Method) _method.get(invoker); | ||
return TypeParameterResolver.resolveReturnType(method, reflector.getType()); | ||
} else if (invoker instanceof GetFieldInvoker) { | ||
Field _field = GetFieldInvoker.class.getDeclaredField("field"); | ||
_field.setAccessible(true); | ||
Field field = (Field) _field.get(invoker); | ||
return TypeParameterResolver.resolveFieldType(field, reflector.getType()); | ||
} | ||
} catch (NoSuchFieldException | IllegalAccessException ignored) { | ||
} | ||
return null; | ||
} | ||
|
||
public boolean hasSetter(String name) { | ||
PropertyTokenizer prop = new PropertyTokenizer(name); | ||
if (prop.hasNext()) { | ||
if (reflector.hasSetter(prop.getName())) { | ||
MetaClass metaProp = metaClassForProperty(prop.getName()); | ||
return metaProp.hasSetter(prop.getChildren()); | ||
} else { | ||
return false; | ||
} | ||
} else { | ||
return reflector.hasSetter(prop.getName()); | ||
} | ||
} | ||
|
||
public boolean hasGetter(String name) { | ||
PropertyTokenizer prop = new PropertyTokenizer(name); | ||
if (prop.hasNext()) { | ||
if (reflector.hasGetter(prop.getName())) { | ||
MetaClass metaProp = metaClassForProperty(prop); | ||
return metaProp.hasGetter(prop.getChildren()); | ||
} else { | ||
return false; | ||
} | ||
} else { | ||
return reflector.hasGetter(prop.getName()); | ||
} | ||
} | ||
|
||
public Invoker getGetInvoker(String name) { | ||
return reflector.getGetInvoker(name); | ||
} | ||
|
||
public Invoker getSetInvoker(String name) { | ||
return reflector.getSetInvoker(name); | ||
} | ||
|
||
/** | ||
* @param name | ||
* @param builder | ||
* @return | ||
*/ | ||
private StringBuilder buildProperty(String name, StringBuilder builder) { | ||
// 获取name的内容 属性解析 | ||
PropertyTokenizer prop = new PropertyTokenizer(name); | ||
if (prop.hasNext()) { | ||
String propertyName = reflector.findPropertyName(prop.getName()); | ||
if (propertyName != null) { | ||
builder.append(propertyName); | ||
builder.append("."); | ||
// 创建下级对象 | ||
MetaClass metaProp = metaClassForProperty(propertyName); | ||
// 设置属性 | ||
metaProp.buildProperty(prop.getChildren(), builder); | ||
} | ||
} else { | ||
// 查找属性 | ||
String propertyName = reflector.findPropertyName(name); | ||
if (propertyName != null) { | ||
// 属性添加 | ||
builder.append(propertyName); | ||
} | ||
} | ||
return builder; | ||
} | ||
|
||
/** | ||
* 是否存在无参数构造方法 | ||
* @return | ||
*/ | ||
public boolean hasDefaultConstructor() { | ||
return reflector.hasDefaultConstructor(); | ||
} | ||
|
||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.github.huifer.ctrpluginexample.repo; | ||
|
||
import com.github.huifer.ctrpluginexample.entity.AppEntity; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.repository.CrudRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface AppRepo extends CrudRepository<AppEntity, Long> { | ||
|
||
// 现在我拥有一个 CrudRepository的实现类,我想要获取这个实现类的Class 我应该怎么操作 | ||
|
||
} |
137 changes: 137 additions & 0 deletions
137
docs/spring/cs2b750eea-90df-11ef-a50a-acde48001122.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/** | ||
* Copyright 2009-2019 the original author or authors. | ||
* <p> | ||
* 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 | ||
* <p> | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* <p> | ||
* 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.executor.resultset; | ||
|
||
import org.apache.ibatis.builder.StaticSqlSource; | ||
import org.apache.ibatis.executor.Executor; | ||
import org.apache.ibatis.executor.ExecutorException; | ||
import org.apache.ibatis.executor.parameter.ParameterHandler; | ||
import org.apache.ibatis.mapping.*; | ||
import org.apache.ibatis.session.Configuration; | ||
import org.apache.ibatis.session.ResultHandler; | ||
import org.apache.ibatis.session.RowBounds; | ||
import org.apache.ibatis.type.TypeHandler; | ||
import org.apache.ibatis.type.TypeHandlerRegistry; | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.jupiter.MockitoExtension; | ||
|
||
import java.sql.*; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.when; | ||
|
||
@ExtendWith(MockitoExtension.class) | ||
class DefaultResultSetHandlerTest { | ||
|
||
@Mock | ||
private Statement stmt; | ||
@Mock | ||
private ResultSet rs; | ||
@Mock | ||
private ResultSetMetaData rsmd; | ||
@Mock | ||
private Connection conn; | ||
@Mock | ||
private DatabaseMetaData dbmd; | ||
|
||
/** | ||
* Contrary to the spec, some drivers require case-sensitive column names when getting result. | ||
* | ||
* @see <a href="http://code.google.com/p/mybatis/issues/detail?id=557">Issue 557</a> | ||
*/ | ||
@Test | ||
void shouldRetainColumnNameCase() throws Exception { | ||
|
||
final MappedStatement ms = getMappedStatement(); | ||
|
||
final Executor executor = null; | ||
final ParameterHandler parameterHandler = null; | ||
final ResultHandler resultHandler = null; | ||
final BoundSql boundSql = null; | ||
final RowBounds rowBounds = new RowBounds(0, 100); | ||
final DefaultResultSetHandler fastResultSetHandler = new DefaultResultSetHandler(executor, ms, parameterHandler, resultHandler, boundSql, rowBounds); | ||
|
||
when(stmt.getResultSet()).thenReturn(rs); | ||
when(rs.getMetaData()).thenReturn(rsmd); | ||
when(rs.getType()).thenReturn(ResultSet.TYPE_FORWARD_ONLY); | ||
when(rs.next()).thenReturn(true).thenReturn(false); | ||
when(rs.getInt("CoLuMn1")).thenReturn(100); | ||
when(rsmd.getColumnCount()).thenReturn(1); | ||
when(rsmd.getColumnLabel(1)).thenReturn("CoLuMn1"); | ||
when(rsmd.getColumnType(1)).thenReturn(Types.INTEGER); | ||
when(rsmd.getColumnClassName(1)).thenReturn(Integer.class.getCanonicalName()); | ||
when(stmt.getConnection()).thenReturn(conn); | ||
when(conn.getMetaData()).thenReturn(dbmd); | ||
when(dbmd.supportsMultipleResultSets()).thenReturn(false); // for simplicity. | ||
|
||
final List<Object> results = fastResultSetHandler.handleResultSets(stmt); | ||
assertEquals(1, results.size()); | ||
assertEquals(100, ((HashMap) results.get(0)).get("cOlUmN1")); | ||
} | ||
|
||
@Test | ||
void shouldThrowExceptionWithColumnName() throws Exception { | ||
final MappedStatement ms = getMappedStatement(); | ||
final RowBounds rowBounds = new RowBounds(0, 100); | ||
|
||
final DefaultResultSetHandler defaultResultSetHandler = new DefaultResultSetHandler(null/*executor*/, ms, | ||
null/*parameterHandler*/, null/*resultHandler*/, null/*boundSql*/, rowBounds); | ||
|
||
final ResultSetWrapper rsw = mock(ResultSetWrapper.class); | ||
when(rsw.getResultSet()).thenReturn(mock(ResultSet.class)); | ||
|
||
final ResultMapping resultMapping = mock(ResultMapping.class); | ||
final TypeHandler typeHandler = mock(TypeHandler.class); | ||
when(resultMapping.getColumn()).thenReturn("column"); | ||
when(resultMapping.getTypeHandler()).thenReturn(typeHandler); | ||
when(typeHandler.getResult(any(ResultSet.class), any(String.class))).thenThrow(new SQLException("exception")); | ||
List<ResultMapping> constructorMappings = Collections.singletonList(resultMapping); | ||
|
||
try { | ||
defaultResultSetHandler.createParameterizedResultObject(rsw, null/*resultType*/, constructorMappings, | ||
null/*constructorArgTypes*/, null/*constructorArgs*/, null/*columnPrefix*/); | ||
Assertions.fail("Should have thrown ExecutorException"); | ||
} catch (Exception e) { | ||
Assertions.assertTrue(e instanceof ExecutorException, "Expected ExecutorException"); | ||
Assertions.assertTrue(e.getMessage().contains("mapping: " + resultMapping.toString())); | ||
} | ||
} | ||
|
||
MappedStatement getMappedStatement() { | ||
final Configuration config = new Configuration(); | ||
final TypeHandlerRegistry registry = config.getTypeHandlerRegistry(); | ||
return new MappedStatement.Builder(config, "testSelect", new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).resultMaps( | ||
new ArrayList<ResultMap>() { | ||
{ | ||
add(new ResultMap.Builder(config, "testMap", HashMap.class, new ArrayList<ResultMapping>() { | ||
{ | ||
add(new ResultMapping.Builder(config, "cOlUmN1", "CoLuMn1", registry.getTypeHandler(Integer.class)).build()); | ||
} | ||
}).build()); | ||
} | ||
}).build(); | ||
} | ||
|
||
} |