Skip to content

Instantly share code, notes, and snippets.

@jackeylu
Created July 14, 2016 12:25
Show Gist options
  • Save jackeylu/3fa72264ca7de02f7030d0ed7b98a3e4 to your computer and use it in GitHub Desktop.
Save jackeylu/3fa72264ca7de02f7030d0ed7b98a3e4 to your computer and use it in GitHub Desktop.

Revisions

  1. jackeylu created this gist Jul 14, 2016.
    34 changes: 34 additions & 0 deletions ClassWrapper.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    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;
    // }
    }
    38 changes: 38 additions & 0 deletions Delegates.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    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;
    }
    };
    }
    69 changes: 69 additions & 0 deletions SerializationUtil.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    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();
    }

    }
    101 changes: 101 additions & 0 deletions SerializationUtilTest.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,101 @@
    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();
    }
    }
    }