开发者

java/scala: faster type-aware serialization of only basic types?

in scala, i have a need to serialize objects that are limited to a small set of basic types: array, list, map, set, int, boolean, etc. i want to be able to serialize and deserialize those in a way that preserves the type information in the serialized format. specifically, if i have serialized an Array[Any], i want to be able to deserialize it and only specify that the resulting object is Array[Any]. that is, i don't want to specify a structure definition for every single thing i'm going to serialize. at the same time it needs to be able to distinguish between int and long, tuple and array, etc.

for example:

val obj = Array[Any](...) // can have any basic开发者_开发技巧 types in here
val ser = serialize(obj)
val newObj = deserialize[Array[Any]](ser) // recovers the exact types from the original obj

json is not appropriate for this case because it has a many-to-one mapping of scala types to json types. i'm currently using java serialization but it's extremely slow. since i don't need to serialize any arbitrary object type, is there a faster alternative for my narrower use case?


I don't about speed or indeed availability of library support, but have you looked at ASN.1?


I'd use a simple interface like this:

public interface Serializer{

    public <T> T deserialize(String serializedData);

    public String serialize(Object data);

}

And an enum to implement it:

public enum StandardSerializer implements Serializer{
    INTEGER("I", Integer.class, int.class){

        @Override
        protected Integer doDeserialize(final String stripped){
            return Integer.valueOf(stripped);
        }

    },

    STRING("I", String.class){

        @Override
        protected Object doDeserialize(final String stripped){
            return stripped;
        }

    },

    LIST("L", List.class){

        @Override
        protected String doSerialize(final Object data){
            final Iterator<?> it = ((List<?>) ((List<?>) data)).iterator();
            final StringBuilder sb = new StringBuilder();
            if(it.hasNext()){
                Object next = it.next();
                sb.append(StandardSerializer
                    .forType(next.getClass())
                    .serialize(next));
                while(it.hasNext()){
                    sb.append(',');
                    next = it.next();
                    sb.append(StandardSerializer
                        .forType(next.getClass())
                        .serialize(next));
                }
            }

            return sb.toString();
        }

        @Override
        protected Object doDeserialize(final String stripped){
            final List<Object> list = new ArrayList<Object>();
            for(final String item : stripped.split(",")){
                list.add(StandardSerializer.forData(item).deserialize(item));
            }
            return list;
        }
    }

    /* feel free to implement more enum entries */
    ;

    private static final String DELIMITER = ":";

    public static StandardSerializer forType(final Class<?> type){
        for(final StandardSerializer candidate : values()){
            for(final Class<?> supportedType : candidate.supportedClasses){
                if(supportedType.isAssignableFrom(type)) return candidate;
            }
        }
        throw new IllegalArgumentException("Unmapped type: " + type);
    }

    private final String prefix;

    private final Class<?>[] supportedClasses;

    private StandardSerializer(final String prefix,
        final Class<?>... supportedClasses){
        this.prefix = prefix;
        this.supportedClasses = supportedClasses;
    }

    private String base64decode(final String removePrefix){
        // TODO call one of the many base64 libraries here
        return null;
    }

    private String base64encode(final String data){
        // TODO call one of the many base64 libraries here
        return null;
    }

    @SuppressWarnings("unchecked")
    @Override
    public final <T> T deserialize(final String serializedData){
        return (T) doDeserialize(base64decode(removePrefix(serializedData)));
    }

    public static StandardSerializer forData(final String serializedData){
        final String prefix =
            serializedData.substring(0, serializedData.indexOf(DELIMITER));
        for(final StandardSerializer candidate : values()){
            if(candidate.prefix.equals(prefix)) return candidate;
        }
        throw new IllegalArgumentException("Unknown prefix: " + prefix);
    }

    protected abstract Object doDeserialize(String strippedData);

    private String removePrefix(final String serializedData){
        return serializedData.substring(prefix.length() + DELIMITER.length());
    }

    // default implementation calles toString()
    protected String doSerialize(final Object data){
        return data.toString();
    }

    @Override
    public String serialize(final Object data){
        return new StringBuilder()
            .append(prefix)
            .append(DELIMITER)
            .append(base64encode(doSerialize(data)))
            .toString();
    }
}

Now here's how you can code against that:

List<?> list = Arrays.asList("abc",123);
String serialized = StandardSerializer.forType(list.getClass()).serialize(list);
List<?> unserialized = StandardSerializer.forData(serialized)
                                         .deserialize(serialized);

(While you might choose a different format for serialization, using an enum strategy pattern is probably still a good idea)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜