From a9566b31be76ebc8aaf9149c1a09d3720c3f2ec9 Mon Sep 17 00:00:00 2001 From: Muga Nishizawa Date: Sun, 12 Sep 2010 22:21:33 +0900 Subject: add annotation utilities for Java --- .../java/org/msgpack/tmp/DynamicCodeGenerator.java | 206 --------- java/src/main/java/org/msgpack/tmp/Image1.java | 47 -- java/src/main/java/org/msgpack/tmp/Image2.java | 85 ---- java/src/main/java/org/msgpack/tmp/Image3.java | 38 -- .../org/msgpack/tmp/ImagePackUnpackPerfTest.java | 134 ------ .../util/annotation/MessagePackOptional.java | 12 + .../util/annotation/MessagePackRequired.java | 12 + .../util/annotation/MessagePackUnpackable.java | 11 + .../msgpack/util/annotation/PackUnpackUtil.java | 498 +++++++++++++++++++++ .../util/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 (limited to '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 78238b4..0000000 --- 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 f1819ed..0000000 --- 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 9c357bf..0000000 --- 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 a28ff53..0000000 --- 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 1f27c1b..0000000 --- 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 0000000..a565292 --- /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 0000000..03e50cf --- /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 0000000..473b541 --- /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 0000000..37b9e0d --- /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 0000000..df3af05 --- /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); + } +} -- cgit v1.2.1