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 java.lang.reflect.*; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.List; 023import java.util.function.Predicate; 024 025/** 026 * 类实例创建者创建者 027 * Created by michael on 17/3/21. 028 */ 029public class ClassUtil { 030 031 private ClassUtil() {} 032 033 //proxy frameworks 034 private static final List<String> PROXY_CLASS_NAMES = Arrays.asList("net.sf.cglib.proxy.Factory" 035 // cglib 036 , "org.springframework.cglib.proxy.Factory" 037 038 // javassist 039 , "javassist.util.proxy.ProxyObject" 040 , "org.apache.ibatis.javassist.util.proxy.ProxyObject"); 041 private static final String ENHANCER_BY = "$$EnhancerBy"; 042 private static final String JAVASSIST_BY = "_$$_"; 043 044 public static boolean isProxy(Class<?> clazz) { 045 for (Class<?> cls : clazz.getInterfaces()) { 046 if (PROXY_CLASS_NAMES.contains(cls.getName())) { 047 return true; 048 } 049 } 050 //java proxy 051 return Proxy.isProxyClass(clazz); 052 } 053 054 public static <T> Class<T> getUsefulClass(Class<T> clazz) { 055 if (isProxy(clazz)) { 056 return getJdkProxySuperClass(clazz); 057 } 058 059 //ControllerTest$ServiceTest$$EnhancerByGuice$$40471411#hello -------> Guice 060 //com.demo.blog.Blog$$EnhancerByCGLIB$$69a17158 ----> CGLIB 061 //io.jboot.test.app.TestAppListener_$$_jvstb9f_0 ------> javassist 062 063 final String name = clazz.getName(); 064 if (name.contains(ENHANCER_BY) || name.contains(JAVASSIST_BY)) { 065 return (Class<T>) clazz.getSuperclass(); 066 } 067 068 return clazz; 069 } 070 071 072 public static Class<?> getWrapType(Class<?> clazz) { 073 if (clazz == null || !clazz.isPrimitive()) { 074 return clazz; 075 } 076 if (clazz == Integer.TYPE) { 077 return Integer.class; 078 } else if (clazz == Long.TYPE) { 079 return Long.class; 080 } else if (clazz == Boolean.TYPE) { 081 return Boolean.class; 082 } else if (clazz == Float.TYPE) { 083 return Float.class; 084 } else if (clazz == Double.TYPE) { 085 return Double.class; 086 } else if (clazz == Short.TYPE) { 087 return Short.class; 088 } else if (clazz == Character.TYPE) { 089 return Character.class; 090 } else if (clazz == Byte.TYPE) { 091 return Byte.class; 092 } else if (clazz == Void.TYPE) { 093 return Void.class; 094 } 095 return clazz; 096 } 097 098 099 public static boolean isArray(Class<?> clazz) { 100 return clazz.isArray() 101 || clazz == int[].class 102 || clazz == long[].class 103 || clazz == short[].class 104 || clazz == float[].class 105 || clazz == double[].class; 106 } 107 108 109 public static <T> T newInstance(Class<T> clazz) { 110 try { 111 Constructor<?> defaultConstructor = null; 112 Constructor<?> otherConstructor = null; 113 114 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); 115 for (Constructor<?> constructor : declaredConstructors) { 116 if (constructor.getParameterCount() == 0) { 117 defaultConstructor = constructor; 118 } else if (Modifier.isPublic(constructor.getModifiers())) { 119 otherConstructor = constructor; 120 } 121 } 122 if (defaultConstructor != null) { 123 return (T) defaultConstructor.newInstance(); 124 } else if (otherConstructor != null) { 125 Class<?>[] parameterTypes = otherConstructor.getParameterTypes(); 126 Object[] parameters = new Object[parameterTypes.length]; 127 for (int i = 0; i < parameterTypes.length; i++) { 128 if (parameterTypes[i].isPrimitive()) { 129 parameters[i] = ConvertUtil.getPrimitiveDefaultValue(parameterTypes[i]); 130 } else { 131 parameters[i] = null; 132 } 133 } 134 return (T) otherConstructor.newInstance(parameters); 135 } 136 throw new IllegalArgumentException("the class \"" + clazz.getName() + "\" has no constructor."); 137 } catch (Exception e) { 138 throw new RuntimeException("Can not newInstance class: " + clazz.getName()); 139 } 140 } 141 142 143 public static <T> T newInstance(Class<T> clazz, Object... paras) { 144 try { 145 Constructor<?>[] constructors = clazz.getDeclaredConstructors(); 146 for (Constructor<?> constructor : constructors) { 147 if (isMatchedParas(constructor, paras)) { 148 Object ret = constructor.newInstance(paras); 149 return (T) ret; 150 } 151 } 152 throw new IllegalArgumentException("Can not find constructor by paras: \"" + Arrays.toString(paras) + "\" in class[" + clazz.getName() + "]"); 153 } catch (Exception e) { 154 e.printStackTrace(); 155 } 156 157 return null; 158 } 159 160 161 private static boolean isMatchedParas(Constructor<?> constructor, Object[] paras) { 162 if (constructor.getParameterCount() == 0) { 163 return paras == null || paras.length == 0; 164 } 165 166 if (constructor.getParameterCount() > 0 167 && (paras == null || paras.length != constructor.getParameterCount())) { 168 return false; 169 } 170 171 Class<?>[] parameterTypes = constructor.getParameterTypes(); 172 for (int i = 0; i < parameterTypes.length; i++) { 173 Class<?> parameterType = parameterTypes[i]; 174 Object paraObject = paras[i]; 175 if (paraObject != null && !parameterType.isAssignableFrom(paraObject.getClass())) { 176 return false; 177 } 178 } 179 180 return true; 181 } 182 183 184 public static List<Field> getAllFields(Class<?> clazz) { 185 List<Field> fields = new ArrayList<>(); 186 doGetFields(clazz, fields, null, false); 187 return fields; 188 } 189 190 public static List<Field> getAllFields(Class<?> clazz, Predicate<Field> predicate) { 191 List<Field> fields = new ArrayList<>(); 192 doGetFields(clazz, fields, predicate, false); 193 return fields; 194 } 195 196 public static Field getFirstField(Class<?> clazz, Predicate<Field> predicate) { 197 List<Field> fields = new ArrayList<>(); 198 doGetFields(clazz, fields, predicate, true); 199 return fields.isEmpty() ? null : fields.get(0); 200 } 201 202 private static void doGetFields(Class<?> clazz, List<Field> fields, Predicate<Field> predicate, boolean firstOnly) { 203 if (clazz == null || clazz == Object.class) { 204 return; 205 } 206 207 Field[] declaredFields = clazz.getDeclaredFields(); 208 for (Field declaredField : declaredFields) { 209 if (predicate == null || predicate.test(declaredField)) { 210 fields.add(declaredField); 211 if (firstOnly) { 212 break; 213 } 214 } 215 } 216 217 if (firstOnly && !fields.isEmpty()) { 218 return; 219 } 220 221 doGetFields(clazz.getSuperclass(), fields, predicate, firstOnly); 222 } 223 224 public static List<Method> getAllMethods(Class<?> clazz) { 225 List<Method> methods = new ArrayList<>(); 226 doGetMethods(clazz, methods, null, false); 227 return methods; 228 } 229 230 public static List<Method> getAllMethods(Class<?> clazz, Predicate<Method> predicate) { 231 List<Method> methods = new ArrayList<>(); 232 doGetMethods(clazz, methods, predicate, false); 233 return methods; 234 } 235 236 public static Method getFirstMethod(Class<?> clazz, Predicate<Method> predicate) { 237 List<Method> methods = new ArrayList<>(); 238 doGetMethods(clazz, methods, predicate, true); 239 return methods.isEmpty() ? null : methods.get(0); 240 } 241 242 243 private static void doGetMethods(Class<?> clazz, List<Method> methods, Predicate<Method> predicate, boolean firstOnly) { 244 if (clazz == null || clazz == Object.class) { 245 return; 246 } 247 248 Method[] declaredMethods = clazz.getDeclaredMethods(); 249 for (Method method : declaredMethods) { 250 if (predicate == null || predicate.test(method)) { 251 methods.add(method); 252 if (firstOnly) { 253 break; 254 } 255 } 256 } 257 258 if (firstOnly && !methods.isEmpty()) { 259 return; 260 } 261 262 doGetMethods(clazz.getSuperclass(), methods, predicate, firstOnly); 263 } 264 265 266 private static <T> Class<T> getJdkProxySuperClass(Class<T> clazz) { 267 final Class<?> proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), clazz.getInterfaces()); 268 return (Class<T>) proxyClass.getInterfaces()[0]; 269 } 270 271}