java/scala:只对基本类型进行更快的类型感知序列化



在scala中,我需要序列化仅限于一小部分基本类型的对象:array、list、map、set、int、boolean等。我希望能够以序列化格式保留类型信息的方式序列化和反序列化这些对象。特别是,如果我已经序列化了Array[Any],我希望能够对其进行反序列化,并且只指定生成的对象是Array[Any]。也就是说,我不想为我要序列化的每一件事都指定一个结构定义。同时,它需要能够区分int和long、元组和数组等。

例如:

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不适合这种情况,因为它有scala类型到json类型的多对一映射。我目前正在使用java序列化,但速度非常慢。由于我不需要序列化任何任意的对象类型,对于我较窄的用例,有没有更快的替代方案?

我不关心库支持的速度或可用性,但您看过ASN.1吗?

我会使用这样一个简单的界面:

public interface Serializer{
    public <T> T deserialize(String serializedData);
    public String serialize(Object data);
}

以及实现它的枚举:

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();
    }
}

下面是如何针对进行编码

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

(虽然您可能会选择不同的序列化格式,但使用枚举策略模式可能仍然是一个好主意)

最新更新