/* * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.io.serialization.kryo; import co.paralleluniverse.io.serialization.ByteArraySerializer; import co.paralleluniverse.io.serialization.IOStreamSerializer; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Registration; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; /** * This class is not thread-safe. * * @author pron */ public class KryoSerializer implements ByteArraySerializer, IOStreamSerializer { private static Queue<Registration> registrations = new ConcurrentLinkedQueue<Registration>(); public final Kryo kryo; private Input input; private Output output; public KryoSerializer() { this.kryo = KryoUtil.newKryo(); KryoUtil.registerCommonClasses(kryo); for (Registration r : registrations) register(r); } public Kryo getKryo() { return kryo; } public static void register(Class type) { register(type, NULL_SERIALIZER, -1); } public static void register(Class type, int id) { register(type, NULL_SERIALIZER, id); } public static void register(Class type, Serializer ser) { register(type, ser, -1); } public static void register(Class type, Serializer ser, int id) { registrations.add(new Registration(type, ser, id)); } private Input getInput() { if (input == null) input = new Input(4096); return input; } private Output getOutput() { if (output == null) output = new Output(4096, -1); return output; } private static Serializer NULL_SERIALIZER = new Serializer<Object>() { @Override public void write(Kryo kryo, Output output, Object object) { throw new UnsupportedOperationException(); } @Override public Object read(Kryo kryo, Input input, Class<Object> type) { throw new UnsupportedOperationException(); } }; private void register(Registration r) { if (r.getId() < 0 && r.getSerializer() == NULL_SERIALIZER) kryo.register(r.getType()); else if (r.getId() < 0) kryo.register(r.getType(), r.getSerializer()); else if (r.getSerializer() == NULL_SERIALIZER) kryo.register(r.getType(), r.getId()); else kryo.register(r.getType(), r.getSerializer(), r.getId()); } @Override public byte[] write(Object object) { final Output out = getOutput(); out.clear(); kryo.writeClassAndObject(out, object); out.flush(); return out.toBytes(); } @Override public Object read(byte[] buf) { return read(buf, 0); } @Override public Object read(byte[] buf, int offset) { final Input in = new Input(buf, offset, buf.length - offset); return kryo.readClassAndObject(in); } public <T> T read(byte[] buf, Class<T> type) { return read(buf, 0, type); } public <T> T read(byte[] buf, int offset, Class<T> type) { final Input in = new Input(buf, offset, buf.length - offset); return kryo.readObjectOrNull(in, type); } @Override public void write(OutputStream os, Object object) { final Output out = getOutput(); out.clear(); out.setOutputStream(os); kryo.writeClassAndObject(out, object); out.flush(); out.setOutputStream(null); } @Override public Object read(InputStream is) throws IOException { final Input in = getInput(); in.setInputStream(is); return kryo.readClassAndObject(in); } public <T> T read(InputStream is, Class<T> type) { final Input in = getInput(); in.setInputStream(is); return kryo.readObjectOrNull(input, type); } }