Search in sources :

Example 11 with LoaderClassPath

use of org.hotswap.agent.javassist.LoaderClassPath in project HotswapAgent by HotswapProjects.

the class PluginClassFileTransformer method createCtClass.

/**
 * Creats javaassist CtClass for bytecode manipulation. Add default
 * classloader.
 *
 * @param bytes new class definition
 * @param classLoader loader
 * @return created class
 * @throws NotFoundException
 */
private static CtClass createCtClass(byte[] bytes, ClassLoader classLoader) throws IOException {
    ClassPool cp = new ClassPool();
    cp.appendSystemPath();
    cp.appendClassPath(new LoaderClassPath(classLoader));
    return cp.makeClass(new ByteArrayInputStream(bytes));
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) ClassPool(org.hotswap.agent.javassist.ClassPool) LoaderClassPath(org.hotswap.agent.javassist.LoaderClassPath)

Example 12 with LoaderClassPath

use of org.hotswap.agent.javassist.LoaderClassPath in project HotswapAgent by HotswapProjects.

the class PluginClassFileTransformer method transform.

/**
 * Transformation callback as registered in initMethod:
 * hotswapTransformer.registerTransformer(). Resolve method parameters to
 * actual values, provide convenience parameters of javassist to streamline
 * the transformation.
 */
private static byte[] transform(PluginManager pluginManager, PluginAnnotation<OnClassLoadEvent> pluginAnnotation, ClassLoader classLoader, String className, Class<?> redefiningClass, ProtectionDomain protectionDomain, byte[] bytes) {
    LOGGER.trace("Transforming.... '{}' using: '{}'", className, pluginAnnotation);
    // skip synthetic classes
    if (pluginAnnotation.getAnnotation().skipSynthetic()) {
        if (isSyntheticClass(className) || (redefiningClass != null && redefiningClass.isSynthetic())) {
            return bytes;
        }
    }
    // skip anonymous class
    if (pluginAnnotation.getAnnotation().skipAnonymous()) {
        if (className.matches("\\$\\d+$")) {
            return bytes;
        }
    }
    // ensure classloader initiated
    if (classLoader != null) {
        pluginManager.initClassLoader(classLoader, protectionDomain);
    }
    // default result
    byte[] result = bytes;
    // we may need to crate CtClass on behalf of the client and close it
    // after invocation.
    CtClass ctClass = null;
    List<Object> args = new ArrayList<Object>();
    for (Class<?> type : pluginAnnotation.getMethod().getParameterTypes()) {
        if (type.isAssignableFrom(ClassLoader.class)) {
            args.add(classLoader);
        } else if (type.isAssignableFrom(String.class)) {
            args.add(className);
        } else if (type.isAssignableFrom(Class.class)) {
            args.add(redefiningClass);
        } else if (type.isAssignableFrom(ProtectionDomain.class)) {
            args.add(protectionDomain);
        } else if (type.isAssignableFrom(byte[].class)) {
            args.add(bytes);
        } else if (type.isAssignableFrom(ClassPool.class)) {
            ClassPool classPool = new ClassPool();
            classPool.appendSystemPath();
            LOGGER.trace("Adding loader classpath " + classLoader);
            classPool.appendClassPath(new LoaderClassPath(classLoader));
            args.add(classPool);
        } else if (type.isAssignableFrom(CtClass.class)) {
            try {
                ctClass = createCtClass(bytes, classLoader);
                args.add(ctClass);
            } catch (IOException e) {
                LOGGER.error("Unable create CtClass for '" + className + "'.", e);
                return result;
            }
        } else if (type.isAssignableFrom(LoadEvent.class)) {
            args.add(redefiningClass == null ? LoadEvent.DEFINE : LoadEvent.REDEFINE);
        } else if (type.isAssignableFrom(AppClassLoaderExecutor.class)) {
            args.add(new AppClassLoaderExecutor(classLoader, protectionDomain));
        } else {
            LOGGER.error("Unable to call init method on plugin '" + pluginAnnotation.getPluginClass() + "'." + " Method parameter type '" + type + "' is not recognized for @Init annotation.");
            return result;
        }
    }
    try {
        // call method on plugin (or if plugin null -> static method)
        Object resultObject = pluginAnnotation.getMethod().invoke(pluginAnnotation.getPlugin(), args.toArray());
        if (resultObject == null) {
        // Ok, nothing has changed
        } else if (resultObject instanceof byte[]) {
            result = (byte[]) resultObject;
        } else if (resultObject instanceof CtClass) {
            result = ((CtClass) resultObject).toBytecode();
            // instance than we created (it is closed elsewhere)
            if (resultObject != ctClass) {
                ((CtClass) resultObject).detach();
            }
        } else {
            LOGGER.error("Unknown result of @OnClassLoadEvent method '" + result.getClass().getName() + "'.");
        }
        // close CtClass if created from here
        if (ctClass != null) {
            // if result not set from the method, use class
            if (resultObject == null) {
                result = ctClass.toBytecode();
            }
            ctClass.detach();
        }
    } catch (IllegalAccessException e) {
        LOGGER.error("IllegalAccessException in transform method on plugin '" + pluginAnnotation.getPluginClass() + "' class '" + className + "'.", e);
    } catch (InvocationTargetException e) {
        LOGGER.error("InvocationTargetException in transform method on plugin '" + pluginAnnotation.getPluginClass() + "' class '" + className + "'.", e);
    } catch (CannotCompileException e) {
        LOGGER.error("Cannot compile class after manipulation on plugin '" + pluginAnnotation.getPluginClass() + "' class '" + className + "'.", e);
    } catch (IOException e) {
        LOGGER.error("IOException in transform method on plugin '" + pluginAnnotation.getPluginClass() + "' class '" + className + "'.", e);
    }
    return result;
}
Also used : ProtectionDomain(java.security.ProtectionDomain) LoadEvent(org.hotswap.agent.annotation.LoadEvent) OnClassLoadEvent(org.hotswap.agent.annotation.OnClassLoadEvent) ArrayList(java.util.ArrayList) ClassPool(org.hotswap.agent.javassist.ClassPool) LoaderClassPath(org.hotswap.agent.javassist.LoaderClassPath) IOException(java.io.IOException) CannotCompileException(org.hotswap.agent.javassist.CannotCompileException) InvocationTargetException(java.lang.reflect.InvocationTargetException) CtClass(org.hotswap.agent.javassist.CtClass) AppClassLoaderExecutor(org.hotswap.agent.util.AppClassLoaderExecutor)

Aggregations

ClassPool (org.hotswap.agent.javassist.ClassPool)12 LoaderClassPath (org.hotswap.agent.javassist.LoaderClassPath)12 CtClass (org.hotswap.agent.javassist.CtClass)6 ByteArrayInputStream (java.io.ByteArrayInputStream)3 CannotCompileException (org.hotswap.agent.javassist.CannotCompileException)2 File (java.io.File)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 ProtectionDomain (java.security.ProtectionDomain)1 ArrayList (java.util.ArrayList)1 LoadEvent (org.hotswap.agent.annotation.LoadEvent)1 OnClassLoadEvent (org.hotswap.agent.annotation.OnClassLoadEvent)1 AnonymousClassInfo (org.hotswap.agent.plugin.jvm.AnonymousClassInfo)1 AnonymousClassInfos (org.hotswap.agent.plugin.jvm.AnonymousClassInfos)1 AppClassLoaderExecutor (org.hotswap.agent.util.AppClassLoaderExecutor)1