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