Package org.gap.jseed

Source Code of org.gap.jseed.MethodInjector

package org.gap.jseed;

import static org.gap.jseed.JavaWriter.braces;
import static org.gap.jseed.JavaWriter.call;
import static org.gap.jseed.JavaWriter.createParameters;
import static org.gap.jseed.JavaWriter.getInvokingMethodCode;
import static org.gap.jseed.JavaWriter.getParameterTypes;
import static org.gap.jseed.JavaWriter.line;
import static org.gap.jseed.JavaWriter.returnCall;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

import org.gap.jseed.annotation.Advice;
import org.gap.jseed.annotation.BeanUtil;

public class MethodInjector extends AbstractInjector {
  private Map<Class<? extends Annotation>, Class<? extends InvocationHandler>> annotations;

  public MethodInjector() {
    annotations = new HashMap<Class<? extends Annotation>, Class<? extends InvocationHandler>>();
  }

  public void injectBehavior(Class<?> theInterface, CtClass abstraction, CtClass implementation) throws ClassNotFoundException, CannotCompileException, NotFoundException {
    for (CtMethod eachMethod : abstraction.getDeclaredMethods()) {
      for (Object eachAnnot : eachMethod.getAnnotations()) {
        for (Class<? extends Annotation> methodAnnotion : annotations.keySet()) {
          if (methodAnnotion.isInstance(eachAnnot)) {
            Class<? extends InvocationHandler> handler = annotations.get(methodAnnotion);
            String propertyName = BeanUtil.getPropertyName(eachMethod.getName() + "_" + handler.getSimpleName());
            injectField(propertyName, implementation, handler);
            Advice advice = methodAnnotion.getAnnotation(Advice.class);
            switch (advice.value()) {
            case METHOD:
              addMethodBody(implementation, eachMethod, propertyName);
              break;
            case BEFORE:
              CtMethod method = addCallSuper(implementation, eachMethod);
              addBeforeBody(implementation, method, propertyName);
              try {
                implementation.addMethod(method);
              } catch (Exception e) {
                // ignore
              }
            }
          }
        }
      }
    }
  }

  private CtMethod addCallSuper(CtClass implementation, CtMethod eachMethod) throws CannotCompileException, NotFoundException {
    CtMethod newMethod = null;
    try {
      newMethod = implementation.getMethod(eachMethod.getName(), null);
    } catch (Exception e) {
      String body = null;
      newMethod = new CtMethod(eachMethod, implementation, null);
      if (eachMethod.getMethodInfo().getCodeAttribute() == null) {
        body = ";";
      } else {
        body = line("super." + eachMethod.getName() + "($1)");
      }
      newMethod.setBody(body);
    }
    return newMethod;
  }

  private void addBeforeBody(CtClass implementation, CtMethod newMethod, String propertyName) throws NotFoundException, CannotCompileException {
    String body = braces(getInvokingMethodCode(newMethod, getParameterTypes(newMethod.getParameterTypes())) + line(returnCall(newMethod, callInvocationHandler(propertyName, newMethod))));
    newMethod.insertBefore(body);
  }

  private void addMethodBody(CtClass implementation, CtMethod eachMethod, String propertyName) throws CannotCompileException, NotFoundException {
    CtMethod newMethod = new CtMethod(eachMethod, implementation, null);

    newMethod.setBody(braces(getInvokingMethodCode(eachMethod, getParameterTypes(newMethod.getParameterTypes())) + line(returnCall(eachMethod, callInvocationHandler(propertyName, newMethod)))));
    implementation.addMethod(newMethod);
  }

  private String callInvocationHandler(String propertyName, CtMethod newMethod) throws NotFoundException {
    return call("invoke", propertyName, "this", "method", createParameters(newMethod.getParameterTypes().length));
  }

  public void add(Class<? extends Annotation> annotation, Class<? extends InvocationHandler> handler) {
    annotations.put(annotation, handler);
  }
}
TOP

Related Classes of org.gap.jseed.MethodInjector

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.