Package net.sourceforge.javautil.bytecode.impl.asm

Source Code of net.sourceforge.javautil.bytecode.impl.asm.BytecodeWriterTypeASM

package net.sourceforge.javautil.bytecode.impl.asm;

import java.util.Map;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import net.sourceforge.javautil.bytecode.BytecodeException;
import net.sourceforge.javautil.bytecode.BytecodeCompiler.Version;
import net.sourceforge.javautil.bytecode.api.IBytecodeAnnotation;
import net.sourceforge.javautil.bytecode.api.IBytecodeField;
import net.sourceforge.javautil.bytecode.api.BytecodeFieldDeclared;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.MethodDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess;
import net.sourceforge.javautil.bytecode.api.IBytecodeAnnotation.AnnotationValue;
import net.sourceforge.javautil.bytecode.api.event.BytecodeEvent;
import net.sourceforge.javautil.bytecode.api.type.AbstractType;
import net.sourceforge.javautil.bytecode.api.type.BytecodeAnnotationDeclaration;
import net.sourceforge.javautil.bytecode.api.type.IBytecodeWriterType;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeMethodConcrete;

/**
* The standard ASM implementation for writing
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class BytecodeWriterTypeASM implements IBytecodeWriterType<BytecodeContextTypeASM>, Opcodes {
 
  protected final BytecodeWriterMethodASM writer = new BytecodeWriterMethodASM();

  public void begin(BytecodeContextTypeASM context) {
    IBytecodeResolvable[] ifaces = context.getEnclosingType().getInterfaces();
    String[] interfaces = new String[ifaces.length];
   
    for (int i=0; i<ifaces.length; i++) {
      interfaces[i] = ifaces[i].getType().getName();
    }
   
    IBytecodeResolvable st = context.getEnclosingType().getSuperType() == null ?
      context.getResolutionPool().resolve(Object.class.getName()) : context.getEnclosingType().getSuperType();
   
    context.getClassWriter().visit(this.getVersion(context.getVersion()), getAccess(context.getEnclosingType()),
      context.getEnclosingType().getType().getName(), null,
      st.getType().getName(),
      interfaces
    );
   
    for (IBytecodeAnnotation annotation : context.getEnclosingType().getDeclaredAnnotations()) {
      this.declareAnnotation(context, annotation, context.getClassWriter().visitAnnotation(
        annotation.getType().getType().toDescriptorString(), true
      ));
    }
   
    context.getClassWriter().visitSource(null, null);
  }
 
  public void writeMethod(BytecodeContextTypeASM context, IBytecodeMethod method) {
    MethodDescriptor md = method.getDescriptor();
   
    String[] exceptions = new String[md.getExceptionTypes() == null ? 0 : md.getExceptionTypes().length];
    for (int i=0; i<exceptions.length; i++) {
      exceptions[i] = md.getExceptionTypes()[i].getName();
    }
   
    int access = getAccess(method);
    String desc = md.toDescriptorString();
   
    MethodVisitor mv = context.getClassWriter().visitMethod(access, method.getName(), desc, null, exceptions);
    for (IBytecodeAnnotation ba : method.getDeclaredAnnotations()) {
      this.declareAnnotation(context, ba, mv.visitAnnotation(ba.getType().getType().toDescriptorString(), true));
    }

    if (method instanceof BytecodeMethodConcrete) {
      BytecodeContextMethodASM ctx = new BytecodeContextMethodASM(mv, method, context, writer);
      ((BytecodeMethodConcrete) method).write(ctx);
    } else {
      mv.visitEnd();
    }
  }

  public void declareField(BytecodeContextTypeASM context, String name, IBytecodeField field) {
    FieldVisitor fv = context.getClassWriter().visitField(getAccess(field.getAccess()), name, field.getType().toDescriptorString(), null, null);
    for (IBytecodeAnnotation ba : field.getDeclaredAnnotations()) {
      this.declareAnnotation(context, ba, fv.visitAnnotation(ba.getType().getType().toDescriptorString(), true));
    }
    fv.visitEnd();
  }

  public void end(BytecodeContextTypeASM context) {
    context.getClassWriter().visitEnd();
  }

  public void handle(BytecodeEvent evt) {
  }
 
  /**
   * @param context The context in which to declare the annotation
   * @param ba The annotation declaration
   * @param av The annotation visitor
   */
  protected void declareAnnotation (BytecodeContextTypeASM context, IBytecodeAnnotation ba, AnnotationVisitor av) {
    IBytecodeResolvable enumType = context.getResolutionPool().resolve(Enum.class.getName());
    IBytecodeResolvable annoType = context.getResolutionPool().resolve(Enum.class.getName());

    Map<String, AnnotationValue> values = ba.getValues();
    for (String name : values.keySet()) {
      AnnotationValue value = values.get(name);
      IBytecodeResolvable avt = context.getResolutionPool().resolve( value.getValue().getClass().getName() );
      if (avt.isInstanceof(context.getResolutionPool(), enumType)) {
        // TODO: support enums
      } else if (avt.getType().isArray() &&
                 context.getResolutionPool().resolve(
                     avt.getType().getComponentType().getClassName()
                 ).isInstanceof(context.getResolutionPool(), annoType)) {
        // TODO: support annotation arrays
      } else {
        av.visit(name, value.getValue());
      }
    }
   
    av.visitEnd();
  }
 
  /**
   * @param version The framework version
   * @return The ASM equivalent
   */
  protected int getVersion (Version version) {
    switch (version) {
      case Version1_1: return V1_1;
      case Version1_2: return V1_2;
      case Version1_3: return V1_3;
      case Version1_4: return V1_4;
      case Version1_5: return V1_5;
      case Version6: return V1_6;
      case Version7: return V1_7;
    }
   
    throw new BytecodeException("Version of bytecode/class file not supported: " + version);
  }
 
  /**
   * @param type The type to get access information for
   * @return The access setting for the type (includes {@link #getAccess(TypeMemberAccess)})
   */
  protected int getAccess (AbstractType type) {
    int access = 0;
   
    switch (type.getClassType()) {
      case Class: access += Opcodes.ACC_SUPER; break;
      case Enum: access += Opcodes.ACC_ENUM; break;
      case Annotation: access += Opcodes.ACC_ANNOTATION;
      case Interface: access += Opcodes.ACC_INTERFACE; break;
    }
   
    return access + getAccess(type.getAccess());
  }
 
  /**
   * @param tma The framework access settings
   * @return The ASM translated access setting for the TMA
   */
  protected int getAccess (TypeMemberAccess tma) {
    int access = 0;
   
    switch (tma.getScope()) {
      case Private: access += Opcodes.ACC_PRIVATE; break;
      case Protected: access += Opcodes.ACC_PROTECTED; break;
      case Public: access += Opcodes.ACC_PUBLIC;
    }

    if (tma.isAbstract()) access += Opcodes.ACC_ABSTRACT;
    if (tma.isFinal()) access += Opcodes.ACC_FINAL;
    if (tma.isStatic()) access += Opcodes.ACC_STATIC;

    return access;
  }
 
  /**
   * @param method The method for which to get access
   * @return The access setting for the specified method
   */
  protected int getAccess (IBytecodeMethod method) {
    int access = 0;
   
    if (method.getDescriptor().isVarArgs()) access += Opcodes.ACC_VARARGS;
   
    return access + getAccess(method.getAccess());
  }

}
TOP

Related Classes of net.sourceforge.javautil.bytecode.impl.asm.BytecodeWriterTypeASM

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.