org.nustaq.serialization.coders.FSTJsonEncoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fst Show documentation
Show all versions of fst Show documentation
A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory.
package org.nustaq.serialization.coders;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.core.io.SerializedString;
import org.nustaq.serialization.*;
import org.nustaq.serialization.util.FSTOutputStream;
import org.nustaq.serialization.util.FSTUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.util.Map;
/**
* Created by ruedi on 20/05/15.
*
*/
public class FSTJsonEncoder implements FSTEncoder {
JsonFactory fac;
FSTConfiguration conf;
FSTJsonFieldNames fieldNames;
protected JsonGenerator gen;
FSTOutputStream out;
public FSTJsonEncoder(FSTConfiguration conf) {
fac = conf.getCoderSpecific();
setConf(conf);
}
@Override
public void setConf(FSTConfiguration conf) {
this.conf = conf;
fieldNames = conf.getJsonFieldNames();
}
@Override
public void writeRawBytes(byte[] bufferedName, int off, int length) throws IOException {
gen.writeBinary(bufferedName,off,length);
}
@Override
public void writePrimitiveArray(Object array, int start, int length) throws IOException {
gen.writeStartArray();
Class> componentType = array.getClass().getComponentType();
if ( componentType != int.class ) {
gen.writeString(componentType.getSimpleName());
} else { // fast path for int
int arr[] = (int[]) array;
for (int i=0; i < length; i++ ) {
gen.writeNumber(arr[i]);
}
gen.writeEndArray();
return;
}
if ( array instanceof boolean[] ) {
boolean arr[] = (boolean[]) array;
for (int i=0; i < length; i++ ) {
gen.writeBoolean(arr[i]);
}
} else if ( array instanceof long[] ) {
long arr[] = (long[]) array;
for (int i=0; i < length; i++ ) {
gen.writeNumber(arr[i]);
}
} else if ( array instanceof double[] ) {
double arr[] = (double[]) array;
for (int i=0; i < length; i++ ) {
gen.writeNumber(arr[i]);
}
} else if ( array instanceof char[] ) {
char arr[] = (char[]) array;
for (int i=0; i < length; i++ ) {
gen.writeNumber(arr[i]);
}
} else {
for (int i=0; i < length; i++ ) {
Number num = (Number) Array.get(array, start + i);
if ( num instanceof Float || num instanceof Double ) {
gen.writeNumber(num.doubleValue());
} else
gen.writeNumber(num.longValue());
}
}
gen.writeEndArray();
}
@Override
public void writeStringUTF(String str) throws IOException {
gen.writeString(str);
}
@Override
public void writeFShort(short c) throws IOException {
gen.writeNumber(c);
}
@Override
public void writeFChar(char c) throws IOException {
gen.writeNumber(c);
}
@Override
public void writeFByte(int v) throws IOException {
gen.writeNumber(v);
}
@Override
public void writeFInt(int anInt) throws IOException {
gen.writeNumber(anInt);
}
@Override
public void writeFLong(long anInt) throws IOException {
gen.writeNumber(anInt);
}
@Override
public void writeFFloat(float value) throws IOException {
gen.writeNumber(value);
}
@Override
public void writeFDouble(double value) throws IOException {
gen.writeNumber(value);
}
@Override
public int getWritten() {
// try {
// gen.flush();
// } catch (IOException e) {
// FSTUtil.rethrow(e);
// }
// System.out.println(pos+" "+out.pos);
return out.pos-out.getOff() + ((FSTConfiguration.JacksonAccessWorkaround)gen).getOutputTail();
}
@Override
public void skip(int i) {
throw new RuntimeException("not supported");
}
@Override
public void close() throws IOException {
gen.close();
out.close();
}
@Override
public void reset(byte[] outbytes) {
if ( gen != null ) {
try {
createGenerator();
} catch (Exception e) {
FSTUtil.rethrow(e);
}
}
if (outbytes==null) {
out.reset();
} else {
out.reset(outbytes);
}
}
@Override
public void flush() throws IOException {
gen.flush();
out.flush();
}
@Override
public void writeInt32At(int position, int v) {
throw new RuntimeException("not supported");
}
@Override
public void setOutstream(OutputStream outstream) {
out = new FSTOutputStream(outstream);
try {
createGenerator();
} catch (IOException e) {
FSTUtil.rethrow(e);
}
}
public void createGenerator() throws IOException {
if ( gen != null )
gen.close();
gen = fac.createGenerator(out);
}
@Override
public void ensureFree(int bytes) throws IOException {
out.ensureFree(bytes);
}
@Override
public byte[] getBuffer() {
try {
gen.flush();
} catch (IOException e) {
FSTUtil.rethrow(e);
}
return out.getBuf();
}
@Override
public void registerClass(Class possible) {
}
@Override
public void writeClass(Class cl) {
// already written in write tag
}
@Override
public void writeClass(FSTClazzInfo clInf) {
// already written in write tag
}
@Override
public boolean writeTag(byte tag, Object infoOrObject, long somValue, Object toWrite, FSTObjectOutput oout) throws IOException {
switch (tag) {
case FSTObjectOutput.HANDLE:
gen.writeStartObject();
gen.writeFieldName(fieldNames.REF_S);
gen.writeNumber(somValue);
gen.writeEndObject();
return true;
case FSTObjectOutput.NULL:
gen.writeNull();
return true;
case FSTObjectOutput.TYPED:
case FSTObjectOutput.OBJECT:
if ( toWrite instanceof Unknown ) {
writeUnkown((Unknown) toWrite,oout);
return true;
}
FSTClazzInfo clzInfo = (FSTClazzInfo) infoOrObject;
if (clzInfo.useCompatibleMode() && clzInfo.getSer() == null ) {
throw new RuntimeException("Unsupported backward compatibility mode for class '"+clzInfo.getClazz().getName()+"'. Pls register a Custom Serializer to fix");
}
if (clzInfo.getClazz() == String.class )
break;
if (clzInfo.getClazz() == Double.class )
break;
if (clzInfo.getClazz() == Float.class )
break;
if (clzInfo.getClazz() == Byte.class )
break;
if (clzInfo.getClazz() == Short.class )
break;
if (clzInfo.getClazz() == Integer.class )
break;
if (clzInfo.getClazz() == Long.class )
break;
if (clzInfo.getClazz() == Character.class )
break;
if (clzInfo.getClazz() == Boolean.class )
break;
if ( clzInfo.getSer()!=null || clzInfo.isExternalizable() ) {
gen.writeStartObject();
gen.writeFieldName(fieldNames.TYPE_S);
writeSymbolicClazz(clzInfo, clzInfo.getClazz());
gen.writeFieldName(fieldNames.OBJ_S);
gen.writeStartArray();
} else
{
gen.writeStartObject();
gen.writeFieldName(fieldNames.TYPE_S);
writeSymbolicClazz(clzInfo,clzInfo.getClazz());
gen.writeFieldName(fieldNames.OBJ_S);
gen.writeStartObject();
}
break;
case FSTObjectOutput.ONE_OF:
throw new RuntimeException("not implemented");
case FSTObjectOutput.STRING:
break; // ignore, header created by calling writeUTF
case FSTObjectOutput.BIG_BOOLEAN_FALSE:
gen.writeBoolean(Boolean.FALSE);
break; // ignore, header created by writing long. FIXME: won't work
case FSTObjectOutput.BIG_BOOLEAN_TRUE:
gen.writeBoolean(Boolean.TRUE);
break; // ignore, header created by writing long. FIXME: won't work
case FSTObjectOutput.BIG_LONG:
break; // ignore, header implicitely created by writing long.
case FSTObjectOutput.BIG_INT:
break;// ignore, header implicitely created by writing int.
case FSTObjectOutput.ARRAY:
Class> clz = infoOrObject.getClass();
Class> componentType = clz.getComponentType();
if ( clz.isArray() && componentType.isPrimitive() )
{
writePrimitiveArray(infoOrObject,0,Array.getLength(infoOrObject));
return true;
} else {
gen.writeStartObject();
gen.writeFieldName(fieldNames.SEQ_TYPE_S);
writeSymbolicClazz(null,clz);
gen.writeFieldName(fieldNames.SEQ_S);
gen.writeStartArray();
}
break;
case FSTObjectOutput.ENUM:
boolean isEnumClass = toWrite.getClass().isEnum();
Class c = toWrite.getClass();
if (!isEnumClass) {
// weird stuff ..
while (c != null && !c.isEnum()) {
c = toWrite.getClass().getSuperclass();
}
if (c == null) {
throw new RuntimeException("Can't handle this enum: " + toWrite.getClass());
}
}
gen.writeStartObject();
gen.writeFieldName(fieldNames.ENUM_S);
writeSymbolicClazz(null,c);
gen.writeFieldName(fieldNames.VAL_S);
gen.writeString(toWrite.toString());
gen.writeEndObject();
return true;
default:
throw new RuntimeException("unexpected tag "+tag);
}
return false;
}
private void writeUnkown(Unknown toWrite, FSTObjectOutput oout) throws IOException {
gen.writeStartObject();
gen.writeFieldName(fieldNames.TYPE_S);
gen.writeString(toWrite.getType());
gen.writeFieldName(fieldNames.OBJ_S);
if ( toWrite.isSequence() ) {
gen.writeStartArray();
for (Object o : toWrite.getItems()) {
oout.writeObject(o);
}
gen.writeEndArray();
} else {
gen.writeStartObject();
for (Map.Entry stringObjectEntry : toWrite.getFields().entrySet()) {
gen.writeFieldName(stringObjectEntry.getKey());
oout.writeObject(stringObjectEntry.getValue());
}
gen.writeEndObject();
}
gen.writeEndObject();
}
private void writeSymbolicClazz(FSTClazzInfo clzInfo, Class> clz) {
try {
if ( clzInfo != null ) {
SerializedString buffered = (SerializedString) clzInfo.getDecoderAttached();
if ( buffered == null ) {
buffered = new SerializedString(classToString(clz));
clzInfo.setDecoderAttached(buffered);
}
gen.writeString(buffered);
} else {
gen.writeString(classToString(clz));
}
} catch (IOException e) {
FSTUtil.rethrow(e);
}
}
protected String classToString(Class clz) {
return conf.getCPNameForClass(clz);
}
@Override
public boolean writeAttributeName(FSTClazzInfo.FSTFieldInfo subInfo, Object outerObjectToWrite) {
try {
SerializedString bufferedName = (SerializedString) subInfo.getBufferedName();
if ( bufferedName == null ) {
bufferedName = new SerializedString(subInfo.getName());
subInfo.setBufferedName(bufferedName);
}
if ( gen.getOutputContext().inArray() ) {
gen.writeString(bufferedName);
}
else {
gen.writeFieldName(bufferedName);
}
if ( subInfo.getField().isAnnotationPresent(JSONAsString.class) ) { // fixme: optimize
try {
Object objectValue = subInfo.getObjectValue(outerObjectToWrite);
if ( objectValue instanceof byte[] ) {
String stringVal = new String((byte[]) objectValue, "UTF-8");
writeStringUTF(stringVal);
return true;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
FSTUtil.rethrow(e);
}
return false;
}
@Override
public void externalEnd(FSTClazzInfo clz) {
try {
Class clazz = clz.getClazz();
if ( clazz == Byte.class ||
clazz == Short.class ||
clazz == Integer.class ||
clazz == Long.class ||
clazz == Float.class ||
clazz == Double.class ||
clazz == Character.class ||
clazz == Boolean.class )
return;
if ( gen.getOutputContext().inArray() )
gen.writeEndArray();
if ( gen.getOutputContext().inObject() )
gen.writeEndObject();
} catch (IOException e) {
FSTUtil.rethrow(e);
}
}
@Override
public boolean isWritingAttributes() {
return true;
}
@Override
public boolean isPrimitiveArray(Object array, Class> componentType) {
return componentType.isPrimitive() && array instanceof double[] == false && array instanceof float[] == false;
}
@Override
public boolean isTagMultiDimSubArrays() {
return true;
}
@Override
public void writeVersionTag(int version) throws IOException {
// versioning not supported for minbin
}
@Override
public boolean isByteArrayBased() {
return true;
}
@Override
public void writeArrayEnd() {
try {
if ( gen.getOutputContext().inArray() )
gen.writeEndArray();
if ( gen.getOutputContext().inObject() )
gen.writeEndObject();
} catch (IOException e) {
FSTUtil.rethrow(e);
}
}
@Override
public void writeFieldsEnd(FSTClazzInfo serializationInfo) {
try {
JsonStreamContext outputContext = gen.getOutputContext();
if ( outputContext.inObject() ) {
gen.writeEndObject();
} else {
gen.writeEndArray();
}
if ( outputContext.inObject() )
gen.writeEndObject();
} catch (IOException e) {
FSTUtil.rethrow(e);
try {
gen.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println( new String(out.buf,0,out.pos) );
}
}
@Override
public FSTConfiguration getConf() {
return conf;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy