You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apex.apache.org by th...@apache.org on 2016/10/21 16:58:29 UTC

[4/4] apex-malhar git commit: APEXMALHAR-1818 Adding BeanClassGenerator for dynamically creating class

APEXMALHAR-1818 Adding BeanClassGenerator for dynamically creating class


Project: http://git-wip-us.apache.org/repos/asf/apex-malhar/repo
Commit: http://git-wip-us.apache.org/repos/asf/apex-malhar/commit/b968e4c3
Tree: http://git-wip-us.apache.org/repos/asf/apex-malhar/tree/b968e4c3
Diff: http://git-wip-us.apache.org/repos/asf/apex-malhar/diff/b968e4c3

Branch: refs/heads/master
Commit: b968e4c39e983fa24e4c1136eafdd1dd45b7cafb
Parents: a059805
Author: Chandni Singh <cs...@apache.org>
Authored: Thu Oct 13 17:33:18 2016 +0530
Committer: Chinmay Kolhatkar <ch...@datatorrent.com>
Committed: Fri Oct 21 21:24:30 2016 +0530

----------------------------------------------------------------------
 .../malhar/sql/codegen/BeanClassGenerator.java  | 796 +++++++++++++++++++
 .../sql/codegen/BeanClassGeneratorTest.java     | 188 +++++
 2 files changed, 984 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/apex-malhar/blob/b968e4c3/sql/src/main/java/org/apache/apex/malhar/sql/codegen/BeanClassGenerator.java
----------------------------------------------------------------------
diff --git a/sql/src/main/java/org/apache/apex/malhar/sql/codegen/BeanClassGenerator.java b/sql/src/main/java/org/apache/apex/malhar/sql/codegen/BeanClassGenerator.java
new file mode 100644
index 0000000..ffeafb5
--- /dev/null
+++ b/sql/src/main/java/org/apache/apex/malhar/sql/codegen/BeanClassGenerator.java
@@ -0,0 +1,796 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.apex.malhar.sql.codegen;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jettison.json.JSONException;
+
+import org.apache.apex.malhar.sql.schema.TupleSchemaRegistry;
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.xbean.asm5.ClassWriter;
+import org.apache.xbean.asm5.Opcodes;
+import org.apache.xbean.asm5.tree.ClassNode;
+import org.apache.xbean.asm5.tree.FieldInsnNode;
+import org.apache.xbean.asm5.tree.FieldNode;
+import org.apache.xbean.asm5.tree.InsnNode;
+import org.apache.xbean.asm5.tree.IntInsnNode;
+import org.apache.xbean.asm5.tree.JumpInsnNode;
+import org.apache.xbean.asm5.tree.LabelNode;
+import org.apache.xbean.asm5.tree.LdcInsnNode;
+import org.apache.xbean.asm5.tree.MethodInsnNode;
+import org.apache.xbean.asm5.tree.MethodNode;
+import org.apache.xbean.asm5.tree.TypeInsnNode;
+import org.apache.xbean.asm5.tree.VarInsnNode;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * Creates a bean class on fly.
+ */
+@InterfaceStability.Evolving
+public class BeanClassGenerator
+{
+  public static final ImmutableMap<String, Character> PRIMITIVE_TYPES;
+
+  static {
+    Map<String, Character> types = Maps.newHashMap();
+    types.put("boolean", 'Z');
+    types.put("char", 'C');
+    types.put("byte", 'B');
+    types.put("short", 'S');
+    types.put("int", 'I');
+    types.put("float", 'F');
+    types.put("long", 'J');
+    types.put("double", 'D');
+    PRIMITIVE_TYPES = ImmutableMap.copyOf(types);
+  }
+
+  /**
+   * Creates a class from give field information and returns byte array of compiled class.
+   *
+   * @param fqcn      fully qualified class name
+   * @param fieldList field list for which POJO needs to be generated.
+   *
+   * @return byte[] representing compiled class.
+   * @throws IOException
+   * @throws JSONException
+   */
+  public static byte[] createAndWriteBeanClass(String fqcn, List<TupleSchemaRegistry.SQLFieldInfo> fieldList)
+    throws IOException, JSONException
+  {
+    return createAndWriteBeanClass(fqcn, fieldList, null);
+  }
+
+  /**
+   * Creates a class from given field information and writes it to the output stream. Also returns byte[] of compiled
+   * class
+   *
+   * @param fqcn         fully qualified class name
+   * @param fieldList    field list describing the class
+   * @param outputStream stream to which the class is persisted
+   * @throws JSONException
+   * @throws IOException
+   */
+  @SuppressWarnings("unchecked")
+  public static byte[] createAndWriteBeanClass(String fqcn, List<TupleSchemaRegistry.SQLFieldInfo> fieldList,
+      FSDataOutputStream outputStream) throws JSONException, IOException
+  {
+    ClassNode classNode = new ClassNode();
+
+    classNode.version = Opcodes.V1_6;  //generated class will only run on JRE 1.6 or above
+    classNode.access = Opcodes.ACC_PUBLIC;
+
+    classNode.name = fqcn.replace('.', '/');
+    classNode.superName = "java/lang/Object";
+
+    // add default constructor
+    addDefaultConstructor(classNode);
+
+    //for each field in json add a field to this class and a getter and setter for it.
+
+    for (TupleSchemaRegistry.SQLFieldInfo fieldInfo : fieldList) {
+      String fieldName = fieldInfo.getColumnName();
+      String fieldType = fieldInfo.getType().getJavaType().getName();
+      String fieldJavaType = getJavaType(fieldType);
+
+      // Add private field
+      FieldNode fieldNode = new FieldNode(Opcodes.ACC_PRIVATE, fieldName, fieldJavaType, null, null);
+      classNode.fields.add(fieldNode);
+
+      String fieldNameForMethods = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
+
+      switch (fieldType) {
+        case "boolean":
+          addIntGetterNSetter(classNode, fieldName, fieldNameForMethods, fieldJavaType, true);
+          break;
+        case "byte":
+        case "char":
+        case "short":
+        case "int":
+          addIntGetterNSetter(classNode, fieldName, fieldNameForMethods, fieldJavaType, false);
+          break;
+        case "long":
+          addLongGetterNSetter(classNode, fieldName, fieldNameForMethods, fieldJavaType);
+          break;
+        case "float":
+          addFloatGetterNSetter(classNode, fieldName, fieldNameForMethods, fieldJavaType);
+          break;
+        case "double":
+          addDoubleGetterNSetter(classNode, fieldName, fieldNameForMethods, fieldJavaType);
+          break;
+        default:
+          if (fieldJavaType.equals(getJavaType("java.util.Date"))) {
+            addDateFields(classNode, fieldName, fieldNameForMethods, "java/util/Date");
+          } else {
+            addObjectGetterNSetter(classNode, fieldName, fieldNameForMethods, fieldJavaType);
+          }
+          break;
+      }
+    }
+
+    addToStringMethod(classNode, fieldList);
+    addHashCodeMethod(classNode, fieldList);
+    addEqualsMethod(classNode, fieldList);
+
+    //Write the class
+    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+    classNode.accept(cw);
+    cw.visitEnd();
+
+    byte[] classBytes = cw.toByteArray();
+
+    if (outputStream != null) {
+      outputStream.write(classBytes);
+      outputStream.close();
+    }
+
+    return classBytes;
+  }
+
+  private static void addDefaultConstructor(ClassNode classNode)
+  {
+    MethodNode constructorNode = new MethodNode(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
+    constructorNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    constructorNode.instructions
+        .add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false));
+    constructorNode.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(constructorNode);
+  }
+
+  /**
+   * Date field is explicitly handled and provided with 3 variants of types of same data.
+   * 1. java.util.Date format
+   * 2. long - Epoc time in ms
+   * 3. int - Epoc time in sec rounded to date
+   *
+   * This is purposefully done because SQL operations on Date etc happens on long or int based on whether its a SQL DATE
+   * field OR SQL TIMESTAMP field. Hence to cater to that 2 more variant of the same data is added to the POJO.
+   */
+  @SuppressWarnings("unchecked")
+  private static void addDateFields(ClassNode classNode, String fieldName, String fieldNameForMethods, String type)
+  {
+    FieldNode fieldNodeSec = new FieldNode(Opcodes.ACC_PRIVATE, fieldName + "Sec", getJavaType("java.lang.Integer"),
+        null, null);
+    classNode.fields.add(fieldNodeSec);
+    FieldNode fieldNodeMs = new FieldNode(Opcodes.ACC_PRIVATE, fieldName + "Ms", getJavaType("java.lang.Long"), null,
+        null);
+    classNode.fields.add(fieldNodeMs);
+
+    // Create getter for Date
+    MethodNode getterNodeDate = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods, "()L" + type + ";",
+        null, null);
+    getterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNodeDate.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, "L" + type + ";"));
+    getterNodeDate.instructions.add(new InsnNode(Opcodes.ARETURN));
+    classNode.methods.add(getterNodeDate);
+
+    // Create getter for Sec
+    MethodNode getterNodeSec = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods + "Sec",
+        "()Ljava/lang/Integer;", null, null);
+    getterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNodeSec.instructions
+      .add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName + "Sec", "Ljava/lang/Integer;"));
+    getterNodeSec.instructions.add(new InsnNode(Opcodes.ARETURN));
+    classNode.methods.add(getterNodeSec);
+
+    // Create getter for Ms
+    MethodNode getterNodeMs = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods + "Ms",
+        "()Ljava/lang/Long;", null, null);
+    getterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNodeMs.instructions
+      .add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName + "Ms", "Ljava/lang/Long;"));
+    getterNodeMs.instructions.add(new InsnNode(Opcodes.ARETURN));
+    classNode.methods.add(getterNodeMs);
+
+    // Create setter for Date
+    MethodNode setterNodeDate = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods,
+        "(L" + type + ";)V", null, null);
+    setterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeDate.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, "L" + type + ";"));
+
+    setterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeDate.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type, "getTime", "()J", false));
+    setterNodeDate.instructions.add(new LdcInsnNode(new Long(1000)));
+    setterNodeDate.instructions.add(new InsnNode(Opcodes.LDIV));
+    setterNodeDate.instructions.add(new InsnNode(Opcodes.L2I));
+    setterNodeDate.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false));
+    setterNodeDate.instructions
+      .add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName + "Sec", "Ljava/lang/Integer;"));
+
+    setterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeDate.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeDate.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, type, "getTime", "()J", false));
+    setterNodeDate.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false));
+    setterNodeDate.instructions
+      .add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName + "Ms", "Ljava/lang/Long;"));
+
+    setterNodeDate.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNodeDate);
+
+    // Create setter for Sec
+    MethodNode setterNodeSec = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods + "Sec",
+        "(Ljava/lang/Integer;)V", null, null);
+    setterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeSec.instructions.add(new TypeInsnNode(Opcodes.NEW, type));
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.DUP));
+    setterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeSec.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false));
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.I2L));
+    setterNodeSec.instructions.add(new LdcInsnNode(new Long(1000)));
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.LMUL));
+    setterNodeSec.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Date", "<init>", "(J)V", false));
+    setterNodeSec.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, "L" + type + ";"));
+
+    setterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeSec.instructions
+      .add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName + "Sec", "Ljava/lang/Integer;"));
+
+    setterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeSec.instructions.add(new TypeInsnNode(Opcodes.NEW, "java/lang/Long"));
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.DUP));
+    setterNodeSec.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeSec.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false));
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.I2L));
+    setterNodeSec.instructions.add(new LdcInsnNode(new Long(1000)));
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.LMUL));
+    setterNodeSec.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Long", "<init>", "(J)V", false));
+    setterNodeSec.instructions
+      .add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName + "Ms", "Ljava/lang/Long;"));
+
+    setterNodeSec.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNodeSec);
+
+    // Create setter for Ms
+    MethodNode setterNodeMs = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods + "Ms",
+        "(Ljava/lang/Long;)V", null, null);
+    setterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeMs.instructions.add(new TypeInsnNode(Opcodes.NEW, type));
+    setterNodeMs.instructions.add(new InsnNode(Opcodes.DUP));
+    setterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeMs.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false));
+    setterNodeMs.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Date", "<init>", "(J)V", false));
+    setterNodeMs.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, "L" + type + ";"));
+
+    setterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeMs.instructions.add(new TypeInsnNode(Opcodes.NEW, "java/lang/Integer"));
+    setterNodeMs.instructions.add(new InsnNode(Opcodes.DUP));
+    setterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeMs.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false));
+    setterNodeMs.instructions.add(new LdcInsnNode(new Long(1000)));
+    setterNodeMs.instructions.add(new InsnNode(Opcodes.LDIV));
+    setterNodeMs.instructions.add(new InsnNode(Opcodes.L2I));
+    setterNodeMs.instructions
+      .add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V", false));
+    setterNodeMs.instructions
+      .add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName + "Sec", "Ljava/lang/Integer;"));
+
+    setterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNodeMs.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNodeMs.instructions
+      .add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName + "Ms", "Ljava/lang/Long;"));
+
+    setterNodeMs.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNodeMs);
+  }
+
+  @SuppressWarnings("unchecked")
+  private static void addIntGetterNSetter(ClassNode classNode, String fieldName, String fieldNameForMethods,
+      String fieldJavaType, boolean isBoolean)
+  {
+    // Create getter
+    String getterSignature = "()" + fieldJavaType;
+    MethodNode getterNode = new MethodNode(Opcodes.ACC_PUBLIC, (isBoolean ? "is" : "get") + fieldNameForMethods,
+        getterSignature, null, null);
+    getterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+    getterNode.instructions.add(new InsnNode(Opcodes.IRETURN));
+    classNode.methods.add(getterNode);
+
+    // Create setter
+    String setterSignature = '(' + fieldJavaType + ')' + 'V';
+    MethodNode setterNode = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods, setterSignature, null,
+        null);
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ILOAD, 1));
+    setterNode.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, fieldJavaType));
+    setterNode.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNode);
+  }
+
+  @SuppressWarnings("unchecked")
+  private static void addLongGetterNSetter(ClassNode classNode, String fieldName, String fieldNameForMethods,
+      String fieldJavaType)
+  {
+    // Create getter
+    String getterSignature = "()" + fieldJavaType;
+    MethodNode getterNode = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods, getterSignature, null,
+        null);
+    getterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+    getterNode.instructions.add(new InsnNode(Opcodes.LRETURN));
+    classNode.methods.add(getterNode);
+
+    // Create setter
+    String setterSignature = '(' + fieldJavaType + ')' + 'V';
+    MethodNode setterNode = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods, setterSignature, null,
+        null);
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNode.instructions.add(new VarInsnNode(Opcodes.LLOAD, 1));
+    setterNode.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, fieldJavaType));
+    setterNode.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNode);
+  }
+
+  @SuppressWarnings("unchecked")
+  private static void addFloatGetterNSetter(ClassNode classNode, String fieldName, String fieldNameForMethods,
+      String fieldJavaType)
+  {
+    // Create getter
+    String getterSignature = "()" + fieldJavaType;
+    MethodNode getterNode = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods, getterSignature, null,
+        null);
+    getterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+    getterNode.instructions.add(new InsnNode(Opcodes.FRETURN));
+    classNode.methods.add(getterNode);
+
+    // Create setter
+    String setterSignature = '(' + fieldJavaType + ')' + 'V';
+    MethodNode setterNode = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods, setterSignature, null,
+        null);
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNode.instructions.add(new VarInsnNode(Opcodes.FLOAD, 1));
+    setterNode.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, fieldJavaType));
+    setterNode.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNode);
+  }
+
+  @SuppressWarnings("unchecked")
+  private static void addDoubleGetterNSetter(ClassNode classNode, String fieldName, String fieldNameForMethods,
+      String fieldJavaType)
+  {
+    // Create getter
+    String getterSignature = "()" + fieldJavaType;
+    MethodNode getterNode = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods, getterSignature, null,
+        null);
+    getterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+    getterNode.instructions.add(new InsnNode(Opcodes.DRETURN));
+    classNode.methods.add(getterNode);
+
+    // Create setter
+    String setterSignature = '(' + fieldJavaType + ')' + 'V';
+    MethodNode setterNode = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods, setterSignature, null,
+        null);
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNode.instructions.add(new VarInsnNode(Opcodes.DLOAD, 1));
+    setterNode.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, fieldJavaType));
+    setterNode.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNode);
+  }
+
+  @SuppressWarnings("unchecked")
+  private static void addObjectGetterNSetter(ClassNode classNode, String fieldName, String fieldNameForMethods,
+      String fieldJavaType)
+  {
+    // Create getter
+    String getterSignature = "()" + fieldJavaType;
+    MethodNode getterNode = new MethodNode(Opcodes.ACC_PUBLIC, "get" + fieldNameForMethods, getterSignature, null,
+        null);
+    getterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    getterNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+    getterNode.instructions.add(new InsnNode(Opcodes.ARETURN));
+    classNode.methods.add(getterNode);
+
+    // Create setter
+    String setterSignature = '(' + fieldJavaType + ')' + 'V';
+    MethodNode setterNode = new MethodNode(Opcodes.ACC_PUBLIC, "set" + fieldNameForMethods, setterSignature, null,
+        null);
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+    setterNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    setterNode.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, fieldJavaType));
+    setterNode.instructions.add(new InsnNode(Opcodes.RETURN));
+    classNode.methods.add(setterNode);
+  }
+
+  /**
+   * Adds a toString method to underlying class. Uses StringBuilder to generate the final string.
+   *
+   * @param classNode
+   * @param fieldList
+   * @throws JSONException
+   */
+  @SuppressWarnings("unchecked")
+  private static void addToStringMethod(ClassNode classNode, List<TupleSchemaRegistry.SQLFieldInfo> fieldList)
+    throws JSONException
+  {
+    MethodNode toStringNode = new MethodNode(Opcodes.ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
+    toStringNode.visitAnnotation("Ljava/lang/Override;", true);
+
+    toStringNode.instructions.add(new TypeInsnNode(Opcodes.NEW, "java/lang/StringBuilder"));
+    toStringNode.instructions.add(new InsnNode(Opcodes.DUP));
+    toStringNode.instructions.add(new LdcInsnNode(classNode.name + "{"));
+    toStringNode.instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder",
+        "<init>", "(Ljava/lang/String;)V", false));
+    toStringNode.instructions.add(new VarInsnNode(Opcodes.ASTORE, 1));
+    toStringNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+
+    for (int i = 0; i < fieldList.size(); i++) {
+      TupleSchemaRegistry.SQLFieldInfo info = fieldList.get(i);
+      String fieldName = info.getColumnName();
+      String fieldType = info.getType().getJavaType().getName();
+      String fieldJavaType = getJavaType(fieldType);
+
+      if (i != 0) {
+        toStringNode.instructions.add(new LdcInsnNode(", "));
+        toStringNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
+            "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false));
+      }
+
+      toStringNode.instructions.add(new LdcInsnNode(fieldName + "="));
+      toStringNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false));
+      toStringNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+      toStringNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+
+      // There is no StringBuilder.append method for short and byte. It takes it as int.
+      if (fieldJavaType.equals("S") || fieldJavaType.equals("B")) {
+        fieldJavaType = "I";
+      }
+
+      Character pchar = PRIMITIVE_TYPES.get(fieldType);
+      if (pchar == null) {
+        // It's not a primitive type. StringBuilder.append method signature takes Object type.
+        fieldJavaType = "Ljava/lang/Object;";
+      }
+
+      toStringNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
+          "(" + fieldJavaType + ")Ljava/lang/StringBuilder;", false));
+    }
+
+    toStringNode.instructions.add(new LdcInsnNode("}"));
+    toStringNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
+        "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false));
+
+    toStringNode.instructions.add(new InsnNode(Opcodes.POP));
+    toStringNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    toStringNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString",
+        "()Ljava/lang/String;", false));
+    toStringNode.instructions.add(new InsnNode(Opcodes.ARETURN));
+
+    classNode.methods.add(toStringNode);
+  }
+
+  /**
+   * This will add a hashCode method for class being generated. <br>
+   * Algorithm is as follows: <br>
+   * <i><p>
+   * int hashCode = 7;
+   * for (field: all fields) {
+   * hashCode = 23 * hashCode + field.hashCode()
+   * }
+   * </p></i>
+   * <br>
+   * <b> For primitive field, hashcode implemenented is similar to the one present in its wrapper class. </b>
+   *
+   * @param classNode
+   * @param fieldList
+   * @throws JSONException
+   */
+  @SuppressWarnings("unchecked")
+  private static void addHashCodeMethod(ClassNode classNode, List<TupleSchemaRegistry.SQLFieldInfo> fieldList)
+    throws JSONException
+  {
+    MethodNode hashCodeNode = new MethodNode(Opcodes.ACC_PUBLIC, "hashCode", "()I", null, null);
+    hashCodeNode.visitAnnotation("Ljava/lang/Override;", true);
+
+    hashCodeNode.instructions.add(new IntInsnNode(Opcodes.BIPUSH, 7));
+    hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ISTORE, 1));
+
+    for (TupleSchemaRegistry.SQLFieldInfo fieldInfo : fieldList) {
+      String fieldName = fieldInfo.getColumnName();
+      String fieldType = fieldInfo.getType().getJavaType().getName();
+      String fieldJavaType = getJavaType(fieldType);
+
+      hashCodeNode.instructions.add(new IntInsnNode(Opcodes.BIPUSH, 23));
+      hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ILOAD, 1));
+      hashCodeNode.instructions.add(new InsnNode(Opcodes.IMUL));
+      hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+      hashCodeNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+
+      switch (fieldType) {
+        case "boolean":
+          LabelNode falseNode = new LabelNode();
+          LabelNode trueNode = new LabelNode();
+          hashCodeNode.instructions.add(new JumpInsnNode(Opcodes.IFEQ, falseNode));
+          hashCodeNode.instructions.add(new IntInsnNode(Opcodes.SIPUSH, 1231));
+          hashCodeNode.instructions.add(new JumpInsnNode(Opcodes.GOTO, trueNode));
+          hashCodeNode.instructions.add(falseNode);
+          hashCodeNode.instructions.add(new IntInsnNode(Opcodes.SIPUSH, 1237));
+          hashCodeNode.instructions.add(trueNode);
+          break;
+        case "byte":
+        case "char":
+        case "short":
+        case "int":
+          break;
+        case "float":
+          hashCodeNode.instructions
+            .add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Float", "floatToIntBits", "(F)I", false));
+          break;
+        case "long":
+          hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+          hashCodeNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+          hashCodeNode.instructions.add(new IntInsnNode(Opcodes.BIPUSH, 32));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.LUSHR));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.LXOR));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.L2I));
+          break;
+        case "double":
+          hashCodeNode.instructions
+            .add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Double", "doubleToLongBits", "(D)J", false));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.DUP2));
+          hashCodeNode.instructions.add(new VarInsnNode(Opcodes.LSTORE, 2));
+          hashCodeNode.instructions.add(new VarInsnNode(Opcodes.LLOAD, 2));
+          hashCodeNode.instructions.add(new IntInsnNode(Opcodes.BIPUSH, 32));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.LUSHR));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.LXOR));
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.L2I));
+          break;
+        default:
+          String objectOwnerType = fieldType.replace('.', '/');
+          LabelNode nullNode = new LabelNode();
+          LabelNode continueNode = new LabelNode();
+          hashCodeNode.instructions.add(new JumpInsnNode(Opcodes.IFNULL, nullNode));
+          hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+          hashCodeNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+          hashCodeNode.instructions
+            .add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, objectOwnerType, "hashCode", "()I", false));
+          hashCodeNode.instructions.add(new JumpInsnNode(Opcodes.GOTO, continueNode));
+          hashCodeNode.instructions.add(nullNode);
+          hashCodeNode.instructions.add(new InsnNode(Opcodes.ICONST_0));
+          hashCodeNode.instructions.add(continueNode);
+          break;
+      }
+      hashCodeNode.instructions.add(new InsnNode(Opcodes.IADD));
+      hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ISTORE, 1));
+    }
+    hashCodeNode.instructions.add(new VarInsnNode(Opcodes.ILOAD, 1));
+    hashCodeNode.instructions.add(new InsnNode(Opcodes.IRETURN));
+
+    classNode.methods.add(hashCodeNode);
+  }
+
+  /**
+   * Adds a equals method to underlying class. <br>
+   * Algorithm is as follows: <br>
+   * <i><p>
+   * if (this == other) return true;
+   * if (other == null) return false;
+   * if (other is not instanceof <this class>) return false;
+   * for (field: all fields) {
+   * if (other.getField() != this.field) return false;
+   * }
+   * return true;
+   * </p></i>
+   * <br>
+   *
+   * @param classNode
+   * @param fieldList
+   * @throws JSONException
+   */
+  @SuppressWarnings("unchecked")
+  private static void addEqualsMethod(ClassNode classNode, List<TupleSchemaRegistry.SQLFieldInfo> fieldList)
+    throws JSONException
+  {
+    MethodNode equalsNode = new MethodNode(Opcodes.ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
+    equalsNode.visitAnnotation("Ljava/lang/Override;", true);
+
+    LabelNode l0 = new LabelNode();
+    LabelNode l1 = new LabelNode();
+    LabelNode l2 = new LabelNode();
+    LabelNode l3 = new LabelNode();
+    LabelNode l4 = new LabelNode();
+
+    equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+
+    // if (this == other) return true;
+    equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    equalsNode.instructions.add(new JumpInsnNode(Opcodes.IF_ACMPNE, l0));
+    equalsNode.instructions.add(new InsnNode(Opcodes.ICONST_1));
+    equalsNode.instructions.add(new InsnNode(Opcodes.IRETURN));
+
+    equalsNode.instructions.add(l0);
+    // if (other == null) return false;
+    equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    equalsNode.instructions.add(new JumpInsnNode(Opcodes.IFNULL, l1));
+    // if (!(other instanceof <this class>)) return false;
+    equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    equalsNode.instructions.add(new TypeInsnNode(Opcodes.INSTANCEOF, classNode.name));
+    equalsNode.instructions.add(new JumpInsnNode(Opcodes.IFNE, l2));
+
+    equalsNode.instructions.add(l1);
+    equalsNode.instructions.add(new InsnNode(Opcodes.ICONST_0));
+    equalsNode.instructions.add(new InsnNode(Opcodes.IRETURN));
+
+    equalsNode.instructions.add(l2);
+    // Check if it other object can cast to <this class>
+    equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 1));
+    equalsNode.instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, classNode.name));
+    equalsNode.instructions.add(new VarInsnNode(Opcodes.ASTORE, 2));
+
+    for (int i = 0; i < fieldList.size(); i++) {
+      boolean isLast = ((i + 1) == fieldList.size());
+      TupleSchemaRegistry.SQLFieldInfo info = fieldList.get(i);
+      String fieldName = info.getColumnName();
+      String fieldType = info.getType().getJavaType().getName();
+      String fieldJavaType = getJavaType(fieldType);
+
+      String getterMethodName = (fieldType.equals("boolean") ? "is" : "get") +
+          Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
+      equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2));
+      equalsNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, classNode.name, getterMethodName,
+          "()" + fieldJavaType, false));
+      equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+      equalsNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+
+      switch (fieldType) {
+        case "boolean":
+        case "byte":
+        case "char":
+        case "short":
+        case "int":
+          equalsNode.instructions
+            .add(new JumpInsnNode(isLast ? Opcodes.IF_ICMPEQ : Opcodes.IF_ICMPNE, isLast ? l4 : l3));
+          break;
+        case "long":
+          equalsNode.instructions.add(new InsnNode(Opcodes.LCMP));
+          equalsNode.instructions.add(new JumpInsnNode(isLast ? Opcodes.IFEQ : Opcodes.IFNE, isLast ? l4 : l3));
+          break;
+        case "float":
+          equalsNode.instructions.add(new InsnNode(Opcodes.FCMPL));
+          equalsNode.instructions.add(new JumpInsnNode(isLast ? Opcodes.IFEQ : Opcodes.IFNE, isLast ? l4 : l3));
+          break;
+        case "double":
+          equalsNode.instructions.add(new InsnNode(Opcodes.DCMPL));
+          equalsNode.instructions.add(new JumpInsnNode(isLast ? Opcodes.IFEQ : Opcodes.IFNE, isLast ? l4 : l3));
+          break;
+        default:
+          String objectOwnerType = fieldType.replace('.', '/');
+
+          LabelNode nonNullNode = new LabelNode();
+          LabelNode continueNode = new LabelNode();
+
+          equalsNode.instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, nonNullNode));
+          equalsNode.instructions.add(new JumpInsnNode(isLast ? Opcodes.IFNULL : Opcodes.IFNONNULL, isLast ? l4 : l3));
+
+          equalsNode.instructions.add(new JumpInsnNode(Opcodes.GOTO, continueNode));
+
+          equalsNode.instructions.add(nonNullNode);
+          equalsNode.instructions.add(new InsnNode(Opcodes.POP));
+          equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
+          equalsNode.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, fieldJavaType));
+          equalsNode.instructions.add(new VarInsnNode(Opcodes.ALOAD, 2));
+          equalsNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, classNode.name, getterMethodName,
+              "()" + fieldJavaType, false));
+          equalsNode.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, objectOwnerType, "equals",
+              "(Ljava/lang/Object;)Z", false));
+          equalsNode.instructions.add(new JumpInsnNode(isLast ? Opcodes.IFNE : Opcodes.IFEQ, isLast ? l4 : l3));
+
+          equalsNode.instructions.add(continueNode);
+          break;
+      }
+    }
+
+    equalsNode.instructions.add(l3);
+    equalsNode.instructions.add(new InsnNode(Opcodes.ICONST_0));
+    equalsNode.instructions.add(new InsnNode(Opcodes.IRETURN));
+
+    equalsNode.instructions.add(l4);
+    equalsNode.instructions.add(new InsnNode(Opcodes.ICONST_1));
+    equalsNode.instructions.add(new InsnNode(Opcodes.IRETURN));
+
+    classNode.methods.add(equalsNode);
+  }
+
+  private static String getJavaType(String fieldType)
+  {
+    Character pchar = PRIMITIVE_TYPES.get(fieldType);
+    if (pchar != null) {
+      //it is a primitive type
+      return Character.toString(pchar);
+    }
+    //non-primitive so find the internal name of the class.
+    return 'L' + fieldType.replace('.', '/') + ';';
+  }
+
+  /**
+   * Given the class name it reads and loads the class from the input stream.
+   *
+   * @param fqcn        fully qualified class name.
+   * @param inputStream stream from which class is read.
+   * @return loaded class
+   * @throws IOException
+   */
+  public static Class<?> readBeanClass(String fqcn, FSDataInputStream inputStream) throws IOException
+  {
+    byte[] bytes = IOUtils.toByteArray(inputStream);
+    inputStream.close();
+    return new ByteArrayClassLoader().defineClass(fqcn, bytes);
+  }
+
+  /**
+   * Given the class name it reads and loads the class from given byte array.
+   *
+   * @param fqcn       fully qualified class name.
+   * @param inputClass byte[] from which class is read.
+   * @return loaded class
+   * @throws IOException
+   */
+  public static Class<?> readBeanClass(String fqcn, byte[] inputClass) throws IOException
+  {
+    return new ByteArrayClassLoader().defineClass(fqcn, inputClass);
+  }
+
+  private static class ByteArrayClassLoader extends ClassLoader
+  {
+    Class<?> defineClass(String name, byte[] ba)
+    {
+      return defineClass(name, ba, 0, ba.length);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/apex-malhar/blob/b968e4c3/sql/src/test/java/org/apache/apex/malhar/sql/codegen/BeanClassGeneratorTest.java
----------------------------------------------------------------------
diff --git a/sql/src/test/java/org/apache/apex/malhar/sql/codegen/BeanClassGeneratorTest.java b/sql/src/test/java/org/apache/apex/malhar/sql/codegen/BeanClassGeneratorTest.java
new file mode 100644
index 0000000..8fcb7f8
--- /dev/null
+++ b/sql/src/test/java/org/apache/apex/malhar/sql/codegen/BeanClassGeneratorTest.java
@@ -0,0 +1,188 @@
+/**
+ * Copyright (c) 2015 DataTorrent, Inc.
+ * All rights reserved.
+ */
+package org.apache.apex.malhar.sql.codegen;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Date;
+
+import org.codehaus.jettison.json.JSONException;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import org.apache.apex.malhar.sql.schema.TupleSchemaRegistry;
+
+import static org.junit.Assert.assertEquals;
+
+public class BeanClassGeneratorTest
+{
+
+  protected class TestMeta extends TestWatcher
+  {
+    String generatedDir;
+
+    @Override
+    protected void starting(Description description)
+    {
+      super.starting(description);
+      generatedDir = "target/" + description.getClassName() + "/" + description.getMethodName();
+    }
+
+    @Override
+    protected void finished(Description description)
+    {
+      super.finished(description);
+    }
+  }
+
+  @Rule
+  public TestMeta testMeta = new TestMeta();
+
+  @Test
+  public void test() throws IOException, JSONException, IllegalAccessException, InstantiationException,
+    NoSuchFieldException, NoSuchMethodException, InvocationTargetException
+  {
+    String addressClassName = TupleSchemaRegistry.FQCN_PACKAGE + "Address_v1";
+
+    TupleSchemaRegistry.Schema schema = new TupleSchemaRegistry.Schema();
+    schema.addField("streetNumber", long.class);
+    schema.addField("streetName", String.class);
+    schema.addField("city", String.class);
+    schema.addField("state", String.class);
+    schema.addField("zip", String.class);
+
+    byte[] beanClass = BeanClassGenerator.createAndWriteBeanClass(addressClassName, schema.fieldList);
+
+    Class<?> clazz = BeanClassGenerator.readBeanClass(addressClassName, beanClass);
+
+    Object o = clazz.newInstance();
+    Field f = clazz.getDeclaredField("streetNumber");
+    Assert.assertNotNull(f);
+
+    Method m = clazz.getDeclaredMethod("setStreetNumber", Long.class);
+    m.invoke(o, 343L);
+
+    m = clazz.getMethod("getStreetNumber");
+    Long result = (Long)m.invoke(o);
+
+    assertEquals("reflect getVal invoke", 343, result.longValue());
+  }
+
+  @Test
+  public void testPrimitive() throws IOException, JSONException, IllegalAccessException, InstantiationException,
+    NoSuchFieldException, NoSuchMethodException, InvocationTargetException
+  {
+    String addressClassName = TupleSchemaRegistry.FQCN_PACKAGE + "Energy_v1";
+
+    TupleSchemaRegistry.Schema schema = new TupleSchemaRegistry.Schema();
+    schema.addField("streetNumber", Integer.class);
+    schema.addField("houseNumber", Long.class);
+    schema.addField("condo", Boolean.class);
+    schema.addField("water-usage", Float.class);
+    schema.addField("electricity-usage", Double.class);
+    schema.addField("startDate", Date.class);
+
+    byte[] beanClass = BeanClassGenerator.createAndWriteBeanClass(addressClassName, schema.fieldList);
+
+    Class<?> clazz = BeanClassGenerator.readBeanClass(addressClassName, beanClass);
+
+    Object o = clazz.newInstance();
+    Field f = clazz.getDeclaredField("streetNumber");
+    Assert.assertNotNull(f);
+
+    //int setter and getter
+    Method m = clazz.getDeclaredMethod("setStreetNumber", Integer.class);
+    m.invoke(o, 343);
+    m = clazz.getMethod("getStreetNumber");
+    Integer result = (Integer)m.invoke(o);
+
+    assertEquals("reflect getStreetNumber invoke", 343, result.intValue());
+
+    //long setter and getter
+    m = clazz.getDeclaredMethod("setHouseNumber", Long.class);
+    m.invoke(o, 123L);
+    m = clazz.getMethod("getHouseNumber");
+    Long houseNum = (Long)m.invoke(o);
+
+    assertEquals("reflect getHouseNumber invoke", 123L, houseNum.longValue());
+
+    //boolean setter and getter
+    m = clazz.getDeclaredMethod("setCondo", Boolean.class);
+    m.invoke(o, true);
+    m = clazz.getMethod("getCondo");
+    Boolean isCondo = (Boolean)m.invoke(o);
+
+    assertEquals("reflect getCondo invoke", true, isCondo);
+
+    //float setter and getter
+    m = clazz.getDeclaredMethod("setWater-usage", Float.class);
+    m.invoke(o, 88.34F);
+    m = clazz.getMethod("getWater-usage");
+    Float waterUsage = (Float)m.invoke(o);
+
+    assertEquals("reflect getWaterUsage invoke", 88.34F, waterUsage.floatValue(), 0);
+
+    //double setter and getter
+    m = clazz.getDeclaredMethod("setElectricity-usage", Double.class);
+    m.invoke(o, 88.343243);
+    m = clazz.getMethod("getElectricity-usage");
+    Double electricityUsage = (Double)m.invoke(o);
+
+    assertEquals("reflect getWaterUsage invoke", 88.343243, electricityUsage, 0);
+
+    Date now = new Date();
+    m = clazz.getDeclaredMethod("setStartDate", Date.class);
+    m.invoke(o, now);
+
+    m = clazz.getMethod("getStartDate");
+    Date startDate = (Date)m.invoke(o);
+    assertEquals("reflect getStartDate invoke", now, startDate);
+
+    m = clazz.getMethod("getStartDateMs");
+    long startDateMs = (long)m.invoke(o);
+    assertEquals("reflect getStartDateMs invoke", now.getTime(), startDateMs, 0);
+
+    m = clazz.getMethod("getStartDateSec");
+    int startDateSec = (int)m.invoke(o);
+    assertEquals("reflect getStartDateSec invoke", now.getTime() / 1000, startDateSec, 0);
+
+    m = clazz.getDeclaredMethod("setStartDateMs", Long.class);
+    m.invoke(o, now.getTime());
+
+    m = clazz.getMethod("getStartDate");
+    startDate = (Date)m.invoke(o);
+    assertEquals("reflect getStartDate invoke", now, startDate);
+
+    m = clazz.getMethod("getStartDateMs");
+    startDateMs = (long)m.invoke(o);
+    assertEquals("reflect getStartDateMs invoke", now.getTime(), startDateMs, 0);
+
+    m = clazz.getMethod("getStartDateSec");
+    startDateSec = (int)m.invoke(o);
+    assertEquals("reflect getStartDateSec invoke", now.getTime() / 1000, startDateSec, 0);
+
+    m = clazz.getDeclaredMethod("setStartDateSec", Integer.class);
+    m.invoke(o, (int)(now.getTime() / 1000));
+
+    now = new Date(now.getTime() / 1000 * 1000);
+    m = clazz.getMethod("getStartDate");
+    startDate = (Date)m.invoke(o);
+    assertEquals("reflect getStartDate invoke", now, startDate);
+
+    m = clazz.getMethod("getStartDateMs");
+    startDateMs = (long)m.invoke(o);
+    assertEquals("reflect getStartDateMs invoke", now.getTime(), startDateMs, 0);
+
+    m = clazz.getMethod("getStartDateSec");
+    startDateSec = (int)m.invoke(o);
+    assertEquals("reflect getStartDateSec invoke", now.getTime() / 1000, startDateSec, 0);
+
+  }
+}