Package net.sourceforge.javautil.bytecode.api.type

Source Code of net.sourceforge.javautil.bytecode.api.type.JavaClass

package net.sourceforge.javautil.bytecode.api.type;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import net.sourceforge.javautil.bytecode.BytecodeCompiler;
import net.sourceforge.javautil.bytecode.BytecodeException;
import net.sourceforge.javautil.bytecode.api.IBytecodeField;
import net.sourceforge.javautil.bytecode.api.BytecodeFieldDeclared;
import net.sourceforge.javautil.bytecode.api.IBytecodeReferenceable;
import net.sourceforge.javautil.bytecode.api.BytecodeResolutionPool;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.MethodDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable.ClassType;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess.Scope;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeBlock;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeConstructor;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeConstructorBase;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeContextMethod;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeMethodConcrete;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod.ArgumentMatch;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod.Util;
import net.sourceforge.javautil.bytecode.api.type.method.invocation.MethodInvocation;
import net.sourceforge.javautil.common.StringUtil;

/**
* A base for all {@link ClassType#Class} types.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public abstract class JavaClass<C extends BytecodeContextType> extends AbstractType<C> {
 
  protected final List<BytecodeConstructorBase> constructors = new ArrayList<BytecodeConstructorBase>();

  public JavaClass(BytecodeCompiler compiler, String name, TypeMemberAccess access) {
    super(compiler, name, access, ClassType.Class);
  }
 
  @Override public Set<IBytecodeConstructor> getDeclaredConstructors() {
    return new LinkedHashSet<IBytecodeConstructor>(constructors);
  }
 
  /**
   * This will resolve the {@link TypeDescriptor}.
   *
   * @see #addInstanceField(String, TypeDescriptor, Scope, boolean)
   */
  public IBytecodeField addInstanceField (String name, Class type, Scope scope, boolean isFinal) {
    return this.addInstanceField(name, TypeDescriptor.getFor(type), scope, isFinal);
  }

  /**
   * @param name The name of the instance field
   * @param type The type of field
   * @param scope The scope for the field
   * @param isFinal True if the field is final, otherwise false
   * @return The new field declaration
   */
  public IBytecodeField addInstanceField (String name, TypeDescriptor type, Scope scope, boolean isFinal) {
    this.fields.put(name, new BytecodeFieldDeclaration(
      name, new TypeMemberAccess(scope, false, false, isFinal), this, type)
    );
    return this.fields.get(name);
  }
 
  public BytecodeConstructorBase addConstructor (Scope scope, boolean varArgs, Class<?>... parameterTypes) {
    TypeDescriptor[] parameters = new TypeDescriptor[parameterTypes.length];
   
    for (int i=0; i<parameters.length; i++) {
      parameters[i] = TypeDescriptor.getFor(parameterTypes[i]);
    }
   
    return this.addConstructor(scope, varArgs, parameters);
  }
 
  /**
   * @param scope The scope for the constructor
   * @param varArgs True if the last argument is an array and can be used as var args
   * @param parameters The parameters for the constructor
   * @return The new constructor
   */
  public BytecodeConstructorBase addConstructor (Scope scope, boolean varArgs, TypeDescriptor... parameters) {
    this.constructors.add(new BytecodeConstructorBase(this, new TypeMemberAccess(scope, false, false, false),
      varArgs, parameters));
    return this.constructors.get(constructors.size()-1);
  }
 
  /**
   * @param name The name of the method
   * @param scope The scope for the method
   * @param isStatic True if the method is static, otherwise false
   * @param isFinal True if the method is final, otherwise false
   * @param descriptor The descriptor for the method return type and parameters
   * @return The new method
   */
  public BytecodeMethodConcrete addMethod (String name, Scope scope, boolean isStatic, boolean isFinal, MethodDescriptor descriptor) {
    return this.addMethod(name, new TypeMemberAccess(scope, false, isStatic, isFinal), descriptor);
  }
 
  public BytecodeMethodConcrete addMethod (String name, TypeMemberAccess access, MethodDescriptor descriptor) {
    BytecodeMethodConcrete method = new BytecodeMethodConcrete(this, name, access, descriptor);
    this.methods.add(method);
    return method;
  }
 
  public BytecodeMethodConcrete implementMethod (IBytecodeMethod abstractMethod, BytecodeBlock code) {
    return this.addMethod(abstractMethod.getName(), abstractMethod.getAccess(), abstractMethod.getDescriptor())
      .setMethodBody(code);
  }
 
  public BytecodeMethodConcrete createJavaBeanProperty (final String fieldName, boolean getterOnly) {
    String name = StringUtil.capitalize(fieldName);
    return this.createJavaBeanProperty(fieldName, "get" + name, getterOnly ? null : "set" + name);
  }
 
  public BytecodeMethodConcrete createJavaBeanProperty (final String fieldName, final String getterName, final String setterName) {
    final BytecodeFieldDeclaration field = this.fields.get(fieldName);
    final boolean isStatic = field.getAccess().isStatic();
   
    BytecodeMethodConcrete getter = this.addMethod(getterName,
      new TypeMemberAccess(Scope.Public, false, isStatic, false),
      new MethodDescriptor(false, field.getType(), new TypeDescriptor[0])).setMethodBody(new BytecodeBlock() {
       
        @Override protected void writeInstructions(BytecodeContextMethod context) {
          context.returnValue(isStatic ? context.getStaticField(fieldName) : context.getThisField(fieldName));
        }
       
      });
   
    if (setterName != null) {
      this.addMethod(setterName,
        new TypeMemberAccess(Scope.Public, false, isStatic, false),
        new MethodDescriptor(false, TypeDescriptor.VOID, new TypeDescriptor[0], field.getType())).setMethodBody(new BytecodeBlock() {
         
          @Override protected void writeInstructions(BytecodeContextMethod context) {
            context.setArrayIndexValue(isStatic ? context.getStaticField(fieldName) : context.getThisField(fieldName), context.getDeclaredParameter(0));
          }
         
        });
    }
   
    return getter;
  }

  @Override public IBytecodeConstructor findConstructor(BytecodeResolutionPool pool, TypeDescriptor... parameters) {
    IBytecodeConstructor c = null;
   
    for (IBytecodeConstructor cc : this.constructors) {
      ArgumentMatch am = cc.compareArguments(pool, parameters);
      if (am == ArgumentMatch.FUNCTIONAL && c == null) c = cc;
      else if (am == ArgumentMatch.EXACT) { c = cc; break; }
    }
   
    return c;
  }
 
  /**
   * Resolves the class name.
   *
   * @see #setSuperType(IBytecodeResolvable)
   */
  public JavaClass setSuperType(String superClassName) {
    return this.setSuperType(compiler.getPool().resolve(superClassName));
  }
 
  /**
   * Resolves the super class.
   *
   * @see #setSuperType(IBytecodeResolvable)
   */
  public JavaClass setSuperType(Class superClass) {
    return this.setSuperType(compiler.getPool().resolve(superClass.getName()));
  }

  /**
   * @param superType The super type for this class
   * @return This for chaining
   */
  public JavaClass setSuperType(IBytecodeResolvable superType) { this.superType = superType; return this; }

  /**
   * This will resolve the type
   *
   * @see #addImplements(IBytecodeResolvable)
   */
  public JavaClass addImplements (String interfaceClassName) {
    return this.addImplements(compiler.getPool().resolve(interfaceClassName));
  }
 
  /**
   * This will resolve the type
   *
   * @see #addImplements(IBytecodeResolvable)
   */
  public JavaClass addImplements (Class<?> iface) {
    return this.addImplements(compiler.getPool().resolve(iface.getName()));
  }
 
  /**
   * @param iface The interface to add
   */
  public JavaClass addImplements (IBytecodeResolvable iface) {
    if (iface.getClassType() != ClassType.Interface)
      throw new BytecodeException("Not an interface: " + iface);
   
    this.interfaces.add(iface);
    return this;
  }

  @Override protected void internalClone(AbstractType target) {
    super.internalClone(target);
    ((JavaClass)target).constructors.addAll(this.constructors);
  }

  @Override protected void writeInternal(C context) {
    if (this.constructors.size() == 0) {
      context.getWriter().writeMethod(context, new DefaultConstructor());
    } else {
      for (BytecodeConstructorBase constructor : this.constructors) {
        context.getWriter().writeMethod(context, constructor);
      }
    }
   
    super.writeInternal(context);
  }

  /**
   * A default constructor.
   *
   * @author elponderador
   * @author $Author$
   * @version $Id$
   */
  public class DefaultConstructor extends BytecodeConstructorBase {

    public DefaultConstructor() {
      super(JavaClass.this, new TypeMemberAccess(Scope.Public, false, false, false), false);
     
      this.setMethodBody(new BytecodeBlock() {
       
        @Override protected void writeInstructions(BytecodeContextMethod context) {
          context.createSuperConstructorInvocation().load(context);
          context.returnVoid();
        }
       
      });
    }
   
  }
 
}
TOP

Related Classes of net.sourceforge.javautil.bytecode.api.type.JavaClass

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.