bpsm / edn-java

a reader for extensible data notation
Eclipse Public License 1.0
100 stars 24 forks source link

Teach default edn parser to produce values that can be serialized #42

Closed bpsm closed 8 years ago

bpsm commented 8 years ago

This addresses a use-case where Apache Spark configuration is stored as edn but needs to be distributed between machines via Java Serialization after parsing because that's the way Spark wants to work.

bpsm commented 8 years ago

Another option worth considering is explicitly wrapping the parsed edn value in an object which provides Java serialization by writing the edn text to the ObjectOutput stream. I expect this will be more compact than plain Java serialization in most cases.

package us.bpsm.edn.serialization;

import us.bpsm.edn.parser.Parser;
import us.bpsm.edn.parser.Parsers;
import us.bpsm.edn.printer.Printer;
import us.bpsm.edn.printer.Printers;
import us.bpsm.edn.protocols.Protocol;

import java.io.*;

@SuppressWarnings("unused")
public class SerializationWrapper implements Externalizable {
    private static final long MAGIC_V1 = 0x2eb534fa9a014827L;
    Object value;
    transient Protocol<Printer.Fn<?>> protocol;

    public SerializationWrapper() {
    }

    public SerializationWrapper(Object value) {
        this(value, Printers.defaultPrinterProtocol());
    }

    public SerializationWrapper(Object value, Protocol<Printer.Fn<?>> protocol) {
        this.value = value;
        this.protocol = protocol;
    }

    public Object getValue() {
        return value;
    }

    private Protocol<Printer.Fn<?>> getProtocol() {
        return protocol == null ? Printers.defaultPrinterProtocol() : protocol;
    }

    @Override
    public void writeExternal(final ObjectOutput out) throws IOException {
        out.writeLong(MAGIC_V1);
        out.writeUTF(Printers.printString(getProtocol(), value));
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        long magic = in.readLong();
        if (magic == MAGIC_V1) {
            Parser parser = Parsers.newParser(Parsers.defaultConfiguration());
            this.value = parser.nextValue(Parsers.newParseable(in.readUTF()));
        } else {
            throw new InvalidObjectException("Unrecognized magic=" + magic);
        }
        if (this.value == Parser.END_OF_INPUT) {
            throw new InvalidObjectException("Unexpected end of edn data");
        }
    }
}
chrisbetz commented 8 years ago

:+1:

bpsm commented 8 years ago

Ok. I'll integrate this feature and include it in the next release. I don't intend to include the SerializationWrapper that I sketched above.

bpsm commented 8 years ago

Superseded by https://github.com/bpsm/edn-java/pull/44