From 18c712cd99d1317d69f628fe58fd6ff9d10865c5 Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Wed, 25 Aug 2010 21:35:52 +0900 Subject: [PATCH 1/8] object serialization with reflection and with dynamic code generation --- java/pom.xml | 12 + .../org/msgpack/tmp/DynamicCodeGenerator.java | 209 ++++++++++++++++++ .../src/main/java/org/msgpack/tmp/Image1.java | 47 ++++ .../src/main/java/org/msgpack/tmp/Image2.java | 85 +++++++ .../src/main/java/org/msgpack/tmp/Image3.java | 38 ++++ .../msgpack/tmp/ImagePackUnpackPerfTest.java | 134 +++++++++++ 6 files changed, 525 insertions(+) create mode 100644 java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java create mode 100644 java/src/main/java/org/msgpack/tmp/Image1.java create mode 100644 java/src/main/java/org/msgpack/tmp/Image2.java create mode 100644 java/src/main/java/org/msgpack/tmp/Image3.java create mode 100644 java/src/main/java/org/msgpack/tmp/ImagePackUnpackPerfTest.java 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); + } +} From ff0e1bbbc070e95be3631459815b0f765c3aab8d Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Thu, 26 Aug 2010 17:53:29 +0900 Subject: [PATCH 2/8] change the part for creating a new constructor within DynamicCodeGenerator --- .../org/msgpack/tmp/DynamicCodeGenerator.java | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java b/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java index 9e4336d3..78238b4f 100644 --- a/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java +++ b/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java @@ -29,6 +29,8 @@ public class DynamicCodeGenerator { private static final String PACKER_CLASS_TYPE_NAME = Packer.class.getName(); + private static final String VOID_TYPE_NAME = "void"; + private static final String PACKER_OBJECT_NAME = "pk"; private static final String UNPACKER_CLASS_TYPE_NAME = Unpacker.class @@ -37,7 +39,7 @@ public class DynamicCodeGenerator { private static final String UNPACKER_OBJECT_NAME = "pk"; private HashMap> classMap; - + private HashMap objectCacheMap; private ClassPool pool; @@ -50,23 +52,23 @@ public class DynamicCodeGenerator { public Object newEnhancedInstance(Class targetClass) throws Exception { String targetClassName = targetClass.getName(); - //Class enhancedClass = classMap.get(targetClassName); + // Class enhancedClass = classMap.get(targetClassName); Object enhancedObject = objectCacheMap.get(targetClassName); - //if (enhancedClass == null) { + // if (enhancedClass == null) { if (enhancedObject == null) { CtClass enhancedCtClass = createEnhancedCtClass(targetClassName); -// System.out.println("enhanced class name: " -// + enhancedCtClass.getName()); + // 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); + // classMap.put(targetClassName, enhancedClass); enhancedObject = enhancedClass.newInstance(); objectCacheMap.put(targetClassName, enhancedObject); } - //return newEnhancedInstance0(enhancedClass); + // return newEnhancedInstance0(enhancedClass); return enhancedObject; } @@ -82,24 +84,18 @@ public class DynamicCodeGenerator { } 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); + CtConstructor newCtConstructor = CtNewConstructor + .defaultConstructor(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( + sb.append(MODIFIER_PUBLIC).append(SPACE).append(VOID_TYPE_NAME).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(); @@ -109,7 +105,7 @@ public class DynamicCodeGenerator { insertCodeOfMessagePack(field, sb); } sb.append("}"); -// System.out.println("messagePack method: " + sb.toString()); + // System.out.println("messagePack method: " + sb.toString()); CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhancedCtClass); enhancedCtClass.addMethod(newCtMethod); } @@ -135,7 +131,7 @@ public class DynamicCodeGenerator { sb .append(MODIFIER_PUBLIC) .append(SPACE) - .append("void") + .append(VOID_TYPE_NAME) .append(SPACE) .append(METHOD_NAME_MESSAGEUNPACK) .append("(") @@ -149,13 +145,14 @@ public class DynamicCodeGenerator { .append("org.msgpack.MessageTypeException, java.io.IOException") .append(SPACE).append("{"); Field[] fields = targetClass.getFields(); - sb.append(UNPACKER_OBJECT_NAME).append(".").append("unpackArray()").append(";"); + 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()); + // System.out.println("messageUnpack method: " + sb.toString()); CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhancedCtClass); enhancedCtClass.addMethod(newCtMethod); } From a9566b31be76ebc8aaf9149c1a09d3720c3f2ec9 Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Sun, 12 Sep 2010 22:21:33 +0900 Subject: [PATCH 3/8] add annotation utilities for Java --- .../org/msgpack/tmp/DynamicCodeGenerator.java | 206 -------- .../src/main/java/org/msgpack/tmp/Image1.java | 47 -- .../src/main/java/org/msgpack/tmp/Image2.java | 85 --- .../src/main/java/org/msgpack/tmp/Image3.java | 38 -- .../msgpack/tmp/ImagePackUnpackPerfTest.java | 134 ----- .../util/annotation/MessagePackOptional.java | 12 + .../util/annotation/MessagePackRequired.java | 12 + .../annotation/MessagePackUnpackable.java | 11 + .../util/annotation/PackUnpackUtil.java | 498 ++++++++++++++++++ .../annotation/PackUnpackUtilException.java | 12 + 10 files changed, 545 insertions(+), 510 deletions(-) delete mode 100644 java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java delete mode 100644 java/src/main/java/org/msgpack/tmp/Image1.java delete mode 100644 java/src/main/java/org/msgpack/tmp/Image2.java delete mode 100644 java/src/main/java/org/msgpack/tmp/Image3.java delete mode 100644 java/src/main/java/org/msgpack/tmp/ImagePackUnpackPerfTest.java create mode 100644 java/src/main/java/org/msgpack/util/annotation/MessagePackOptional.java create mode 100644 java/src/main/java/org/msgpack/util/annotation/MessagePackRequired.java create mode 100644 java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java create mode 100644 java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java create mode 100644 java/src/main/java/org/msgpack/util/annotation/PackUnpackUtilException.java diff --git a/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java b/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java deleted file mode 100644 index 78238b4f..00000000 --- a/java/src/main/java/org/msgpack/tmp/DynamicCodeGenerator.java +++ /dev/null @@ -1,206 +0,0 @@ -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 VOID_TYPE_NAME = "void"; - - 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 { - CtConstructor newCtConstructor = CtNewConstructor - .defaultConstructor(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_TYPE_NAME).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_TYPE_NAME) - .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 deleted file mode 100644 index f1819ed6..00000000 --- a/java/src/main/java/org/msgpack/tmp/Image1.java +++ /dev/null @@ -1,47 +0,0 @@ -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 deleted file mode 100644 index 9c357bf3..00000000 --- a/java/src/main/java/org/msgpack/tmp/Image2.java +++ /dev/null @@ -1,85 +0,0 @@ -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 deleted file mode 100644 index a28ff53f..00000000 --- a/java/src/main/java/org/msgpack/tmp/Image3.java +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 1f27c1b1..00000000 --- a/java/src/main/java/org/msgpack/tmp/ImagePackUnpackPerfTest.java +++ /dev/null @@ -1,134 +0,0 @@ -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); - } -} diff --git a/java/src/main/java/org/msgpack/util/annotation/MessagePackOptional.java b/java/src/main/java/org/msgpack/util/annotation/MessagePackOptional.java new file mode 100644 index 00000000..a565292d --- /dev/null +++ b/java/src/main/java/org/msgpack/util/annotation/MessagePackOptional.java @@ -0,0 +1,12 @@ +package org.msgpack.util.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.CLASS) +public @interface MessagePackOptional { + int value() default -1; +} \ No newline at end of file diff --git a/java/src/main/java/org/msgpack/util/annotation/MessagePackRequired.java b/java/src/main/java/org/msgpack/util/annotation/MessagePackRequired.java new file mode 100644 index 00000000..03e50cf3 --- /dev/null +++ b/java/src/main/java/org/msgpack/util/annotation/MessagePackRequired.java @@ -0,0 +1,12 @@ +package org.msgpack.util.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.CLASS) +public @interface MessagePackRequired { + int value() default -1; +} \ No newline at end of file diff --git a/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java b/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java new file mode 100644 index 00000000..473b5412 --- /dev/null +++ b/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java @@ -0,0 +1,11 @@ +package org.msgpack.util.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface MessagePackUnpackable { +} diff --git a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java new file mode 100644 index 00000000..37b9e0d5 --- /dev/null +++ b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java @@ -0,0 +1,498 @@ +package org.msgpack.util.annotation; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtConstructor; +import javassist.CtField; +import javassist.CtMethod; +import javassist.CtNewConstructor; +import javassist.CtNewMethod; +import javassist.NotFoundException; + +import org.msgpack.MessageConvertable; +import org.msgpack.MessagePackable; +import org.msgpack.MessageTypeException; +import org.msgpack.MessageUnpackable; +import org.msgpack.Packer; +import org.msgpack.Unpacker; + +public class PackUnpackUtil { + static class Constants { + static final String POSTFIX_TYPE_NAME_ENHANCER = "_$$_Enhanced"; + + static final String KEYWORD_MODIFIER_PUBLIC = "public"; + + static final String KEYWORD_THROWS = "throws"; + + static final String TYPE_NAME_VOID = void.class.getName(); + + static final String TYPE_NAME_BOOLEAN = boolean.class.getName(); + + static final String TYPE_NAME_BYTE = byte.class.getName(); + + static final String TYPE_NAME_DOUBLE = double.class.getName(); + + static final String TYPE_NAME_FLOAT = float.class.getName(); + + static final String TYPE_NAME_INT = int.class.getName(); + + static final String TYPE_NAME_LONG = long.class.getName(); + + static final String TYPE_NAME_SHORT = short.class.getName(); + + static final String TYPE_NAME_OBJECT = Object.class.getName(); + + static final String TYPE_NAME_BIGINTEGER = BigInteger.class.getName(); + + static final String TYPE_NAME_STRING = String.class.getName(); + + static final String TYPE_NAME_BOOLEAN2 = Boolean.class.getName(); + + static final String TYPE_NAME_BYTE2 = Byte.class.getName(); + + static final String TYPE_NAME_DOUBLE2 = Double.class.getName(); + + static final String TYPE_NAME_FLOAT2 = Float.class.getName(); + + static final String TYPE_NAME_INT2 = Integer.class.getName(); + + static final String TYPE_NAME_LONG2 = Long.class.getName(); + + static final String TYPE_NAME_SHORT2 = Short.class.getName(); + + static final String TYPE_NAME_BYTEARRAY = byte[].class.getName(); + + static final String TYPE_NAME_LIST = List.class.getName(); + + static final String TYPE_NAME_MAP = Map.class.getName(); + + static final String TYPE_NAME_IOEXCEPTION = IOException.class.getName(); + + static final String TYPE_NAME_PACKER = Packer.class.getName(); + + static final String TYPE_NAME_UNPACKER = Unpacker.class.getName(); + + static final String TYPE_NAME_MSGPACKABLE = MessagePackable.class + .getName(); + + static final String TYPE_NAME_MSGUNPACKABLE = MessageUnpackable.class + .getName(); + + static final String TYPE_NAME_MSGCONVERTABLE = MessageConvertable.class + .getName(); + + static final String TYPE_NAME_MSGTYPEEXCEPTION = MessageTypeException.class + .getName(); + + static final String TYPE_NAME_MSGPACKUNPACKABLE = MessagePackUnpackable.class + .getName(); + + static final String TYPE_NAME_MSGPACKOPTIONAL = MessagePackOptional.class + .getName(); + + static final String TYPE_NAME_MSGPACKOREQUIRED = MessagePackRequired.class + .getName(); + + static final String CHAR_NAME_SPACE = " "; + + static final String CHAR_NAME_COMMA = ","; + + static final String CHAR_NAME_EQUAL = "="; + + static final String CHAR_NAME_RIGHT_PARENTHESIS = ")"; + + static final String CHAR_NAME_LEFT_PARENTHESIS = "("; + + static final String CHAR_NAME_RIGHT_CURLY_BRACHET = "}"; + + static final String CHAR_NAME_LEFT_CURLY_BRACHET = "{"; + + static final String CHAR_NAME_DOT = "."; + + static final String CHAR_NAME_SEMICOLON = ";"; + + static final String VARIABLE_NAME_PK = "pk"; + + static final String VARIABLE_NAME_OBJ = "obj"; + + static final String METHOD_NAME_MSGPACK = "messagePack"; + + static final String METHOD_NAME_MSGUNPACK = "messageUnpack"; + + static final String METHOD_NAME_MSGCONVERT = "messageConvert"; + + static final String METHOD_NAME_PACK = "pack"; + + static final String METHOD_NAME_PACKARRAY = "packArray"; + + static final String METHOD_NAME_UNPACK = "unpack"; + + static final String METHOD_NAME_UNPACKBOOLEAN = "unpackBoolean"; + + static final String METHOD_NAME_UNPACKBYTE = "unpackByte"; + + static final String METHOD_NAME_UNPACKDOUBLE = "unpackDouble"; + + static final String METHOD_NAME_UNPACKFLOAT = "unpackFloat"; + + static final String METHOD_NAME_UNPACKINT = "unpackInt"; + + static final String METHOD_NAME_UNPACKLONG = "unpackLong"; + + static final String METHOD_NAME_UNPACKSHORT = "unpackShort"; + + static final String METHOD_NAME_UNPACKSTRING = "unpackString"; + + static final String METHOD_NAME_UNPACKBIGINTEGER = "unpackBigInteger"; + + static final String METHOD_NAME_UNPACKOBJECT = "unpackObject"; + + static final String METHOD_NAME_UNPACKBYTEARRAY = "unpackByteArray"; + + static final String METHOD_NAME_UNPACKARRAY = "unpackArray"; + + static final String METHOD_NAME_UNPACKMAP = "unpackMap"; + } + + public static class Enhancer { + + private ConcurrentHashMap> classCache; + + private ClassPool pool; + + protected Enhancer() { + classCache = new ConcurrentHashMap>(); + pool = ClassPool.getDefault(); + } + + protected Class getCache(String origName) { + return classCache.get(origName); + } + + protected void setCache(String origName, Class enhClass) { + classCache.putIfAbsent(origName, enhClass); + } + + protected Class generate(Class origClass) + throws NotFoundException, CannotCompileException { + String origName = origClass.getName(); + String enhName = origName + Constants.POSTFIX_TYPE_NAME_ENHANCER; + CtClass origCtClass = pool.get(origName); + checkPackUnpackAnnotation(origCtClass); + CtClass enhCtClass = pool.makeClass(enhName); + setSuperclass(enhCtClass, origCtClass); + setInterfaces(enhCtClass); + addConstructor(enhCtClass); + addMessagePackMethod(enhCtClass, origCtClass); + addMessageUnpackMethod(enhCtClass, origCtClass); + addMessageConvertMethod(enhCtClass, origCtClass); + return createClass(enhCtClass); + } + + private void checkPackUnpackAnnotation(CtClass origCtClass) { + try { + Object[] objs = origCtClass.getAnnotations(); + for (Object obj : objs) { + if (obj instanceof MessagePackUnpackable) { + return; + } + } + throw new PackUnpackUtilException( + "Not annotated with this class: " + + origCtClass.getName()); + } catch (ClassNotFoundException e) { + throw new PackUnpackUtilException(e.getMessage(), e); + } + } + + private void setSuperclass(CtClass enhCtClass, CtClass origCtClass) + throws CannotCompileException { + enhCtClass.setSuperclass(origCtClass); + } + + private void setInterfaces(CtClass enhCtClass) throws NotFoundException { + CtClass pacCtClass = pool.get(Constants.TYPE_NAME_MSGPACKABLE); + enhCtClass.addInterface(pacCtClass); + CtClass unpacCtClass = pool.get(Constants.TYPE_NAME_MSGUNPACKABLE); + enhCtClass.addInterface(unpacCtClass); + CtClass convCtClass = pool.get(Constants.TYPE_NAME_MSGCONVERTABLE); + enhCtClass.addInterface(convCtClass); + } + + private void addConstructor(CtClass enhCtClass) + throws CannotCompileException { + CtConstructor newCtCons = CtNewConstructor + .defaultConstructor(enhCtClass); + enhCtClass.addConstructor(newCtCons); + } + + private void addMessagePackMethod(CtClass enhCtClass, + CtClass origCtClass) throws CannotCompileException, + NotFoundException { + StringBuilder sb = new StringBuilder(); + sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( + Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) + .append(Constants.CHAR_NAME_SPACE).append( + Constants.METHOD_NAME_MSGPACK).append( + Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + Constants.TYPE_NAME_PACKER).append( + Constants.CHAR_NAME_SPACE).append( + Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SPACE).append( + Constants.KEYWORD_THROWS).append( + Constants.CHAR_NAME_SPACE).append( + Constants.TYPE_NAME_IOEXCEPTION).append( + Constants.CHAR_NAME_SPACE).append( + Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( + Constants.CHAR_NAME_SPACE); + CtField[] fields = origCtClass.getDeclaredFields(); + sb.append(Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_DOT).append( + Constants.METHOD_NAME_PACKARRAY).append( + Constants.CHAR_NAME_LEFT_PARENTHESIS).append(fields.length) + .append(Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SEMICOLON).append( + Constants.CHAR_NAME_SPACE); + for (CtField field : fields) { + insertCodeOfMessagePack(field, sb); + } + sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); + System.out.println("messagePack method: " + sb.toString()); + CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhCtClass); + enhCtClass.addMethod(newCtMethod); + } + + private void insertCodeOfMessagePack(CtField field, StringBuilder sb) + throws NotFoundException { + sb.append(Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_DOT).append(Constants.METHOD_NAME_PACK) + .append(Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + field.getName()).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SEMICOLON).append( + Constants.CHAR_NAME_SPACE); + } + + private void addMessageUnpackMethod(CtClass enhCtClass, + CtClass origCtClass) throws CannotCompileException, + NotFoundException { + StringBuilder sb = new StringBuilder(); + sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( + Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) + .append(Constants.CHAR_NAME_SPACE).append( + Constants.METHOD_NAME_MSGUNPACK).append( + Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + Constants.TYPE_NAME_UNPACKER).append( + Constants.CHAR_NAME_SPACE).append( + Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SPACE).append( + Constants.KEYWORD_THROWS).append( + Constants.CHAR_NAME_SPACE).append( + Constants.TYPE_NAME_MSGTYPEEXCEPTION).append( + Constants.CHAR_NAME_COMMA).append( + Constants.CHAR_NAME_SPACE).append( + Constants.TYPE_NAME_IOEXCEPTION).append( + Constants.CHAR_NAME_SPACE).append( + Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( + Constants.CHAR_NAME_SPACE); + CtField[] fields = origCtClass.getFields(); + sb.append(Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_DOT).append( + Constants.METHOD_NAME_UNPACKARRAY).append( + Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SEMICOLON).append( + Constants.CHAR_NAME_SPACE); + for (CtField field : fields) { + insertCodeOfMessageUnpack(field, sb); + } + sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); + System.out.println("messageUnpack method: " + sb.toString()); + CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhCtClass); + enhCtClass.addMethod(newCtMethod); + } + + private void insertCodeOfMessageUnpack(CtField field, StringBuilder sb) + throws NotFoundException { + CtClass type = field.getType(); + sb.append(field.getName()).append(Constants.CHAR_NAME_SPACE) + .append(Constants.CHAR_NAME_EQUAL).append( + Constants.CHAR_NAME_SPACE).append( + Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_DOT); + if (type.equals(CtClass.booleanType)) { // boolean + sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); + } else if (type.equals(CtClass.byteType)) { // byte + sb.append(Constants.METHOD_NAME_UNPACKBYTE); + } else if (type.equals(CtClass.doubleType)) { // double + sb.append(Constants.METHOD_NAME_UNPACKDOUBLE); + } else if (type.equals(CtClass.floatType)) { // float + sb.append(Constants.METHOD_NAME_UNPACKFLOAT); + } else if (type.equals(CtClass.intType)) { // int + sb.append(Constants.METHOD_NAME_UNPACKINT); + } else if (type.equals(CtClass.longType)) { // long + sb.append(Constants.METHOD_NAME_UNPACKLONG); + } else if (type.equals(CtClass.shortType)) { // short + sb.append(Constants.METHOD_NAME_UNPACKSHORT); + } else { // reference type + if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2))) { // Boolean + sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); + } else if (type.equals(pool.get(Constants.TYPE_NAME_BYTE2))) { // Byte + sb.append(Constants.METHOD_NAME_UNPACKBYTE); + } else if (type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2))) { // Double + sb.append(Constants.METHOD_NAME_UNPACKDOUBLE); + } else if (type.equals(pool.get(Constants.TYPE_NAME_FLOAT2))) { // Float + sb.append(Constants.METHOD_NAME_UNPACKFLOAT); + } else if (type.equals(pool.get(Constants.TYPE_NAME_INT2))) { // Integer + sb.append(Constants.METHOD_NAME_UNPACKINT); + } else if (type.equals(pool.get(Constants.TYPE_NAME_LONG2))) { // Long + sb.append(Constants.METHOD_NAME_UNPACKLONG); + } else if (type.equals(pool.get(Constants.TYPE_NAME_SHORT2))) { // Short + sb.append(Constants.METHOD_NAME_UNPACKSHORT); + } else if (type + .equals(pool.get(Constants.TYPE_NAME_BIGINTEGER))) { // BigInteger + sb.append(Constants.METHOD_NAME_UNPACKBIGINTEGER); + } else if (type.equals(pool.get(Constants.TYPE_NAME_STRING))) { // String + sb.append(Constants.METHOD_NAME_UNPACKSTRING); + } else if (type.equals(pool.get(Constants.TYPE_NAME_BYTEARRAY))) { // byte[] + sb.append(Constants.METHOD_NAME_UNPACKBYTEARRAY); + } else if (type.subtypeOf(pool.get(Constants.TYPE_NAME_LIST))) { // List + sb.append(Constants.METHOD_NAME_UNPACKARRAY); + } else if (type.subtypeOf(pool.get(Constants.TYPE_NAME_MAP))) { // Map + sb.append(Constants.METHOD_NAME_UNPACKMAP); + } else if (type.subtypeOf(pool + .get(Constants.TYPE_NAME_MSGUNPACKABLE))) { // MessageUnpackable + sb.append(Constants.METHOD_NAME_UNPACKOBJECT); + } else { + throw new NotFoundException("unknown type: " + + type.getName()); + } + } + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SEMICOLON).append( + Constants.CHAR_NAME_SPACE); + } + + private void addMessageConvertMethod(CtClass enhCtClass, + CtClass origCtClass) throws CannotCompileException { + StringBuilder sb = new StringBuilder(); + sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( + Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) + .append(Constants.CHAR_NAME_SPACE).append( + Constants.METHOD_NAME_MSGCONVERT).append( + Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + Constants.TYPE_NAME_OBJECT).append( + Constants.CHAR_NAME_SPACE).append( + Constants.VARIABLE_NAME_OBJ).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( + Constants.CHAR_NAME_SPACE).append( + Constants.KEYWORD_THROWS).append( + Constants.CHAR_NAME_SPACE).append( + Constants.TYPE_NAME_MSGTYPEEXCEPTION).append( + Constants.CHAR_NAME_SPACE).append( + Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( + Constants.CHAR_NAME_SPACE); + // TODO + sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); + System.out.println("messageConvert method: " + sb.toString()); + CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhCtClass); + enhCtClass.addMethod(newCtMethod); + } + + private Class createClass(CtClass enhCtClass) + throws CannotCompileException { + return enhCtClass.toClass(null, null); + } + } + + private static Enhancer enhancer; + + public static Class getEnhancedClass(Class origClass) { + if (enhancer == null) { + enhancer = new Enhancer(); + } + + String origName = origClass.getName(); + Class enhClass = enhancer.getCache(origName); + if (enhClass == null) { + // generate a class object related to the original class + try { + enhClass = enhancer.generate(origClass); + } catch (NotFoundException e) { + throw new PackUnpackUtilException(e.getMessage(), e); + } catch (CannotCompileException e) { + throw new PackUnpackUtilException(e.getMessage(), e); + } + // set the generated class to the cache + enhancer.setCache(origName, enhClass); + } + return enhClass; + } + + public static Object newEnhancedInstance(Class origClass) { + try { + Class enhClass = getEnhancedClass(origClass); + // create a new object of the generated class + return enhClass.newInstance(); + } catch (InstantiationException e) { + throw new PackUnpackUtilException(e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new PackUnpackUtilException(e.getMessage(), e); + } + } + + public static void main(final String[] args) throws Exception { + @MessagePackUnpackable + class Image { + public String uri = ""; + + public String title = ""; + + public int width = 0; + + public int height = 0; + + public int size = 0; + + public boolean equals(Image 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() != Image.class) { + return false; + } + return equals((Image) obj); + } + } + + PackUnpackUtil.getEnhancedClass(Image.class); + Image src = (Image) PackUnpackUtil.newEnhancedInstance(Image.class); + src.title = "msgpack"; + src.uri = "http://msgpack.org/"; + src.width = 2560; + src.height = 1600; + src.size = 4096000; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + Image dst = (Image) PackUnpackUtil.newEnhancedInstance(Image.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + System.out.println(src.equals(dst)); + } +} diff --git a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtilException.java b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtilException.java new file mode 100644 index 00000000..df3af058 --- /dev/null +++ b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtilException.java @@ -0,0 +1,12 @@ +package org.msgpack.util.annotation; + +public class PackUnpackUtilException extends RuntimeException { + + public PackUnpackUtilException(String reason) { + super(reason); + } + + public PackUnpackUtilException(String reason, Throwable t) { + super(reason, t); + } +} From 599b200ca5dda7957b47fb5156199a75a50a57ae Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Sun, 12 Sep 2010 23:04:23 +0900 Subject: [PATCH 4/8] change the version of javassist 3.12.1.GA --- java/pom.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index 6591a727..70da6a6f 100755 --- a/java/pom.xml +++ b/java/pom.xml @@ -29,11 +29,11 @@ 4.8.1 test - - jboss + javassist javassist - 3.7.ga + 3.12.1.GA + compile @@ -107,11 +107,12 @@ MessagePack Maven2 Repository http://msgpack.org/maven2 - - repo2.maven.org - repo2.maven.org Maven2 Repository - http://repo2.maven.org/maven2 + repository.jboss.org + https://repository.jboss.org/nexus/content/groups/public/ + + false + From 95b820305ae55823ee5b64476acfa5c2a7f44beb Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Tue, 14 Sep 2010 13:34:11 +0900 Subject: [PATCH 5/8] add a new test program for annotation-utilities --- .../util/annotation/PackUnpackUtil.java | 116 +++++++- .../annotation/TestMessagePackUnpackable.java | 280 ++++++++++++++++++ 2 files changed, 385 insertions(+), 11 deletions(-) create mode 100644 java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java diff --git a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java index 37b9e0d5..5efef792 100644 --- a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java +++ b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java @@ -3,6 +3,7 @@ package org.msgpack.util.annotation; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.lang.reflect.Modifier; import java.math.BigInteger; import java.util.List; import java.util.Map; @@ -124,6 +125,8 @@ public class PackUnpackUtil { static final String VARIABLE_NAME_OBJ = "obj"; + static final String METHOD_NAME_VALUEOF = "valueOf"; + static final String METHOD_NAME_MSGPACK = "messagePack"; static final String METHOD_NAME_MSGUNPACK = "messageUnpack"; @@ -187,7 +190,8 @@ public class PackUnpackUtil { String origName = origClass.getName(); String enhName = origName + Constants.POSTFIX_TYPE_NAME_ENHANCER; CtClass origCtClass = pool.get(origName); - checkPackUnpackAnnotation(origCtClass); + checkClassValidation(origCtClass); + checkDefaultConstructorValidation(origCtClass); CtClass enhCtClass = pool.makeClass(enhName); setSuperclass(enhCtClass, origCtClass); setInterfaces(enhCtClass); @@ -198,6 +202,28 @@ public class PackUnpackUtil { return createClass(enhCtClass); } + private void checkClassValidation(CtClass origCtClass) { + // not public, abstract, final + int mod = origCtClass.getModifiers(); + if ((!Modifier.isPublic(mod)) || Modifier.isAbstract(mod) + || Modifier.isFinal(mod)) { + throwClassValidationException(origCtClass); + } + // interface, enum + if (origCtClass.isInterface() || origCtClass.isEnum()) { + throwClassValidationException(origCtClass); + } + // annotation + checkPackUnpackAnnotation(origCtClass); + } + + private static void throwClassValidationException(CtClass origCtClass) { + throw new PackUnpackUtilException( + "it must be a public class and have @" + + MessagePackUnpackable.class.getName() + ": " + + origCtClass.getName()); + } + private void checkPackUnpackAnnotation(CtClass origCtClass) { try { Object[] objs = origCtClass.getAnnotations(); @@ -206,14 +232,32 @@ public class PackUnpackUtil { return; } } - throw new PackUnpackUtilException( - "Not annotated with this class: " - + origCtClass.getName()); + throwClassValidationException(origCtClass); } catch (ClassNotFoundException e) { throw new PackUnpackUtilException(e.getMessage(), e); } } + private void checkDefaultConstructorValidation(CtClass origCtClass) { + CtConstructor cons = null; + try { + cons = origCtClass.getDeclaredConstructor(new CtClass[0]); + } catch (NotFoundException e) { + throwConstructoValidationException(origCtClass); + } + int mod = cons.getModifiers(); + if (!(Modifier.isPublic(mod) || Modifier.isProtected(mod))) { + throwConstructoValidationException(origCtClass); + } + } + + private static void throwConstructoValidationException( + CtClass origCtClass) { + throw new PackUnpackUtilException( + "it must have a public zero-argument constructor: " + + origCtClass.getName()); + } + private void setSuperclass(CtClass enhCtClass, CtClass origCtClass) throws CannotCompileException { enhCtClass.setSuperclass(origCtClass); @@ -328,9 +372,43 @@ public class PackUnpackUtil { CtClass type = field.getType(); sb.append(field.getName()).append(Constants.CHAR_NAME_SPACE) .append(Constants.CHAR_NAME_EQUAL).append( - Constants.CHAR_NAME_SPACE).append( - Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_DOT); + Constants.CHAR_NAME_SPACE); + insertValueOfMethodAndLeftParenthesis(sb, type); + sb.append(Constants.VARIABLE_NAME_PK).append( + Constants.CHAR_NAME_DOT); + insertUnpackMethod(sb, type); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS).append( + Constants.CHAR_NAME_RIGHT_PARENTHESIS); + insertValueOfMethodAndRightParenthesis(sb, type); + sb.append(Constants.CHAR_NAME_SEMICOLON).append( + Constants.CHAR_NAME_SPACE); + + } + + private void insertValueOfMethodAndLeftParenthesis(StringBuilder sb, + CtClass type) throws NotFoundException { + if (type.isPrimitive()) { // primitive type + return; + } else { // reference type + if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2)) // Boolean + || type.equals(pool.get(Constants.TYPE_NAME_BYTE2)) // Byte + || type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2)) // Double + || type.equals(pool.get(Constants.TYPE_NAME_FLOAT2)) // Float + || type.equals(pool.get(Constants.TYPE_NAME_INT2)) // Integer + || type.equals(pool.get(Constants.TYPE_NAME_LONG2)) // Long + || type.equals(pool.get(Constants.TYPE_NAME_SHORT2)) // Short + ) { + sb.append(type.getName()).append(Constants.CHAR_NAME_DOT) + .append(Constants.METHOD_NAME_VALUEOF).append( + Constants.CHAR_NAME_LEFT_PARENTHESIS); + } else { + return; + } + } + } + + private void insertUnpackMethod(StringBuilder sb, CtClass type) + throws NotFoundException { if (type.equals(CtClass.booleanType)) { // boolean sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); } else if (type.equals(CtClass.byteType)) { // byte @@ -379,10 +457,26 @@ public class PackUnpackUtil { + type.getName()); } } - sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS).append( - Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( - Constants.CHAR_NAME_SEMICOLON).append( - Constants.CHAR_NAME_SPACE); + } + + private void insertValueOfMethodAndRightParenthesis(StringBuilder sb, + CtClass type) throws NotFoundException { + if (type.isPrimitive()) { // primitive type + return; + } else { // reference type + if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2)) // Boolean + || type.equals(pool.get(Constants.TYPE_NAME_BYTE2)) // Byte + || type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2)) // Double + || type.equals(pool.get(Constants.TYPE_NAME_FLOAT2)) // Float + || type.equals(pool.get(Constants.TYPE_NAME_INT2)) // Integer + || type.equals(pool.get(Constants.TYPE_NAME_LONG2)) // Long + || type.equals(pool.get(Constants.TYPE_NAME_SHORT2)) // Short + ) { + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + } else { + return; + } + } } private void addMessageConvertMethod(CtClass enhCtClass, diff --git a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java new file mode 100644 index 00000000..1ec7d64e --- /dev/null +++ b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java @@ -0,0 +1,280 @@ +package org.msgpack.util.annotation; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; + +import junit.framework.TestCase; + +import org.junit.Test; +import org.msgpack.MessageUnpackable; +import org.msgpack.Packer; +import org.msgpack.Unpacker; + +public class TestMessagePackUnpackable extends TestCase { + + @Test + public void testGeneralPrimitiveTypeFieldsClass() throws Exception { + GeneralPrimitiveTypeFieldsClass src = (GeneralPrimitiveTypeFieldsClass) PackUnpackUtil + .newEnhancedInstance(GeneralPrimitiveTypeFieldsClass.class); + src.f0 = (byte) 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f6 = false; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + GeneralPrimitiveTypeFieldsClass dst = (GeneralPrimitiveTypeFieldsClass) PackUnpackUtil + .newEnhancedInstance(GeneralPrimitiveTypeFieldsClass.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + } + + @MessagePackUnpackable + public static class GeneralPrimitiveTypeFieldsClass { + public byte f0; + public short f1; + public int f2; + public long f3; + public float f4; + public double f5; + public boolean f6; + + public GeneralPrimitiveTypeFieldsClass() { + } + } + + @Test + public void testGeneralReferenceTypeFieldsClass() throws Exception { + GeneralReferenceTypeFieldsClass src = (GeneralReferenceTypeFieldsClass) PackUnpackUtil + .newEnhancedInstance(GeneralReferenceTypeFieldsClass.class); + src.f0 = 0; + src.f1 = 1; + src.f2 = 2; + src.f3 = (long) 3; + src.f4 = (float) 4; + src.f5 = (double) 5; + src.f6 = false; + src.f7 = new BigInteger("7"); + src.f8 = "8"; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + GeneralReferenceTypeFieldsClass dst = (GeneralReferenceTypeFieldsClass) PackUnpackUtil + .newEnhancedInstance(GeneralReferenceTypeFieldsClass.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertEquals(src.f0, dst.f0); + assertEquals(src.f1, dst.f1); + assertEquals(src.f2, dst.f2); + assertEquals(src.f3, dst.f3); + assertEquals(src.f4, dst.f4); + assertEquals(src.f5, dst.f5); + assertEquals(src.f6, dst.f6); + assertEquals(src.f7, dst.f7); + assertEquals(src.f8, dst.f8); + } + + @MessagePackUnpackable + public static class GeneralReferenceTypeFieldsClass { + public Byte f0; + public Short f1; + public Integer f2; + public Long f3; + public Float f4; + public Double f5; + public Boolean f6; + public BigInteger f7; + public String f8; + + public GeneralReferenceTypeFieldsClass() { + } + } + + @Test + public void testPublicDefaultConstructorClass() throws Exception { + try { + PackUnpackUtil.newEnhancedInstance(NoDefaultConstructorClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(PrivateDefaultConstructorClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(ProtectedDefaultConstructorClass.class); + assertTrue(true); + } catch (PackUnpackUtilException e) { + fail(); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(PackageDefaultConstructorClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + } + + @MessagePackUnpackable + public static class NoDefaultConstructorClass { + public NoDefaultConstructorClass(int i) { + } + } + + @MessagePackUnpackable + public static class PrivateDefaultConstructorClass { + private PrivateDefaultConstructorClass() { + } + } + + @MessagePackUnpackable + public static class ProtectedDefaultConstructorClass { + protected ProtectedDefaultConstructorClass() { + } + } + + @MessagePackUnpackable + public static class PackageDefaultConstructorClass { + PackageDefaultConstructorClass() { + } + } + + @Test + public void testPublicModifierClass() throws Exception { + try { + PackUnpackUtil.newEnhancedInstance(PrivateModifierClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(ProtectedModifierClass.class); + assertTrue(true); + } catch (PackUnpackUtilException e) { + fail(); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(PackageModifierClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + } + + @MessagePackUnpackable + private static class PrivateModifierClass { + } + + @MessagePackUnpackable + protected static class ProtectedModifierClass { + protected ProtectedModifierClass() { + } + } + + @MessagePackUnpackable + static class PackageModifierClass { + } + + @Test + public void testFinalAndAbstractModifierClass() throws Exception { + try { + PackUnpackUtil.newEnhancedInstance(FinalModifierClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(AbstractModifierClass.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + } + + @MessagePackUnpackable + public final static class FinalModifierClass { + } + + @MessagePackUnpackable + public abstract static class AbstractModifierClass { + } + + @Test + public void testInterfaceAndEnum() throws Exception { + try { + PackUnpackUtil.newEnhancedInstance(SampleInterface.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + try { + PackUnpackUtil.newEnhancedInstance(SampleEnum.class); + fail(); + } catch (PackUnpackUtilException e) { + assertTrue(true); + } + assertTrue(true); + } + + @MessagePackUnpackable + public interface SampleInterface { + } + + @MessagePackUnpackable + public enum SampleEnum { + } + + @Test + public void testFinalFieldClass() throws Exception { + + } + + @Test + public void testPrivateFieldClass() throws Exception { + + } + + @Test + public void testProtectedFieldClass() throws Exception { + + } + + @Test + public void testNonModifierFieldClass() throws Exception { + + } + + @Test + public void testNestedAnnotatedFieldClass() throws Exception { + + } + + @Test + public void testSuperClass() throws Exception { + + } +} From c7f8b94ccdde64512aced14930ebdc0e14825e66 Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Tue, 14 Sep 2010 22:26:04 +0900 Subject: [PATCH 6/8] fixed several bugs of a verify error within annotation-utilities --- .../util/annotation/PackUnpackUtil.java | 170 ++++++++++++++---- .../annotation/TestMessagePackUnpackable.java | 160 ++++++++++++++--- 2 files changed, 270 insertions(+), 60 deletions(-) diff --git a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java index 5efef792..a58b4bd5 100644 --- a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java +++ b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java @@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; import java.math.BigInteger; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -196,9 +197,10 @@ public class PackUnpackUtil { setSuperclass(enhCtClass, origCtClass); setInterfaces(enhCtClass); addConstructor(enhCtClass); - addMessagePackMethod(enhCtClass, origCtClass); - addMessageUnpackMethod(enhCtClass, origCtClass); - addMessageConvertMethod(enhCtClass, origCtClass); + CtField[] fields = getDeclaredFields(origCtClass); + addMessagePackMethod(enhCtClass, origCtClass, fields); + addMessageUnpackMethod(enhCtClass, origCtClass, fields); + addMessageConvertMethod(enhCtClass, origCtClass, fields); return createClass(enhCtClass); } @@ -279,9 +281,54 @@ public class PackUnpackUtil { enhCtClass.addConstructor(newCtCons); } + private CtField[] getDeclaredFields(CtClass origCtClass) { + ArrayList allFields = new ArrayList(); + try { + CtClass nextCtClass = origCtClass; + while (!nextCtClass + .equals(pool.get(Constants.TYPE_NAME_OBJECT))) { + CtField[] fields = nextCtClass.getDeclaredFields(); + for (CtField field : fields) { + try { + checkFieldValidation(field, allFields); + allFields.add(field); + } catch (PackUnpackUtilException e) { // ignore + } + } + nextCtClass = nextCtClass.getSuperclass(); + } + + } catch (NotFoundException e) { + throw new PackUnpackUtilException(e.getMessage(), e); + } + return allFields.toArray(new CtField[0]); + } + + private void checkFieldValidation(CtField field, + ArrayList allFields) { + // check modifiers (public or protected) + int mod = field.getModifiers(); + if ((!(Modifier.isPublic(mod) || Modifier.isProtected(mod))) + || Modifier.isStatic(mod) || Modifier.isFinal(mod) + || Modifier.isTransient(mod)) { + throwFieldValidationException(field); + } + // check same name + for (CtField f : allFields) { + if (f.getName().equals(field.getName())) { + throwFieldValidationException(field); + } + } + } + + private static void throwFieldValidationException(CtField field) { + throw new PackUnpackUtilException("it must be a public field: " + + field.getName()); + } + private void addMessagePackMethod(CtClass enhCtClass, - CtClass origCtClass) throws CannotCompileException, - NotFoundException { + CtClass origCtClass, CtField[] fields) + throws CannotCompileException, NotFoundException { StringBuilder sb = new StringBuilder(); sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) @@ -299,7 +346,6 @@ public class PackUnpackUtil { Constants.CHAR_NAME_SPACE).append( Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( Constants.CHAR_NAME_SPACE); - CtField[] fields = origCtClass.getDeclaredFields(); sb.append(Constants.VARIABLE_NAME_PK).append( Constants.CHAR_NAME_DOT).append( Constants.METHOD_NAME_PACKARRAY).append( @@ -328,8 +374,8 @@ public class PackUnpackUtil { } private void addMessageUnpackMethod(CtClass enhCtClass, - CtClass origCtClass) throws CannotCompileException, - NotFoundException { + CtClass origCtClass, CtField[] fields) + throws CannotCompileException, NotFoundException { StringBuilder sb = new StringBuilder(); sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) @@ -350,7 +396,6 @@ public class PackUnpackUtil { Constants.CHAR_NAME_SPACE).append( Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( Constants.CHAR_NAME_SPACE); - CtField[] fields = origCtClass.getFields(); sb.append(Constants.VARIABLE_NAME_PK).append( Constants.CHAR_NAME_DOT).append( Constants.METHOD_NAME_UNPACKARRAY).append( @@ -370,21 +415,53 @@ public class PackUnpackUtil { private void insertCodeOfMessageUnpack(CtField field, StringBuilder sb) throws NotFoundException { CtClass type = field.getType(); - sb.append(field.getName()).append(Constants.CHAR_NAME_SPACE) - .append(Constants.CHAR_NAME_EQUAL).append( - Constants.CHAR_NAME_SPACE); + insertRightVariable(sb, field, type); insertValueOfMethodAndLeftParenthesis(sb, type); sb.append(Constants.VARIABLE_NAME_PK).append( Constants.CHAR_NAME_DOT); insertUnpackMethod(sb, type); - sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS).append( - Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + insertUnpackMethodArgumenet(sb, field, type); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); insertValueOfMethodAndRightParenthesis(sb, type); sb.append(Constants.CHAR_NAME_SEMICOLON).append( Constants.CHAR_NAME_SPACE); } + private void insertRightVariable(StringBuilder sb, CtField field, + CtClass type) throws NotFoundException { + if (type.isPrimitive()) { // primitive type + sb.append(field.getName()).append(Constants.CHAR_NAME_SPACE) + .append(Constants.CHAR_NAME_EQUAL).append( + Constants.CHAR_NAME_SPACE); + } else { // reference type + if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2)) // Boolean + || type.equals(pool.get(Constants.TYPE_NAME_BYTE2)) // Byte + || type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2)) // Double + || type.equals(pool.get(Constants.TYPE_NAME_FLOAT2)) // Float + || type.equals(pool.get(Constants.TYPE_NAME_INT2)) // Integer + || type.equals(pool.get(Constants.TYPE_NAME_LONG2)) // Long + || type.equals(pool.get(Constants.TYPE_NAME_SHORT2)) // Short + || type + .equals(pool + .get(Constants.TYPE_NAME_BIGINTEGER)) // BigInteger + || type.equals(pool.get(Constants.TYPE_NAME_STRING)) // String + || type.equals(pool.get(Constants.TYPE_NAME_BYTEARRAY)) // byte[] + || type.subtypeOf(pool.get(Constants.TYPE_NAME_LIST)) // List + || type.subtypeOf(pool.get(Constants.TYPE_NAME_MAP)) // Map + ) { + sb.append(field.getName()) + .append(Constants.CHAR_NAME_SPACE).append( + Constants.CHAR_NAME_EQUAL).append( + Constants.CHAR_NAME_SPACE); + } else { // MessageUnpackable + return; + } + } + + } + private void insertValueOfMethodAndLeftParenthesis(StringBuilder sb, CtClass type) throws NotFoundException { if (type.isPrimitive()) { // primitive type @@ -424,6 +501,7 @@ public class PackUnpackUtil { } else if (type.equals(CtClass.shortType)) { // short sb.append(Constants.METHOD_NAME_UNPACKSHORT); } else { // reference type + Class c = null; if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2))) { // Boolean sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); } else if (type.equals(pool.get(Constants.TYPE_NAME_BYTE2))) { // Byte @@ -450,8 +528,9 @@ public class PackUnpackUtil { } else if (type.subtypeOf(pool.get(Constants.TYPE_NAME_MAP))) { // Map sb.append(Constants.METHOD_NAME_UNPACKMAP); } else if (type.subtypeOf(pool - .get(Constants.TYPE_NAME_MSGUNPACKABLE))) { // MessageUnpackable - sb.append(Constants.METHOD_NAME_UNPACKOBJECT); + .get(Constants.TYPE_NAME_MSGUNPACKABLE)) + || ((c = getCache(type.getName())) != null)) { // MessageUnpackable + sb.append(Constants.METHOD_NAME_UNPACK); } else { throw new NotFoundException("unknown type: " + type.getName()); @@ -459,6 +538,22 @@ public class PackUnpackUtil { } } + private void insertUnpackMethodArgumenet(StringBuilder sb, + CtField field, CtClass type) throws NotFoundException { + if (type.isPrimitive()) { // primitive type + return; + } else { // reference type + Class c = null; + if (type.equals(pool.get(Constants.TYPE_NAME_MSGUNPACKABLE)) + || ((c = getCache(type.getName())) != null)) { + sb.append("(org.msgpack.MessageUnpackable)"); + sb.append(field.getName()); + } else { + return; + } + } + } + private void insertValueOfMethodAndRightParenthesis(StringBuilder sb, CtClass type) throws NotFoundException { if (type.isPrimitive()) { // primitive type @@ -480,7 +575,8 @@ public class PackUnpackUtil { } private void addMessageConvertMethod(CtClass enhCtClass, - CtClass origCtClass) throws CannotCompileException { + CtClass origCtClass, CtField[] fields) + throws CannotCompileException { StringBuilder sb = new StringBuilder(); sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) @@ -547,33 +643,33 @@ public class PackUnpackUtil { } } - public static void main(final String[] args) throws Exception { - @MessagePackUnpackable - class Image { - public String uri = ""; + @MessagePackUnpackable + public static class Image { + public String uri = ""; - public String title = ""; + public String title = ""; - public int width = 0; + public int width = 0; - public int height = 0; + public int height = 0; - public int size = 0; + public int size = 0; - public boolean equals(Image 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() != Image.class) { - return false; - } - return equals((Image) obj); - } + public boolean equals(Image 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() != Image.class) { + return false; + } + return equals((Image) obj); + } + } + + public static void main(final String[] args) throws Exception { PackUnpackUtil.getEnhancedClass(Image.class); Image src = (Image) PackUnpackUtil.newEnhancedInstance(Image.class); src.title = "msgpack"; diff --git a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java index 1ec7d64e..4f6e74ef 100644 --- a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java +++ b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java @@ -3,6 +3,8 @@ package org.msgpack.util.annotation; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.math.BigInteger; +import java.util.List; +import java.util.Map; import junit.framework.TestCase; @@ -14,7 +16,7 @@ import org.msgpack.Unpacker; public class TestMessagePackUnpackable extends TestCase { @Test - public void testGeneralPrimitiveTypeFieldsClass() throws Exception { + public void testGeneralPrimitiveTypeFields() throws Exception { GeneralPrimitiveTypeFieldsClass src = (GeneralPrimitiveTypeFieldsClass) PackUnpackUtil .newEnhancedInstance(GeneralPrimitiveTypeFieldsClass.class); src.f0 = (byte) 0; @@ -101,8 +103,21 @@ public class TestMessagePackUnpackable extends TestCase { } } + public void testListAndMap() throws Exception { + // TODO + } + + @MessagePackUnpackable + public static class ListAndMapClass { + public List f0; + public Map f1; + + public ListAndMapClass() { + } + } + @Test - public void testPublicDefaultConstructorClass() throws Exception { + public void testDefaultConstructorModifiers() throws Exception { try { PackUnpackUtil.newEnhancedInstance(NoDefaultConstructorClass.class); fail(); @@ -111,21 +126,24 @@ public class TestMessagePackUnpackable extends TestCase { } assertTrue(true); try { - PackUnpackUtil.newEnhancedInstance(PrivateDefaultConstructorClass.class); + PackUnpackUtil + .newEnhancedInstance(PrivateDefaultConstructorClass.class); fail(); } catch (PackUnpackUtilException e) { assertTrue(true); } assertTrue(true); try { - PackUnpackUtil.newEnhancedInstance(ProtectedDefaultConstructorClass.class); + PackUnpackUtil + .newEnhancedInstance(ProtectedDefaultConstructorClass.class); assertTrue(true); } catch (PackUnpackUtilException e) { fail(); } assertTrue(true); try { - PackUnpackUtil.newEnhancedInstance(PackageDefaultConstructorClass.class); + PackUnpackUtil + .newEnhancedInstance(PackageDefaultConstructorClass.class); fail(); } catch (PackUnpackUtilException e) { assertTrue(true); @@ -158,7 +176,7 @@ public class TestMessagePackUnpackable extends TestCase { } @Test - public void testPublicModifierClass() throws Exception { + public void testClassModifiers() throws Exception { try { PackUnpackUtil.newEnhancedInstance(PrivateModifierClass.class); fail(); @@ -197,7 +215,7 @@ public class TestMessagePackUnpackable extends TestCase { } @Test - public void testFinalAndAbstractModifierClass() throws Exception { + public void testFinalClassAndAbstractClass() throws Exception { try { PackUnpackUtil.newEnhancedInstance(FinalModifierClass.class); fail(); @@ -223,7 +241,7 @@ public class TestMessagePackUnpackable extends TestCase { } @Test - public void testInterfaceAndEnum() throws Exception { + public void testInterfaceAndEnumType() throws Exception { try { PackUnpackUtil.newEnhancedInstance(SampleInterface.class); fail(); @@ -249,32 +267,128 @@ public class TestMessagePackUnpackable extends TestCase { } @Test - public void testFinalFieldClass() throws Exception { - + public void testFieldModifiers() throws Exception { + FieldModifiersClass src = (FieldModifiersClass) PackUnpackUtil + .newEnhancedInstance(FieldModifiersClass.class); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + FieldModifiersClass dst = (FieldModifiersClass) PackUnpackUtil + .newEnhancedInstance(FieldModifiersClass.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 == dst.f3); + assertTrue(src.f4 != dst.f4); } - @Test - public void testPrivateFieldClass() throws Exception { - - } - - @Test - public void testProtectedFieldClass() throws Exception { - - } - - @Test - public void testNonModifierFieldClass() throws Exception { + @MessagePackUnpackable + public static class FieldModifiersClass { + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + public FieldModifiersClass() { + } } @Test public void testNestedAnnotatedFieldClass() throws Exception { + NestedClass src2 = (NestedClass) PackUnpackUtil + .newEnhancedInstance(NestedClass.class); + BaseClass src = (BaseClass) PackUnpackUtil + .newEnhancedInstance(BaseClass.class); + src.f0 = 0; + src2.f2 = 2; + src.f1 = src2; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + NestedClass dst2 = (NestedClass) PackUnpackUtil + .newEnhancedInstance(NestedClass.class); + BaseClass dst = (BaseClass) PackUnpackUtil + .newEnhancedInstance(BaseClass.class); + dst.f1 = dst2; + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertTrue(src.f0 == dst.f0); + assertTrue(src2.f2 == dst.f1.f2); + } + @MessagePackUnpackable + public static class BaseClass { + public int f0; + public NestedClass f1; + + public BaseClass() { + } + } + + @MessagePackUnpackable + public static class NestedClass { + public int f2; + + public NestedClass() { + } } @Test - public void testSuperClass() throws Exception { + public void testExtendedClass() throws Exception { + SampleSubClass src = (SampleSubClass) PackUnpackUtil + .newEnhancedInstance(SampleSubClass.class); + src.f0 = 0; + src.f2 = 2; + src.f3 = 3; + src.f4 = 4; + src.f5 = 5; + src.f8 = 8; + src.f9 = 9; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + SampleSubClass dst = (SampleSubClass) PackUnpackUtil + .newEnhancedInstance(SampleSubClass.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertTrue(src.f0 == dst.f0); + assertTrue(src.f1 == dst.f1); + assertTrue(src.f2 != dst.f2); + assertTrue(src.f3 == dst.f3); + assertTrue(src.f4 != dst.f4); + assertTrue(src.f5 == dst.f5); + assertTrue(src.f6 == dst.f6); + assertTrue(src.f8 == dst.f8); + assertTrue(src.f9 != dst.f9); + } + @MessagePackUnpackable + public static class SampleSubClass extends SampleSuperClass { + public int f0; + public final int f1 = 1; + private int f2; + protected int f3; + int f4; + + public SampleSubClass() { + } + } + + public static class SampleSuperClass { + public int f5; + public final int f6 = 2; + private int f7; + protected int f8; + int f9; + + public SampleSuperClass() { + } } } From 56ece4db0f03f086c2d4608472de4b20e6a83a19 Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Tue, 14 Sep 2010 23:23:09 +0900 Subject: [PATCH 7/8] fixed a bug the program for packing and unpacking byte[] in annotation-utility --- .../java/org/msgpack/util/annotation/PackUnpackUtil.java | 3 ++- .../msgpack/util/annotation/TestMessagePackUnpackable.java | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java index a58b4bd5..f92c51a0 100644 --- a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java +++ b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java @@ -71,7 +71,8 @@ public class PackUnpackUtil { static final String TYPE_NAME_SHORT2 = Short.class.getName(); - static final String TYPE_NAME_BYTEARRAY = byte[].class.getName(); + //static final String TYPE_NAME_BYTEARRAY = byte[].class.getName(); + static final String TYPE_NAME_BYTEARRAY = "byte[]"; static final String TYPE_NAME_LIST = List.class.getName(); diff --git a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java index 4f6e74ef..1cde65f2 100644 --- a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java +++ b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java @@ -69,6 +69,7 @@ public class TestMessagePackUnpackable extends TestCase { src.f6 = false; src.f7 = new BigInteger("7"); src.f8 = "8"; + src.f9 = new byte[] { 0x01, 0x02 }; ByteArrayOutputStream out = new ByteArrayOutputStream(); new Packer(out).pack(src); GeneralReferenceTypeFieldsClass dst = (GeneralReferenceTypeFieldsClass) PackUnpackUtil @@ -85,6 +86,8 @@ public class TestMessagePackUnpackable extends TestCase { assertEquals(src.f6, dst.f6); assertEquals(src.f7, dst.f7); assertEquals(src.f8, dst.f8); + assertEquals(src.f9[0], dst.f9[0]); + assertEquals(src.f9[1], dst.f9[1]); } @MessagePackUnpackable @@ -98,13 +101,13 @@ public class TestMessagePackUnpackable extends TestCase { public Boolean f6; public BigInteger f7; public String f8; + public byte[] f9; public GeneralReferenceTypeFieldsClass() { } } public void testListAndMap() throws Exception { - // TODO } @MessagePackUnpackable From 9eeb702ca536f0e97e53202b177d9db5ac9e322f Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Wed, 15 Sep 2010 22:28:46 +0900 Subject: [PATCH 8/8] change an annotation-utility in Java. it allows users to pack and unpack a List object. --- .../annotation/MessagePackUnpackable.java | 2 +- .../util/annotation/PackUnpackUtil.java | 705 ++++++++++-------- .../annotation/TestMessagePackUnpackable.java | 105 ++- 3 files changed, 499 insertions(+), 313 deletions(-) diff --git a/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java b/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java index 473b5412..77f6e6de 100644 --- a/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java +++ b/java/src/main/java/org/msgpack/util/annotation/MessagePackUnpackable.java @@ -6,6 +6,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) +@Retention(RetentionPolicy.RUNTIME) public @interface MessagePackUnpackable { } diff --git a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java index f92c51a0..52384448 100644 --- a/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java +++ b/java/src/main/java/org/msgpack/util/annotation/PackUnpackUtil.java @@ -3,9 +3,14 @@ package org.msgpack.util.annotation; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; import java.math.BigInteger; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -14,7 +19,6 @@ import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; -import javassist.CtField; import javassist.CtMethod; import javassist.CtNewConstructor; import javassist.CtNewMethod; @@ -33,51 +37,16 @@ public class PackUnpackUtil { static final String KEYWORD_MODIFIER_PUBLIC = "public"; + static final String KEYWORD_FOR = "for"; + static final String KEYWORD_THROWS = "throws"; + static final String KEYWORD_NEW = "new"; + static final String TYPE_NAME_VOID = void.class.getName(); - static final String TYPE_NAME_BOOLEAN = boolean.class.getName(); - - static final String TYPE_NAME_BYTE = byte.class.getName(); - - static final String TYPE_NAME_DOUBLE = double.class.getName(); - - static final String TYPE_NAME_FLOAT = float.class.getName(); - - static final String TYPE_NAME_INT = int.class.getName(); - - static final String TYPE_NAME_LONG = long.class.getName(); - - static final String TYPE_NAME_SHORT = short.class.getName(); - static final String TYPE_NAME_OBJECT = Object.class.getName(); - static final String TYPE_NAME_BIGINTEGER = BigInteger.class.getName(); - - static final String TYPE_NAME_STRING = String.class.getName(); - - static final String TYPE_NAME_BOOLEAN2 = Boolean.class.getName(); - - static final String TYPE_NAME_BYTE2 = Byte.class.getName(); - - static final String TYPE_NAME_DOUBLE2 = Double.class.getName(); - - static final String TYPE_NAME_FLOAT2 = Float.class.getName(); - - static final String TYPE_NAME_INT2 = Integer.class.getName(); - - static final String TYPE_NAME_LONG2 = Long.class.getName(); - - static final String TYPE_NAME_SHORT2 = Short.class.getName(); - - //static final String TYPE_NAME_BYTEARRAY = byte[].class.getName(); - static final String TYPE_NAME_BYTEARRAY = "byte[]"; - - static final String TYPE_NAME_LIST = List.class.getName(); - - static final String TYPE_NAME_MAP = Map.class.getName(); - static final String TYPE_NAME_IOEXCEPTION = IOException.class.getName(); static final String TYPE_NAME_PACKER = Packer.class.getName(); @@ -111,6 +80,10 @@ public class PackUnpackUtil { static final String CHAR_NAME_EQUAL = "="; + static final String CHAR_NAME_PLUS = "+"; + + static final String CHAR_NAME_LESSTHAN = "<"; + static final String CHAR_NAME_RIGHT_PARENTHESIS = ")"; static final String CHAR_NAME_LEFT_PARENTHESIS = "("; @@ -127,8 +100,16 @@ public class PackUnpackUtil { static final String VARIABLE_NAME_OBJ = "obj"; + static final String VARIABLE_NAME_SIZE = "len"; + + static final String VARIABLE_NAME_I = "i"; + static final String METHOD_NAME_VALUEOF = "valueOf"; + static final String METHOD_NAME_ADD = "add"; + + static final String METHOD_NAME_PUT = "put"; + static final String METHOD_NAME_MSGPACK = "messagePack"; static final String METHOD_NAME_MSGUNPACK = "messageUnpack"; @@ -192,73 +173,68 @@ public class PackUnpackUtil { String origName = origClass.getName(); String enhName = origName + Constants.POSTFIX_TYPE_NAME_ENHANCER; CtClass origCtClass = pool.get(origName); - checkClassValidation(origCtClass); - checkDefaultConstructorValidation(origCtClass); + checkClassValidation(origClass); + checkDefaultConstructorValidation(origClass); CtClass enhCtClass = pool.makeClass(enhName); setSuperclass(enhCtClass, origCtClass); setInterfaces(enhCtClass); addConstructor(enhCtClass); - CtField[] fields = getDeclaredFields(origCtClass); + Field[] fields = getDeclaredFields(origClass); addMessagePackMethod(enhCtClass, origCtClass, fields); addMessageUnpackMethod(enhCtClass, origCtClass, fields); addMessageConvertMethod(enhCtClass, origCtClass, fields); return createClass(enhCtClass); } - private void checkClassValidation(CtClass origCtClass) { + private void checkClassValidation(Class origClass) { // not public, abstract, final - int mod = origCtClass.getModifiers(); - if ((!Modifier.isPublic(mod)) || Modifier.isAbstract(mod) - || Modifier.isFinal(mod)) { - throwClassValidationException(origCtClass); + int mod = origClass.getModifiers(); + if ((!(Modifier.isPublic(mod) || Modifier.isProtected(mod))) + || Modifier.isAbstract(mod) || Modifier.isFinal(mod)) { + throwClassValidationException(origClass); } // interface, enum - if (origCtClass.isInterface() || origCtClass.isEnum()) { - throwClassValidationException(origCtClass); + if (origClass.isInterface() || origClass.isEnum()) { + throwClassValidationException(origClass); } // annotation - checkPackUnpackAnnotation(origCtClass); + checkPackUnpackAnnotation(origClass); } - private static void throwClassValidationException(CtClass origCtClass) { + private static void throwClassValidationException(Class origClass) { throw new PackUnpackUtilException( "it must be a public class and have @" + MessagePackUnpackable.class.getName() + ": " - + origCtClass.getName()); + + origClass.getName()); } - private void checkPackUnpackAnnotation(CtClass origCtClass) { - try { - Object[] objs = origCtClass.getAnnotations(); - for (Object obj : objs) { - if (obj instanceof MessagePackUnpackable) { - return; - } - } - throwClassValidationException(origCtClass); - } catch (ClassNotFoundException e) { - throw new PackUnpackUtilException(e.getMessage(), e); + private void checkPackUnpackAnnotation(Class origClass) { + Annotation anno = origClass + .getAnnotation(MessagePackUnpackable.class); + if (anno == null) { + throwClassValidationException(origClass); } } - private void checkDefaultConstructorValidation(CtClass origCtClass) { - CtConstructor cons = null; + private void checkDefaultConstructorValidation(Class origClass) { + Constructor cons = null; try { - cons = origCtClass.getDeclaredConstructor(new CtClass[0]); - } catch (NotFoundException e) { - throwConstructoValidationException(origCtClass); + cons = origClass.getDeclaredConstructor(new Class[0]); + } catch (Exception e1) { + throwConstructoValidationException(origClass); } + int mod = cons.getModifiers(); if (!(Modifier.isPublic(mod) || Modifier.isProtected(mod))) { - throwConstructoValidationException(origCtClass); + throwConstructoValidationException(origClass); } } private static void throwConstructoValidationException( - CtClass origCtClass) { + Class origClass) { throw new PackUnpackUtilException( "it must have a public zero-argument constructor: " - + origCtClass.getName()); + + origClass.getName()); } private void setSuperclass(CtClass enhCtClass, CtClass origCtClass) @@ -282,301 +258,430 @@ public class PackUnpackUtil { enhCtClass.addConstructor(newCtCons); } - private CtField[] getDeclaredFields(CtClass origCtClass) { - ArrayList allFields = new ArrayList(); - try { - CtClass nextCtClass = origCtClass; - while (!nextCtClass - .equals(pool.get(Constants.TYPE_NAME_OBJECT))) { - CtField[] fields = nextCtClass.getDeclaredFields(); - for (CtField field : fields) { - try { - checkFieldValidation(field, allFields); - allFields.add(field); - } catch (PackUnpackUtilException e) { // ignore - } + private Field[] getDeclaredFields(Class origClass) { + ArrayList allFields = new ArrayList(); + Class nextClass = origClass; + while (nextClass != Object.class) { + Field[] fields = nextClass.getDeclaredFields(); + for (Field field : fields) { + try { + checkFieldValidation(field, allFields); + allFields.add(field); + } catch (PackUnpackUtilException e) { // ignore } - nextCtClass = nextCtClass.getSuperclass(); } - - } catch (NotFoundException e) { - throw new PackUnpackUtilException(e.getMessage(), e); + nextClass = nextClass.getSuperclass(); } - return allFields.toArray(new CtField[0]); + return allFields.toArray(new Field[0]); } - private void checkFieldValidation(CtField field, - ArrayList allFields) { + private void checkFieldValidation(Field field, List fields) { // check modifiers (public or protected) int mod = field.getModifiers(); if ((!(Modifier.isPublic(mod) || Modifier.isProtected(mod))) || Modifier.isStatic(mod) || Modifier.isFinal(mod) - || Modifier.isTransient(mod)) { + || Modifier.isTransient(mod) || field.isSynthetic()) { throwFieldValidationException(field); } // check same name - for (CtField f : allFields) { + for (Field f : fields) { if (f.getName().equals(field.getName())) { throwFieldValidationException(field); } } } - private static void throwFieldValidationException(CtField field) { + private static void throwFieldValidationException(Field field) { throw new PackUnpackUtilException("it must be a public field: " + field.getName()); } private void addMessagePackMethod(CtClass enhCtClass, - CtClass origCtClass, CtField[] fields) + CtClass origCtClass, Field[] fields) throws CannotCompileException, NotFoundException { StringBuilder sb = new StringBuilder(); - sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( - Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) - .append(Constants.CHAR_NAME_SPACE).append( - Constants.METHOD_NAME_MSGPACK).append( - Constants.CHAR_NAME_LEFT_PARENTHESIS).append( - Constants.TYPE_NAME_PACKER).append( - Constants.CHAR_NAME_SPACE).append( - Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( - Constants.CHAR_NAME_SPACE).append( - Constants.KEYWORD_THROWS).append( - Constants.CHAR_NAME_SPACE).append( - Constants.TYPE_NAME_IOEXCEPTION).append( - Constants.CHAR_NAME_SPACE).append( - Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( - Constants.CHAR_NAME_SPACE); - sb.append(Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_DOT).append( - Constants.METHOD_NAME_PACKARRAY).append( - Constants.CHAR_NAME_LEFT_PARENTHESIS).append(fields.length) - .append(Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( - Constants.CHAR_NAME_SEMICOLON).append( - Constants.CHAR_NAME_SPACE); - for (CtField field : fields) { - insertCodeOfMessagePack(field, sb); + sb.append(Constants.KEYWORD_MODIFIER_PUBLIC); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.TYPE_NAME_VOID); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.METHOD_NAME_MSGPACK); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.TYPE_NAME_PACKER); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.KEYWORD_THROWS); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.TYPE_NAME_IOEXCEPTION); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LEFT_CURLY_BRACHET); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_PACKARRAY); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(fields.length); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + for (Field field : fields) { + insertCodeOfMessagePack(sb, field); } sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); - System.out.println("messagePack method: " + sb.toString()); + //System.out.println("messagePack method: " + sb.toString()); CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhCtClass); enhCtClass.addMethod(newCtMethod); } - private void insertCodeOfMessagePack(CtField field, StringBuilder sb) - throws NotFoundException { - sb.append(Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_DOT).append(Constants.METHOD_NAME_PACK) - .append(Constants.CHAR_NAME_LEFT_PARENTHESIS).append( - field.getName()).append( - Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( - Constants.CHAR_NAME_SEMICOLON).append( - Constants.CHAR_NAME_SPACE); + private void insertCodeOfMessagePack(StringBuilder sb, Field field) { + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_PACK); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); } private void addMessageUnpackMethod(CtClass enhCtClass, - CtClass origCtClass, CtField[] fields) + CtClass origCtClass, Field[] fields) throws CannotCompileException, NotFoundException { StringBuilder sb = new StringBuilder(); - sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( - Constants.CHAR_NAME_SPACE).append(Constants.TYPE_NAME_VOID) - .append(Constants.CHAR_NAME_SPACE).append( - Constants.METHOD_NAME_MSGUNPACK).append( - Constants.CHAR_NAME_LEFT_PARENTHESIS).append( - Constants.TYPE_NAME_UNPACKER).append( - Constants.CHAR_NAME_SPACE).append( - Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( - Constants.CHAR_NAME_SPACE).append( - Constants.KEYWORD_THROWS).append( - Constants.CHAR_NAME_SPACE).append( - Constants.TYPE_NAME_MSGTYPEEXCEPTION).append( - Constants.CHAR_NAME_COMMA).append( - Constants.CHAR_NAME_SPACE).append( - Constants.TYPE_NAME_IOEXCEPTION).append( - Constants.CHAR_NAME_SPACE).append( - Constants.CHAR_NAME_LEFT_CURLY_BRACHET).append( - Constants.CHAR_NAME_SPACE); - sb.append(Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_DOT).append( - Constants.METHOD_NAME_UNPACKARRAY).append( - Constants.CHAR_NAME_LEFT_PARENTHESIS).append( - Constants.CHAR_NAME_RIGHT_PARENTHESIS).append( - Constants.CHAR_NAME_SEMICOLON).append( - Constants.CHAR_NAME_SPACE); - for (CtField field : fields) { - insertCodeOfMessageUnpack(field, sb); + sb.append(Constants.KEYWORD_MODIFIER_PUBLIC); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.TYPE_NAME_VOID); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.METHOD_NAME_MSGUNPACK); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.TYPE_NAME_UNPACKER); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.KEYWORD_THROWS); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.TYPE_NAME_MSGTYPEEXCEPTION); + sb.append(Constants.CHAR_NAME_COMMA); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.TYPE_NAME_IOEXCEPTION); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LEFT_CURLY_BRACHET); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_UNPACKARRAY); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + for (Field field : fields) { + insertCodeOfMessageUnpack(sb, field, field.getType()); } sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); - System.out.println("messageUnpack method: " + sb.toString()); + //System.out.println("messageUnpack method: " + sb.toString()); CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhCtClass); enhCtClass.addMethod(newCtMethod); } - private void insertCodeOfMessageUnpack(CtField field, StringBuilder sb) - throws NotFoundException { - CtClass type = field.getType(); - insertRightVariable(sb, field, type); - insertValueOfMethodAndLeftParenthesis(sb, type); - sb.append(Constants.VARIABLE_NAME_PK).append( - Constants.CHAR_NAME_DOT); - insertUnpackMethod(sb, type); - sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); - insertUnpackMethodArgumenet(sb, field, type); - sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); - insertValueOfMethodAndRightParenthesis(sb, type); - sb.append(Constants.CHAR_NAME_SEMICOLON).append( - Constants.CHAR_NAME_SPACE); - - } - - private void insertRightVariable(StringBuilder sb, CtField field, - CtClass type) throws NotFoundException { - if (type.isPrimitive()) { // primitive type - sb.append(field.getName()).append(Constants.CHAR_NAME_SPACE) - .append(Constants.CHAR_NAME_EQUAL).append( - Constants.CHAR_NAME_SPACE); - } else { // reference type - if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2)) // Boolean - || type.equals(pool.get(Constants.TYPE_NAME_BYTE2)) // Byte - || type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2)) // Double - || type.equals(pool.get(Constants.TYPE_NAME_FLOAT2)) // Float - || type.equals(pool.get(Constants.TYPE_NAME_INT2)) // Integer - || type.equals(pool.get(Constants.TYPE_NAME_LONG2)) // Long - || type.equals(pool.get(Constants.TYPE_NAME_SHORT2)) // Short - || type - .equals(pool - .get(Constants.TYPE_NAME_BIGINTEGER)) // BigInteger - || type.equals(pool.get(Constants.TYPE_NAME_STRING)) // String - || type.equals(pool.get(Constants.TYPE_NAME_BYTEARRAY)) // byte[] - || type.subtypeOf(pool.get(Constants.TYPE_NAME_LIST)) // List - || type.subtypeOf(pool.get(Constants.TYPE_NAME_MAP)) // Map - ) { - sb.append(field.getName()) - .append(Constants.CHAR_NAME_SPACE).append( - Constants.CHAR_NAME_EQUAL).append( - Constants.CHAR_NAME_SPACE); - } else { // MessageUnpackable - return; - } - } - - } - - private void insertValueOfMethodAndLeftParenthesis(StringBuilder sb, - CtClass type) throws NotFoundException { - if (type.isPrimitive()) { // primitive type - return; - } else { // reference type - if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2)) // Boolean - || type.equals(pool.get(Constants.TYPE_NAME_BYTE2)) // Byte - || type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2)) // Double - || type.equals(pool.get(Constants.TYPE_NAME_FLOAT2)) // Float - || type.equals(pool.get(Constants.TYPE_NAME_INT2)) // Integer - || type.equals(pool.get(Constants.TYPE_NAME_LONG2)) // Long - || type.equals(pool.get(Constants.TYPE_NAME_SHORT2)) // Short - ) { - sb.append(type.getName()).append(Constants.CHAR_NAME_DOT) - .append(Constants.METHOD_NAME_VALUEOF).append( - Constants.CHAR_NAME_LEFT_PARENTHESIS); - } else { - return; - } + private void insertCodeOfMessageUnpack(StringBuilder sb, Field field, + Class type) throws NotFoundException { + if (type.isPrimitive()) { + // primitive type + insertCodeOfMessageUnpackForPrimitiveTypes(sb, field, type); + } else if (type.equals(Boolean.class) || // Boolean + type.equals(Byte.class) || // Byte + type.equals(Double.class) || // Double + type.equals(Float.class) || // Float + type.equals(Integer.class) || // Integer + type.equals(Long.class) || // Long + type.equals(Short.class)) { // Short + // reference type (wrapper type) + insertCodeOfMessageUnpackForWrapperTypes(sb, field, type); + } else if (type.equals(BigInteger.class) || // BigInteger + type.equals(String.class) || // String + type.equals(byte[].class)) { // byte[] + // reference type (other type) + insertCodeOfMessageUnpackForPrimitiveTypes(sb, field, type); + } else if (List.class.isAssignableFrom(type)) { + // List + insertCodeOfMessageUnpackForListType(sb, field, type); + } else if (Map.class.isAssignableFrom(type)) { + // Map + insertCodeOfMessageUnpackForMapType(sb, field, type); + } else if (MessageUnpackable.class.isAssignableFrom(type) + || (getCache(type.getName()) != null)) { + // MessageUnpackable + insertCodeOfMessageUnpackForMsgUnpackableType(sb, field, type); + } else { + throw new NotFoundException("unknown type: " + type.getName()); } } - private void insertUnpackMethod(StringBuilder sb, CtClass type) + private void insertCodeOfMessageUnpackForPrimitiveTypes( + StringBuilder sb, Field field, Class type) throws NotFoundException { - if (type.equals(CtClass.booleanType)) { // boolean + // insert a right variable + if (field != null) { + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + } + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + // insert unpack method + if (type.equals(boolean.class)) { // boolean sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); - } else if (type.equals(CtClass.byteType)) { // byte + } else if (type.equals(byte.class)) { // byte sb.append(Constants.METHOD_NAME_UNPACKBYTE); - } else if (type.equals(CtClass.doubleType)) { // double + } else if (type.equals(double.class)) { // double sb.append(Constants.METHOD_NAME_UNPACKDOUBLE); - } else if (type.equals(CtClass.floatType)) { // float + } else if (type.equals(float.class)) { // float sb.append(Constants.METHOD_NAME_UNPACKFLOAT); - } else if (type.equals(CtClass.intType)) { // int + } else if (type.equals(int.class)) { // int sb.append(Constants.METHOD_NAME_UNPACKINT); - } else if (type.equals(CtClass.longType)) { // long + } else if (type.equals(long.class)) { // long sb.append(Constants.METHOD_NAME_UNPACKLONG); - } else if (type.equals(CtClass.shortType)) { // short + } else if (type.equals(short.class)) { // short sb.append(Constants.METHOD_NAME_UNPACKSHORT); } else { // reference type - Class c = null; - if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2))) { // Boolean - sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); - } else if (type.equals(pool.get(Constants.TYPE_NAME_BYTE2))) { // Byte - sb.append(Constants.METHOD_NAME_UNPACKBYTE); - } else if (type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2))) { // Double - sb.append(Constants.METHOD_NAME_UNPACKDOUBLE); - } else if (type.equals(pool.get(Constants.TYPE_NAME_FLOAT2))) { // Float - sb.append(Constants.METHOD_NAME_UNPACKFLOAT); - } else if (type.equals(pool.get(Constants.TYPE_NAME_INT2))) { // Integer - sb.append(Constants.METHOD_NAME_UNPACKINT); - } else if (type.equals(pool.get(Constants.TYPE_NAME_LONG2))) { // Long - sb.append(Constants.METHOD_NAME_UNPACKLONG); - } else if (type.equals(pool.get(Constants.TYPE_NAME_SHORT2))) { // Short - sb.append(Constants.METHOD_NAME_UNPACKSHORT); - } else if (type - .equals(pool.get(Constants.TYPE_NAME_BIGINTEGER))) { // BigInteger + if (type.equals(BigInteger.class)) { // BigInteger sb.append(Constants.METHOD_NAME_UNPACKBIGINTEGER); - } else if (type.equals(pool.get(Constants.TYPE_NAME_STRING))) { // String + } else if (type.equals(String.class)) { // String sb.append(Constants.METHOD_NAME_UNPACKSTRING); - } else if (type.equals(pool.get(Constants.TYPE_NAME_BYTEARRAY))) { // byte[] + } else if (type.equals(byte[].class)) { // byte[] sb.append(Constants.METHOD_NAME_UNPACKBYTEARRAY); - } else if (type.subtypeOf(pool.get(Constants.TYPE_NAME_LIST))) { // List - sb.append(Constants.METHOD_NAME_UNPACKARRAY); - } else if (type.subtypeOf(pool.get(Constants.TYPE_NAME_MAP))) { // Map - sb.append(Constants.METHOD_NAME_UNPACKMAP); - } else if (type.subtypeOf(pool - .get(Constants.TYPE_NAME_MSGUNPACKABLE)) - || ((c = getCache(type.getName())) != null)) { // MessageUnpackable - sb.append(Constants.METHOD_NAME_UNPACK); } else { throw new NotFoundException("unknown type: " + type.getName()); } } - } - - private void insertUnpackMethodArgumenet(StringBuilder sb, - CtField field, CtClass type) throws NotFoundException { - if (type.isPrimitive()) { // primitive type - return; - } else { // reference type - Class c = null; - if (type.equals(pool.get(Constants.TYPE_NAME_MSGUNPACKABLE)) - || ((c = getCache(type.getName())) != null)) { - sb.append("(org.msgpack.MessageUnpackable)"); - sb.append(field.getName()); - } else { - return; - } + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + if (field != null) { + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); } } - private void insertValueOfMethodAndRightParenthesis(StringBuilder sb, - CtClass type) throws NotFoundException { - if (type.isPrimitive()) { // primitive type - return; - } else { // reference type - if (type.equals(pool.get(Constants.TYPE_NAME_BOOLEAN2)) // Boolean - || type.equals(pool.get(Constants.TYPE_NAME_BYTE2)) // Byte - || type.equals(pool.get(Constants.TYPE_NAME_DOUBLE2)) // Double - || type.equals(pool.get(Constants.TYPE_NAME_FLOAT2)) // Float - || type.equals(pool.get(Constants.TYPE_NAME_INT2)) // Integer - || type.equals(pool.get(Constants.TYPE_NAME_LONG2)) // Long - || type.equals(pool.get(Constants.TYPE_NAME_SHORT2)) // Short - ) { - sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); - } else { - return; - } + private void insertCodeOfMessageUnpackForWrapperTypes(StringBuilder sb, + Field field, Class type) throws NotFoundException { + // insert a right variable + if (field != null) { + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); } + sb.append(type.getName()); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_VALUEOF); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + // insert the name of a unpack method + if (type.equals(Boolean.class)) { // Boolean + sb.append(Constants.METHOD_NAME_UNPACKBOOLEAN); + } else if (type.equals(Byte.class)) { // Byte + sb.append(Constants.METHOD_NAME_UNPACKBYTE); + } else if (type.equals(Double.class)) { // Double + sb.append(Constants.METHOD_NAME_UNPACKDOUBLE); + } else if (type.equals(Float.class)) { // Float + sb.append(Constants.METHOD_NAME_UNPACKFLOAT); + } else if (type.equals(Integer.class)) { // Integer + sb.append(Constants.METHOD_NAME_UNPACKINT); + } else if (type.equals(Long.class)) { // Long + sb.append(Constants.METHOD_NAME_UNPACKLONG); + } else if (type.equals(Short.class)) { // Short + sb.append(Constants.METHOD_NAME_UNPACKSHORT); + } else { + throw new NotFoundException("unknown type: " + type.getName()); + } + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + if (field != null) { + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + } + } + + private void insertCodeOfMessageUnpackForListType(StringBuilder sb, + Field field, Class type) throws NotFoundException { + ParameterizedType generic = (ParameterizedType) field + .getGenericType(); + Class genericType = (Class) generic.getActualTypeArguments()[0]; + + // len + sb.append(int.class.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_SIZE); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_UNPACKARRAY); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + + // field initializer + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.KEYWORD_NEW); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(ArrayList.class.getName()); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + + // for loop + sb.append(Constants.KEYWORD_FOR); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(int.class.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_I); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(0); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_I); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LESSTHAN); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_SIZE); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_PLUS); + sb.append(Constants.CHAR_NAME_PLUS); + sb.append(Constants.VARIABLE_NAME_I); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LEFT_CURLY_BRACHET); + sb.append(Constants.CHAR_NAME_SPACE); + + // block + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_ADD); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + insertCodeOfMessageUnpack(sb, null, genericType); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + + sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); + sb.append(Constants.CHAR_NAME_SPACE); + } + + private void insertCodeOfMessageUnpackForMapType(StringBuilder sb, + Field field, Class type) throws NotFoundException { + ParameterizedType generic = (ParameterizedType) field + .getGenericType(); + Class genericType0 = (Class) generic.getActualTypeArguments()[0]; + Class genericType1 = (Class) generic.getActualTypeArguments()[1]; + + // len + sb.append(int.class.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_SIZE); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_UNPACKMAP); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + + // field initializer + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.KEYWORD_NEW); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(HashMap.class.getName()); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + + // for loop + sb.append(Constants.KEYWORD_FOR); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(int.class.getName()); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_I); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_EQUAL); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(0); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_I); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LESSTHAN); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.VARIABLE_NAME_SIZE); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_PLUS); + sb.append(Constants.CHAR_NAME_PLUS); + sb.append(Constants.VARIABLE_NAME_I); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SPACE); + sb.append(Constants.CHAR_NAME_LEFT_CURLY_BRACHET); + sb.append(Constants.CHAR_NAME_SPACE); + + // block map. + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_PUT); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + insertCodeOfMessageUnpack(sb, null, genericType0); + sb.append(Constants.CHAR_NAME_COMMA); + sb.append(Constants.CHAR_NAME_SPACE); + insertCodeOfMessageUnpack(sb, null, genericType1); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); + + sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); + sb.append(Constants.CHAR_NAME_SPACE); + } + + private void insertCodeOfMessageUnpackForMsgUnpackableType( + StringBuilder sb, Field field, Class type) { + // insert a right variable // ignore + sb.append(Constants.VARIABLE_NAME_PK); + sb.append(Constants.CHAR_NAME_DOT); + sb.append(Constants.METHOD_NAME_UNPACK); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_LEFT_PARENTHESIS); + sb.append(MessageUnpackable.class.getName()); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(field.getName()); + sb.append(Constants.CHAR_NAME_RIGHT_PARENTHESIS); + sb.append(Constants.CHAR_NAME_SEMICOLON); + sb.append(Constants.CHAR_NAME_SPACE); } private void addMessageConvertMethod(CtClass enhCtClass, - CtClass origCtClass, CtField[] fields) + CtClass origCtClass, Field[] fields) throws CannotCompileException { StringBuilder sb = new StringBuilder(); sb.append(Constants.KEYWORD_MODIFIER_PUBLIC).append( @@ -597,7 +702,7 @@ public class PackUnpackUtil { Constants.CHAR_NAME_SPACE); // TODO sb.append(Constants.CHAR_NAME_RIGHT_CURLY_BRACHET); - System.out.println("messageConvert method: " + sb.toString()); + //System.out.println("messageConvert method: " + sb.toString()); CtMethod newCtMethod = CtNewMethod.make(sb.toString(), enhCtClass); enhCtClass.addMethod(newCtMethod); } @@ -684,6 +789,6 @@ public class PackUnpackUtil { ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); Unpacker pac = new Unpacker(in); pac.unpack((MessageUnpackable) dst); - System.out.println(src.equals(dst)); + //System.out.println(src.equals(dst)); } } diff --git a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java index 1cde65f2..dbea7cb2 100644 --- a/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java +++ b/java/src/test/java/org/msgpack/util/annotation/TestMessagePackUnpackable.java @@ -3,6 +3,9 @@ package org.msgpack.util.annotation; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -16,9 +19,9 @@ import org.msgpack.Unpacker; public class TestMessagePackUnpackable extends TestCase { @Test - public void testGeneralPrimitiveTypeFields() throws Exception { - GeneralPrimitiveTypeFieldsClass src = (GeneralPrimitiveTypeFieldsClass) PackUnpackUtil - .newEnhancedInstance(GeneralPrimitiveTypeFieldsClass.class); + public void testPrimitiveTypeFields() throws Exception { + PrimitiveTypeFieldsClass src = (PrimitiveTypeFieldsClass) PackUnpackUtil + .newEnhancedInstance(PrimitiveTypeFieldsClass.class); src.f0 = (byte) 0; src.f1 = 1; src.f2 = 2; @@ -28,8 +31,8 @@ public class TestMessagePackUnpackable extends TestCase { src.f6 = false; ByteArrayOutputStream out = new ByteArrayOutputStream(); new Packer(out).pack(src); - GeneralPrimitiveTypeFieldsClass dst = (GeneralPrimitiveTypeFieldsClass) PackUnpackUtil - .newEnhancedInstance(GeneralPrimitiveTypeFieldsClass.class); + PrimitiveTypeFieldsClass dst = (PrimitiveTypeFieldsClass) PackUnpackUtil + .newEnhancedInstance(PrimitiveTypeFieldsClass.class); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); Unpacker pac = new Unpacker(in); pac.unpack((MessageUnpackable) dst); @@ -43,7 +46,7 @@ public class TestMessagePackUnpackable extends TestCase { } @MessagePackUnpackable - public static class GeneralPrimitiveTypeFieldsClass { + public static class PrimitiveTypeFieldsClass { public byte f0; public short f1; public int f2; @@ -52,7 +55,7 @@ public class TestMessagePackUnpackable extends TestCase { public double f5; public boolean f6; - public GeneralPrimitiveTypeFieldsClass() { + public PrimitiveTypeFieldsClass() { } } @@ -107,15 +110,93 @@ public class TestMessagePackUnpackable extends TestCase { } } - public void testListAndMap() throws Exception { + public void testListTypes() throws Exception { + SampleListTypes src = (SampleListTypes) PackUnpackUtil + .newEnhancedInstance(SampleListTypes.class); + src.f0 = new ArrayList(); + src.f1 = new ArrayList(); + src.f1.add(1); + src.f1.add(2); + src.f1.add(3); + src.f2 = new ArrayList(); + src.f2.add("e1"); + src.f2.add("e2"); + src.f2.add("e3"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + SampleListTypes dst = (SampleListTypes) PackUnpackUtil + .newEnhancedInstance(SampleListTypes.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + for (int i = 0; i < src.f1.size(); ++i) { + assertEquals(src.f1.get(i), dst.f1.get(i)); + } + assertEquals(src.f2.size(), dst.f2.size()); + for (int i = 0; i < src.f2.size(); ++i) { + assertEquals(src.f2.get(i), dst.f2.get(i)); + } } @MessagePackUnpackable - public static class ListAndMapClass { - public List f0; - public Map f1; + public static class SampleListTypes { + public List f0; + public List f1; + public List f2; - public ListAndMapClass() { + public SampleListTypes() { + } + } + + public void testMapTypes() throws Exception { + SampleMapTypes src = (SampleMapTypes) PackUnpackUtil + .newEnhancedInstance(SampleMapTypes.class); + src.f0 = new HashMap(); + src.f1 = new HashMap(); + src.f1.put(1, 1); + src.f1.put(2, 2); + src.f1.put(3, 3); + src.f2 = new HashMap(); + src.f2.put("k1", 1); + src.f2.put("k2", 2); + src.f2.put("k3", 3); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + new Packer(out).pack(src); + SampleMapTypes dst = (SampleMapTypes) PackUnpackUtil + .newEnhancedInstance(SampleMapTypes.class); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Unpacker pac = new Unpacker(in); + pac.unpack((MessageUnpackable) dst); + assertEquals(src.f0.size(), dst.f0.size()); + assertEquals(src.f1.size(), dst.f1.size()); + Iterator srcf1 = src.f1.keySet().iterator(); + Iterator dstf1 = dst.f1.keySet().iterator(); + while (srcf1.hasNext()) { + Integer s1 = srcf1.next(); + Integer d1 = dstf1.next(); + assertEquals(s1, d1); + assertEquals(src.f1.get(s1), dst.f1.get(d1)); + } + assertEquals(src.f2.size(), dst.f2.size()); + Iterator srcf2 = src.f2.keySet().iterator(); + Iterator dstf2 = dst.f2.keySet().iterator(); + while (srcf2.hasNext()) { + String s2 = srcf2.next(); + String d2 = dstf2.next(); + assertEquals(s2, d2); + assertEquals(src.f2.get(s2), dst.f2.get(d2)); + } + } + + @MessagePackUnpackable + public static class SampleMapTypes { + public Map f0; + public Map f1; + public Map f2; + + public SampleMapTypes() { } }