diff --git a/src/main/java/org/nustaq/serialization/FSTClazzInfo.java b/src/main/java/org/nustaq/serialization/FSTClazzInfo.java index 554713aa..f9bf606e 100644 --- a/src/main/java/org/nustaq/serialization/FSTClazzInfo.java +++ b/src/main/java/org/nustaq/serialization/FSTClazzInfo.java @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; +import java.util.zip.CRC32; /** * Created with IntelliJ IDEA. @@ -121,12 +122,19 @@ public void setDecoderAttached(Object decoderAttached) { boolean crossPlatform; public FSTClazzInfo(FSTConfiguration conf, Class clazz, FSTClazzInfoRegistry infoRegistry, boolean ignoreAnnotations) { + this(conf, clazz, infoRegistry, ignoreAnnotations, null); + } + + /** + * new constructor with the serialized order of fields and the uniqueId for each field + */ + public FSTClazzInfo(FSTConfiguration conf, Class clazz, FSTClazzInfoRegistry infoRegistry, boolean ignoreAnnotations, long[] fieldsUniqueId) { this.conf = conf; // fixme: historically was not bound to conf but now is. Remove redundant state + refs (note: may still be useful because of less pointerchasing) crossPlatform = conf.isCrossPlatform(); this.clazz = clazz; enumConstants = clazz.getEnumConstants(); ignoreAnn = ignoreAnnotations; - createFields(clazz); + createFields(clazz, fieldsUniqueId); instantiator = conf.getInstantiator(clazz); if (Externalizable.class.isAssignableFrom(clazz)) { @@ -357,45 +365,53 @@ private FSTMap buildFieldMap() { return res; } - private void createFields(Class c) { + private void createFields(Class c, long[] fieldsUniqueId) { if (c.isInterface() || c.isPrimitive()) { return; } List fields = getAllFields(c, null); - fieldInfo = new FSTFieldInfo[fields.size()]; - for (int i = 0; i < fields.size(); i++) { - Field field = fields.get(i); - fieldInfo[i] = createFieldInfo(field); + if(fieldsUniqueId != null){ + // retains only the fields that are in the fields unique + // and keep the given order. for those in unique that + // are not present - just add a FSTFieldInfo with missing set to true + // in order to jump over the data and ignore it + List fstFields = new ArrayList(fields.size()); + int fieldsLen = fields.size(); + for (int i = 0; i < fieldsLen; i++) { + fstFields.add(createFieldInfo(fields.get(i))); + } + // create the fields list + final int lenFieldsUniqueId = fieldsUniqueId.length; + fieldInfo = new FSTFieldInfo[lenFieldsUniqueId]; + long uid; + boolean foundIt; + for(int i=0;i infocomp = new Comparator() { - @Override - public int compare(FSTFieldInfo o1, FSTFieldInfo o2) { - int res = 0; - res = o1.getType().getSimpleName().compareTo(o2.getType().getSimpleName()); - if (res == 0) - res = o1.getType().getName().compareTo(o2.getType().getName()); - if (res == 0) { - Class declaringClass = o1.getType().getDeclaringClass(); - Class declaringClass1 = o2.getType().getDeclaringClass(); - if (declaringClass == null && declaringClass1 == null) { - return 0; - } - if (declaringClass != null && declaringClass1 == null) { - return 1; - } - if (declaringClass == null && declaringClass1 != null) { - return -1; - } - if (res == 0) { - return declaringClass.getName().compareTo(declaringClass1.getName()); - } - } - return res; - } - }; - + // check if we actually need to build up compatibility info (memory intensive) boolean requiresCompatibilityData = false; if ( ! Externalizable.class.isAssignableFrom(c) && getSerNoStore() == null ) { @@ -443,6 +459,33 @@ public int compare(FSTFieldInfo o1, FSTFieldInfo o2) { } } } + // compatibility info sort order + Comparator infocomp = new Comparator() { + @Override + public int compare(FSTFieldInfo o1, FSTFieldInfo o2) { + int res = 0; + res = o1.getType().getSimpleName().compareTo(o2.getType().getSimpleName()); + if (res == 0) + res = o1.getType().getName().compareTo(o2.getType().getName()); + if (res == 0) { + Class declaringClass = o1.getType().getDeclaringClass(); + Class declaringClass1 = o2.getType().getDeclaringClass(); + if (declaringClass == null && declaringClass1 == null) { + return 0; + } + if (declaringClass != null && declaringClass1 == null) { + return 1; + } + if (declaringClass == null && declaringClass1 != null) { + return -1; + } + if (res == 0) { + return declaringClass.getName().compareTo(declaringClass1.getName()); + } + } + return res; + } + }; Collections.sort(curClzFields, infocomp); FSTCompatibilityInfo info = new FSTCompatibilityInfo(curClzFields, curCl); getCompInfo().put(curCl, info); @@ -456,12 +499,14 @@ public int compare(FSTFieldInfo o1, FSTFieldInfo o2) { // default sort order Comparator comp = defFieldComparator; - if (!conf.isStructMode()) + if (!conf.isStructMode() && (fieldsUniqueId == null)) Arrays.sort(fieldInfo, comp); int off = 8; // object header: length + clzId for (int i = 0; i < fieldInfo.length; i++) { FSTFieldInfo fstFieldInfo = fieldInfo[i]; - Align al = fstFieldInfo.getField().getAnnotation(Align.class); + // ARC: managing the missing fields + Field field; + Align al = (field = fstFieldInfo.getField())==null? null : field.getAnnotation(Align.class); if (al != null) { fstFieldInfo.align = al.value(); int alignOff = fstFieldInfo.align(off); @@ -581,6 +626,40 @@ public final static class FSTFieldInfo { // in rare cases, a field used in putField is not present as a real field // in this case only these of a fieldinfo are set public String fakeName; + + // ARC: crc unique of the field name + Long uniqueId; + public boolean hasUniqueId() { + return (field!=null) || (fakeName == null); + } + public long getUniqueId(){ + if(uniqueId == null){ + if(field==null && fakeName == null){ + // this should not happen + throw new UnsupportedOperationException("no unique id"); + }else{ + try{ + CRC32 crc = new CRC32(); + if(field==null){ + crc.update(fakeName.getBytes("UTF-8")); + }else{ + crc.update(field.getDeclaringClass().getName().getBytes("UTF-8")); + crc.update('.'); + crc.update(field.getName().getBytes("UTF-8")); + } + uniqueId = crc.getValue(); + }catch(UnsupportedEncodingException e){ + throw new RuntimeException(e); + } + } + } + return uniqueId; + } + boolean missing = false; + + public boolean isMissing() { + return missing; + } public FSTFieldInfo(Class[] possibleClasses, Field fi, boolean ignoreAnnotations) { this.possibleClasses = possibleClasses; diff --git a/src/main/java/org/nustaq/serialization/FSTClazzInfoRegistry.java b/src/main/java/org/nustaq/serialization/FSTClazzInfoRegistry.java index 15196389..5287900a 100644 --- a/src/main/java/org/nustaq/serialization/FSTClazzInfoRegistry.java +++ b/src/main/java/org/nustaq/serialization/FSTClazzInfoRegistry.java @@ -115,6 +115,10 @@ public FSTClazzInfoRegistry() { } public FSTClazzInfo getCLInfo(Class c, FSTConfiguration conf) { + return getCLInfo(c, conf, null); + } + + public FSTClazzInfo getCLInfo(Class c, FSTConfiguration conf, long[] fieldsUniqueId) { while(!rwLock.compareAndSet(false,true)); try { FSTClazzInfo res = (FSTClazzInfo) mInfos.get(c); @@ -126,7 +130,7 @@ public FSTClazzInfo getCLInfo(Class c, FSTConfiguration conf) { if ( ! conf.getVerifier().allowClassDeserialization(c) ) throw new RuntimeException("tried to deserialize forbidden class "+c.getName() ); } - res = new FSTClazzInfo(conf, c, this, ignoreAnnotations); + res = new FSTClazzInfo(conf, c, this, ignoreAnnotations, fieldsUniqueId); mInfos.put(c, res); } return res; diff --git a/src/main/java/org/nustaq/serialization/FSTClazzNameRegistry.java b/src/main/java/org/nustaq/serialization/FSTClazzNameRegistry.java index f04f49f3..f97a9e7f 100644 --- a/src/main/java/org/nustaq/serialization/FSTClazzNameRegistry.java +++ b/src/main/java/org/nustaq/serialization/FSTClazzNameRegistry.java @@ -16,6 +16,7 @@ package org.nustaq.serialization; import org.nustaq.offheap.structs.unsafeimpl.FSTStructFactory; +import org.nustaq.serialization.FSTClazzInfo.FSTFieldInfo; import org.nustaq.serialization.util.FSTIdentity2IdMap; import org.nustaq.serialization.util.FSTObject2IntMap; import org.nustaq.serialization.util.FSTUtil; @@ -42,7 +43,13 @@ */ public class FSTClazzNameRegistry { - public static final int LOWEST_CLZ_ID = 3; + /** + * it seems that originally only bit 0 and 1 was used (<3) + * + * we will use the bit 2 to signal that the fields uniqueId are saved with the class info + * + */ + public static final int LOWEST_CLZ_ID = FSTConfiguration.FIELDS_FIX ? 4 : 3; public static final int FIRST_USER_CLZ_ID = 1000; FSTIdentity2IdMap clzToId; @@ -133,29 +140,56 @@ public void encodeClass(FSTEncoder out, FSTClazzInfo ci) throws IOException { // ugly hack, also making assumptions about // on how the encoder works internally final byte[] bufferedName = ci.getBufferedName(); - out.writeFShort((short) 1); // no direct cl id ascii enc + if(FSTConfiguration.FIELDS_FIX) + out.writeFShort((short) 3); // no direct cl id ascii enc + else + out.writeFShort((short) 1); // no direct cl id ascii enc out.writeFInt((char) bufferedName.length); out.writeRawBytes(bufferedName,0,bufferedName.length); + // + if(FSTConfiguration.FIELDS_FIX){ + FSTFieldInfo[] fields = ci.getFieldInfo(); + int len = fields==null ? 0 : fields.length; + out.writeFShort((short)fields.length); + for(int i=0;i 2 !! } else { - encodeClassName(out, c, out.getConf() ); + encodeClassName(out, c, out.getConf(), ci ); } } - private void encodeClassName(FSTEncoder out, Class c, FSTConfiguration conf) throws IOException { - out.writeFShort((short) 0); // no direct cl id + private void encodeClassName(FSTEncoder out, Class c, FSTConfiguration conf, FSTClazzInfo ci) throws IOException { + if(FSTConfiguration.FIELDS_FIX && ci!=null) + out.writeFShort((short) 2); // no direct cl id + else + out.writeFShort((short) 0); // no direct cl id out.writeStringUTF(c.getName()); + if(FSTConfiguration.FIELDS_FIX && ci!=null){ + final FSTFieldInfo[] fields = ci.getFieldInfo(); + final int len = fields==null ? 0 : fields.length; + out.writeFShort((short)fields.length); + for(int i=0;i 1 ) { + final FSTDecoder getCodec = getCodec(); for (int i = 0; i < possibles.length; i++) { Class possible = possibles[i]; - getCodec().registerClass(possible); + getCodec.registerClass(possible); } } Object res = readObjectInternal(possibles); @@ -342,8 +343,9 @@ public Object readObjectInternal(Class... expected) throws ClassNotFoundExceptio public Object readObjectWithHeader(FSTClazzInfo.FSTFieldInfo referencee) throws Exception { FSTClazzInfo clzSerInfo; Class c; - final int readPos = getCodec().getInputPos(); - byte code = getCodec().readObjectHeaderTag(); // NOTICE: THIS ADVANCES THE INPUT STREAM... + final FSTDecoder getCodec = getCodec(); + final int readPos = getCodec.getInputPos(); + byte code = getCodec.readObjectHeaderTag(); // NOTICE: THIS ADVANCES THE INPUT STREAM... if (code == FSTObjectOutput.OBJECT ) { // class name clzSerInfo = readClass(); @@ -370,7 +372,7 @@ public Object readObjectWithHeader(FSTClazzInfo.FSTFieldInfo referencee) throws FSTObjectSerializer ser = clzSerInfo.getSer(); if (ser != null) { Object res = instantiateAndReadWithSer(c, ser, clzSerInfo, referencee, readPos); - getCodec().readArrayEnd(clzSerInfo); + getCodec.readArrayEnd(clzSerInfo); return res; } else { Object res = instantiateAndReadNoSer(c, clzSerInfo, referencee, readPos); @@ -383,8 +385,9 @@ public Object readObjectWithHeader(FSTClazzInfo.FSTFieldInfo referencee) throws } protected Object instantiateSpecialTag(FSTClazzInfo.FSTFieldInfo referencee, int readPos, byte code) throws Exception { + final FSTDecoder getCodec = getCodec(); if ( code == FSTObjectOutput.STRING ) { // faster than switch, note: currently string tag not used by all codecs .. - String res = getCodec().readStringUTF(); + String res = getCodec.readStringUTF(); objects.registerObjectForRead(res, readPos); return res; } else if ( code == FSTObjectOutput.BIG_INT ) { @@ -395,18 +398,18 @@ protected Object instantiateSpecialTag(FSTClazzInfo.FSTFieldInfo referencee, int { switch (code) { // case FSTObjectOutput.BIG_INT: { return instantiateBigInt(); } - case FSTObjectOutput.BIG_LONG: { return Long.valueOf(getCodec().readFLong()); } + case FSTObjectOutput.BIG_LONG: { return Long.valueOf(getCodec.readFLong()); } case FSTObjectOutput.BIG_BOOLEAN_FALSE: { return Boolean.FALSE; } case FSTObjectOutput.BIG_BOOLEAN_TRUE: { return Boolean.TRUE; } - case FSTObjectOutput.ONE_OF: { return referencee.getOneOf()[getCodec().readFByte()]; } + case FSTObjectOutput.ONE_OF: { return referencee.getOneOf()[getCodec.readFByte()]; } // case FSTObjectOutput.NULL: { return null; } case FSTObjectOutput.DIRECT_ARRAY_OBJECT: { - Object directObject = getCodec().getDirectObject(); + Object directObject = getCodec.getDirectObject(); objects.registerObjectForRead(directObject,readPos); return directObject; } case FSTObjectOutput.DIRECT_OBJECT: { - Object directObject = getCodec().getDirectObject(); + Object directObject = getCodec.getDirectObject(); if (directObject.getClass() == byte[].class) { // fixme. special for minibin, move it there if ( referencee != null && referencee.getType() == boolean[].class ) { @@ -421,10 +424,10 @@ protected Object instantiateSpecialTag(FSTClazzInfo.FSTFieldInfo referencee, int objects.registerObjectForRead(directObject,readPos); return directObject; } -// case FSTObjectOutput.STRING: return getCodec().readStringUTF(); +// case FSTObjectOutput.STRING: return getCodec.readStringUTF(); case FSTObjectOutput.HANDLE: { Object res = instantiateHandle(referencee); - getCodec().readObjectEnd(); + getCodec.readObjectEnd(); return res; } case FSTObjectOutput.ARRAY: { @@ -475,22 +478,46 @@ on the intent of the if ( ! referencee.isFlat() ) so I wanted to comment on that protected Object instantiateEnum(FSTClazzInfo.FSTFieldInfo referencee, int readPos) throws IOException, ClassNotFoundException { FSTClazzInfo clzSerInfo; - Class c; + //Class c; clzSerInfo = readClass(); - c = clzSerInfo.getClazz(); - int ordinal = getCodec().readFInt(); - Object[] enumConstants = clzSerInfo.getEnumConstants(); - if ( enumConstants == null ) { - // pseudo enum of anonymous classes tom style ? - return null; - } - Object res = enumConstants[ordinal]; - if ( REGISTER_ENUMS_READ ) { - if ( ! referencee.isFlat() ) { // should be unnecessary - objects.registerObjectForRead(res, readPos); - } + //c = clzSerInfo.getClazz(); + if (FSTConfiguration.FIELDS_FIX_ENUM_WITH_NAME) { + String name = getCodec().readStringUTF(); + Object[] enumConstants = clzSerInfo.getEnumConstants(); + if ( enumConstants == null ) { + // pseudo enum of anonymous classes tom style ? + return null; + } + Object res = null; + { + for(Object o : enumConstants){ + if(((Enum)o).name().equals(name)){ + res = o; + break; + } + } + } + if ( REGISTER_ENUMS_READ ) { + if ( ! referencee.isFlat() ) { // should be unnecessary + objects.registerObjectForRead(res, readPos); + } + } + return res; + } else { + int ordinal = getCodec().readFInt(); + Object[] enumConstants = clzSerInfo.getEnumConstants(); + if ( enumConstants == null ) { + // pseudo enum of anonymous classes tom style ? + return null; + } + Object res = enumConstants[ordinal]; + if ( REGISTER_ENUMS_READ ) { + if ( ! referencee.isFlat() ) { // should be unnecessary + objects.registerObjectForRead(res, readPos); + } + } + return res; } - return res; } protected Object instantiateBigInt() throws IOException { @@ -499,10 +526,11 @@ protected Object instantiateBigInt() throws IOException { } protected Object instantiateAndReadWithSer(Class c, FSTObjectSerializer ser, FSTClazzInfo clzSerInfo, FSTClazzInfo.FSTFieldInfo referencee, int readPos) throws Exception { + final FSTDecoder getCodec = getCodec(); boolean serInstance = false; Object newObj = ser.instantiate(c, this, clzSerInfo, referencee, readPos); if (newObj == null) { - newObj = clzSerInfo.newInstance(getCodec().isMapBased()); + newObj = clzSerInfo.newInstance(getCodec.isMapBased()); } else serInstance = true; if (newObj == null) { @@ -524,13 +552,14 @@ protected Object instantiateAndReadWithSer(Class c, FSTObjectSerializer ser, FST if ( !serInstance ) ser.readObject(this, newObj, clzSerInfo, referencee); } - getCodec().consumeEndMarker(); //=> bug when writing objects unlimited + getCodec.consumeEndMarker(); //=> bug when writing objects unlimited return newObj; } protected Object instantiateAndReadNoSer(Class c, FSTClazzInfo clzSerInfo, FSTClazzInfo.FSTFieldInfo referencee, int readPos) throws Exception { + final FSTDecoder getCodec = getCodec(); Object newObj; - newObj = clzSerInfo.newInstance(getCodec().isMapBased()); + newObj = clzSerInfo.newInstance(getCodec.isMapBased()); if (newObj == null) { throw new IOException(referencee.getDesc() + ":Failed to instantiate '" + c.getName() + "'. Register a custom serializer implementing instantiate or define empty constructor."); } @@ -546,9 +575,9 @@ protected Object instantiateAndReadNoSer(Class c, FSTClazzInfo clzSerInfo, FSTCl if ( clzSerInfo.isExternalizable() ) { int tmp = readPos; - getCodec().ensureReadAhead(readExternalReadAHead); + getCodec.ensureReadAhead(readExternalReadAHead); ((Externalizable)newObj).readExternal(this); - getCodec().readExternalEnd(); + getCodec.readExternalEnd(); if ( clzSerInfo.getReadResolveMethod() != null ) { final Object prevNew = newObj; newObj = handleReadRessolve(clzSerInfo, newObj); @@ -604,7 +633,8 @@ protected void readObjectCompatibleRecursive(FSTClazzInfo.FSTFieldInfo reference if ( tag == 66 ) { // no write method defined, but read method defined ... // expect defaultReadObject - getCodec().moveTo(getCodec().getInputPos() - 1); // need to push back tag, cause defaultWriteObject on writer side does not write tag + final FSTDecoder getCodec = getCodec(); + getCodec.moveTo(getCodec.getInputPos() - 1); // need to push back tag, cause defaultWriteObject on writer side does not write tag // input.pos--; } ObjectInputStream objectInputStream = getObjectInputStream(cl, serializationInfo, referencee, toRead); @@ -649,11 +679,11 @@ public void defaultReadObject(FSTClazzInfo.FSTFieldInfo referencee, FSTClazzInfo } protected void readObjectFields(FSTClazzInfo.FSTFieldInfo referencee, FSTClazzInfo serializationInfo, FSTClazzInfo.FSTFieldInfo[] fieldInfo, Object newObj, int startIndex, int version) throws Exception { - - if ( getCodec().isMapBased() ) { + final FSTDecoder getCodec = getCodec(); + if ( getCodec.isMapBased() ) { readFieldsMapBased(referencee, serializationInfo, newObj); if ( version >= 0 /*&& newObj instanceof Unknown == false*/ ) { - getCodec().readObjectEnd(); + getCodec.readObjectEnd(); } return; } @@ -663,11 +693,13 @@ protected void readObjectFields(FSTClazzInfo.FSTFieldInfo referencee, FSTClazzIn int boolcount = 8; final int length = fieldInfo.length; int conditional = 0; + byte[] storedSizeBuff = new byte[4]; for (int i = startIndex; i < length; i++) { try { - FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[i]; + FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[i]; + // if (subInfo.getVersion() > version ) { - int nextVersion = getCodec().readVersionTag(); + int nextVersion = getCodec.readVersionTag(); if ( nextVersion == 0 ) // old object read { oldVersionRead(newObj); @@ -679,47 +711,73 @@ protected void readObjectFields(FSTClazzInfo.FSTFieldInfo referencee, FSTClazzIn readObjectFields(referencee,serializationInfo,fieldInfo,newObj,i,nextVersion); return; } - if (subInfo.isPrimitive()) { - int integralType = subInfo.getIntegralType(); - if (integralType == FSTClazzInfo.FSTFieldInfo.BOOL) { - if (boolcount == 8) { - booleanMask = ((int) getCodec().readFByte() + 256) &0xff; - boolcount = 0; - } - boolean val = (booleanMask & 128) != 0; - booleanMask = booleanMask << 1; - boolcount++; - subInfo.setBooleanValue(newObj, val); - } else { - switch (integralType) { - case FSTClazzInfo.FSTFieldInfo.BYTE: subInfo.setByteValue(newObj, getCodec().readFByte()); break; - case FSTClazzInfo.FSTFieldInfo.CHAR: subInfo.setCharValue(newObj, getCodec().readFChar()); break; - case FSTClazzInfo.FSTFieldInfo.SHORT: subInfo.setShortValue(newObj, getCodec().readFShort()); break; - case FSTClazzInfo.FSTFieldInfo.INT: subInfo.setIntValue(newObj, getCodec().readFInt()); break; - case FSTClazzInfo.FSTFieldInfo.LONG: subInfo.setLongValue(newObj, getCodec().readFLong()); break; - case FSTClazzInfo.FSTFieldInfo.FLOAT: subInfo.setFloatValue(newObj, getCodec().readFFloat()); break; - case FSTClazzInfo.FSTFieldInfo.DOUBLE: subInfo.setDoubleValue(newObj, getCodec().readFDouble()); break; - } - } - } else { - if ( subInfo.isConditional() ) { - if ( conditional == 0 ) { - conditional = getCodec().readPlainInt(); - if ( skipConditional(newObj, conditional, subInfo) ) { - getCodec().moveTo(conditional); - continue; - } - } - } - // object - Object subObject = readObjectWithHeader(subInfo); - subInfo.setObjectValue(newObj, subObject); + // ARC: read the size in case that we are + int storedSize = -1; + if(FSTConfiguration.FIELDS_FIX_LENGTH){ + storedSizeBuff[0] = getCodec.readFByte(); + boolean extraSize = (storedSizeBuff[0] & 1) == 1; + if(!extraSize){ + storedSize = ((storedSizeBuff[0] & 0xFE) >> 1); + }else{ + // it's a int size + int ch1 = (storedSizeBuff[0] & 0xFF); + int ch2 = (getCodec.readFByte() & 0xFF); + int ch3 = (getCodec.readFByte() & 0xFF); + int ch4 = (getCodec.readFByte() & 0xFF); + + storedSize = ((((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)) & 0xFFFE) >> 1); + } + } + if(subInfo.isMissing() && FSTConfiguration.FIELDS_FIX_LENGTH){ + // skip it + getCodec.skip(storedSize); + }else{ + if (subInfo.isPrimitive()) { + int integralType = subInfo.getIntegralType(); + if (integralType == FSTClazzInfo.FSTFieldInfo.BOOL) { + if(FSTConfiguration.FIELDS_FIX_LENGTH){ + subInfo.setBooleanValue(newObj, getCodec.readFByte() == 1); + }else{ + if (boolcount == 8) { + booleanMask = ((int) getCodec.readFByte() + 256) &0xff; + boolcount = 0; + } + boolean val = (booleanMask & 128) != 0; + booleanMask = booleanMask << 1; + boolcount++; + subInfo.setBooleanValue(newObj, val); + } + } else { + switch (integralType) { + case FSTClazzInfo.FSTFieldInfo.BYTE: subInfo.setByteValue(newObj, getCodec.readFByte()); break; + case FSTClazzInfo.FSTFieldInfo.CHAR: subInfo.setCharValue(newObj, getCodec.readFChar()); break; + case FSTClazzInfo.FSTFieldInfo.SHORT: subInfo.setShortValue(newObj, getCodec.readFShort()); break; + case FSTClazzInfo.FSTFieldInfo.INT: subInfo.setIntValue(newObj, getCodec.readFInt()); break; + case FSTClazzInfo.FSTFieldInfo.LONG: subInfo.setLongValue(newObj, getCodec.readFLong()); break; + case FSTClazzInfo.FSTFieldInfo.FLOAT: subInfo.setFloatValue(newObj, getCodec.readFFloat()); break; + case FSTClazzInfo.FSTFieldInfo.DOUBLE: subInfo.setDoubleValue(newObj, getCodec.readFDouble()); break; + } + } + } else { + if ( subInfo.isConditional() ) { + if ( conditional == 0 ) { + conditional = getCodec.readPlainInt(); + if ( skipConditional(newObj, conditional, subInfo) ) { + getCodec.moveTo(conditional); + continue; + } + } + } + // object + Object subObject = readObjectWithHeader(subInfo); + subInfo.setObjectValue(newObj, subObject); + } } } catch (IllegalAccessException ex) { throw new IOException(ex); } } - int debug = getCodec().readVersionTag();// just consume '0' + int debug = getCodec.readVersionTag();// just consume '0' } public VersionConflictListener getVersionConflictListener() { @@ -740,27 +798,28 @@ protected void oldVersionRead(Object newObj) { } protected void readFieldsMapBased(FSTClazzInfo.FSTFieldInfo referencee, FSTClazzInfo serializationInfo, Object newObj) throws Exception { + final FSTDecoder getCodec = getCodec(); String name; - int len = getCodec().getObjectHeaderLen(); // check if len is known in advance + int len = getCodec.getObjectHeaderLen(); // check if len is known in advance if ( len < 0 ) len = Integer.MAX_VALUE; int count = 0; boolean isUnknown = newObj.getClass() == Unknown.class; // json - boolean inArray = isUnknown && getCodec().inArray(); // json externalized/custom serialized - getCodec().startFieldReading(newObj); + boolean inArray = isUnknown && getCodec.inArray(); // json externalized/custom serialized + getCodec.startFieldReading(newObj); // fixme: break up this loop into separate impls. while( count < len ) { if ( inArray ) { // unknwon json object written by externalize or custom serializer Object o = readObjectWithHeader(null); - if ( o != null && getCodec().isEndMarker(o.toString()) ) + if ( o != null && getCodec.isEndMarker(o.toString()) ) return; ((Unknown)newObj).add(o); continue; } - name= getCodec().readStringUTF(); - //int debug = getCodec().getInputPos(); - if ( len == Integer.MAX_VALUE && getCodec().isEndMarker(name) ) + name= getCodec.readStringUTF(); + //int debug = getCodec.getInputPos(); + if ( len == Integer.MAX_VALUE && getCodec.isEndMarker(name) ) return; count++; if (isUnknown) { @@ -781,41 +840,41 @@ protected void readFieldsMapBased(FSTClazzInfo.FSTFieldInfo referencee, FSTClazz // direct primitive field switch (fieldInfo.getIntegralType()) { case FSTClazzInfo.FSTFieldInfo.BOOL: - fieldInfo.setBooleanValue(newObj, getCodec().readFByte() == 0 ? false : true); + fieldInfo.setBooleanValue(newObj, getCodec.readFByte() == 0 ? false : true); break; case FSTClazzInfo.FSTFieldInfo.BYTE: - fieldInfo.setByteValue(newObj, getCodec().readFByte()); + fieldInfo.setByteValue(newObj, getCodec.readFByte()); break; case FSTClazzInfo.FSTFieldInfo.CHAR: - fieldInfo.setCharValue(newObj, getCodec().readFChar()); + fieldInfo.setCharValue(newObj, getCodec.readFChar()); break; case FSTClazzInfo.FSTFieldInfo.SHORT: - fieldInfo.setShortValue(newObj, getCodec().readFShort()); + fieldInfo.setShortValue(newObj, getCodec.readFShort()); break; case FSTClazzInfo.FSTFieldInfo.INT: - fieldInfo.setIntValue(newObj, getCodec().readFInt()); + fieldInfo.setIntValue(newObj, getCodec.readFInt()); break; case FSTClazzInfo.FSTFieldInfo.LONG: - fieldInfo.setLongValue(newObj, getCodec().readFLong()); + fieldInfo.setLongValue(newObj, getCodec.readFLong()); break; case FSTClazzInfo.FSTFieldInfo.FLOAT: - fieldInfo.setFloatValue(newObj, getCodec().readFFloat()); + fieldInfo.setFloatValue(newObj, getCodec.readFFloat()); break; case FSTClazzInfo.FSTFieldInfo.DOUBLE: - fieldInfo.setDoubleValue(newObj, getCodec().readFDouble()); + fieldInfo.setDoubleValue(newObj, getCodec.readFDouble()); break; default: throw new RuntimeException("unkown primitive type " + fieldInfo); } } else { Object toSet = readObjectWithHeader(fieldInfo); - toSet = getCodec().coerceElement(fieldInfo.getType(), toSet); + toSet = getCodec.coerceElement(fieldInfo.getType(), toSet); fieldInfo.setObjectValue(newObj, toSet); } } } } - getCodec().endFieldReading(newObj); + getCodec.endFieldReading(newObj); } protected boolean skipConditional(Object newObj, int conditional, FSTClazzInfo.FSTFieldInfo subInfo) { @@ -833,9 +892,10 @@ protected void readCompatibleObjectFields(FSTClazzInfo.FSTFieldInfo referencee, FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[i]; if (subInfo.isIntegral() && !subInfo.isArray()) { final Class subInfoType = subInfo.getType(); + final FSTDecoder getCodec = getCodec(); if (subInfoType == boolean.class) { if (boolcount == 8) { - booleanMask = ((int) getCodec().readFByte() + 256) &0xff; + booleanMask = ((int) getCodec.readFByte() + 256) &0xff; boolcount = 0; } boolean val = (booleanMask & 128) != 0; @@ -844,19 +904,19 @@ protected void readCompatibleObjectFields(FSTClazzInfo.FSTFieldInfo referencee, res.put(subInfo.getName(), val); } if (subInfoType == byte.class) { - res.put(subInfo.getName(), getCodec().readFByte()); + res.put(subInfo.getName(), getCodec.readFByte()); } else if (subInfoType == char.class) { - res.put(subInfo.getName(), getCodec().readFChar()); + res.put(subInfo.getName(), getCodec.readFChar()); } else if (subInfoType == short.class) { - res.put(subInfo.getName(), getCodec().readFShort()); + res.put(subInfo.getName(), getCodec.readFShort()); } else if (subInfoType == int.class) { - res.put(subInfo.getName(), getCodec().readFInt()); + res.put(subInfo.getName(), getCodec.readFInt()); } else if (subInfoType == double.class) { - res.put(subInfo.getName(), getCodec().readFDouble()); + res.put(subInfo.getName(), getCodec.readFDouble()); } else if (subInfoType == float.class) { - res.put(subInfo.getName(), getCodec().readFFloat()); + res.put(subInfo.getName(), getCodec.readFFloat()); } else if (subInfoType == long.class) { - res.put(subInfo.getName(), getCodec().readFLong()); + res.put(subInfo.getName(), getCodec.readFLong()); } } else { // object @@ -883,20 +943,22 @@ public String readStringAsc() throws IOException { } protected Object readArray(FSTClazzInfo.FSTFieldInfo referencee, int pos) throws Exception { - Object classOrArray = getCodec().readArrayHeader(); + final FSTDecoder getCodec = getCodec(); + Object classOrArray = getCodec.readArrayHeader(); if (pos < 0) - pos = getCodec().getInputPos(); + pos = getCodec.getInputPos(); if ( classOrArray instanceof Class == false ) return classOrArray; if ( classOrArray == null ) return null; Object o = readArrayNoHeader(referencee, pos, (Class) classOrArray); - getCodec().readArrayEnd(null); + getCodec.readArrayEnd(null); return o; } protected Object readArrayNoHeader(FSTClazzInfo.FSTFieldInfo referencee, int pos, Class arrCl) throws Exception { - final int len = getCodec().readFInt(); + final FSTDecoder getCodec = getCodec(); + final int len = getCodec.readFInt(); if (len == -1) { return null; } @@ -906,15 +968,15 @@ protected Object readArrayNoHeader(FSTClazzInfo.FSTFieldInfo referencee, int pos if ( ! referencee.isFlat() ) objects.registerObjectForRead(array, pos ); if (arrType.isPrimitive()) { - return getCodec().readFPrimitiveArray(array, arrType, len); + return getCodec.readFPrimitiveArray(array, arrType, len); } else { // Object Array Object arr[] = (Object[]) array; for (int i = 0; i < len; i++) { Object value = readObjectWithHeader(referencee); - value = getCodec().coerceElement(arrType, value); + value = getCodec.coerceElement(arrType, value); arr[i] = value; } - getCodec().readObjectEnd(); + getCodec.readObjectEnd(); } return array; } else { // multidim array @@ -958,8 +1020,9 @@ public void resetForReuse(InputStream in) throws IOException { if ( closed ) { throw new RuntimeException("can't reuse closed stream"); } - getCodec().reset(); - getCodec().setInputStream(in); + final FSTDecoder getCodec = getCodec(); + getCodec.reset(); + getCodec.setInputStream(in); objects.clearForRead(conf); callbacks = null; //fix memory leak on reuse from default FstConfiguration } @@ -968,9 +1031,10 @@ public void resetForReuseCopyArray(byte bytes[], int off, int len) throws IOExce if ( closed ) { throw new RuntimeException("can't reuse closed stream"); } - getCodec().reset(); + final FSTDecoder getCodec = getCodec(); + getCodec.reset(); objects.clearForRead(conf); - getCodec().resetToCopyOf(bytes, off, len); + getCodec.resetToCopyOf(bytes, off, len); callbacks = null; //fix memory leak on reuse from default FstConfiguration } diff --git a/src/main/java/org/nustaq/serialization/FSTObjectOutput.java b/src/main/java/org/nustaq/serialization/FSTObjectOutput.java index 66bfa806..970a0118 100644 --- a/src/main/java/org/nustaq/serialization/FSTObjectOutput.java +++ b/src/main/java/org/nustaq/serialization/FSTObjectOutput.java @@ -16,6 +16,7 @@ package org.nustaq.serialization; import org.nustaq.logging.FSTLogger; +import org.nustaq.serialization.FSTClazzInfo.FSTFieldInfo; import org.nustaq.serialization.util.FSTUtil; import java.io.*; @@ -286,9 +287,10 @@ public void writeObject(Object obj, Class... possibles) throws IOException { return; } if ( possibles != null && possibles.length > 1 ) { + final FSTEncoder getCodec = getCodec(); for (int i = 0; i < possibles.length; i++) { Class possible = possibles[i]; - getCodec().registerClass(possible); + getCodec.registerClass(possible); } } writeObjectInternal(obj, null, possibles); @@ -372,13 +374,14 @@ protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referenc protected int tmp[] = {0}; // splitting this slows down ... protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referencee, Object toWrite, FSTClazzInfo ci) throws IOException { + final FSTEncoder getCodec = getCodec(); int startPosition = 0; try { if ( toWrite == null ) { - getCodec().writeTag(NULL, null, 0, toWrite, this); + getCodec.writeTag(NULL, null, 0, toWrite, this); return null; } - startPosition = getCodec().getWritten(); + startPosition = getCodec.getWritten(); objectWillBeWritten(toWrite, startPosition); final Class clazz = toWrite.getClass(); if ( clazz == String.class ) { @@ -387,8 +390,8 @@ protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referenc for (int i = 0; i < oneOf.length; i++) { String s = oneOf[i]; if ( s.equals(toWrite) ) { - getCodec().writeTag(ONE_OF, oneOf, i, toWrite, this); - getCodec().writeFByte(i); + getCodec.writeTag(ONE_OF, oneOf, i, toWrite, this); + getCodec.writeFByte(i); return null; } } @@ -396,19 +399,19 @@ protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referenc // shortpath if (! dontShare && writeHandleIfApplicable(toWrite, stringInfo)) return stringInfo; - getCodec().writeTag(STRING, toWrite, 0, toWrite, this); - getCodec().writeStringUTF((String) toWrite); + getCodec.writeTag(STRING, toWrite, 0, toWrite, this); + getCodec.writeStringUTF((String) toWrite); return null; } else if ( clazz == Integer.class ) { - getCodec().writeTag(BIG_INT, null, 0, toWrite, this); - getCodec().writeFInt(((Integer) toWrite).intValue()); + getCodec.writeTag(BIG_INT, null, 0, toWrite, this); + getCodec.writeFInt(((Integer) toWrite).intValue()); return null; } else if ( clazz == Long.class ) { - getCodec().writeTag(BIG_LONG, null, 0, toWrite, this); - getCodec().writeFLong(((Long) toWrite).longValue()); + getCodec.writeTag(BIG_LONG, null, 0, toWrite, this); + getCodec.writeFLong(((Long) toWrite).longValue()); return null; } else if ( clazz == Boolean.class ) { - getCodec().writeTag(((Boolean) toWrite).booleanValue() ? BIG_BOOLEAN_TRUE : BIG_BOOLEAN_FALSE, null, 0, toWrite, this); return null; + getCodec.writeTag(((Boolean) toWrite).booleanValue() ? BIG_BOOLEAN_TRUE : BIG_BOOLEAN_FALSE, null, 0, toWrite, this); return null; } else if ( (referencee.getType() != null && referencee.getType().isEnum()) || toWrite instanceof Enum ) { return writeEnum(referencee, toWrite); } @@ -422,10 +425,10 @@ protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referenc return serializationInfo; } if (clazz.isArray()) { - if (getCodec().writeTag(ARRAY, toWrite, 0, toWrite, this)) + if (getCodec.writeTag(ARRAY, toWrite, 0, toWrite, this)) return serializationInfo; // some codecs handle primitive arrays like an primitive type writeArray(referencee, toWrite); - getCodec().writeArrayEnd(); + getCodec.writeArrayEnd(); } else if ( ser == null ) { // default write object wihtout custom serializer // handle write replace @@ -457,35 +460,36 @@ protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referenc if ( ser == null ) { defaultWriteObject(toWrite, serializationInfo); if ( serializationInfo.isExternalizable() ) - getCodec().externalEnd(serializationInfo); + getCodec.externalEnd(serializationInfo); } else { // handle edge case: there is a serializer registered for replaced class // copied from below :( - int pos = getCodec().getWritten(); + int pos = getCodec.getWritten(); // write object depending on type (custom, externalizable, serializable/java, default) ser.writeObject(this, toWrite, serializationInfo, referencee, pos); - getCodec().externalEnd(serializationInfo); + getCodec.externalEnd(serializationInfo); } } return originalInfo; } else { // object has custom serializer // Object header (nothing written till here) if (! writeObjectHeader(serializationInfo, referencee, toWrite) ) { // skip in case code can write object as primitive - int pos = getCodec().getWritten(); + int pos = getCodec.getWritten(); // write object depending on type (custom, externalizable, serializable/java, default) ser.writeObject(this, toWrite, serializationInfo, referencee, pos); - getCodec().externalEnd(serializationInfo); + getCodec.externalEnd(serializationInfo); } } return serializationInfo; } finally { - objectHasBeenWritten(toWrite, startPosition, getCodec().getWritten()); + objectHasBeenWritten(toWrite, startPosition, getCodec.getWritten()); } } protected FSTClazzInfo writeEnum(FSTClazzInfo.FSTFieldInfo referencee, Object toWrite) throws IOException { - if ( ! getCodec().writeTag(ENUM, toWrite, 0, toWrite, this) ) { + final FSTEncoder getCodec = getCodec(); + if ( ! getCodec.writeTag(ENUM, toWrite, 0, toWrite, this) ) { boolean isEnumClass = toWrite.getClass().isEnum(); if (!isEnumClass) { // anonymous enum subclass @@ -494,28 +498,37 @@ protected FSTClazzInfo writeEnum(FSTClazzInfo.FSTFieldInfo referencee, Object to if (c == null) { throw new RuntimeException("Can't handle this enum: " + toWrite.getClass()); } - getCodec().writeClass(c); + getCodec.writeClass(c); } else { FSTClazzInfo fstClazzInfo = getFstClazzInfo(referencee, toWrite.getClass()); - getCodec().writeClass(fstClazzInfo); - getCodec().writeFInt(((Enum) toWrite).ordinal()); + getCodec.writeClass(fstClazzInfo); + if(FSTConfiguration.FIELDS_FIX_ENUM_WITH_NAME){ + getCodec.writeStringUTF(((Enum) toWrite).name()); + }else{ + getCodec.writeFInt(((Enum) toWrite).ordinal()); + } return fstClazzInfo; } - getCodec().writeFInt(((Enum) toWrite).ordinal()); + if(FSTConfiguration.FIELDS_FIX_ENUM_WITH_NAME){ + getCodec.writeStringUTF(((Enum) toWrite).name()); + }else{ + getCodec.writeFInt(((Enum) toWrite).ordinal()); + } } return null; } protected boolean writeHandleIfApplicable(Object toWrite, FSTClazzInfo serializationInfo) throws IOException { - int writePos = getCodec().getWritten(); + final FSTEncoder getCodec = getCodec(); + int writePos = getCodec.getWritten(); int handle = objects.registerObjectForWrite(toWrite, writePos, serializationInfo, tmp); // determine class header if ( handle >= 0 ) { final boolean isIdentical = tmp[0] == 0; //objects.getReadRegisteredObject(handle) == toWrite; if ( isIdentical ) { // System.out.println("POK writeHandle"+handle+" "+toWrite.getClass().getName()); - if ( ! getCodec().writeTag(HANDLE, null, handle, toWrite, this) ) - getCodec().writeFInt(handle); + if ( ! getCodec.writeTag(HANDLE, null, handle, toWrite, this) ) + getCodec.writeFInt(handle); return true; } } @@ -579,28 +592,29 @@ protected void writeObjectCompatibleRecursive(FSTClazzInfo.FSTFieldInfo referenc } protected void writeObjectFields(Object toWrite, FSTClazzInfo serializationInfo, FSTClazzInfo.FSTFieldInfo[] fieldInfo, int startIndex, int version) throws IOException { + final FSTEncoder getCodec = getCodec(); try { int booleanMask = 0; int boolcount = 0; final int length = fieldInfo.length; int j = startIndex; - if ( ! getCodec().isWritingAttributes() ) { // pack bools into bits in case it's not a chatty codec + if ( ! getCodec.isWritingAttributes() && !FSTConfiguration.FIELDS_FIX_LENGTH ) { // pack bools into bits in case it's not a chatty codec for (;; j++) { if ( j == length || fieldInfo[j].getVersion() != version ) { if ( boolcount > 0 ) { - getCodec().writeFByte(booleanMask << (8 - boolcount)); + getCodec.writeFByte(booleanMask << (8 - boolcount)); } break; } final FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[j]; - if ( subInfo.getIntegralType() != subInfo.BOOL ) { + if ( subInfo.getIntegralType() != FSTFieldInfo.BOOL ) { if ( boolcount > 0 ) { - getCodec().writeFByte(booleanMask << (8 - boolcount)); + getCodec.writeFByte(booleanMask << (8 - boolcount)); } break; } else { if ( boolcount == 8 ) { - getCodec().writeFByte(booleanMask << (8 - boolcount)); + getCodec.writeFByte(booleanMask << (8 - boolcount)); boolcount = 0; booleanMask = 0; } boolean booleanValue = subInfo.getBooleanValue( toWrite); @@ -614,59 +628,96 @@ protected void writeObjectFields(Object toWrite, FSTClazzInfo serializationInfo, { final FSTClazzInfo.FSTFieldInfo subInfo = fieldInfo[i]; if (subInfo.getVersion() != version ) { - getCodec().writeVersionTag(subInfo.getVersion()); + getCodec.writeVersionTag(subInfo.getVersion()); writeObjectFields(toWrite, serializationInfo, fieldInfo, i, subInfo.getVersion()); return; } - if ( getCodec().writeAttributeName(subInfo, toWrite) ) { + if ( getCodec.writeAttributeName(subInfo, toWrite) ) { continue; - } + } if ( subInfo.isPrimitive() ) { - // speed safe - int integralType = subInfo.getIntegralType(); + // speed safe + final int integralType = subInfo.getIntegralType(); + if(FSTConfiguration.FIELDS_FIX_LENGTH){ + /** + * + * ARC: fieldsFix header is always composed of a byte and extra bytes + * + * 0 byte signals that we have 4 bytes or 1 byte + * + */ + // in this case extra size = 1 byte + getCodec.writeFByte(2); + } switch (integralType) { case FSTClazzInfo.FSTFieldInfo.BOOL: - getCodec().writeFByte(subInfo.getBooleanValue(toWrite) ? 1 : 0); break; + getCodec.writeFByte(subInfo.getBooleanValue(toWrite) ? 1 : 0); break; case FSTClazzInfo.FSTFieldInfo.BYTE: - getCodec().writeFByte(subInfo.getByteValue(toWrite)); break; + getCodec.writeFByte(subInfo.getByteValue(toWrite)); break; case FSTClazzInfo.FSTFieldInfo.CHAR: - getCodec().writeFChar((char) subInfo.getCharValue(toWrite)); break; + getCodec.writeFChar((char) subInfo.getCharValue(toWrite)); break; case FSTClazzInfo.FSTFieldInfo.SHORT: - getCodec().writeFShort((short) subInfo.getShortValue(toWrite)); break; + getCodec.writeFShort((short) subInfo.getShortValue(toWrite)); break; case FSTClazzInfo.FSTFieldInfo.INT: - getCodec().writeFInt(subInfo.getIntValue(toWrite)); break; + getCodec.writeFInt(subInfo.getIntValue(toWrite)); break; case FSTClazzInfo.FSTFieldInfo.LONG: - getCodec().writeFLong(subInfo.getLongValue(toWrite)); break; + getCodec.writeFLong(subInfo.getLongValue(toWrite)); break; case FSTClazzInfo.FSTFieldInfo.FLOAT: - getCodec().writeFFloat(subInfo.getFloatValue(toWrite)); break; + getCodec.writeFFloat(subInfo.getFloatValue(toWrite)); break; case FSTClazzInfo.FSTFieldInfo.DOUBLE: - getCodec().writeFDouble(subInfo.getDoubleValue(toWrite)); break; + getCodec.writeFDouble(subInfo.getDoubleValue(toWrite)); break; } } else if (subInfo.isConditional()) { - final int conditional = getCodec().getWritten(); - getCodec().skip(4); + final int conditional = getCodec.getWritten(); + getCodec.skip(4); // object Object subObject = subInfo.getObjectValue(toWrite); if ( subObject == null ) { - getCodec().writeTag(NULL, null, 0, toWrite, this); + getCodec.writeTag(NULL, null, 0, toWrite, this); } else { writeObjectWithContext(subInfo, subObject); } - int v = getCodec().getWritten(); - getCodec().writeInt32At(conditional, v); + int v = getCodec.getWritten(); + getCodec.writeInt32At(conditional, v); } else { // object Object subObject = subInfo.getObjectValue(toWrite); if ( subObject == null ) { - getCodec().writeTag(NULL, null, 0, toWrite, this); + if(FSTConfiguration.FIELDS_FIX_LENGTH){ + /** + * ARC: see the fieldsHeader comment + * here the size is 1 + * + * null one position + */ + getCodec.writeFByte(2); + } + getCodec.writeTag(NULL, null, 0, toWrite, this); } else { + int position = -1; + if(FSTConfiguration.FIELDS_FIX_LENGTH){ + /** + * ARC: see the fieldsHeader comment + * here the size is 4 + */ + position = getCodec.getWritten(); + getCodec.skip(4); + } writeObjectWithContext(subInfo, subObject); + if(FSTConfiguration.FIELDS_FIX_LENGTH){ + int size = getCodec.getWritten() - position -4; + size = (size << 1) | 1; + getCodec.writeByteAt(position++, (byte)((size >>> 0) & 0xFF)); + getCodec.writeByteAt(position++, (byte)((size >>> 8) & 0xFF)); + getCodec.writeByteAt(position++, (byte)((size >>> 0) & 0xFF)); + getCodec.writeByteAt(position++, (byte)((size >>> 0) & 0xFF)); + } } } } - getCodec().writeVersionTag((byte) 0); - getCodec().writeFieldsEnd(serializationInfo); + getCodec.writeVersionTag((byte) 0); + getCodec.writeFieldsEnd(serializationInfo); } catch (IllegalAccessException ex) { FSTUtil.rethrow(ex); } @@ -675,6 +726,7 @@ protected void writeObjectFields(Object toWrite, FSTClazzInfo serializationInfo, // write identical to other version, but take field values from hashmap (because of annoying putField/getField feature) protected void writeCompatibleObjectFields(Object toWrite, Map fields, FSTClazzInfo.FSTFieldInfo[] fieldInfo) throws IOException { + final FSTEncoder getCodec = getCodec(); int booleanMask = 0; int boolcount = 0; for (int i = 0; i < fieldInfo.length; i++) { @@ -684,14 +736,14 @@ protected void writeCompatibleObjectFields(Object toWrite, Map fields, FSTClazzI Class subInfType = subInfo.getType(); if ( subInfType != boolean.class || isarr) { if ( boolcount > 0 ) { - getCodec().writeFByte(booleanMask << (8 - boolcount)); + getCodec.writeFByte(booleanMask << (8 - boolcount)); boolcount = 0; booleanMask = 0; } } if ( subInfo.isIntegral() && !isarr) { if ( subInfType == boolean.class ) { if ( boolcount == 8 ) { - getCodec().writeFByte(booleanMask << (8 - boolcount)); + getCodec.writeFByte(booleanMask << (8 - boolcount)); boolcount = 0; booleanMask = 0; } boolean booleanValue = ((Boolean)fields.get(subInfo.getName())).booleanValue(); @@ -700,25 +752,25 @@ protected void writeCompatibleObjectFields(Object toWrite, Map fields, FSTClazzI boolcount++; } else if ( subInfType == int.class ) { - getCodec().writeFInt(((Number) fields.get(subInfo.getName())).intValue()); + getCodec.writeFInt(((Number) fields.get(subInfo.getName())).intValue()); } else if ( subInfType == long.class ) { - getCodec().writeFLong(((Number) fields.get(subInfo.getName())).longValue()); + getCodec.writeFLong(((Number) fields.get(subInfo.getName())).longValue()); } else if ( subInfType == byte.class ) { - getCodec().writeFByte(((Number) fields.get(subInfo.getName())).byteValue()); + getCodec.writeFByte(((Number) fields.get(subInfo.getName())).byteValue()); } else if ( subInfType == char.class ) { - getCodec().writeFChar((char) ((Number) fields.get(subInfo.getName())).intValue()); + getCodec.writeFChar((char) ((Number) fields.get(subInfo.getName())).intValue()); } else if ( subInfType == short.class ) { - getCodec().writeFShort(((Number) fields.get(subInfo.getName())).shortValue()); + getCodec.writeFShort(((Number) fields.get(subInfo.getName())).shortValue()); } else if ( subInfType == float.class ) { - getCodec().writeFFloat(((Number) fields.get(subInfo.getName())).floatValue()); + getCodec.writeFFloat(((Number) fields.get(subInfo.getName())).floatValue()); } else if ( subInfType == double.class ) { - getCodec().writeFDouble(((Number) fields.get(subInfo.getName())).doubleValue()); + getCodec.writeFDouble(((Number) fields.get(subInfo.getName())).doubleValue()); } } else { // object @@ -730,7 +782,7 @@ protected void writeCompatibleObjectFields(Object toWrite, Map fields, FSTClazzI } } if ( boolcount > 0 ) { - getCodec().writeFByte(booleanMask << (8 - boolcount)); + getCodec.writeFByte(booleanMask << (8 - boolcount)); } } @@ -743,15 +795,16 @@ protected void writeCompatibleObjectFields(Object toWrite, Map fields, FSTClazzI * @throws IOException */ protected boolean writeObjectHeader(final FSTClazzInfo clsInfo, final FSTClazzInfo.FSTFieldInfo referencee, final Object toWrite) throws IOException { + final FSTEncoder getCodec = getCodec(); if ( toWrite.getClass() == referencee.getType() && ! clsInfo.useCompatibleMode() ) { - return getCodec().writeTag(TYPED, clsInfo, 0, toWrite, this); + return getCodec.writeTag(TYPED, clsInfo, 0, toWrite, this); } else { final Class[] possibleClasses = referencee.getPossibleClasses(); if ( possibleClasses == null ) { - if ( !getCodec().writeTag(OBJECT, clsInfo, 0, toWrite, this) ) { - getCodec().writeClass(clsInfo); + if ( !getCodec.writeTag(OBJECT, clsInfo, 0, toWrite, this) ) { + getCodec.writeClass(clsInfo); return false; } else { return true; @@ -761,12 +814,12 @@ protected boolean writeObjectHeader(final FSTClazzInfo clsInfo, final FSTClazzIn for (int j = 0; j < length; j++) { final Class possibleClass = possibleClasses[j]; if ( possibleClass == toWrite.getClass() ) { - getCodec().writeFByte(j + 1); + getCodec.writeFByte(j + 1); return false; } } - if (!getCodec().writeTag(OBJECT, clsInfo, 0, toWrite, this) ) { - getCodec().writeClass(clsInfo); + if (!getCodec.writeTag(OBJECT, clsInfo, 0, toWrite, this) ) { + getCodec.writeClass(clsInfo); return false; } else { return true; @@ -777,18 +830,19 @@ protected boolean writeObjectHeader(final FSTClazzInfo clsInfo, final FSTClazzIn // incoming array is already registered protected void writeArray(FSTClazzInfo.FSTFieldInfo referencee, Object array) throws IOException { + final FSTEncoder getCodec = getCodec(); if ( array == null ) { - getCodec().writeClass(Object.class); - getCodec().writeFInt(-1); + getCodec.writeClass(Object.class); + getCodec.writeFInt(-1); return; } final int len = Array.getLength(array); Class componentType = array.getClass().getComponentType(); - getCodec().writeClass(array.getClass()); - getCodec().writeFInt(len); + getCodec.writeClass(array.getClass()); + getCodec.writeFInt(len); if ( ! componentType.isArray() ) { - if (getCodec().isPrimitiveArray(array, componentType)) { - getCodec().writePrimitiveArray(array, 0, len); + if (getCodec.isPrimitiveArray(array, componentType)) { + getCodec.writePrimitiveArray(array, 0, len); } else { // objects Object arr[] = (Object[])array; Class lastClz = null; @@ -809,16 +863,16 @@ protected void writeArray(FSTClazzInfo.FSTFieldInfo referencee, Object array) th for ( int i = 0; i < len; i++ ) { Object subArr = arr[i]; boolean needsWrite = true; - if ( getCodec().isTagMultiDimSubArrays() ) { + if ( getCodec.isTagMultiDimSubArrays() ) { if ( subArr == null ) { - needsWrite = !getCodec().writeTag(NULL, null, 0, null, this); + needsWrite = !getCodec.writeTag(NULL, null, 0, null, this); } else { - needsWrite = !getCodec().writeTag(ARRAY, subArr, 0, subArr, this); + needsWrite = !getCodec.writeTag(ARRAY, subArr, 0, subArr, this); } } if ( needsWrite ) { writeArray(ref1, subArr); - getCodec().writeArrayEnd(); + getCodec.writeArrayEnd(); } } } @@ -1100,12 +1154,13 @@ public byte[] getBuffer() { * note: in case of non-stream based serialization (directbuffer, offheap mem) getBuffer will return a copy anyways. */ public byte[] getCopyOfWrittenBuffer() { - if ( ! getCodec().isByteArrayBased() ) { + final FSTEncoder getCodec = getCodec(); + if ( ! getCodec.isByteArrayBased() ) { return getBuffer(); } - byte res [] = new byte[getCodec().getWritten()]; + byte res [] = new byte[getCodec.getWritten()]; byte[] buffer = getBuffer(); - System.arraycopy(buffer,0,res,0, getCodec().getWritten()); + System.arraycopy(buffer,0,res,0, getCodec.getWritten()); return res; } diff --git a/src/main/java/org/nustaq/serialization/coders/FSTBytezEncoder.java b/src/main/java/org/nustaq/serialization/coders/FSTBytezEncoder.java index a0e5064d..d1691aa1 100644 --- a/src/main/java/org/nustaq/serialization/coders/FSTBytezEncoder.java +++ b/src/main/java/org/nustaq/serialization/coders/FSTBytezEncoder.java @@ -263,6 +263,15 @@ public void writeInt32At(int position, int v) { } buffout.putInt(position,v); } + @Override + public void writeByteAt(int position, byte v) { + try { + ensureFree( position+1); + } catch (IOException e) { + FSTUtil.rethrow(e); + } + buffout.put(position,v); + } /** * if output stream is null, just encode into a byte array diff --git a/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java b/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java index 49f92298..b9491497 100644 --- a/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java +++ b/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java @@ -176,6 +176,10 @@ public void flush() throws IOException { public void writeInt32At(int position, int v) { throw new RuntimeException("not supported"); } + @Override + public void writeByteAt(int position, byte v) { + throw new RuntimeException("not supported"); + } @Override public void setOutstream(OutputStream outstream) { diff --git a/src/main/java/org/nustaq/serialization/coders/FSTMinBinEncoder.java b/src/main/java/org/nustaq/serialization/coders/FSTMinBinEncoder.java index 043e838c..c82e0111 100644 --- a/src/main/java/org/nustaq/serialization/coders/FSTMinBinEncoder.java +++ b/src/main/java/org/nustaq/serialization/coders/FSTMinBinEncoder.java @@ -157,6 +157,10 @@ public void flush() throws IOException { public void writeInt32At(int position, int v) { throw new RuntimeException("not supported"); } + @Override + public void writeByteAt(int position, byte v) { + throw new RuntimeException("not supported"); + } /** * if output stream is null, just encode into a byte array diff --git a/src/main/java/org/nustaq/serialization/coders/FSTStreamEncoder.java b/src/main/java/org/nustaq/serialization/coders/FSTStreamEncoder.java index f1f756df..1115ce98 100644 --- a/src/main/java/org/nustaq/serialization/coders/FSTStreamEncoder.java +++ b/src/main/java/org/nustaq/serialization/coders/FSTStreamEncoder.java @@ -499,6 +499,10 @@ public void writeInt32At(int position, int v) { buffout.buf[position+2] = (byte) (v >>> 16); buffout.buf[position+3] = (byte) (v >>> 24); } + @Override + public void writeByteAt(int position, byte v) { + buffout.buf[position] = v; + } /** * if output stream is null, just encode into a byte array