Skip to content

Instantly share code, notes, and snippets.

@jackeylu
Created July 14, 2016 12:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jackeylu/3fa72264ca7de02f7030d0ed7b98a3e4 to your computer and use it in GitHub Desktop.
Save jackeylu/3fa72264ca7de02f7030d0ed7b98a3e4 to your computer and use it in GitHub Desktop.
package example.protostuff;
/**
* wrapper is needed for interface and abstract modifier
* Created by jackeylv on 2016/7/14.
*/
public class ClassWrapper {
private Object wrappedValue;
public ClassWrapper(){
wrappedValue = null;
}
public Object getValue() {
return wrappedValue;
}
public void setValue(Object value) {
this.wrappedValue = value;
}
// public Class getRealClass(){
// if (null == value)
// return ClassWrapper.class;
//
// Class clz = value.getClass();
// if (clz.isInterface()
// || Modifier.isAbstract(clz.getModifiers())){
// return ClassWrapper.class;
// }
//
// return clz;
// }
}
package example.protostuff;
import io.protostuff.Input;
import io.protostuff.Output;
import io.protostuff.Pipe;
import io.protostuff.WireFormat;
import io.protostuff.runtime.Delegate;
import java.io.IOException;
import java.sql.Date;
/**
* Created by jackeylv on 2016/7/14.
*/
public class Delegates {
public static final Delegate<Date> DATE_DELEGATE = new Delegate<Date>() {
public WireFormat.FieldType getFieldType() {
return WireFormat.FieldType.FIXED64;
}
public Date readFrom(Input input) throws IOException {
return new Date(input.readFixed64());
}
public void writeTo(Output output, int number, Date value, boolean repeated) throws IOException {
output.writeFixed64(number, value.getTime(), repeated);
}
public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated) throws IOException {
output.writeFixed64(number, input.readFixed64(), repeated);
}
public Class<?> typeClass() {
return Date.class;
}
};
}
package example.protostuff;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.DefaultIdStrategy;
import io.protostuff.runtime.RuntimeSchema;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by jackeylv on 2016/7/14.
*/
public class SerializationUtil {
private static ConcurrentHashMap<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap(256);
private static DefaultIdStrategy strategy = new DefaultIdStrategy();
static {
strategy.registerDelegate(Delegates.DATE_DELEGATE);
}
private static ThreadLocal<ClassWrapper> clazzWrapper = new ThreadLocal<ClassWrapper>(){
@Override
protected ClassWrapper initialValue() {
return new ClassWrapper();
}
};
private SerializationUtil(){}
private static Schema getSchema(Class clz){
Schema schema = cachedSchema.get(clz);
if (null == schema){
schema = RuntimeSchema.getSchema(clz, strategy);
if (null != schema){
cachedSchema.put(clz, schema);
} else {
throw new IllegalStateException("Failed to create schema for class " + clz);
}
}
return schema;
}
/**
* @param obj
* @return
*/
public static byte[] marshall(Object obj){
clazzWrapper.get().setValue(obj);
LinkedBuffer buffer = LinkedBuffer.allocate();
try {
Schema schema = getSchema(ClassWrapper.class);
return ProtostuffIOUtil.toByteArray(clazzWrapper.get(), schema, buffer);
}finally {
buffer.clear();
}
}
public static Object unmarshall(byte[] bytes){
if (0 == bytes.length)
return null;
Schema schema = getSchema(ClassWrapper.class);
assert null != schema : "schema is null";
ClassWrapper message = (ClassWrapper) schema.newMessage();
ProtostuffIOUtil.mergeFrom(bytes, message, schema);
return message.getValue();
}
}
package example.protostuff;
import example.protostuff.SerializationUtil;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
import static org.junit.Assert.*;
/**
* Created by jackeylv on 2016/7/14.
*/
public class SerializationUtilTest {
private void testHelper(Object obj){
byte[] bytes = SerializationUtil.marshall(obj);
System.out.printf("object = %s, object.class = %s, bytes.length = %d, bytes = %s%n",
obj, null != obj ? obj.getClass() : null, bytes.length, bytes);
Object desr = SerializationUtil.unmarshall(bytes);
if (null == obj && null == desr){
return;
}
if (null == obj && null != desr){
Assert.fail("desc != null");
}
if (obj.getClass().isArray()){
System.out.println(Arrays.deepToString((Object[]) obj));
System.out.println(Arrays.deepToString((Object[]) desr));
Assert.assertArrayEquals(((Object[]) obj), ((Object[]) desr));
} else {
Assert.assertEquals(obj, desr);
}
}
@Test
public void testListWithNullElement() throws Exception {
LinkedList lst = new LinkedList();
testHelper(lst);
lst.add(1);
lst.add("hello");
lst.add("2.456");
testHelper(lst);
lst.add(null);
lst.add("hi");
testHelper(lst);
}
@Test
public void testSetWithNullElement() throws Exception {
HashSet set = null;
testHelper(set);
set = new HashSet();
testHelper(set);
set.add(1);
set.add("23");
set.add(null);
testHelper(set);
}
@Test
public void testObjectArrayWithNullElements() throws Exception {
Object[] objects = new Object[]{
1, null, "hello", null, 345
};
testHelper(objects);
}
/**
* FIXME We can fix it with {@link ClassWrapper}. Or any other suggestions?
* java.lang.RuntimeException: The root object can neither be an abstract class nor interface: "[Ljava.lang.Integer;
* @throws Exception
*/
@Test
public void testIntArrayWithRawPS() throws Exception {
Integer[] arr = new Integer[]{0,1,2,3};
Schema schema = RuntimeSchema.getSchema(arr.getClass());
LinkedBuffer buffer = LinkedBuffer.allocate();
try {
byte[] bytes = ProtostuffIOUtil.toByteArray(arr,schema,buffer);
Integer[] ret = (Integer[]) schema.newMessage();
ProtostuffIOUtil.mergeFrom(bytes, ret, schema);
Assert.assertArrayEquals(arr, ret);
} finally {
buffer.clear();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment