BeanClassGenerator.java :  » Scripting » Pnuts » org » pnuts » lib » Java Open Source

Java Open Source » Scripting » Pnuts 
Pnuts » org » pnuts » lib » BeanClassGenerator.java
/*
 * @(#)BeanClassGenerator.java 1.2 04/12/06
 *
 * Copyright (c) 2003,2004 Sun Microsystems, Inc. All Rights Reserved.
 *
 * See the file "LICENSE.txt" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */
package org.pnuts.lib;

import pnuts.compiler.*;
import org.pnuts.lang.ClassFileLoader;
import java.io.*;
import java.util.*;

public class BeanClassGenerator {

  public static ClassFile generateClassFile(Map typeMap,
                        String className,
                        String superClassName,
                        String[] interfaces,
                        String[] constructorParams)
    {
      if (superClassName == null){
        superClassName = "java.lang.Object";
      }
      ClassFile cf = new ClassFile(className,  superClassName,  null, Constants.ACC_PUBLIC);
      if (interfaces != null){
        for (int i = 0; i < interfaces.length; i++){
          cf.addInterface(interfaces[i]);
        }
      }
      cf.openMethod("<init>", "()V", Constants.ACC_PUBLIC);
      cf.add(Opcode.ALOAD_0);
      cf.add(Opcode.INVOKESPECIAL, superClassName, "<init>", "()", "V");
      cf.add(Opcode.RETURN);
      cf.closeMethod();


      if (constructorParams != null){
        boolean constructorParamsAreValid = true;
        StringBuffer sbuf = new StringBuffer("(");
        for (int i = 0; i < constructorParams.length; i++){
          String param = constructorParams[i];
          Class type = (Class)typeMap.get(param);
          if (type == null){
            constructorParamsAreValid = false;
            break;
          }
          sbuf.append(ClassFile.signature(type));
        }
        if (constructorParamsAreValid){
          sbuf.append(")V");
          cf.openMethod("<init>", sbuf.toString(), Constants.ACC_PUBLIC);

          cf.add(Opcode.ALOAD_0);
          cf.add(Opcode.INVOKESPECIAL, superClassName, "<init>", "()", "V");
          for (int i = 0; i < constructorParams.length; i++){
            cf.add(Opcode.ALOAD_0);
            String param = constructorParams[i];
            Class type = (Class)typeMap.get(param);
            if (type.isPrimitive()){
              loadPrimitive(cf, type, i + 1);
            } else {
              cf.loadLocal(i + 1);
            }
            cf.add(Opcode.PUTFIELD, cf.getClassName(), param, ClassFile.signature(type));
          }
          cf.add(Opcode.RETURN);
          cf.closeMethod();
        }
      }

      for (Iterator it = typeMap.entrySet().iterator();
         it.hasNext(); )
      {
        Map.Entry entry = (Map.Entry)it.next();
        String key = (String)entry.getKey();
        Class type = (Class)entry.getValue();
        emit(cf, key, type);
      }
      return cf;
    }

  private static void loadPrimitive(ClassFile cf, Class primitive, int index){
    if (primitive == int.class){
      cf.iloadLocal(index);
    } else if (primitive == byte.class){
      cf.iloadLocal(index);
    } else if (primitive == short.class){
      cf.iloadLocal(index);
    } else if (primitive == char.class){
      cf.iloadLocal(index);
    } else if (primitive == long.class){
      cf.lloadLocal(index);
    } else if (primitive == float.class){
      cf.floadLocal(index);
    } else if (primitive == double.class){
      cf.dloadLocal(index);
    } else if (primitive == boolean.class){
      cf.iloadLocal(index);
    }
  }

  static void emit(ClassFile cf, String propertyName, Class type){
    cf.addField(propertyName, ClassFile.signature(type), Constants.ACC_PRIVATE);
    /*
     * getter
     */
    cf.openMethod(getterName(propertyName, type),
            makeSignature(null, type),
            (short)Constants.ACC_PUBLIC);
    cf.add(Opcode.ALOAD_0);
    cf.add(Opcode.GETFIELD, cf.getClassName(), propertyName, ClassFile.signature(type));
    if (!type.isPrimitive()){
      cf.add(Opcode.ARETURN);
    } else {
      if (type == long.class){
        cf.add(Opcode.LRETURN);
      } else if (type == float.class){
        cf.add(Opcode.FRETURN);
      } else if (type == double.class){
        cf.add(Opcode.DRETURN);
      } else {
        cf.add(Opcode.IRETURN);
      }
    }
    cf.closeMethod();

    /*
     * setter
     */
    cf.openMethod(setterName(propertyName),
            makeSignature(type, void.class),
            Constants.ACC_PUBLIC);
    cf.add(Opcode.ALOAD_0);
    if (!type.isPrimitive()){
      cf.add(Opcode.ALOAD_1);
    } else {
      if (type == long.class){
        cf.add(Opcode.LLOAD_1);
      } else if (type == float.class){
        cf.add(Opcode.FLOAD_1);
      } else if (type == double.class){
        cf.add(Opcode.DLOAD_1);
      } else {
        cf.add(Opcode.ILOAD_1);
      }
    }
    cf.add(Opcode.PUTFIELD, cf.getClassName(), propertyName, ClassFile.signature(type));
    cf.add(Opcode.RETURN);
    cf.closeMethod();
  }

  static String capitalize(String s) {
    char chars[] = s.toCharArray();
    chars[0] = Character.toUpperCase(chars[0]);
    return new String(chars);
  }

  static String getterName(String property, Class type){
    if (type == boolean.class){
      return "is" + capitalize(property);
    } else {
      return "get" + capitalize(property);
    }
  }

  static String setterName(String property){
    return "set" + capitalize(property);
  }

  static String makeSignature(Class type, Class returnType){
    StringBuffer sbuf = new StringBuffer();
    if (type == null){
      sbuf.append("()");
    } else {
      sbuf.append(ClassFile.signature(new Class[]{type}));
    }
    if (returnType == void.class){
      sbuf.append('V');
    } else {
      sbuf.append(ClassFile.signature(returnType));
    }
    return sbuf.toString();
  }

  /**
   * Generates a JavaBeans class from type map
   *
   * @param typeName [propertyName, type] mapping
   * @param className the class name
   * @param superClassName the super class mame, null implies java.lang.Object
   * @param interfaces the array of interface names, null if none.
   * @return the generated class
   */
  public static Class generate(Map typeMap,
                 String className,
                 String superClassName,
                 String[] interfaces)
    throws IOException
  {
    return generate(typeMap, className, superClassName, interfaces, Thread.currentThread().getContextClassLoader());
  }

  /**
   * Generates a JavaBeans class from type map
   *
   * @param typeName [propertyName, type] mapping
   * @param className the class name
   * @param superClassName the super class mame, null implies java.lang.Object
   * @param interfaces the array of interface names, null if none.
   * @param loader the parent ClassLoader
   * @return the generated class
   */
  public static Class generate(Map typeMap,
                 String className,
                 String superClassName,
                 String[] interfaces,
                 ClassLoader loader)
    throws IOException
  {
    ClassFile cf = generateClassFile(typeMap, className, superClassName, interfaces, null);
    return (Class)new ClassFileLoader(loader).handle(cf);
  }

  /**
   * Generates a JavaBeans class from type map,
   * and write the byte code to the specified output stream.
   *
   * @param typeName [propertyName, type] mapping
   * @param className the class name
   * @param superClassName the super class mame, null implies java.lang.Object
   * @param interfaces the array of interface names, null if none.
   * @param out the output stream
   */
  public static void generate(Map typeMap,
                String className,
                String superClassName,
                String[] interfaces,
                OutputStream out)
    throws IOException
  {
    ClassFile cf = generateClassFile(typeMap, className, superClassName, interfaces, null);
    cf.write(out);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.