mirror of
https://gitee.com/best_handsome/mybatis-plus-join
synced 2025-07-11 00:02:22 +08:00
同步mp相关代码
This commit is contained in:
parent
0519bd47ee
commit
bee3f83dea
@ -9,14 +9,13 @@ import com.baomidou.mybatisplus.core.injector.methods.*;
|
||||
import com.baomidou.mybatisplus.core.mapper.Mapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
||||
import com.github.yulichang.adapter.base.tookit.VersionUtils;
|
||||
import com.github.yulichang.adapter.v3431.AbstractMethodV3431;
|
||||
import com.github.yulichang.method.*;
|
||||
import com.github.yulichang.toolkit.MPJTableMapperHelper;
|
||||
import com.github.yulichang.toolkit.ReflectionKit;
|
||||
import com.github.yulichang.toolkit.TableHelper;
|
||||
import com.github.yulichang.toolkit.reflect.GenericTypeUtils;
|
||||
import lombok.Getter;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
@ -173,7 +172,7 @@ public class MPJSqlInjector extends DefaultSqlInjector {
|
||||
|
||||
@Override
|
||||
public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
|
||||
Class<?> modelClass = getSuperClassGenericType(mapperClass, Mapper.class, 0);
|
||||
Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);
|
||||
super.inspectInject(builderAssistant, mapperClass);
|
||||
MPJTableMapperHelper.init(modelClass, mapperClass);
|
||||
Supplier<Class<?>> supplier = () -> {
|
||||
@ -186,11 +185,6 @@ public class MPJSqlInjector extends DefaultSqlInjector {
|
||||
TableHelper.init(modelClass, supplier.get());
|
||||
}
|
||||
|
||||
public static Class<?> getSuperClassGenericType(final Class<?> clazz, final Class<?> genericIfc, final int index) {
|
||||
Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(ClassUtils.getUserClass(clazz), genericIfc);
|
||||
return null == typeArguments ? null : typeArguments[index];
|
||||
}
|
||||
|
||||
@SuppressWarnings("IfStatementWithIdenticalBranches")
|
||||
protected Class<?> extractModelClassOld(Class<?> mapperClass) {
|
||||
Type[] types = mapperClass.getGenericInterfaces();
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.github.yulichang.interceptor.pagination;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Assert;
|
||||
import com.github.yulichang.toolkit.ReflectionKit;
|
||||
import com.github.yulichang.toolkit.MPJReflectionKit;
|
||||
import org.apache.ibatis.mapping.ParameterMapping;
|
||||
import org.apache.ibatis.mapping.SqlSource;
|
||||
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
|
||||
@ -102,8 +102,8 @@ public final class ParseHelper {
|
||||
public static String getOriginalSql(Object parameter, DynamicSqlSource sqlSource) {
|
||||
Assert.notNull(sqlSource, "sqlSource must not be null");
|
||||
SqlSourceWrapper sqlSourceWrapper = SQL_SOURCE_CACHE.computeIfAbsent(sqlSource, key -> {
|
||||
Configuration configuration = ReflectionKit.getFieldValue(sqlSource, "configuration");
|
||||
SqlNode sqlNode = ReflectionKit.getFieldValue(sqlSource, "rootSqlNode");
|
||||
Configuration configuration = MPJReflectionKit.getFieldValue(sqlSource, "configuration");
|
||||
SqlNode sqlNode = MPJReflectionKit.getFieldValue(sqlSource, "rootSqlNode");
|
||||
return new SqlSourceWrapper(configuration, sqlNode);
|
||||
});
|
||||
return ParseHelper.decode(sqlSourceWrapper.getSql(parameter), null, ParseHelper.format.apply(""));
|
||||
|
@ -130,8 +130,7 @@ public final class ClassUtils {
|
||||
Constructor<T> constructor = clazz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw ExceptionUtils.mpe("实例化对象时出现错误,请尝试给 %s 添加无参的构造方法", e, clazz.getName());
|
||||
}
|
||||
}
|
||||
|
@ -110,4 +110,15 @@ public final class MPJReflectionKit {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
return (clazz.isPrimitive() || PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz));
|
||||
}
|
||||
|
||||
public static <T> T getFieldValue(Object object, String fieldName) {
|
||||
try {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
//noinspection unchecked
|
||||
return (T) field.get(object);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,12 @@ import com.baomidou.mybatisplus.core.toolkit.Assert;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
||||
import com.github.yulichang.toolkit.reflect.GenericTypeUtils;
|
||||
import com.github.yulichang.toolkit.reflect.TypeParameterResolver;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
@ -70,14 +73,19 @@ public final class ReflectionKit {
|
||||
* @param entity 实体
|
||||
* @param fieldName 字段名称
|
||||
* @return 属性值
|
||||
* @deprecated 3.5.4
|
||||
*/
|
||||
public static <T> T getFieldValue(Object entity, String fieldName) {
|
||||
@Deprecated
|
||||
public static Object getFieldValue(Object entity, String fieldName) {
|
||||
Class<?> cls = entity.getClass();
|
||||
Map<String, Field> fieldMaps = getFieldMap(cls);
|
||||
try {
|
||||
Field field = entity.getClass().getDeclaredField(fieldName);
|
||||
Field field = fieldMaps.get(fieldName);
|
||||
Assert.notNull(field, "Error: NoSuchField in %s for %s. Cause:", cls.getSimpleName(), fieldName);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(entity);
|
||||
return field.get(entity);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw ExceptionUtils.mpe("Error: Cannot read field in %s. Cause:", e, entity.getClass().getSimpleName());
|
||||
throw ExceptionUtils.mpe("Error: Cannot read field in %s. Cause:", e, cls.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,9 +100,13 @@ public final class ReflectionKit {
|
||||
* @return Class
|
||||
*/
|
||||
public static Class<?> getSuperClassGenericType(final Class<?> clazz, final Class<?> genericIfc, final int index) {
|
||||
//update by noear @2021-09-03
|
||||
Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(ClassUtils.getUserClass(clazz), genericIfc);
|
||||
return null == typeArguments ? null : typeArguments[index];
|
||||
// 这里泛型逻辑提取进行了调整,如果在Spring项目情况或者自定义了泛型提取,那就优先走这里,否则使用框架内置的进行泛型提取.
|
||||
Class<?> userClass = ClassUtils.getUserClass(clazz);
|
||||
if (GenericTypeUtils.hasGenericTypeResolver()) {
|
||||
Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(userClass, genericIfc);
|
||||
return null == typeArguments ? null : typeArguments[index];
|
||||
}
|
||||
return (Class<?>) TypeParameterResolver.resolveClassIndexedParameter(userClass, genericIfc, index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,7 +132,7 @@ public final class ReflectionKit {
|
||||
if (Objects.isNull(clazz)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return computeIfAbsent(CLASS_FIELD_CACHE, clazz, k -> {
|
||||
return CLASS_FIELD_CACHE.computeIfAbsent(clazz, k -> {
|
||||
Field[] fields = k.getDeclaredFields();
|
||||
List<Field> superFields = new ArrayList<>();
|
||||
Class<?> currentClass = k.getSuperclass();
|
||||
@ -181,11 +193,17 @@ public final class ReflectionKit {
|
||||
return (clazz.isPrimitive() && clazz != void.class ? PRIMITIVE_TYPE_TO_WRAPPER_MAP.get(clazz) : clazz);
|
||||
}
|
||||
|
||||
public static <K, V> V computeIfAbsent(Map<K, V> concurrentHashMap, K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
V v = concurrentHashMap.get(key);
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
return concurrentHashMap.computeIfAbsent(key, mappingFunction);
|
||||
/**
|
||||
* 设置可访问对象的可访问权限为 true
|
||||
*
|
||||
* @param object 可访问的对象
|
||||
* @param <T> 类型
|
||||
* @return 返回设置后的对象
|
||||
* @deprecated 3.5.4 {@link java.security.AccessController}
|
||||
*/
|
||||
@Deprecated
|
||||
public static <T extends AccessibleObject> T setAccessible(T object) {
|
||||
return AccessController.doPrivileged(new SetAccessibleAction<>(object));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.github.yulichang.toolkit.reflect;
|
||||
|
||||
import com.github.yulichang.toolkit.ClassUtils;
|
||||
|
||||
/**
|
||||
* 泛型类工具(用于隔离Spring的代码)
|
||||
*
|
||||
@ -24,6 +26,22 @@ package com.github.yulichang.toolkit.reflect;
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public class GenericTypeUtils {
|
||||
|
||||
/**
|
||||
* 能否加载SpringCore包
|
||||
*
|
||||
* @since 3.5.4
|
||||
*/
|
||||
private static boolean loadSpringCore = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
ClassUtils.toClassConfident("org.springframework.core.GenericTypeResolver");
|
||||
loadSpringCore = true;
|
||||
} catch (Exception exception) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
private static IGenericTypeResolver GENERIC_TYPE_RESOLVER;
|
||||
|
||||
/**
|
||||
@ -43,4 +61,15 @@ public class GenericTypeUtils {
|
||||
public static void setGenericTypeResolver(IGenericTypeResolver genericTypeResolver) {
|
||||
GENERIC_TYPE_RESOLVER = genericTypeResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否有自定泛型提取类或能否加载SpringCore进行泛型提取
|
||||
*
|
||||
* @return 是否有实现
|
||||
* @since 3.5.4
|
||||
*/
|
||||
public static boolean hasGenericTypeResolver() {
|
||||
return GENERIC_TYPE_RESOLVER != null || loadSpringCore;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2024, baomidou (jobob@qq.com).
|
||||
*
|
||||
* 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 com.github.yulichang.toolkit.reflect;
|
||||
|
||||
import java.lang.reflect.GenericDeclaration;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 类型参数实现收集器,采集类型实现中各个类型参数的实际值
|
||||
* <p>
|
||||
* Create by hcl at 2023/9/25
|
||||
*/
|
||||
public class TypeParameterResolver {
|
||||
private final Map<TypeVariable<?>, Type> map;
|
||||
private final Set<Type> distinct;
|
||||
|
||||
protected TypeParameterResolver(Map<TypeVariable<?>, Type> map) {
|
||||
this.map = map;
|
||||
this.distinct = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型上指定索引位置参数的实现信息
|
||||
*
|
||||
* @param source 类型
|
||||
* @param index 索引
|
||||
* @param type 实现类型
|
||||
* @return 返回类型实现或者 null
|
||||
*/
|
||||
public static Type resolveClassIndexedParameter(Type type, Class<?> source, int index) {
|
||||
return calculateParameterValue(resolveParameterValues(type), source.getTypeParameters()[index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算参数值
|
||||
*
|
||||
* @param map 变量 Map
|
||||
* @param parameter 参数
|
||||
* @return 返回参数值
|
||||
*/
|
||||
public static Type calculateParameterValue(Map<TypeVariable<?>, Type> map, TypeVariable<?> parameter) {
|
||||
Type res = map.get(parameter);
|
||||
while (res instanceof TypeVariable<?>) {
|
||||
res = map.get(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析指定类型下的泛型参数实现信息
|
||||
*
|
||||
* @param from 起始类型
|
||||
* @return 返回全部的泛型参数及其映射类型值
|
||||
*/
|
||||
public static Map<TypeVariable<?>, Type> resolveParameterValues(Type from) {
|
||||
Map<TypeVariable<?>, Type> map = new HashMap<>();
|
||||
new TypeParameterResolver(map).visitType(from);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问类型,类型中需要关注两个:{@link Class} 和 {@link ParameterizedType}
|
||||
*
|
||||
* @param type 类型
|
||||
*/
|
||||
public void visitType(Type type) {
|
||||
if (!distinct.add(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
visitClass((Class<?>) type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type instanceof ParameterizedType) {
|
||||
visitParameterizedType((ParameterizedType) type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问类型,类型的树可以分解为父类和接口,这两个地方都要解析。
|
||||
*
|
||||
* @param c 类
|
||||
*/
|
||||
private void visitClass(Class<?> c) {
|
||||
visitType(c.getGenericSuperclass());
|
||||
for (Type i : c.getGenericInterfaces()) {
|
||||
visitType(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问参数化类型,类型参数映射的主要逻辑就在这里
|
||||
*
|
||||
* @param parameterized 参数化类型
|
||||
*/
|
||||
private void visitParameterizedType(ParameterizedType parameterized) {
|
||||
Type raw = parameterized.getRawType();
|
||||
visitType(raw);
|
||||
|
||||
if (raw instanceof GenericDeclaration) {
|
||||
GenericDeclaration declaration = (GenericDeclaration) raw;
|
||||
TypeVariable<?>[] parameters = declaration.getTypeParameters();
|
||||
Type[] arguments = parameterized.getActualTypeArguments();
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
TypeVariable<?> parameter = parameters[i];
|
||||
Type argument = arguments[i];
|
||||
map.put(parameter, argument);
|
||||
visitType(argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user