mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-10-15 23:20:08 +02:00
add annotation utilities for Java
This commit is contained in:
@@ -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<String, Class<?>> classMap;
|
||||
|
||||
private HashMap<String, Object> objectCacheMap;
|
||||
|
||||
private ClassPool pool;
|
||||
|
||||
public DynamicCodeGenerator() {
|
||||
classMap = new HashMap<String, Class<?>>();
|
||||
objectCacheMap = new HashMap<String, Object>();
|
||||
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));
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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 {
|
||||
}
|
@@ -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<String, Class<?>> classCache;
|
||||
|
||||
private ClassPool pool;
|
||||
|
||||
protected Enhancer() {
|
||||
classCache = new ConcurrentHashMap<String, Class<?>>();
|
||||
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));
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user