package org.corfudb.util.serializer; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; import lombok.extern.slf4j.Slf4j; import org.corfudb.runtime.CorfuRuntime; import org.corfudb.runtime.object.ICorfuSMR; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.UUID; /** * Created by mwei on 2/10/16. */ @Slf4j public class JSONSerializer implements ISerializer { final private byte type; private static final Gson gson = new GsonBuilder() .create(); public JSONSerializer(byte type) { this.type = type; } @Override public byte getType() { return type; } /** * Deserialize an object from a given byte buffer. * * @param b The bytebuf to deserialize. * @return The deserialized object. */ @Override public Object deserialize(ByteBuf b, CorfuRuntime rt) { int classNameLength = b.readShort(); byte[] classNameBytes = new byte[classNameLength]; b.readBytes(classNameBytes, 0, classNameLength); String className = new String(classNameBytes); if (className.equals("null")) { return null; } else if (className.equals("CorfuObject")) { int SMRClassNameLength = b.readShort(); byte[] SMRClassNameBytes = new byte[SMRClassNameLength]; b.readBytes(SMRClassNameBytes, 0, SMRClassNameLength); String SMRClassName = new String(SMRClassNameBytes); try { return rt.getObjectsView().build() .setStreamID(new UUID(b.readLong(), b.readLong())) .setType(Class.forName(SMRClassName)) .open(); } catch (ClassNotFoundException cnfe) { log.error("Exception during deserialization!", cnfe); throw new RuntimeException(cnfe); } } else { try (ByteBufInputStream bbis = new ByteBufInputStream(b)) { try (InputStreamReader r = new InputStreamReader(bbis)) { return gson.fromJson(r, Class.forName(className)); } } catch (IOException | ClassNotFoundException ie) { log.error("Exception during deserialization!", ie); throw new RuntimeException(ie); } } } /** * Serialize an object into a given byte buffer. * * @param o The object to serialize. * @param b The bytebuf to serialize it into. */ @Override public void serialize(Object o, ByteBuf b) { String className = o == null ? "null" : o.getClass().getName(); if (className.endsWith(ICorfuSMR.CORFUSMR_SUFFIX)) { String SMRClass = className.split("\\$")[0]; className = "CorfuObject"; byte[] classNameBytes = className.getBytes(); b.writeShort(classNameBytes.length); b.writeBytes(classNameBytes); byte[] SMRClassNameBytes = SMRClass.getBytes(); b.writeShort(SMRClassNameBytes.length); b.writeBytes(SMRClassNameBytes); UUID id = ((ICorfuSMR) o).getCorfuStreamID(); log.trace("Serializing a CorfuObject of type {} as a stream pointer to {}", SMRClass, id); b.writeLong(id.getMostSignificantBits()); b.writeLong(id.getLeastSignificantBits()); } else { byte[] classNameBytes = className.getBytes(); b.writeShort(classNameBytes.length); b.writeBytes(classNameBytes); if (o == null) { return; } try (ByteBufOutputStream bbos = new ByteBufOutputStream(b)) { try (OutputStreamWriter osw = new OutputStreamWriter(bbos)) { gson.toJson(o, o.getClass(), osw); } } catch (IOException ie) { log.error("Exception during serialization!", ie); } } } }