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