Java tutorial
/* * Copyright 2007-2107 the original author or authors. * * 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 net.ymate.platform.commons.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.net.JarURLConnection; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import net.ymate.platform.commons.lang.PairObject; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.esotericsoftware.reflectasm.MethodAccess; import com.thoughtworks.paranamer.AdaptiveParanamer; /** * <p> * ClassUtils * </p> * <p> * ? * </p> * * @author (suninformation@163.com) * @version 0.0.0 * <table style="border:1px solid gray;"> * <tr> * <th width="100px">?</th><th width="100px"></th><th * width="100px"></th><th width="100px"></th> * </tr> * <!-- Table ?? --> * <tr> * <td>0.0.0</td> * <td></td> * <td></td> * <td>2012-12-5?6:41:23</td> * </tr> * </table> */ public class ClassUtils { private static final Log _LOG = LogFactory.getLog(ClassUtils.class); private static InnerClassLoader _INNER_CLASS_LOADER = new InnerClassLoader(new URL[] {}, ClassUtils.class.getClassLoader()); /** * @return */ public static ClassLoader getDefaultClassLoader() { return _INNER_CLASS_LOADER; } /** * ?packageNamesclazz??? * * @param clazz * @param packageNames * @param callingClass * @return */ public static <T> Collection<Class<T>> findClassByClazz(Class<T> clazz, Collection<String> packageNames, Class<?> callingClass) { List<Class<T>> _returnValue = new ArrayList<Class<T>>(); try { for (String _packageName : packageNames) { Iterator<URL> _urls = ResourceUtils.getResources(_packageName.replaceAll("\\.", "/"), callingClass, true); while (_urls.hasNext()) { URL _url = _urls.next(); __doProcessURL(_url, _returnValue, clazz, _packageName, callingClass); } } } catch (Exception e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } return _returnValue; } private static <T> void __doProcessURL(URL _url, Collection<Class<T>> collections, Class<T> clazz, String _packageName, Class<?> callingClass) throws URISyntaxException, IOException { if (_url.getProtocol().equalsIgnoreCase("file") || _url.getProtocol().equalsIgnoreCase("vfsfile")) { File[] _files = new File(_url.toURI()).listFiles(); for (File _file : _files != null ? _files : new File[0]) { __doFindClassByClazz(collections, clazz, _packageName, _file, callingClass); } } else if (_url.getProtocol().equalsIgnoreCase("jar") || _url.getProtocol().equalsIgnoreCase("wsjar")) { JarFile _jarFileObj = ((JarURLConnection) _url.openConnection()).getJarFile(); __doFindClassByJar(collections, clazz, _packageName, _jarFileObj, callingClass); } else if (_url.getProtocol().equalsIgnoreCase("zip")) { __doFindClassByZip(collections, clazz, _packageName, _url, callingClass); } } @SuppressWarnings("unchecked") protected static <T> void __doFindClassByZip(Collection<Class<T>> collections, Class<T> clazz, String packageName, URL zipUrl, Class<?> callingClass) { ZipInputStream _zipStream = null; try { String _zipFilePath = zipUrl.toString(); if (_zipFilePath.indexOf('!') > 0) { _zipFilePath = StringUtils.substringBetween(zipUrl.toString(), "zip:", "!"); } else { _zipFilePath = StringUtils.substringAfter(zipUrl.toString(), "zip:"); } _zipStream = new ZipInputStream(new FileInputStream(new File(_zipFilePath))); ZipEntry _zipEntry = null; while (null != (_zipEntry = _zipStream.getNextEntry())) { if (!_zipEntry.isDirectory()) { if (_zipEntry.getName().endsWith(".class") && _zipEntry.getName().indexOf('$') < 0) { Class<?> _class = __doProcessEntry(zipUrl, _zipEntry); if (_class != null) { if (clazz.isAnnotation()) { if (isAnnotationOf(_class, (Class<Annotation>) clazz)) { collections.add((Class<T>) _class); } } else if (clazz.isInterface()) { if (isInterfaceOf(_class, clazz)) { collections.add((Class<T>) _class); } } else if (isSubclassOf(_class, clazz)) { collections.add((Class<T>) _class); } } } } _zipStream.closeEntry(); } } catch (Exception e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } finally { if (_zipStream != null) { try { _zipStream.close(); } catch (IOException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } } } private static Class<?> __doProcessEntry(URL zipUrl, ZipEntry entry) { if (entry.getName().endsWith(".class")) { try { _INNER_CLASS_LOADER.addURL(zipUrl); // ~~?? String _className = entry.getName().replace("/", "."); _className = _className.substring(0, _className.length() - 6); return Class.forName(_className, true, _INNER_CLASS_LOADER); } catch (Throwable e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } return null; } /** * ?.class??'$'??Java"com/ymatesoft/common/A.class"~"com.ymatesoft.common.A" * * @param collections * @param clazz * @param packageName * @param packageFile * @param callingClass */ @SuppressWarnings("unchecked") protected static <T> void __doFindClassByClazz(Collection<Class<T>> collections, Class<T> clazz, String packageName, File packageFile, Class<?> callingClass) { if (packageFile.isFile()) { try { if (packageFile.getName().endsWith(".class") && packageFile.getName().indexOf('$') < 0) { Class<?> _class = ResourceUtils.loadClass( packageName + "." + packageFile.getName().replace(".class", ""), callingClass); if (_class != null) { if (clazz.isAnnotation()) { if (isAnnotationOf(_class, (Class<Annotation>) clazz)) { collections.add((Class<T>) _class); } } else if (clazz.isInterface()) { if (isInterfaceOf(_class, clazz)) { collections.add((Class<T>) _class); } } else if (isSubclassOf(_class, clazz)) { collections.add((Class<T>) _class); } } } } catch (NoClassDefFoundError e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } catch (ClassNotFoundException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } else { File[] _tmpfiles = packageFile.listFiles(); for (File _tmpFile : _tmpfiles != null ? _tmpfiles : new File[0]) { __doFindClassByClazz(collections, clazz, packageName + "." + packageFile.getName(), _tmpFile, callingClass); } } } /** * ? Jar .class??'$'??Java"com/ymatesoft/common/A.class"~"com.ymatesoft.common.A" * * @param collections * @param clazz * @param packageName * @param jarFile * @param callingClass */ @SuppressWarnings("unchecked") protected static <T> void __doFindClassByJar(Collection<Class<T>> collections, Class<T> clazz, String packageName, JarFile jarFile, Class<?> callingClass) { Enumeration<JarEntry> _entriesEnum = jarFile.entries(); for (; _entriesEnum.hasMoreElements();) { JarEntry _entry = _entriesEnum.nextElement(); // ??? '/' '.'?.class???'$'?? String _className = _entry.getName().replaceAll("/", "."); if (_className.endsWith(".class") && _className.indexOf('$') < 0) { if (_className.startsWith(packageName)) { Class<?> _class = null; try { _class = ResourceUtils.loadClass(_className.substring(0, _className.lastIndexOf('.')), callingClass); if (_class != null) { if (clazz.isAnnotation()) { if (isAnnotationOf(_class, (Class<Annotation>) clazz)) { collections.add((Class<T>) _class); } } else if (clazz.isInterface()) { if (isInterfaceOf(_class, clazz)) { collections.add((Class<T>) _class); } } else if (isSubclassOf(_class, clazz)) { collections.add((Class<T>) _class); } } } catch (NoClassDefFoundError e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } catch (ClassNotFoundException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } } } } static class InnerClassLoader extends URLClassLoader { public InnerClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } @Override public void addURL(URL url) { super.addURL(url); } } /** * ????? * * @param <T> * @param className ?? * @param interfaceClass ???? * @param callingClass * @return ??? */ @SuppressWarnings("unchecked") public static <T> T impl(String className, Class<T> interfaceClass, Class<?> callingClass) { if (StringUtils.isNotBlank(className)) { try { Class<?> implClass = ResourceUtils.loadClass(className, callingClass); if (interfaceClass == null || interfaceClass.isAssignableFrom(implClass)) { try { return (T) implClass.newInstance(); } catch (InstantiationException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } catch (IllegalAccessException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } } catch (ClassNotFoundException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } return null; } @SuppressWarnings("unchecked") public static <T> T impl(Class<?> implClass, Class<T> interfaceClass) { if (implClass != null) { if (interfaceClass == null || interfaceClass.isAssignableFrom(implClass)) { try { return (T) implClass.newInstance(); } catch (InstantiationException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } catch (IllegalAccessException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } } } return null; } /** * clazz?superClass? * * @param clazz * @param superClass * @return */ public static boolean isSubclassOf(Class<?> clazz, Class<?> superClass) { boolean _flag = false; do { Class<?> cc = clazz.getSuperclass(); if (cc != null) { if (cc.equals(superClass)) { _flag = true; break; } else { clazz = clazz.getSuperclass(); } } else { break; } } while ((clazz != null && clazz != Object.class)); return _flag; } /** * @param clazz * @param interfaceClass ? * @return clazz?interfaceClass? */ public static boolean isInterfaceOf(Class<?> clazz, Class<?> interfaceClass) { boolean _flag = false; do { for (Class<?> cc : clazz.getInterfaces()) { if (cc.equals(interfaceClass)) { _flag = true; } } clazz = clazz.getSuperclass(); } while (!_flag && (clazz != null && clazz != Object.class)); return _flag; } /** * @param target ??Field?MethodClass * @param annotationClass * @return target?annotationClass */ public static boolean isAnnotationOf(Object target, Class<? extends Annotation> annotationClass) { if (target instanceof Field) { if (((Field) target).isAnnotationPresent(annotationClass)) { return true; } } else if (target instanceof Method) { if (((Method) target).isAnnotationPresent(annotationClass)) { return true; } } else if (target instanceof Class) { if (((Class<?>) target).isAnnotationPresent(annotationClass)) { return true; } } return false; } /** * @param clazz * @return ???? */ public static String[] getInterfaceNames(Class<?> clazz) { Class<?>[] interfaces = clazz.getInterfaces(); List<String> names = new ArrayList<String>(); for (Class<?> i : interfaces) { names.add(i.getName()); } return names.toArray(new String[names.size()]); } /** * @param clazz * @return ????, ??RawType */ public static List<Class<?>> getParameterizedTypes(Class<?> clazz) { List<Class<?>> _clazzs = new ArrayList<Class<?>>(); Type _types = clazz.getGenericSuperclass(); if (ParameterizedType.class.isAssignableFrom(_types.getClass())) { for (Type _type : ((ParameterizedType) _types).getActualTypeArguments()) { if (ParameterizedType.class.isAssignableFrom(_type.getClass())) { _clazzs.add((Class<?>) ((ParameterizedType) _type).getRawType()); } else { _clazzs.add((Class<?>) _type); } } } else { _clazzs.add((Class<?>) _types); } return _clazzs; } /** * ?clazzField? * * @param clazz * @param parent ?? * @return Field? */ public static List<Field> getFields(Class<?> clazz, boolean parent) { List<Field> fieldList = new ArrayList<Field>(); Class<?> clazzin = clazz; do { if (clazzin == null) { break; } fieldList.addAll(Arrays.asList(clazzin.getDeclaredFields())); if (parent) { clazzin = clazzin.getSuperclass(); } else { clazzin = null; } } while (true); return fieldList; } /** * @param <A> * @param clazz * @param annotationClazz * @param onlyFirst * @return ?clazz?annotationClazz */ public static <A extends Annotation> List<PairObject<Field, A>> getFieldAnnotations(Class<?> clazz, Class<A> annotationClazz, boolean onlyFirst) { List<PairObject<Field, A>> _annotations = new ArrayList<PairObject<Field, A>>(); for (Field _field : ClassUtils.getFields(clazz, true)) { A _annotation = _field.getAnnotation(annotationClazz); if (_annotation != null) { _annotations.add(new PairObject<Field, A>(_field, _annotation)); if (onlyFirst) { break; } } } return _annotations; } /** * @param method * @return ???? */ public static String[] getMethodParamNames(final Method method) { return new AdaptiveParanamer().lookupParameterNames(method); } /** * @param clazz * @return */ public static Class<?> getArrayClassType(Class<?> clazz) { try { return Class.forName(StringUtils.substringBetween(clazz.getName(), "[L", ";")); } catch (ClassNotFoundException e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } return null; } /** * @param clazz * @return ??? */ public static <T> ClassBeanWrapper<T> wrapper(Class<T> clazz) { try { return wrapper(clazz.newInstance()); } catch (Exception e) { _LOG.warn("", RuntimeUtils.unwrapThrow(e)); } return null; } /** * @param target * @return ??? */ public static <T> ClassBeanWrapper<T> wrapper(T target) { return new ClassBeanWrapper<T>(target); } /** * <p> * ClassBeanWrapper * </p> * <p> * ?? * </p> * * @author (suninformation@163.com) * @version 0.0.0 * <table style="border:1px solid gray;"> * <tr> * <th width="100px">?</th><th width="100px"></th><th * width="100px"></th><th width="100px"></th> * </tr> * <!-- Table ?? --> * <tr> * <td>0.0.0</td> * <td></td> * <td></td> * <td>2012-12-23?12:46:50</td> * </tr> * </table> */ public static class ClassBeanWrapper<T> { protected static Map<Class<?>, MethodAccess> __methodCache = new WeakHashMap<Class<?>, MethodAccess>(); private T target; private Map<String, Field> _fields; private MethodAccess methodAccess; /** * * @param target */ protected ClassBeanWrapper(T target) { this.target = target; this._fields = new HashMap<String, Field>(); for (Field _field : getFields(target.getClass(), true)/*target.getClass().getDeclaredFields()*/) { if (Modifier.isStatic(_field.getModifiers())) { continue; } this._fields.put(_field.getName(), _field); } // this.methodAccess = __methodCache.get(target.getClass()); if (this.methodAccess == null) { this.methodAccess = MethodAccess.get(target.getClass()); __methodCache.put(target.getClass(), this.methodAccess); } } public T getTarget() { return target; } public Set<String> getFieldNames() { return _fields.keySet(); } public Annotation[] getFieldAnnotations(String fieldName) { return getField(fieldName).getAnnotations(); } public Field getField(String fieldName) { return _fields.get(StringUtils.uncapitalize(fieldName)); } public Class<?> getFieldType(String fieldName) { return getField(fieldName).getType(); } public ClassBeanWrapper<T> setValue(String fieldName, Object value) { methodAccess.invoke(this.target, "set" + StringUtils.capitalize(fieldName), value); return this; } public Object getValue(String fieldName) { return methodAccess.invoke(this.target, "get" + StringUtils.capitalize(fieldName)); } /** * ???dist * * @param dist * @param <D> * @return */ public <D> D copy(D dist) { ClassBeanWrapper<D> _wrapDist = wrapper(dist); for (String _fieldName : getFieldNames()) { if (_wrapDist.getFieldNames().contains(_fieldName)) { try { _wrapDist.setValue(_fieldName, getValue(_fieldName)); } catch (Exception e) { continue; } } } return _wrapDist.getTarget(); } } }