All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.activiti.engine.impl.util.ReflectUtil Maven / Gradle / Ivy

The newest version!
/* 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 org.activiti.engine.impl.util;

import org.activiti.engine.ActivitiClassLoadingException;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Arrays;
import java.util.Locale;
import java.util.regex.Pattern;

/**

 */
public abstract class ReflectUtil {

  private static final Logger LOG = LoggerFactory.getLogger(ReflectUtil.class);

  private static final Pattern GETTER_PATTERN = Pattern.compile("(get|is)[A-Z].*");
  private static final Pattern SETTER_PATTERN = Pattern.compile("set[A-Z].*");

  public static ClassLoader getClassLoader() {
    ClassLoader loader = getCustomClassLoader();
    if (loader == null) {
      loader = Thread.currentThread().getContextClassLoader();
    }
    return loader;
  }

  public static Class loadClass(String className) {
    Class clazz = null;
    ClassLoader classLoader = getCustomClassLoader();

    // First exception in chain of classloaders will be used as cause when
    // no class is found in any of them
    Throwable throwable = null;

    if (classLoader != null) {
      try {
        LOG.trace("Trying to load class with custom classloader: {}", className);
        clazz = loadClass(classLoader, className);
      } catch (Throwable t) {
        throwable = t;
      }
    }
    if (clazz == null) {
      try {
        LOG.trace("Trying to load class with current thread context classloader: {}", className);
        clazz = loadClass(Thread.currentThread().getContextClassLoader(), className);
      } catch (Throwable t) {
        if (throwable == null) {
          throwable = t;
        }
      }
      if (clazz == null) {
        try {
          LOG.trace("Trying to load class with local classloader: {}", className);
          clazz = loadClass(ReflectUtil.class.getClassLoader(), className);
        } catch (Throwable t) {
          if (throwable == null) {
            throwable = t;
          }
        }
      }
    }

    if (clazz == null) {
      throw new ActivitiClassLoadingException(className, throwable);
    }
    return clazz;
  }

  public static InputStream getResourceAsStream(String name) {
    InputStream resourceStream = null;
    ClassLoader classLoader = getCustomClassLoader();
    if (classLoader != null) {
      resourceStream = classLoader.getResourceAsStream(name);
    }

    if (resourceStream == null) {
      // Try the current Thread context classloader
      classLoader = Thread.currentThread().getContextClassLoader();
      resourceStream = classLoader.getResourceAsStream(name);
      if (resourceStream == null) {
        // Finally, try the classloader for this class
        classLoader = ReflectUtil.class.getClassLoader();
        resourceStream = classLoader.getResourceAsStream(name);
      }
    }
    return resourceStream;
  }

  public static URL getResource(String name) {
    URL url = null;
    ClassLoader classLoader = getCustomClassLoader();
    if (classLoader != null) {
      url = classLoader.getResource(name);
    }
    if (url == null) {
      // Try the current Thread context classloader
      classLoader = Thread.currentThread().getContextClassLoader();
      url = classLoader.getResource(name);
      if (url == null) {
        // Finally, try the classloader for this class
        classLoader = ReflectUtil.class.getClassLoader();
        url = classLoader.getResource(name);
      }
    }

    return url;
  }

  public static Object instantiate(String className) {
    try {
      Class clazz = loadClass(className);
      return clazz.newInstance();
    } catch (Exception e) {
      throw new ActivitiException("couldn't instantiate class " + className, e);
    }
  }

  public static Object invoke(Object target, String methodName, Object[] args) {
    try {
      Class clazz = target.getClass();
      Method method = findMethod(clazz, methodName, args);
      method.setAccessible(true);
      return method.invoke(target, args);
    } catch (Exception e) {
      throw new ActivitiException("couldn't invoke " + methodName + " on " + target, e);
    }
  }

  /**
   * Returns the field of the given object or null if it doesn't exist.
   */
  public static Field getField(String fieldName, Object object) {
    return getField(fieldName, object.getClass());
  }

  /**
   * Returns the field of the given class or null if it doesn't exist.
   */
  public static Field getField(String fieldName, Class clazz) {
    Field field = null;
    try {
      field = clazz.getDeclaredField(fieldName);
    } catch (SecurityException e) {
      throw new ActivitiException("not allowed to access field " + field + " on class " + clazz.getCanonicalName());
    } catch (NoSuchFieldException e) {
      // for some reason getDeclaredFields doesn't search superclasses
      // (which getFields() does ... but that gives only public fields)
      Class superClass = clazz.getSuperclass();
      if (superClass != null) {
        return getField(fieldName, superClass);
      }
    }
    return field;
  }

  public static void setField(Field field, Object object, Object value) {
    try {
      field.setAccessible(true);
      field.set(object, value);
    } catch (IllegalArgumentException e) {
      throw new ActivitiException("Could not set field " + field.toString(), e);
    } catch (IllegalAccessException e) {
      throw new ActivitiException("Could not set field " + field.toString(), e);
    }
  }

  /**
   * Returns the setter-method for the given field name or null if no setter exists.
   */
  public static Method getSetter(String fieldName, Class clazz, Class fieldType) {
    String setterName = "set" + Character.toTitleCase(fieldName.charAt(0)) + fieldName.substring(1, fieldName.length());
    try {
      // Using getMethods(), getMethod(...) expects exact parameter type
      // matching and ignores inheritance-tree.
      Method[] methods = clazz.getMethods();
      for (Method method : methods) {
        if (method.getName().equals(setterName)) {
          Class[] paramTypes = method.getParameterTypes();
          if (paramTypes != null && paramTypes.length == 1 && paramTypes[0].isAssignableFrom(fieldType)) {
            return method;
          }
        }
      }
      return null;
    } catch (SecurityException e) {
      throw new ActivitiException("Not allowed to access method " + setterName + " on class " + clazz.getCanonicalName());
    }
  }

  private static Method findMethod(Class clazz, String methodName, Object[] args) {
    for (Method method : clazz.getDeclaredMethods()) {
      // TODO add parameter matching
      if (method.getName().equals(methodName) && matches(method.getParameterTypes(), args)) {
        return method;
      }
    }
    Class superClass = clazz.getSuperclass();
    if (superClass != null) {
      return findMethod(superClass, methodName, args);
    }
    return null;
  }

  public static Object instantiate(String className, Object[] args) {
    Class clazz = loadClass(className);
    Constructor constructor = findMatchingConstructor(clazz, args);
    if (constructor == null) {
      throw new ActivitiException("couldn't find constructor for " + className + " with args " + Arrays.asList(args));
    }
    try {
      return constructor.newInstance(args);
    } catch (Exception e) {
      throw new ActivitiException("couldn't find constructor for " + className + " with args " + Arrays.asList(args), e);
    }
  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
  private static  Constructor findMatchingConstructor(Class clazz, Object[] args) {
    for (Constructor constructor : clazz.getDeclaredConstructors()) { // cannot
                                                                      // use
                                                                      // 
                                                                      // or
                                                                      // 
                                                                      // due
                                                                      // to
                                                                      // JDK
                                                                      // 5/6
                                                                      // incompatibility
      if (matches(constructor.getParameterTypes(), args)) {
        return constructor;
      }
    }
    return null;
  }

  private static boolean matches(Class[] parameterTypes, Object[] args) {
    if ((parameterTypes == null) || (parameterTypes.length == 0)) {
      return ((args == null) || (args.length == 0));
    }
    if ((args == null) || (parameterTypes.length != args.length)) {
      return false;
    }
    for (int i = 0; i < parameterTypes.length; i++) {
      if ((args[i] != null) && (!parameterTypes[i].isAssignableFrom(args[i].getClass()))) {
        return false;
      }
    }
    return true;
  }

  private static ClassLoader getCustomClassLoader() {
    ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
    if (processEngineConfiguration != null) {
      final ClassLoader classLoader = processEngineConfiguration.getClassLoader();
      if (classLoader != null) {
        return classLoader;
      }
    }
    return null;
  }

  private static Class loadClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
    ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
    boolean useClassForName = processEngineConfiguration == null || processEngineConfiguration.isUseClassForNameClassLoading();
    return useClassForName ? Class.forName(className, true, classLoader) : classLoader.loadClass(className);
  }

  public static boolean isGetter(Method method) {
    String name = method.getName();
    Class type = method.getReturnType();
    Class params[] = method.getParameterTypes();

    if (!GETTER_PATTERN.matcher(name).matches()) {
      return false;
    }

    // special for isXXX boolean
    if (name.startsWith("is")) {
      return params.length == 0 && type.getSimpleName().equalsIgnoreCase("boolean");
    }

    return params.length == 0 && !type.equals(Void.TYPE);
  }

  public static boolean isSetter(Method method, boolean allowBuilderPattern) {
    String name = method.getName();
    Class type = method.getReturnType();
    Class params[] = method.getParameterTypes();

    if (!SETTER_PATTERN.matcher(name).matches()) {
      return false;
    }

    return params.length == 1 && (type.equals(Void.TYPE) || (allowBuilderPattern && method.getDeclaringClass().isAssignableFrom(type)));
  }

  public static boolean isSetter(Method method) {
    return isSetter(method, false);
  }

  public static String getGetterShorthandName(Method method) {
    if (!isGetter(method)) {
      return method.getName();
    }

    String name = method.getName();
    if (name.startsWith("get")) {
      name = name.substring(3);
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    } else if (name.startsWith("is")) {
      name = name.substring(2);
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }

  public static String getSetterShorthandName(Method method) {
    if (!isSetter(method)) {
      return method.getName();
    }

    String name = method.getName();
    if (name.startsWith("set")) {
      name = name.substring(3);
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy