diff --git a/java/pom.xml b/java/pom.xml
index 44806d51..6591a727 100755
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -29,6 +29,12 @@
4.8.1
test
+
+
+ jboss
+ javassist
+ 3.7.ga
+
@@ -101,6 +107,12 @@
MessagePack Maven2 Repository
http://msgpack.org/maven2
+
+
+ repo2.maven.org
+ repo2.maven.org Maven2 Repository
+ http://repo2.maven.org/maven2
+
diff --git a/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java b/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java
new file mode 100644
index 00000000..9e4336d3
--- /dev/null
+++ b/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java
@@ -0,0 +1,209 @@
+package org.msgpack.tmp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtMethod;
+import javassist.CtNewConstructor;
+import javassist.CtNewMethod;
+
+import org.msgpack.Packer;
+import org.msgpack.Unpacker;
+
+public class DynamicCodeGenerator {
+
+ private static final String ENHANCED_CLASS_NAME_POSTFIX = "_$$_Enhanced";
+
+ private static final String SPACE = " ";
+
+ private static final String MODIFIER_PUBLIC = "public";
+
+ private static final String METHOD_NAME_MESSAGEPACK = "messagePack";
+
+ private static final String METHOD_NAME_MESSAGEUNPACK = "messageUnpack";
+
+ private static final String PACKER_CLASS_TYPE_NAME = Packer.class.getName();
+
+ private static final String PACKER_OBJECT_NAME = "pk";
+
+ private static final String UNPACKER_CLASS_TYPE_NAME = Unpacker.class
+ .getName();
+
+ private static final String UNPACKER_OBJECT_NAME = "pk";
+
+ private HashMap> classMap;
+
+ private HashMap objectCacheMap;
+
+ private ClassPool pool;
+
+ public DynamicCodeGenerator() {
+ classMap = new HashMap>();
+ objectCacheMap = new HashMap();
+ pool = ClassPool.getDefault();
+ }
+
+ public Object newEnhancedInstance(Class> targetClass) throws Exception {
+ String targetClassName = targetClass.getName();
+ //Class> enhancedClass = classMap.get(targetClassName);
+ Object enhancedObject = objectCacheMap.get(targetClassName);
+ //if (enhancedClass == null) {
+ if (enhancedObject == null) {
+ CtClass enhancedCtClass = createEnhancedCtClass(targetClassName);
+// System.out.println("enhanced class name: "
+// + enhancedCtClass.getName());
+ addSuperclass(enhancedCtClass, targetClassName);
+ addConstructor(enhancedCtClass);
+ createMessagePackMethod(enhancedCtClass, targetClass);
+ createMessageUnpackMethod(enhancedCtClass, targetClass);
+ Class enhancedClass = loadEnhancedClass(enhancedCtClass);
+ //classMap.put(targetClassName, enhancedClass);
+ enhancedObject = enhancedClass.newInstance();
+ objectCacheMap.put(targetClassName, enhancedObject);
+ }
+ //return newEnhancedInstance0(enhancedClass);
+ return enhancedObject;
+ }
+
+ private CtClass createEnhancedCtClass(final String targetClassName)
+ throws Exception {
+ return pool.makeClass(targetClassName + ENHANCED_CLASS_NAME_POSTFIX);
+ }
+
+ private void addSuperclass(CtClass enhancedCtClass,
+ final String targetClassName) throws Exception {
+ CtClass targetCtClass = pool.get(targetClassName);
+ enhancedCtClass.setSuperclass(targetCtClass);
+ }
+
+ private void addConstructor(CtClass enhancedCtClass) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ sb.append(MODIFIER_PUBLIC).append(SPACE).append(
+ // enhancedCtClass.getName()).append("(").append(")")
+ "Image3_$$_Enhanced").append("(").append(")").append(SPACE)
+ .append("{ super(); }"); // TODO
+// System.out.println("cons: " + sb.toString());
+ CtConstructor newCtConstructor = CtNewConstructor.make(sb.toString(),
+ enhancedCtClass);
+ enhancedCtClass.addConstructor(newCtConstructor);
+ }
+
+ private void createMessagePackMethod(CtClass enhancedCtClass,
+ Class> targetClass) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ sb.append(MODIFIER_PUBLIC).append(SPACE).append("void").append(SPACE)
+ .append(METHOD_NAME_MESSAGEPACK).append("(").append(
+ PACKER_CLASS_TYPE_NAME).append(SPACE).append(
+ PACKER_OBJECT_NAME).append(")").append(SPACE).append(
+ "throws").append(SPACE).append("java.io.IOException")
+ .append(SPACE).append("{");
+ Field[] fields = targetClass.getFields();
+ sb.append(PACKER_OBJECT_NAME).append(".").append("packArray").append(
+ "(").append(fields.length).append(")").append(";");
+ for (Field field : fields) {
+ insertCodeOfMessagePack(field, sb);
+ }
+ sb.append("}");
+// System.out.println("messagePack method: " + sb.toString());
+ CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhancedCtClass);
+ enhancedCtClass.addMethod(newCtMethod);
+ }
+
+ private void insertCodeOfMessagePack(Field field, StringBuilder sb) {
+ Class> type = field.getType();
+ if (type.equals(int.class)) {
+ sb.append(PACKER_OBJECT_NAME).append(".").append("pack")
+ .append("(").append(field.getName()).append(")")
+ .append(";");
+ } else if (type.equals(String.class)) {
+ sb.append(PACKER_OBJECT_NAME).append(".").append("pack")
+ .append("(").append(field.getName()).append(")")
+ .append(";");
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private void createMessageUnpackMethod(CtClass enhancedCtClass,
+ Class> targetClass) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ sb
+ .append(MODIFIER_PUBLIC)
+ .append(SPACE)
+ .append("void")
+ .append(SPACE)
+ .append(METHOD_NAME_MESSAGEUNPACK)
+ .append("(")
+ .append(UNPACKER_CLASS_TYPE_NAME)
+ .append(SPACE)
+ .append(UNPACKER_OBJECT_NAME)
+ .append(")")
+ .append(SPACE)
+ .append("throws")
+ .append(SPACE)
+ .append("org.msgpack.MessageTypeException, java.io.IOException")
+ .append(SPACE).append("{");
+ Field[] fields = targetClass.getFields();
+ sb.append(UNPACKER_OBJECT_NAME).append(".").append("unpackArray()").append(";");
+ // TODO
+ for (Field field : fields) {
+ insertCodeOfMessageUnpack(field, sb);
+ }
+ sb.append("}");
+// System.out.println("messageUnpack method: " + sb.toString());
+ CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhancedCtClass);
+ enhancedCtClass.addMethod(newCtMethod);
+ }
+
+ private void insertCodeOfMessageUnpack(Field field, StringBuilder sb) {
+ Class> type = field.getType();
+ if (type.equals(int.class)) {
+ sb.append(field.getName()).append(SPACE).append("=").append(SPACE)
+ .append(PACKER_OBJECT_NAME).append(".").append("unpackInt")
+ .append("(").append(")").append(";");
+ } else if (type.equals(String.class)) {
+ sb.append(field.getName()).append(SPACE).append("=").append(SPACE)
+ .append(PACKER_OBJECT_NAME).append(".").append(
+ "unpackString").append("(").append(")").append(";");
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private Class> loadEnhancedClass(CtClass enhancedCtClass)
+ throws Exception {
+ return enhancedCtClass.toClass(null, null);
+ }
+
+ private Object newEnhancedInstance0(Class> enhancedClass) {
+ try {
+ return enhancedClass.newInstance();
+ } catch (Exception e) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ DynamicCodeGenerator gen = new DynamicCodeGenerator();
+ Image3 src = (Image3) gen.newEnhancedInstance(Image3.class);
+ src.title = "msgpack";
+ src.uri = "http://msgpack.org/";
+ src.width = 2560;
+ src.height = 1600;
+ src.size = 4096000;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ src.messagePack(new Packer(out));
+ Image3 dst = (Image3) gen.newEnhancedInstance(Image3.class);
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ Unpacker pac = new Unpacker(in);
+ dst.messageUnpack(pac);
+
+// System.out.println(dst.equals(src));
+ }
+}
diff --git a/java/src/main/java/org/msgpack/tmp/Image1.java b/java/src/main/java/org/msgpack/tmp/Image1.java
new file mode 100644
index 00000000..f1819ed6
--- /dev/null
+++ b/java/src/main/java/org/msgpack/tmp/Image1.java
@@ -0,0 +1,47 @@
+package org.msgpack.tmp;
+
+import org.msgpack.*;
+import java.io.*;
+
+public class Image1 implements MessagePackable, MessageUnpackable {
+ public String uri = "";
+ public String title = "";
+ public int width = 0;
+ public int height = 0;
+ public int size = 0;
+
+ public void messagePack(Packer pk) throws IOException {
+ pk.packArray(5);
+ pk.pack(uri);
+ pk.pack(title);
+ pk.pack(width);
+ pk.pack(height);
+ pk.pack(size);
+ }
+
+ public void messageUnpack(Unpacker pac) throws IOException,
+ MessageTypeException {
+ int length = pac.unpackArray();
+ if (length != 5) {
+ throw new MessageTypeException();
+ }
+ uri = pac.unpackString();
+ title = pac.unpackString();
+ width = pac.unpackInt();
+ height = pac.unpackInt();
+ size = pac.unpackInt();
+ }
+
+ public boolean equals(Image1 obj) {
+ return uri.equals(obj.uri) && title.equals(obj.title)
+ && width == obj.width && height == obj.height
+ && size == obj.size;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj.getClass() != Image1.class) {
+ return false;
+ }
+ return equals((Image1) obj);
+ }
+}
diff --git a/java/src/main/java/org/msgpack/tmp/Image2.java b/java/src/main/java/org/msgpack/tmp/Image2.java
new file mode 100644
index 00000000..9c357bf3
--- /dev/null
+++ b/java/src/main/java/org/msgpack/tmp/Image2.java
@@ -0,0 +1,85 @@
+package org.msgpack.tmp;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+import org.msgpack.MessageTypeException;
+import org.msgpack.Packer;
+import org.msgpack.Unpacker;
+
+public class Image2 {
+ public String uri = "";
+ public String title = "";
+ public int width = 0;
+ public int height = 0;
+ public int size = 0;
+
+ public void messagePack(Packer pk) throws IOException {
+ messagePackWithReflection(pk);
+ }
+
+ public void messagePackWithReflection(Packer pk) throws IOException {
+ Class> cl = this.getClass();
+ Field[] fields = cl.getFields();
+ pk.packArray(fields.length);
+ for (Field field : fields) {
+ try {
+ Object obj = field.get(this);
+ pk.pack(obj);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void messageUnpack(Unpacker pac) throws IOException,
+ MessageTypeException {
+ messageUnpackWithReflection(pac);
+ }
+
+ public void messageUnpackWithReflection(Unpacker pac) throws IOException,
+ MessageTypeException {
+ Class> cl = this.getClass();
+ Field[] fields = cl.getFields();
+ int length = pac.unpackArray();
+ if (length != fields.length) {
+ throw new MessageTypeException();
+ }
+ for (Field field : fields) {
+ try {
+ field.set(this, unpack(pac, field.getType()));
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static Object unpack(Unpacker pk, Class> cl) throws IOException {
+ if (cl == int.class) {
+ return pk.unpackInt();
+ } else if (cl == String.class) {
+ return pk.unpackString();
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public boolean equals(Image2 obj) {
+ return uri.equals(obj.uri) && title.equals(obj.title)
+ && width == obj.width && height == obj.height
+ && size == obj.size;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj.getClass() != Image2.class) {
+ return false;
+ }
+ return equals((Image2) obj);
+ }
+}
diff --git a/java/src/main/java/org/msgpack/tmp/Image3.java b/java/src/main/java/org/msgpack/tmp/Image3.java
new file mode 100644
index 00000000..a28ff53f
--- /dev/null
+++ b/java/src/main/java/org/msgpack/tmp/Image3.java
@@ -0,0 +1,38 @@
+package org.msgpack.tmp;
+
+import java.io.IOException;
+import org.msgpack.MessagePackable;
+import org.msgpack.MessageTypeException;
+import org.msgpack.MessageUnpackable;
+import org.msgpack.Packer;
+import org.msgpack.Unpacker;
+
+public class Image3 implements MessagePackable, MessageUnpackable {
+ public String uri = "";
+ public String title = "";
+ public int width = 0;
+ public int height = 0;
+ public int size = 0;
+
+ public void messagePack(Packer pk) throws IOException {
+ // empty
+ }
+
+ public void messageUnpack(Unpacker pac) throws IOException,
+ MessageTypeException {
+ // empty
+ }
+
+ public boolean equals(Image3 obj) {
+ return uri.equals(obj.uri) && title.equals(obj.title)
+ && width == obj.width && height == obj.height
+ && size == obj.size;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj.getClass() != Image3.class) {
+ return false;
+ }
+ return equals((Image3) obj);
+ }
+}
\ No newline at end of file
diff --git a/java/src/main/java/org/msgpack/tmp/ImagePackUnpackPerfTest.java b/java/src/main/java/org/msgpack/tmp/ImagePackUnpackPerfTest.java
new file mode 100644
index 00000000..1f27c1b1
--- /dev/null
+++ b/java/src/main/java/org/msgpack/tmp/ImagePackUnpackPerfTest.java
@@ -0,0 +1,134 @@
+package org.msgpack.tmp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.msgpack.Packer;
+import org.msgpack.Unpacker;
+
+public class ImagePackUnpackPerfTest {
+
+ private static int BIG_LOOP = 5;
+
+ private static int SMALL_LOOP = 50000;
+
+ private static DynamicCodeGenerator gen;
+
+ private static void doGc() {
+ try {
+ Thread.sleep(50L);
+ } catch (InterruptedException ie) {
+ System.err
+ .println("Interrupted while sleeping in serializers.BenchmarkRunner.doGc()");
+ }
+ System.gc();
+ try { // longer sleep afterwards (not needed by GC, but may help with
+ // scheduling)
+ Thread.sleep(200L);
+ } catch (InterruptedException ie) {
+ System.err
+ .println("Interrupted while sleeping in serializers.BenchmarkRunner.doGc()");
+ }
+ }
+
+ public void doIt(int versionID) {
+ try {
+ doIt0(versionID);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ for (int j = 0; j < BIG_LOOP; ++j) {
+ long t = System.currentTimeMillis();
+ doIt0(versionID);
+ t = System.currentTimeMillis() - t;
+ System.out.println("time: " + t);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void doIt0(int versionID) throws Exception {
+ for (int i = 0; i < SMALL_LOOP; ++i) {
+ switch (versionID) {
+ case 0:
+ doCurrentVersion();
+ break;
+ case 1:
+ doWithReflection();
+ break;
+ case 2:
+ doWithDynamicCodeGeneration();
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ public void doCurrentVersion() throws Exception {
+ Image1 src = new Image1();
+ src.title = "msgpack";
+ src.uri = "http://msgpack.org/";
+ src.width = 2560;
+ src.height = 1600;
+ src.size = 4096000;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ src.messagePack(new Packer(out));
+ Image1 dst = new Image1();
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ Unpacker pac = new Unpacker(in);
+ dst.messageUnpack(pac);
+ }
+
+ public void doWithReflection() throws Exception {
+ Image2 src = new Image2();
+ src.title = "msgpack";
+ src.uri = "http://msgpack.org/";
+ src.width = 2560;
+ src.height = 1600;
+ src.size = 4096000;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ src.messagePack(new Packer(out));
+ Image2 dst = new Image2();
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ Unpacker pac = new Unpacker(in);
+ dst.messageUnpack(pac);
+ }
+
+ public void doWithDynamicCodeGeneration() throws Exception {
+ Image3 src = (Image3) gen.newEnhancedInstance(Image3.class);
+ src.title = "msgpack";
+ src.uri = "http://msgpack.org/";
+ src.width = 2560;
+ src.height = 1600;
+ src.size = 4096000;
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ src.messagePack(new Packer(out));
+ Image3 dst = (Image3) gen.newEnhancedInstance(Image3.class);
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ Unpacker pac = new Unpacker(in);
+ dst.messageUnpack(pac);
+ }
+
+ public static void main(String[] args) {
+ ImagePackUnpackPerfTest test = new ImagePackUnpackPerfTest();
+
+ doGc();
+ System.out.println("test current version");
+ test.doIt(0);
+
+ doGc();
+ System.out.println("test with reflection");
+ test.doIt(1);
+
+ doGc();
+ System.out.println("test with dynamic codegen");
+ gen = new DynamicCodeGenerator();
+ test.doIt(2);
+ }
+}