001/* 002 * Copyright (c) 2022-2025, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.util; 017 018 019import org.apache.ibatis.javassist.util.proxy.ProxyObject; 020 021import java.lang.annotation.Annotation; 022import java.lang.reflect.*; 023import java.util.*; 024import java.util.function.Predicate; 025 026/** 027 * 类实例创建者创建者 028 * 029 * @author michael 030 * @date 17/3/21 031 */ 032@SuppressWarnings("unchecked") 033public class ClassUtil { 034 035 private ClassUtil() { 036 } 037 038 private static final String[] OBJECT_METHODS = new String[]{ 039 "toString", 040 "getClass", 041 "equals", 042 "hashCode", 043 "wait", 044 "notify", 045 "notifyAll", 046 "clone", 047 "finalize" 048 }; 049 050 //proxy frameworks 051 private static final List<String> PROXY_CLASS_NAMES = Arrays.asList("net.sf.cglib.proxy.Factory" 052 // cglib 053 , "org.springframework.cglib.proxy.Factory" 054 055 // javassist 056 , "javassist.util.proxy.ProxyObject" 057 , "org.apache.ibatis.javassist.util.proxy.ProxyObject"); 058 private static final String ENHANCER_BY = "$$EnhancerBy"; 059 private static final String JAVASSIST_BY = "_$$_"; 060 061 public static boolean isProxy(Class<?> clazz) { 062 for (Class<?> cls : clazz.getInterfaces()) { 063 if (PROXY_CLASS_NAMES.contains(cls.getName())) { 064 return true; 065 } 066 } 067 //java proxy 068 return Proxy.isProxyClass(clazz); 069 } 070 071 public static <T> Class<T> getUsefulClass(Class<T> clazz) { 072 073 if (ProxyObject.class.isAssignableFrom(clazz)) { 074 return (Class<T>) clazz.getSuperclass(); 075 } 076 077 if (isProxy(clazz)) { 078 return getJdkProxySuperClass(clazz); 079 } 080 081 //ControllerTest$ServiceTest$$EnhancerByGuice$$40471411#hello -------> Guice 082 //com.demo.blog.Blog$$EnhancerByCGLIB$$69a17158 ----> CGLIB 083 //io.jboot.test.app.TestAppListener_$$_jvstb9f_0 ------> javassist 084 final String name = clazz.getName(); 085 if (name.contains(ENHANCER_BY) || name.contains(JAVASSIST_BY)) { 086 return (Class<T>) clazz.getSuperclass(); 087 } 088 089 return clazz; 090 } 091 092 093 public static Class<?> getWrapType(Class<?> clazz) { 094 if (clazz == null || !clazz.isPrimitive()) { 095 return clazz; 096 } 097 if (clazz == Integer.TYPE) { 098 return Integer.class; 099 } else if (clazz == Long.TYPE) { 100 return Long.class; 101 } else if (clazz == Boolean.TYPE) { 102 return Boolean.class; 103 } else if (clazz == Float.TYPE) { 104 return Float.class; 105 } else if (clazz == Double.TYPE) { 106 return Double.class; 107 } else if (clazz == Short.TYPE) { 108 return Short.class; 109 } else if (clazz == Character.TYPE) { 110 return Character.class; 111 } else if (clazz == Byte.TYPE) { 112 return Byte.class; 113 } else if (clazz == Void.TYPE) { 114 return Void.class; 115 } 116 return clazz; 117 } 118 119 120 public static boolean isArray(Class<?> clazz) { 121 return clazz.isArray() 122 || clazz == int[].class 123 || clazz == long[].class 124 || clazz == short[].class 125 || clazz == float[].class 126 || clazz == double[].class; 127 } 128 129 public static boolean canInstance(int mod) { 130 return !Modifier.isAbstract(mod) || !Modifier.isInterface(mod); 131 } 132 133 134 public static <T> T newInstance(Class<T> clazz) { 135 try { 136 Constructor<?> defaultConstructor = null; 137 Constructor<?> otherConstructor = null; 138 139 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); 140 for (Constructor<?> constructor : declaredConstructors) { 141 if (constructor.getParameterCount() == 0 && Modifier.isPublic(constructor.getModifiers())) { 142 defaultConstructor = constructor; 143 } else if (Modifier.isPublic(constructor.getModifiers())) { 144 otherConstructor = constructor; 145 } 146 } 147 if (defaultConstructor != null) { 148 return (T) defaultConstructor.newInstance(); 149 } else if (otherConstructor != null) { 150 Class<?>[] parameterTypes = otherConstructor.getParameterTypes(); 151 Object[] parameters = new Object[parameterTypes.length]; 152 for (int i = 0; i < parameterTypes.length; i++) { 153 if (parameterTypes[i].isPrimitive()) { 154 parameters[i] = ConvertUtil.getPrimitiveDefaultValue(parameterTypes[i]); 155 } else { 156 parameters[i] = null; 157 } 158 } 159 return (T) otherConstructor.newInstance(parameters); 160 } 161 // 没有任何构造函数的情况下,去查找 static 工厂方法,满足 lombok 注解的需求 162 else { 163 Method factoryMethod = ClassUtil.getFirstMethod(clazz, m -> m.getParameterCount() == 0 164 && m.getReturnType().isAssignableFrom(clazz) 165 && Modifier.isPublic(m.getModifiers()) 166 && Modifier.isStatic(m.getModifiers())); 167 168 if (factoryMethod != null) { 169 return (T) factoryMethod.invoke(null); 170 } 171 } 172 throw new IllegalArgumentException("the class \"" + clazz.getName() + "\" has no constructor."); 173 } catch (Exception e) { 174 throw new RuntimeException("Can not newInstance class: " + clazz.getName(), e); 175 } 176 } 177 178 179 public static <T> T newInstance(Class<T> clazz, Object... paras) { 180 try { 181 Constructor<?>[] constructors = clazz.getDeclaredConstructors(); 182 for (Constructor<?> constructor : constructors) { 183 if (isMatchedParas(constructor, paras)) { 184 Object ret = constructor.newInstance(paras); 185 return (T) ret; 186 } 187 } 188 throw new IllegalArgumentException("Can not find constructor by paras: \"" + Arrays.toString(paras) + "\" in class[" + clazz.getName() + "]"); 189 } catch (Exception e) { 190 throw new RuntimeException(e.toString(), e); 191 } 192 } 193 194 195 private static boolean isMatchedParas(Constructor<?> constructor, Object[] paras) { 196 if (constructor.getParameterCount() == 0) { 197 return paras == null || paras.length == 0; 198 } 199 200 if (constructor.getParameterCount() > 0 201 && (paras == null || paras.length != constructor.getParameterCount())) { 202 return false; 203 } 204 205 Class<?>[] parameterTypes = constructor.getParameterTypes(); 206 for (int i = 0; i < parameterTypes.length; i++) { 207 Class<?> parameterType = parameterTypes[i]; 208 Object paraObject = paras[i]; 209 if (paraObject != null && !parameterType.isAssignableFrom(paraObject.getClass())) { 210 return false; 211 } 212 } 213 214 return true; 215 } 216 217 218 public static List<Field> getAllFields(Class<?> clazz) { 219 List<Field> fields = new ArrayList<>(); 220 doGetFields(clazz, fields, null, false); 221 return fields; 222 } 223 224 public static List<Field> getAllFields(Class<?> clazz, Predicate<Field> predicate) { 225 List<Field> fields = new ArrayList<>(); 226 doGetFields(clazz, fields, predicate, false); 227 return fields; 228 } 229 230 public static Field getFirstField(Class<?> clazz, Predicate<Field> predicate) { 231 List<Field> fields = new ArrayList<>(); 232 doGetFields(clazz, fields, predicate, true); 233 return fields.isEmpty() ? null : fields.get(0); 234 } 235 236 /** 237 * 应用类及其除Object外的所有父类 238 * 239 * @param clazz 需要应用的类 240 * @param checkToContinue 应用当前类并检测是否继续应用, 返回false则停止应用, 返回true继续向上取父类 241 * @author KAMOsama 242 */ 243 public static void applyAllClass(Class<?> clazz, Predicate<Class<?>> checkToContinue) { 244 Class<?> currentClass = clazz; 245 while (currentClass != null && currentClass != Object.class && checkToContinue.test(currentClass)) { 246 currentClass = currentClass.getSuperclass(); 247 } 248 } 249 250 private static void doGetFields(Class<?> clazz, List<Field> fields, Predicate<Field> predicate, boolean firstOnly) { 251 applyAllClass(clazz, currentClass -> { 252 Field[] declaredFields = currentClass.getDeclaredFields(); 253 for (Field declaredField : declaredFields) { 254 if (predicate == null || predicate.test(declaredField)) { 255 fields.add(declaredField); 256 if (firstOnly) { 257 break; 258 } 259 } 260 } 261 // 不止要获取第一个或集合为空就继续获取遍历父类 262 return !firstOnly || fields.isEmpty(); 263 }); 264 } 265 266 public static List<Method> getAllMethods(Class<?> clazz) { 267 List<Method> methods = new ArrayList<>(); 268 doGetMethods(clazz, methods, null, false); 269 return methods; 270 } 271 272 public static List<Method> getAllMethods(Class<?> clazz, Predicate<Method> predicate) { 273 List<Method> methods = new ArrayList<>(); 274 doGetMethods(clazz, methods, predicate, false); 275 return methods; 276 } 277 278 public static Method getAnyMethod(Class<?> clazz, String... methodNames) { 279 return getFirstMethod(clazz, method -> ArrayUtil.contains(methodNames, method.getName())); 280 } 281 282 public static Method getFirstMethod(Class<?> clazz, Predicate<Method> predicate) { 283 List<Method> methods = new ArrayList<>(); 284 doGetMethods(clazz, methods, predicate, true); 285 return methods.isEmpty() ? null : methods.get(0); 286 } 287 288 public static Method getFirstMethodByAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) { 289 Set<Class<?>> visited = new HashSet<>(); 290 return findMethod(clazz, annotationClass, visited); 291 } 292 293 private static Method findMethod(Class<?> clazz, Class<? extends Annotation> annotationClass, Set<Class<?>> visited) { 294 if (clazz == null || clazz == Object.class || visited.contains(clazz)) { 295 return null; 296 } 297 visited.add(clazz); 298 299 Method[] methods = clazz.getDeclaredMethods(); 300 for (Method method : methods) { 301 if (method.isAnnotationPresent(annotationClass)) { 302 return method; 303 } 304 } 305 306 for (Class<?> inter : clazz.getInterfaces()) { 307 Method method = findMethod(inter, annotationClass, visited); 308 if (method != null) { 309 return method; 310 } 311 } 312 313 return findMethod(clazz.getSuperclass(), annotationClass, visited); 314 } 315 316 317 private static void doGetMethods(Class<?> clazz, List<Method> methods, Predicate<Method> predicate, boolean firstOnly) { 318 applyAllClass(clazz, currentClass -> { 319 Method[] declaredMethods = currentClass.getDeclaredMethods(); 320 if (currentClass.isInterface()) { 321 for (Method method : declaredMethods) { 322 // 接口类只需要获取 default 方法 323 if (method.isDefault() && (predicate == null || predicate.test(method))) { 324 methods.add(method); 325 if (firstOnly) { 326 break; 327 } 328 } 329 } 330 } else { 331 for (Method method : declaredMethods) { 332 if (predicate == null || predicate.test(method)) { 333 methods.add(method); 334 if (firstOnly) { 335 break; 336 } 337 } 338 } 339 } 340 // 只获取第一个并且集合不为空就结束遍历 341 if (firstOnly && !methods.isEmpty()) { 342 return false; 343 } 344 Class<?>[] interfaces = currentClass.getInterfaces(); 345 for (Class<?> anInterface : interfaces) { 346 doGetMethods(anInterface, methods, predicate, firstOnly); 347 // 只获取第一个并且集合不为空就结束遍历 348 if (firstOnly && !methods.isEmpty()) { 349 return false; 350 } 351 } 352 return true; 353 }); 354 } 355 356 private static <T> Class<T> getJdkProxySuperClass(Class<T> clazz) { 357 final Class<?> proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), clazz.getInterfaces()); 358 return (Class<T>) proxyClass.getInterfaces()[0]; 359 } 360 361 362 public static boolean isGetterMethod(Method method, String property) { 363 String methodName = method.getName(); 364 if (methodName.startsWith("get") && methodName.length() > 3) { 365 return StringUtil.firstCharToUpperCase(property).equals(methodName.substring(3)); 366 } else if (methodName.startsWith("is") && methodName.length() > 2) { 367 return StringUtil.firstCharToUpperCase(property).equals(methodName.substring(2)); 368 } else { 369 return false; 370 } 371 } 372 373 public static boolean isObjectMethod(String methodName) { 374 return ArrayUtil.contains(OBJECT_METHODS, methodName); 375 } 376 377}