Package com.cedarsoft.annotations.instrumentation

Source Code of com.cedarsoft.annotations.instrumentation.UiThreadAnnotationTransformer

package com.cedarsoft.annotations.instrumentation;

import com.cedarsoft.annotations.NonUiThread;
import com.cedarsoft.annotations.UiThread;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;

import javax.annotation.Nonnull;
import java.lang.annotation.Annotation;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

/**
* @author Johannes Schneider (<a href="mailto:js@cedarsoft.com">js@cedarsoft.com</a>)
*/
public class UiThreadAnnotationTransformer implements ClassFileTransformer {
  @Override
  public byte[] transform( @Nonnull ClassLoader loader, @Nonnull String className, @Nonnull Class<?> classBeingRedefined, @Nonnull ProtectionDomain protectionDomain, @Nonnull byte[] classfileBuffer ) throws IllegalClassFormatException {
    try {
      final CtClass ctClass = UiThreadAnnotationTransformer.getCtClass( loader, classBeingRedefined.getName() );

      if (ctClass.isInterface()) {
        return classfileBuffer;
      }

      transformClass( ctClass );
      return ctClass.toBytecode();

    } catch ( Exception e ) {
      throw new RuntimeException( e );
    }
  }

  @Nonnull
  private static CtClass getCtClass( @Nonnull final ClassLoader loader, @Nonnull String className ) throws NotFoundException {
    final ClassPool pool = new ClassPool(true);
    pool.appendClassPath(new LoaderClassPath(loader));

    return pool.get(className);
  }

  private static boolean isAnnotated( @Nonnull CtMethod method, @Nonnull Class<? extends Annotation> annotationType ) throws ClassNotFoundException {
    for ( Object annotation : method.getAvailableAnnotations() ) {
      if ( annotationType.isAssignableFrom( annotation.getClass() ) ) {
        return true;
      }
    }

    return false;
  }

  private static void transformClass( @Nonnull CtClass ctClass ) throws ClassNotFoundException, CannotCompileException {
    for ( CtMethod method : ctClass.getMethods() ) {
      boolean uiThread = isAnnotated( method, UiThread.class );
      boolean nonUiThread = isAnnotated( method, NonUiThread.class );

      if ( uiThread && nonUiThread ) {
        throw new IllegalStateException( "Must not have both annotations in " + ctClass.getName() + "#" + method.getName() + ": " + UiThread.class.getName() + " and " + NonUiThread.class.getName() );
      }

      if ( uiThread ) {
        insertUiThreadVerification( method );
      }
      if ( nonUiThread ) {
        insertNonUiThreadVerification( method );
      }
    }
  }

  private static void insertUiThreadVerification( @Nonnull CtMethod method ) throws CannotCompileException {
    StringBuilder body = new StringBuilder();

    body.append( "{" );
    body.append( appendUiThreadVerificationCode() );
    body.append( "}" );

    method.insertBefore( body.toString() );
  }

  private static void insertNonUiThreadVerification( @Nonnull CtMethod method ) throws CannotCompileException {
    StringBuilder body = new StringBuilder();

    body.append( "{" );
    body.append( appendNonUiThreadVerificationCode() );
    body.append( "}" );

    method.insertBefore( body.toString() );
  }

  @Nonnull
  private static String appendUiThreadVerificationCode() {
    return "com.cedarsoft.annotations.verification.VerifyUiThread.verifyUiThreadAsserted();";
  }

  @Nonnull
  private static String appendNonUiThreadVerificationCode() {
    return "com.cedarsoft.annotations.verification.VerifyUiThread.verifyNonUiThreadAsserted();";
  }
}
TOP

Related Classes of com.cedarsoft.annotations.instrumentation.UiThreadAnnotationTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.