同步mp相关代码

This commit is contained in:
yulichang 2024-09-20 13:54:44 +08:00
parent 0519bd47ee
commit bee3f83dea
7 changed files with 213 additions and 27 deletions

View File

@ -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();

View File

@ -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(""));

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -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,10 +100,14 @@ 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);
// 这里泛型逻辑提取进行了调整,如果在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);
}
/**
* <p>
@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}