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

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

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

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sourceforge.javautil.bytecode.BytecodeCompiler;
import net.sourceforge.javautil.bytecode.BytecodeException;
import net.sourceforge.javautil.bytecode.BytecodeCompiler.Version;
import net.sourceforge.javautil.bytecode.api.IBytecodeAnnotated;
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.IBytecodeReferenceable;
import net.sourceforge.javautil.bytecode.api.BytecodeResolutionPool;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.BytecodeResolvableAbstract;
import net.sourceforge.javautil.bytecode.api.IBytecodeSource;
import net.sourceforge.javautil.bytecode.api.IBytecodeWriter;
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.IBytecodeAnnotation.AnnotationValue;
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.BytecodeEmbedded;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeConstructor;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeContextMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeInstruction;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeMethodConcrete;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod.ArgumentMatch;

/**
* The base interface for all Java types defined in this framework.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public abstract class AbstractType<C extends BytecodeContextType> extends BytecodeResolvableAbstract implements IBytecodeSource<C>, IBytecodeResolvable {
 
  protected final TypeMemberAccess access;
  protected final BytecodeCompiler compiler;
 
  protected IBytecodeResolvable superType;
  protected Set<IBytecodeResolvable> interfaces = new LinkedHashSet<IBytecodeResolvable>();
 
  protected Map<String, BytecodeFieldDeclaration> fields = new LinkedHashMap<String, BytecodeFieldDeclaration>();
  protected Map<String, IBytecodeReferenceable> defaultStaticValues = new HashMap<String, IBytecodeReferenceable>();
  protected List<IBytecodeMethod> methods = new ArrayList<IBytecodeMethod>();
 
  protected Set<BytecodeAnnotationDeclaration> annotations = new LinkedHashSet<BytecodeAnnotationDeclaration>();
 
  protected AbstractType(BytecodeCompiler compiler, String name, TypeMemberAccess access, ClassType type) {
    super(type, TypeDescriptor.getFor(name));
    this.access = access;
    this.compiler = compiler;
  }

  public Scope getAccessScope() {
    return access.getScope();
  }

  public boolean isFinal() {
    return access.isFinal();
  }

  public boolean isStatic() {
    return access.isStatic();
  }

  public boolean isAbstract() {
    return access.isAbstract();
  }

  public Set<IBytecodeConstructor> getDeclaredConstructors() { return Collections.EMPTY_SET; }

  public Set<IBytecodeField> getDeclaredFields() {
    return new LinkedHashSet<IBytecodeField>( fields.values() );
  }

  public Set<IBytecodeMethod> getDeclaredMethods() {
    return new LinkedHashSet<IBytecodeMethod>(methods);
  }

  public Set<BytecodeAnnotationDeclaration> getDeclaredAnnotations() {
    return Collections.unmodifiableSet( this.annotations );
  }
 
  /**
   * Facility for linkable annotation declarations.
   *
   * @see #annotate(IBytecodeResolvable)
   */
  public BytecodeAnnotationDeclaration annotate (Class<? extends Annotation> annotationType) {
    return this.annotate(this.compiler.getPool().resolve(annotationType.getName()));
  }
 
  /**
   * @param annotationType The type of the annotation
   * @return The newly created annotation declaration
   */
  public BytecodeAnnotationDeclaration annotate (IBytecodeResolvable annotationType) {
    BytecodeAnnotationDeclaration bad = new BytecodeAnnotationDeclaration(annotationType);
    this.annotations.add(bad);
    return bad;
  }
 
  /**
   * Copy all of the annotations found on the annotated member.
   *
   * @param annotated The annotated from which to copy the annotations
   */
  public void copyAnnotations (IBytecodeAnnotated annotated) {
    for (IBytecodeAnnotation annotation : annotated.getDeclaredAnnotations()) {
      BytecodeAnnotationDeclaration bad = this.annotate(annotation.getType());
      Map<String, AnnotationValue> values = annotation.getValues();
      for (String name : values.keySet()) {
        bad.setValue(name, values.get(name).getValue());
      }
    }
  }

  /**
   * @param name The name of the static field
   * @param type The type of the field
   * @param initialValue The initial value
   * @return The delcaration for the field
   */
  public IBytecodeField addStaticField (String name, Class type, Scope scope, boolean isFinal, IBytecodeReferenceable defaultValue) {
    this.fields.put(name, new BytecodeFieldDeclaration(name, new TypeMemberAccess(scope, false, true, isFinal), this, TypeDescriptor.getFor(type)));

    if (defaultValue != null)
      this.defaultStaticValues.put(name, defaultValue);
   
    return this.fields.get(name);
  }
 
  /**
   * @return The names of the fields for this type
   */
  public Set<String> getFieldNames () { return fields.keySet(); }
 
  public IBytecodeField getField (BytecodeResolutionPool pool, String name) {
    IBytecodeField thisField = this.fields.get(name);
   
    if (thisField == null && superType != null) {
      thisField = this.superType.getField(pool, name);
    }
   
    return thisField;
  }
 
  /**
   * @return The amount of methods declared in this type
   */
  public int getMethodCount () {
    return this.methods.size();
  }
 
  /**
   * @param idx The index of the method
   * @return The corresponding method
   */
  public IBytecodeMethod getMethod (int idx) {
    return this.methods.get(idx);
  }
 
  public void write(C context) {
    context.getWriter().begin(context);
   
    for (String field : this.fields.keySet()) {
      context.getWriter().declareField(context, field, this.fields.get(field));
    }
   
    final BytecodeEmbedded cinit = this.getClassInitializer();
   
    if (cinit != null || this.defaultStaticValues.size() > 0) {
      BytecodeMethodConcrete clinit = new BytecodeMethodConcrete(this, "<clinit>", new TypeMemberAccess(Scope.Private, false, true, true),
        new MethodDescriptor(false, void.class, new Class[0], new Class[0]));
     
      clinit.setMethodBody(new BytecodeBlock() {
       
        @Override protected void writeInstructions(BytecodeContextMethod context) {
          for (String name : defaultStaticValues.keySet()) {
            context.set(context.getStaticField(name), defaultStaticValues.get(name));
          }
         
          if (cinit != null) cinit.write(context);
        }
       
      });
     
      context.getWriter().writeMethod(context, clinit);
    }
   
    this.writeInternal(context);
   
    context.getWriter().end(context);
  }
 
  /**
   * @return The interfaces implemented/extended for this type
   */
  public IBytecodeResolvable[] getInterfaces() { return interfaces.toArray(new IBytecodeResolvable[interfaces.size()]); }

  /**
   * @param context The context in which to write the type body
   */
  protected void writeInternal (C context) {
    for (IBytecodeMethod method : this.methods) {
      context.getWriter().writeMethod(context, method);
    }
  }
 
  public IBytecodeResolvable getSuperType() { return superType; }

  /**
   * @return The java class name for this type
   */
  public String getName() { return descriptor.getClassName(); }
 
  /**
   * @return The generated class
   */
  public Class compile () { return compiler.compile(this); }
 
  /**
   * @param version The version to compile to
   * @return The generated class
   */
  public Class compile (Version version) { return compiler.compile(this, version); }
 
  /**
   * @param name The name of the new type
   * @param isStatic True if the cloned type should be static
   * @param isFinal True if the cloned type should be final
   * @return A type with the same fields, interfaces, super type, methods and constructors
   */
  public abstract AbstractType cloneAs (String name, boolean isStatic, boolean isFinal);
 
  /**
   * @param target The target type to which to copy internal class information
   */
  protected void internalClone (AbstractType target) {
    target.fields.putAll(this.fields);
    target.interfaces.addAll(this.interfaces);
    target.methods.addAll(this.methods);
    target.superType = this.superType;
    target.defaultStaticValues.putAll(this.defaultStaticValues);
  }
 
  /**
   * @return The access rules for this type
   */
  public TypeMemberAccess getAccess() {
    return access;
  }

  public boolean isInstanceof(BytecodeResolutionPool pool, IBytecodeResolvable resolvable) {
    if (this.superType != null) {
      boolean isst = this.superType.isInstanceof(pool, resolvable);
      if (isst) return true;
    }
   
    for (IBytecodeResolvable iface : this.interfaces) {
      if (iface.isInstanceof(pool, resolvable)) return true;
    }
   
    if (resolvable.getType().getName().equals(Object.class.getName())) return true;
    return false;
  }

  public IBytecodeConstructor findConstructor(BytecodeResolutionPool pool, TypeDescriptor... parameters) {
    throw new BytecodeException("Cannot instantiate this type: " + getName());
  }

  public IBytecodeMethod findMethod(BytecodeResolutionPool pool, String name, TypeDescriptor... parameters) {
    IBytecodeMethod bm = null;
   
    for (IBytecodeMethod method : this.methods) {
      if (!method.getName().equals(name)) continue;
      ArgumentMatch am = method.compareArguments(pool, parameters);
      if (am == ArgumentMatch.FUNCTIONAL && bm == null) bm = method;
      else if (am == ArgumentMatch.EXACT) { bm = method; break; }
    }
   
    if (bm == null) {
      IBytecodeResolvable st = this.superType;
      if (st == null) st = pool.resolve(Object.class.getName());
      return st.findMethod(pool, name, parameters);
    }
   
    return bm;
  }
 
  /**
   * This will be called when the static initializer is being written and after
   * any static field values have been assigned default values if any.
   *
   * @return Embedded source code instructions to be written in the static class initializer method, or null if none to write
    */
  protected BytecodeEmbedded getClassInitializer () { return null; };

}
TOP

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

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.