org.nustaq.serialization.FSTClazzInfo 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.
/*
* Copyright 2014 Ruediger Moeller.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nustaq.serialization;
import org.nustaq.offheap.structs.Align;
import org.nustaq.serialization.annotations.*;
import org.nustaq.serialization.util.FSTMap;
import org.nustaq.serialization.util.FSTUtil;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created with IntelliJ IDEA.
* User: Möller
* Date: 03.11.12
* Time: 13:08
* To change this template use File | Settings | File Templates.
*/
public final class FSTClazzInfo {
// cache constructor per class (big saving in permspace)
public static boolean BufferConstructorMeta = true;
// cache and share class.getDeclaredFields amongst all fstconfigs
public static boolean BufferFieldMeta = true;
/**
* cache + share j.reflect.Field. This can be cleared in case it gets too fat/leaks mem (e.g. class reloading)
*/
public static ConcurrentHashMap sharedFieldSets = new ConcurrentHashMap<>();
public static final Comparator defFieldComparator = new Comparator() {
@Override
public int compare(FSTFieldInfo o1, FSTFieldInfo o2) {
int res = 0;
if ( o1.getVersion() != o2.getVersion() ) {
return o1.getVersion() < o2.getVersion() ? -1 : 1;
}
// order: version, boolean, primitives, conditionals, object references
if (o1.getType() == boolean.class && o2.getType() != boolean.class) {
return -1;
}
if (o1.getType() != boolean.class && o2.getType() == boolean.class) {
return 1;
}
if (o1.isConditional() && !o2.isConditional()) {
res = 1;
} else if (!o1.isConditional() && o2.isConditional()) {
res = -1;
} else if (o1.isPrimitive() && !o2.isPrimitive()) {
res = -1;
} else if (!o1.isPrimitive() && o2.isPrimitive())
res = 1;
// if (res == 0) // 64 bit / 32 bit issues
// res = (int) (o1.getMemOffset() - o2.getMemOffset());
if (res == 0)
res = o1.getType().getSimpleName().compareTo(o2.getType().getSimpleName());
if (res == 0)
res = o1.getName().compareTo(o2.getName());
if (res == 0) {
return o1.getField().getDeclaringClass().getName().compareTo(o2.getField().getDeclaringClass().getName());
}
return res;
}
};
Class[] predict;
private boolean ignoreAnn;
FSTMap fieldMap;
Method writeReplaceMethod, readResolveMethod;
FSTMap compInfo;
Object decoderAttached; // for decoders
public Object getDecoderAttached() {
return decoderAttached;
}
public void setDecoderAttached(Object decoderAttached) {
this.decoderAttached = decoderAttached;
}
boolean requiresCompatibleMode;
boolean externalizable;
boolean flat; // never share instances of this class
boolean isAsciiNameShortString = false;
boolean requiresInit = false;
boolean hasTransient;
FSTObjectSerializer ser;
FSTFieldInfo fieldInfo[]; // serializable fields
Class clazz;
Object[] enumConstants;
Constructor cons;
int clzId = -1;
int structSize = 0;
FSTConfiguration conf;
protected FSTClassInstantiator instantiator; // initialized from FSTConfiguration in constructor
boolean crossPlatform;
public FSTClazzInfo(FSTConfiguration conf, Class clazz, FSTClazzInfoRegistry infoRegistry, boolean ignoreAnnotations) {
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);
instantiator = conf.getInstantiator(clazz);
if (Externalizable.class.isAssignableFrom(clazz)) {
externalizable = true;
cons = instantiator.findConstructorForExternalize(clazz);
} else if (Serializable.class.isAssignableFrom(clazz) || clazz == Object.class) {
externalizable = false;
cons = instantiator.findConstructorForSerializable(clazz);
} else {
if (!conf.isStructMode()) {
if ( conf.isForceSerializable() || getSer() != null ) {
externalizable = false;
cons = instantiator.findConstructorForSerializable(clazz);
} else {
throw new RuntimeException("Class " + clazz.getName() + " does not implement Serializable or externalizable");
}
} else {
cons = instantiator.findConstructorForSerializable(clazz);
}
}
if (!ignoreAnnotations) {
Predict annotation = (Predict) clazz.getAnnotation(Predict.class);
if (annotation != null) {
predict = annotation.value();
}
flat = clazz.isAnnotationPresent(Flat.class);
}
if (cons != null) {
cons.setAccessible(true);
}
final String name = clazz.getName();
if (name.length() < 127) {
isAsciiNameShortString = true;
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) > 127) {
isAsciiNameShortString = false;
break;
}
}
}
requiresInit = isExternalizable() || useCompatibleMode() || hasTransient || conf.isForceClzInit();
if (useCompatibleMode() && crossPlatform && getSer() == null && !clazz.isEnum())
throw new RuntimeException("cannot support legacy JDK serialization methods in crossplatform mode. Define a serializer for this class " + clazz.getName());
}
byte[] bufferedName;
public byte[] getBufferedName() {
if (bufferedName == null) {
bufferedName = getClazz().getName().getBytes();
}
return bufferedName;
}
@Override
public String toString() {
return "FSTClazzInfo{" +
"clazz=" + clazz +
'}';
}
public boolean isAsciiNameShortString() {
return isAsciiNameShortString;
}
public int getClzId() {
return clzId;
}
public void setClzId(int clzId) {
this.clzId = clzId;
}
public int getNumBoolFields() {
FSTFieldInfo[] fis = getFieldInfo();
for (int i = 0; i < fis.length; i++) {
FSTFieldInfo fstFieldInfo = fis[i];
if (fstFieldInfo.getType() != boolean.class) {
return i;
}
}
return fis.length;
}
public boolean isExternalizable() {
return externalizable;
}
public final boolean isFlat() {
return flat;
}
public final Class[] getPredict() {
return predict;
}
public final Object newInstance(boolean doesRequireInit) {
return instantiator.newInstance(clazz, cons, doesRequireInit || requiresInit, conf.isForceSerializable() );
}
/**
* Sideeffect: sets hasTransient
*
* @param c
* @param res
* @return
*/
static ReentrantLock shareLock = new ReentrantLock(false);
public final List getAllFields(Class c, List res) {
try {
if ( BufferFieldMeta ) {
shareLock.lock();
}
if (res == null) {
res = new ArrayList();
}
if (c == null) {
return res;
}
Field[] declaredFields = BufferFieldMeta && !conf.isStructMode() ? sharedFieldSets.get(c) : null;
if (declaredFields == null) {
declaredFields = c.getDeclaredFields();
if (BufferFieldMeta && !conf.isStructMode())
sharedFieldSets.put(c, declaredFields);
}
List c1 = Arrays.asList(declaredFields);
Collections.reverse(c1);
for (int i = 0; i < c1.size(); i++) {
Field field = c1.get(i);
res.add(0, field);
}
for (int i = 0; i < res.size(); i++) {
Field field = res.get(i);
if (Modifier.isStatic(field.getModifiers()) || isTransient(c, field)) {
if (isTransient(c, field)) {
hasTransient = true;
}
res.remove(i);
i--;
}
}
List allFields = getAllFields(c.getSuperclass(), res);
return new ArrayList<>(allFields);
} finally {
if ( BufferFieldMeta )
shareLock.unlock();
}
}
private boolean isTransient(Class c, Field field) {
if (Modifier.isTransient(field.getModifiers()))
return true;
while (c.getName().indexOf("$") >= 0) {
c = c.getSuperclass(); // patch fuer reallive queries, kontraktor spore
}
if ( field.getName().startsWith("this$") && c.getAnnotation(AnonymousTransient.class) != null )
return true;
return (c.getAnnotation(Transient.class) != null && field.getAnnotation(Serialize.class) == null);
}
public final FSTFieldInfo[] getFieldInfo() {
return fieldInfo;
}
public final FSTFieldInfo[] getFieldInfoFiltered(Class... toRemove) {
FSTFieldInfo[] fis = getFieldInfo();
int count = 0;
for (int i = 0; i < fis.length; i++) {
FSTFieldInfo fi = fis[i];
boolean skip = false;
for (int j = 0; j < toRemove.length; j++) {
Class aClass = toRemove[j];
if (fi.getField().getDeclaringClass() == aClass) {
skip = true;
break;
}
}
if (!skip) {
count++;
}
}
FSTFieldInfo res[] = new FSTFieldInfo[count];
count = 0;
for (int i = 0; i < fis.length; i++) {
FSTFieldInfo fi = fis[i];
boolean skip = false;
for (int j = 0; j < toRemove.length; j++) {
Class aClass = toRemove[j];
if (fi.getField().getDeclaringClass() == aClass) {
skip = true;
break;
}
}
if (!skip) {
res[count++] = fis[i];
}
}
return res;
}
public final FSTFieldInfo getFieldInfo(String name, Class declaringClass) {
if ( fieldMap != null ) {
if (declaringClass == null) {
return fieldMap.get(name);
}
return fieldMap.get(declaringClass.getName() + "#" + name); //FIXME: THIS IS VERY SLOW (only used by JSON / compatibility mode)
} else {
synchronized (this) {
fieldMap = buildFieldMap();
return getFieldInfo(name,declaringClass);
}
}
}
private FSTMap buildFieldMap() {
FSTMap res = new FSTMap<>(fieldInfo.length);
for (int i = 0; i < fieldInfo.length; i++) {
Field field = fieldInfo[i].getField();
if ( field != null ) {
res.put(field.getDeclaringClass().getName() + "#" + field.getName(), fieldInfo[i]);
res.put(field.getName(), fieldInfo[i]);
}
}
return res;
}
private void createFields(Class c) {
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);
}
// 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;
}
};
// check if we actually need to build up compatibility info (memory intensive)
boolean requiresCompatibilityData = false;
if ( ! Externalizable.class.isAssignableFrom(c) && getSerNoStore() == null ) {
Class tmpCls = c;
while( tmpCls != Object.class ) {
if ( FSTUtil.findPrivateMethod(tmpCls, "writeObject", new Class>[]{ObjectOutputStream.class}, Void.TYPE) != null ||
FSTUtil.findPrivateMethod(tmpCls, "readObject", new Class>[]{ObjectInputStream.class},Void.TYPE) != null ||
FSTUtil.findDerivedMethod(tmpCls, "writeReplace", null, Object.class) != null ||
FSTUtil.findDerivedMethod(tmpCls, "readResolve", null, Object.class) != null ) {
requiresCompatibilityData = true;
break;
}
tmpCls = tmpCls.getSuperclass();
}
}
if (!conf.isStructMode() && requiresCompatibilityData ) {
getCompInfo();
fieldMap = buildFieldMap();
Class curCl = c;
fields.clear();
while (curCl != Object.class) {
ObjectStreamClass os = null;
try {
os = ObjectStreamClass.lookup(curCl);
} catch (Exception e) {
FSTUtil.rethrow(e);
}
if (os != null) {
final ObjectStreamField[] fi = os.getFields();
List curClzFields = new ArrayList();
if (fi != null) {
for (int i = 0; i < fi.length; i++) {
ObjectStreamField objectStreamField = fi[i];
String ff = objectStreamField.getName();
final FSTFieldInfo fstFieldInfo = fieldMap.get(curCl.getName() + "#" + ff);
if (fstFieldInfo != null && fstFieldInfo.getField() != null) {
curClzFields.add(fstFieldInfo);
fields.add(fstFieldInfo.getField());
} else {
FSTFieldInfo fake = new FSTFieldInfo(null, null, true );
fake.type = objectStreamField.getType();
fake.fakeName = objectStreamField.getName();
curClzFields.add(fake);
}
}
}
Collections.sort(curClzFields, infocomp);
FSTCompatibilityInfo info = new FSTCompatibilityInfo(curClzFields, curCl);
getCompInfo().put(curCl, info);
if (info.needsCompatibleMode()) {
requiresCompatibleMode = true;
}
}
curCl = curCl.getSuperclass();
}
}
// default sort order
Comparator comp = defFieldComparator;
if (!conf.isStructMode())
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);
if (al != null) {
fstFieldInfo.align = al.value();
int alignOff = fstFieldInfo.align(off);
fstFieldInfo.alignPad = alignOff - off;
off = alignOff;
}
fstFieldInfo.setStructOffset(off);
off += fstFieldInfo.getStructSize();
}
structSize = off;
writeReplaceMethod = FSTUtil.findDerivedMethod(
c, "writeReplace", null, Object.class);
readResolveMethod = FSTUtil.findDerivedMethod(
c, "readResolve", null, Object.class);
if (writeReplaceMethod != null) {
writeReplaceMethod.setAccessible(true);
}
if (readResolveMethod != null) {
readResolveMethod.setAccessible(true);
}
for (int i = 0; i < fieldInfo.length; i++) {
FSTFieldInfo fstFieldInfo = fieldInfo[i];
fstFieldInfo.indexId = i;
}
}
public int getStructSize() {
return structSize;
}
public boolean useCompatibleMode() {
return requiresCompatibleMode || writeReplaceMethod != null || readResolveMethod != null;
}
static AtomicInteger fiCount = new AtomicInteger(0);
static AtomicInteger missCount = new AtomicInteger(0);
protected FSTFieldInfo createFieldInfo(Field field) {
FSTConfiguration.FieldKey key = null;
if ( conf.fieldInfoCache != null ) {
key = new FSTConfiguration.FieldKey(field.getDeclaringClass(), field.getName());
FSTFieldInfo res = conf.fieldInfoCache.get(key);
if ( res != null ) {
fiCount.incrementAndGet();
return res;
}
}
field.setAccessible(true);
Predict predict = crossPlatform ? null : field.getAnnotation(Predict.class); // needs to be iognored cross platform
FSTFieldInfo result = new FSTFieldInfo(predict != null ? predict.value() : null, field, ignoreAnn);
if ( conf.fieldInfoCache != null && key != null ) {
conf.fieldInfoCache.put(key,result);
}
missCount.incrementAndGet();
return result;
}
public final Method getReadResolveMethod() {
return readResolveMethod;
}
public final Method getWriteReplaceMethod() {
return writeReplaceMethod;
}
public final Class getClazz() {
return clazz;
}
public Object[] getEnumConstants() {
return enumConstants;
}
public FSTMap getCompInfo() {
if (compInfo == null)
compInfo = new FSTMap<>(3); // just avoid edge case NPE's
return compInfo;
}
public final static class FSTFieldInfo {
final public static int BOOL = 1;
final public static int BYTE = 2;
final public static int CHAR = 3;
final public static int SHORT = 4;
final public static int INT = 5;
final public static int LONG = 6;
final public static int FLOAT = 7;
final public static int DOUBLE = 8;
Class possibleClasses[];
FSTClazzInfo lastInfo; // cache last class stored (can save a hash lookup)
String oneOf[] = null;
int arrayDim;
Class arrayType;
boolean flat = false;
boolean isConditional = false;
final Field field;
Class type;
boolean integral = false;
boolean primitive = false;
boolean isArr = false;
byte version;
int integralType;
long memOffset = -1;
boolean isAndroid = FSTConfiguration.isAndroid; // hope for better locality
int structOffset = 0;
int indexId; // position in serializable fields array
int align = 0;
int alignPad = 0;
Object bufferedName; // cache byte rep of field name (used for cross platform)
// hack required for compatibility with ancient JDK mechanics (cross JDK, e.g. Android <=> OpenJDK ).
// 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;
public FSTFieldInfo(Class[] possibleClasses, Field fi, boolean ignoreAnnotations) {
this.possibleClasses = possibleClasses;
field = fi;
if (fi == null) {
isArr = false;
} else {
isArr = field.getType().isArray();
type = fi.getType();
primitive = type.isPrimitive();
if (FSTUtil.unFlaggedUnsafe != null ) {
fi.setAccessible(true);
if (!Modifier.isStatic(fi.getModifiers())) {
try {
memOffset = (int) FSTUtil.unFlaggedUnsafe.objectFieldOffset(fi);
} catch (Throwable th) {
//throw FSTUtil.rethrow(th);
}
}
}
}
if (isArray()) {
String clName = field.getType().getName();
arrayDim = 1 + clName.lastIndexOf('[');
arrayType = calcComponentType(field.getType());
}
calcIntegral();
if (fi != null && !ignoreAnnotations) {
version = (byte) (fi.isAnnotationPresent(Version.class) ? fi.getAnnotation(Version.class).value() : 0);
flat = fi.isAnnotationPresent(Flat.class);
isConditional = fi.isAnnotationPresent(Conditional.class);
if (isIntegral()) {
isConditional = false;
}
OneOf annotation = fi.getAnnotation(OneOf.class);
if (annotation != null) {
oneOf = annotation.value();
}
}
}
public byte getVersion() {
return version;
}
public Object getBufferedName() {
return bufferedName;
}
public void setBufferedName(Object bufferedName) {
this.bufferedName = bufferedName;
}
public int align(int off) {
while ((off / align) * align != off)
off++;
return off;
}
public int getIndexId() {
return indexId;
}
public int getStructOffset() {
return structOffset;
}
public void setStructOffset(int structOffset) {
this.structOffset = structOffset;
}
public String[] getOneOf() {
return oneOf;
}
public long getMemOffset() {
return memOffset;
}
public int getAlign() {
return align;
}
public int getAlignPad() {
return alignPad;
}
public boolean isConditional() {
return isConditional;
}
public FSTClazzInfo getLastInfo() {
return lastInfo;
}
public void setLastInfo(FSTClazzInfo lastInfo) {
this.lastInfo = lastInfo;
}
Class calcComponentType(Class c) {
if (c.isArray()) {
return calcComponentType(c.getComponentType());
}
return c;
}
public boolean isVolatile() {
return Modifier.isVolatile(getField().getModifiers());
}
public final Class getType() {
return type;
}
public boolean isArray() {
return isArr;
}
public int getArrayDepth() {
return arrayDim;
}
public Class getArrayType() {
return arrayType;
}
public Class[] getPossibleClasses() {
return possibleClasses;
}
void setPossibleClasses(Class[] possibleClasses) {
this.possibleClasses = possibleClasses;
}
public Field getField() {
return field;
}
public void calcIntegral() {
if (field == null) {
return;
}
if (isArray()) {
integral = isIntegral(getArrayType());
} else {
integral = isIntegral(field.getType());
Class type = field.getType();
integralType = getIntegralCode(type);
}
}
public static int getIntegralCode(Class type) {
if (type == boolean.class) {
return BOOL;
} else if (type == byte.class) {
return BYTE;
} else if (type == char.class) {
return CHAR;
} else if (type == short.class) {
return SHORT;
} else if (type == int.class) {
return INT;
} else if (type == long.class) {
return LONG;
} else if (type == float.class) {
return FLOAT;
} else if (type == double.class) {
return DOUBLE;
}
return 0;
}
/**
* only set if is not an array, but a direct native field type
*
* @return
*/
public int getIntegralType() {
return integralType;
}
public boolean isIntegral(Class type) {
return type.isPrimitive();
}
/**
* @return wether this is primitive or an array of primitives
*/
public boolean isIntegral() {
return integral;
}
public String getDesc() {
return field != null ? "<" + field.getName() + " of " + field.getDeclaringClass().getSimpleName() + ">" : "";
}
public String toString() {
return getDesc();
}
public boolean isFlat() {
return flat;
}
public int getComponentStructSize() {
if (arrayType == boolean.class || arrayType == byte.class)
return 1;
if (arrayType == char.class || arrayType == short.class)
return 2;
if (arrayType == int.class || arrayType == float.class)
return 4;
if (arrayType == long.class || arrayType == double.class)
return 8;
return 0; // object => cannot decide
}
public int getStructSize() {
if (type == boolean.class || type == byte.class)
return 1;
if (type == char.class || type == short.class)
return 2;
if (type == int.class || type == float.class)
return 4;
if (type == long.class || type == double.class)
return 8;
if (isArray()) {
if (isIntegral())
return 8; // pointer+length
else // object array
return 16; // pointer+length+elemsiz+pointertype
}
return 4;
}
public boolean isPrimitive() {
return primitive;
}
public final int getByteValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getByte(obj, memOffset);
}
return field.getByte(obj);
}
public final int getCharValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getChar(obj, memOffset);
}
return field.getChar(obj);
}
public final int getShortValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getShort(obj, memOffset);
}
return field.getShort(obj);
}
public final int getIntValueUnsafe(Object obj) throws IllegalAccessException {
return FSTUtil.unFlaggedUnsafe.getInt(obj, memOffset);
}
public final long getLongValueUnsafe(Object obj) throws IllegalAccessException {
return FSTUtil.unFlaggedUnsafe.getLong(obj, memOffset);
}
public final boolean getBooleanValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getBoolean(obj, memOffset);
}
return field.getBoolean(obj);
}
/**
* Warning: crashes if not an object ref !
* use getField().get() for a safe version ..
*
* @param obj
* @return
* @throws IllegalAccessException
*/
public final Object getObjectValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getObject(obj, memOffset);
}
return field.get(obj);
}
public final float getFloatValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getFloat(obj, memOffset);
}
return field.getFloat(obj);
}
public final void setCharValue(Object newObj, char c) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putChar(newObj, memOffset, c);
return;
}
field.setChar(newObj, c);
}
public final void setShortValue(Object newObj, short i1) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putShort(newObj, memOffset, i1);
return;
}
field.setShort(newObj, i1);
}
public final void setObjectValue(Object target, Object value) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putObject(target, memOffset, value);
return;
}
field.set(target, value);
}
public final void setFloatValue(Object newObj, float l) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putFloat(newObj, memOffset, l);
return;
}
field.setFloat(newObj, l);
}
public final void setDoubleValue(Object newObj, double l) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putDouble(newObj, memOffset, l);
return;
}
field.setDouble(newObj, l);
}
public final void setLongValue(Object newObj, long i1) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putLong(newObj, memOffset, i1);
return;
}
field.setLong(newObj, i1);
}
public final long getLongValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getLong(obj, memOffset);
}
return field.getLong(obj);
}
public final double getDoubleValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getDouble(obj, memOffset);
}
return field.getDouble(obj);
}
public final void setIntValue(Object newObj, int i1) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putInt(newObj, memOffset, i1);
return;
}
field.setInt(newObj, i1);
}
public final int getIntValue(Object obj) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
return FSTUtil.unFlaggedUnsafe.getInt(obj, memOffset);
}
return field.getInt(obj);
}
public final void setBooleanValue(Object newObj, boolean i1) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putBoolean(newObj, memOffset, i1);
return;
}
field.setBoolean(newObj, i1);
}
public final void setByteValue(Object newObj, byte b) throws IllegalAccessException {
if (!isAndroid && memOffset >= 0) {
FSTUtil.unFlaggedUnsafe.putByte(newObj, memOffset, b);
return;
}
field.setByte(newObj, b);
}
public String getName() {
return field != null ? field.getName() : fakeName;
}
}
/**
* sideeffecting: if no ser is found, next lookup will return null immediate
* @return
*/
public FSTObjectSerializer getSer() {
if (ser == null) {
if (clazz == null) {
return null;
}
ser = getSerNoStore();
if (ser == null) {
ser = FSTSerializerRegistry.NULL;
}
}
if (ser == FSTSerializerRegistry.NULL) {
return null;
}
return ser;
}
// no sideffecting lookup
public FSTObjectSerializer getSerNoStore() {
return conf.getCLInfoRegistry().getSerializerRegistry().getSerializer(clazz);
}
static class FSTCompatibilityInfo {
Method writeMethod, readMethod;
ObjectStreamClass objectStreamClass;
List infos;
Class clazz;
FSTFieldInfo infoArr[];
public FSTCompatibilityInfo(List inf, Class c) {
readClazz(c);
infos = inf;
clazz = c;
}
public List getFields() {
return infos;
}
public FSTFieldInfo[] getFieldArray() {
if (infoArr == null) {
List fields = getFields();
final FSTFieldInfo[] fstFieldInfos = new FSTFieldInfo[fields.size()];
fields.toArray(fstFieldInfos);
Arrays.sort(fstFieldInfos, defFieldComparator);
infoArr = fstFieldInfos;
}
return infoArr;
}
public Class getClazz() {
return clazz;
}
public boolean needsCompatibleMode() {
return writeMethod != null || readMethod != null;
}
public void readClazz(Class c) {
writeMethod = FSTUtil.findPrivateMethod(c, "writeObject",
new Class>[]{ObjectOutputStream.class},
Void.TYPE);
readMethod = FSTUtil.findPrivateMethod(c, "readObject",
new Class>[]{ObjectInputStream.class},
Void.TYPE);
if (writeMethod != null) {
writeMethod.setAccessible(true);
}
if (readMethod != null) {
readMethod.setAccessible(true);
}
}
public Method getReadMethod() {
return readMethod;
}
public void setReadMethod(Method readMethod) {
this.readMethod = readMethod;
}
public Method getWriteMethod() {
return writeMethod;
}
public void setWriteMethod(Method writeMethod) {
this.writeMethod = writeMethod;
}
public boolean isAsymmetric() {
return (getReadMethod() == null && getWriteMethod() != null) || (getWriteMethod() == null && getReadMethod() != null);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy