Skip to content

Commit 4a47981

Browse files
committed
Introduce FieldSerializerConfig to encapsulate config in Kryo
The `Kryo` class is more and more used for "global" configuration of serializers like `FieldSerializer` etc (here's another PR: #365). The semantics of such settings and especially for which serializer it's applied can often only be clarified via documentation. This change introduces a `FieldSerializerConfig` class that encapsulates configuration for `FieldSerializer`. It allows to configure settings for all `FieldSerializer` instances created via `Kryo.getFieldSerializerConfig`. On each `FieldSerializer` the config can be changed/overridden, this is done directly on the serializer (instead e.g. requiring to invoke `fieldSerializer.getConfig.setSomeThing`) to stay binary compatible and because forcing to use the config here does not seem to be of much value. The `FieldSerializer` internally uses the config object so that any further settings are directly added to `FieldSerializerConfig` and there's only a single place to keep config settings. `Kryo.asmEnabled` might be used by different serializers, but because until now it was only used by `FieldSerializer` this setting is also kept in `FieldSerializerConfig`. `Kryo.set/getAsmEnabled` is marked as deprecated with a hint to use `getFieldSerializerConfig` instead - this is done to stay binary compatible. `Kryo.setCopyTransient` is removed because it was introduced after the latest release 3.0.3 and therefore not yet a published/released. Now `Kryo.getFieldSerializerConfig.setCopyTransient` has to be used. If this is considered to be merged then #365 should also follow this approach.
1 parent c10fd76 commit 4a47981

File tree

4 files changed

+163
-83
lines changed

4 files changed

+163
-83
lines changed

src/com/esotericsoftware/kryo/Kryo.java

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.TreeSet;
4646

4747
import com.esotericsoftware.kryo.serializers.DefaultSerializers.URLSerializer;
48+
import com.esotericsoftware.kryo.serializers.FieldSerializerConfig;
4849
import com.esotericsoftware.kryo.serializers.OptionalSerializers;
4950
import com.esotericsoftware.kryo.serializers.GenericsResolver;
5051
import com.esotericsoftware.kryo.serializers.TimeSerializers;
@@ -143,12 +144,11 @@ public class Kryo {
143144

144145
private int copyDepth;
145146
private boolean copyShallow;
146-
private boolean copyTransient = true;
147147
private IdentityMap originalToCopy;
148148
private Object needsCopyReference;
149149
private GenericsResolver genericsResolver = new GenericsResolver();
150-
/** Tells if ASM-based backend should be used by new serializer instances created using this Kryo instance. */
151-
private boolean asmEnabled = false;
150+
151+
private FieldSerializerConfig fieldSerializerConfig = new FieldSerializerConfig();
152152

153153
private StreamFactory streamFactory;
154154

@@ -1058,22 +1058,11 @@ public void setCopyReferences (boolean copyReferences) {
10581058
this.copyReferences = copyReferences;
10591059
}
10601060

1061-
/**
1062-
* If false, when {@link #copy(Object)} is called all transient fields that are accessible will be ignored from
1063-
* being copied. This has to be set before registering classes with kryo for it to be used by all field
1064-
* serializers. If transient fields has to be copied for specific classes then use {@link FieldSerializer#setCopyTransient(boolean)}.
1065-
* Default is true.
1066-
*/
1067-
public void setCopyTransient(boolean copyTransient) {
1068-
this.copyTransient = copyTransient;
1069-
}
1070-
1071-
/**
1072-
* Returns true if copying of transient fields is enabled for {@link #copy(Object)}.
1073-
* @return true if transient field copy is enable
1074-
*/
1075-
public boolean getCopyTransient() {
1076-
return copyTransient;
1061+
/** The default configuration for {@link FieldSerializer} instances. Already existing serializer instances (e.g.
1062+
* implicitely created for already registered classes) are not affected by this configuration. You can override
1063+
* the configuration for a single {@link FieldSerializer}. */
1064+
public FieldSerializerConfig getFieldSerializerConfig() {
1065+
return fieldSerializerConfig;
10771066
}
10781067

10791068
/** Sets the reference resolver and enables references. */
@@ -1209,13 +1198,18 @@ public void setStreamFactory (StreamFactory streamFactory) {
12091198
* </p>
12101199
*
12111200
* @param flag if true, ASM-based backend will be used. Otherwise Unsafe-based backend could be used by some serializers, e.g.
1212-
* FieldSerializer */
1201+
* FieldSerializer
1202+
*
1203+
* @deprecated Use {@link #getFieldSerializerConfig()} to change the default {@link FieldSerializer} configuration. */
1204+
@Deprecated
12131205
public void setAsmEnabled (boolean flag) {
1214-
this.asmEnabled = flag;
1206+
fieldSerializerConfig.setUseAsm(flag);
12151207
}
12161208

1209+
/** @deprecated Use {@link #getFieldSerializerConfig()} to change the default {@link FieldSerializer} configuration. */
1210+
@Deprecated
12171211
public boolean getAsmEnabled () {
1218-
return asmEnabled;
1212+
return fieldSerializerConfig.isUseAsm();
12191213
}
12201214

12211215
static public class DefaultInstantiatorStrategy implements org.objenesis.strategy.InstantiatorStrategy {

src/com/esotericsoftware/kryo/serializers/FieldSerializer.java

Lines changed: 22 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,17 @@
6464
* @author Nathan Sweet <[email protected]>
6565
* @author Roman Levenstein <[email protected]> */
6666
public class FieldSerializer<T> extends Serializer<T> implements Comparator<FieldSerializer.CachedField> {
67+
6768
final Kryo kryo;
6869
final Class type;
6970
/** type variables declared for this type */
7071
final TypeVariable[] typeParameters;
7172
final Class componentType;
73+
private final FieldSerializerConfig config;
7274
private CachedField[] fields = new CachedField[0];
7375
private CachedField[] transientFields = new CachedField[0];
7476
protected HashSet<CachedField> removedFields = new HashSet();
7577
Object access;
76-
private boolean fieldsCanBeNull = true, setFieldsAsAccessible = true;
77-
private boolean ignoreSyntheticFields = true;
78-
private boolean fixedFieldTypes;
79-
/** If set, ASM-backend is used. Otherwise Unsafe-based backend or reflection is used */
80-
private boolean useAsmEnabled;
8178
private FieldSerializerUnsafeUtil unsafeUtil;
8279

8380
private FieldSerializerGenericsUtil genericsUtil;
@@ -101,9 +98,6 @@ public class FieldSerializer<T> extends Serializer<T> implements Comparator<Fiel
10198
* </p> */
10299
private boolean useMemRegions = false;
103100

104-
/** If set, transient fields will be copied */
105-
private boolean copyTransient = true;
106-
107101
/** If set, transient fields will be serialized */
108102
private final boolean serializeTransient = false;
109103

@@ -130,29 +124,12 @@ public class FieldSerializer<T> extends Serializer<T> implements Comparator<Fiel
130124
}
131125

132126
{
133-
useAsmEnabled = !unsafeAvailable;
134127
varIntsEnabled = true;
135128
if (TRACE) trace("kryo", "Optimize ints: " + varIntsEnabled);
136129
}
137130

138131
public FieldSerializer (Kryo kryo, Class type) {
139-
this.kryo = kryo;
140-
this.type = type;
141-
this.typeParameters = type.getTypeParameters();
142-
if (this.typeParameters == null || this.typeParameters.length == 0)
143-
this.componentType = type.getComponentType();
144-
else
145-
this.componentType = null;
146-
this.useAsmEnabled = kryo.getAsmEnabled();
147-
if (!this.useAsmEnabled && !unsafeAvailable) {
148-
this.useAsmEnabled = true;
149-
if (TRACE) trace("kryo", "sun.misc.Unsafe is unavailable, using ASM.");
150-
}
151-
this.genericsUtil = new FieldSerializerGenericsUtil(this);
152-
this.unsafeUtil = FieldSerializerUnsafeUtil.Factory.getInstance(this);
153-
this.annotationsUtil = new FieldSerializerAnnotationsUtil(this);
154-
this.copyTransient = kryo.getCopyTransient();
155-
rebuildCachedFields();
132+
this(kryo, type, null);
156133
}
157134

158135
public FieldSerializer (Kryo kryo, Class type, Class[] generics) {
@@ -164,15 +141,10 @@ public FieldSerializer (Kryo kryo, Class type, Class[] generics) {
164141
this.componentType = type.getComponentType();
165142
else
166143
this.componentType = null;
167-
this.useAsmEnabled = kryo.getAsmEnabled();
168-
if (!this.useAsmEnabled && !unsafeAvailable) {
169-
this.useAsmEnabled = true;
170-
if (TRACE) trace("kryo", "sun.misc.Unsafe is unavailable, using ASM.");
171-
}
144+
this.config = kryo.getFieldSerializerConfig().clone();
172145
this.genericsUtil = new FieldSerializerGenericsUtil(this);
173146
this.unsafeUtil = FieldSerializerUnsafeUtil.Factory.getInstance(this);
174147
this.annotationsUtil = new FieldSerializerAnnotationsUtil(this);
175-
this.copyTransient = kryo.getCopyTransient();
176148
rebuildCachedFields();
177149
}
178150

@@ -226,7 +198,7 @@ protected void rebuildCachedFields (boolean minorRebuild) {
226198
ObjectMap context = kryo.getContext();
227199

228200
// Sort fields by their offsets
229-
if (useMemRegions && !useAsmEnabled && unsafeAvailable) {
201+
if (useMemRegions && !config.isUseAsm() && unsafeAvailable) {
230202
try {
231203
Field[] allFieldsArray = (Field[])sortFieldsByOffsetMethod.invoke(null, allFields);
232204
allFields = Arrays.asList(allFieldsArray);
@@ -242,7 +214,7 @@ protected void rebuildCachedFields (boolean minorRebuild) {
242214
validTransientFields = buildValidFields(true, allFields, context, useAsm);
243215

244216
// Use ReflectASM for any public fields.
245-
if (useAsmEnabled && !Util.isAndroid && Modifier.isPublic(type.getModifiers()) && useAsm.indexOf(1) != -1) {
217+
if (config.isUseAsm() && !Util.isAndroid && Modifier.isPublic(type.getModifiers()) && useAsm.indexOf(1) != -1) {
246218
try {
247219
access = FieldAccess.get(type);
248220
} catch (RuntimeException ignored) {
@@ -299,10 +271,10 @@ private List<Field> buildValidFields (boolean transientFields, List<Field> allFi
299271
int modifiers = field.getModifiers();
300272
if (Modifier.isTransient(modifiers) != transientFields) continue;
301273
if (Modifier.isStatic(modifiers)) continue;
302-
if (field.isSynthetic() && ignoreSyntheticFields) continue;
274+
if (field.isSynthetic() && config.isIgnoreSyntheticFields()) continue;
303275

304276
if (!field.isAccessible()) {
305-
if (!setFieldsAsAccessible) continue;
277+
if (!config.isSetFieldsAsAccessible()) continue;
306278
try {
307279
field.setAccessible(true);
308280
} catch (AccessControlException ex) {
@@ -324,7 +296,7 @@ private List<Field> buildValidFields (boolean transientFields, List<Field> allFi
324296

325297
private void createCachedFields (IntArray useAsm, List<Field> validFields, List<CachedField> cachedFields, int baseIndex) {
326298

327-
if (useAsmEnabled || !useMemRegions) {
299+
if (config.isUseAsm() || !useMemRegions) {
328300
for (int i = 0, n = validFields.size(); i < n; i++) {
329301
Field field = validFields.get(i);
330302
int accessIndex = -1;
@@ -376,16 +348,16 @@ CachedField newCachedField (Field field, int fieldIndex, int accessIndex) {
376348
cachedField.field = field;
377349
cachedField.varIntsEnabled = varIntsEnabled;
378350

379-
if (!useAsmEnabled) {
351+
if (!config.isUseAsm()) {
380352
cachedField.offset = unsafeUtil.getObjectFieldOffset(field);
381353
}
382354

383355
cachedField.access = (FieldAccess)access;
384356
cachedField.accessIndex = accessIndex;
385-
cachedField.canBeNull = fieldsCanBeNull && !fieldClass[0].isPrimitive() && !field.isAnnotationPresent(NotNull.class);
357+
cachedField.canBeNull = config.isFieldsCanBeNull() && !fieldClass[0].isPrimitive() && !field.isAnnotationPresent(NotNull.class);
386358

387359
// Always use the same serializer for this field if the field's class is final.
388-
if (kryo.isFinal(fieldClass[0]) || fixedFieldTypes) cachedField.valueClass = fieldClass[0];
360+
if (kryo.isFinal(fieldClass[0]) || config.isFixedFieldTypes()) cachedField.valueClass = fieldClass[0];
389361

390362
return cachedField;
391363
}
@@ -395,7 +367,7 @@ CachedField newMatchingCachedField (Field field, int accessIndex, Class fieldCla
395367
CachedField cachedField;
396368
if (accessIndex != -1) {
397369
cachedField = getAsmFieldFactory().createCachedField(fieldClass, field, this);
398-
} else if (!useAsmEnabled) {
370+
} else if (!config.isUseAsm()) {
399371
cachedField = getUnsafeFieldFactory().createCachedField(fieldClass, field, this);
400372
} else {
401373
cachedField = getObjectFieldFactory().createCachedField(fieldClass, field, this);
@@ -444,8 +416,7 @@ public int compare (CachedField o1, CachedField o2) {
444416
* cached fields}.
445417
* @param fieldsCanBeNull False if none of the fields are null. Saves 0-1 byte per field. True if it is not known (default). */
446418
public void setFieldsCanBeNull (boolean fieldsCanBeNull) {
447-
this.fieldsCanBeNull = fieldsCanBeNull;
448-
if (TRACE) trace("kryo", "setFieldsCanBeNull: " + fieldsCanBeNull);
419+
config.setFieldsCanBeNull(fieldsCanBeNull);
449420
rebuildCachedFields();
450421
}
451422

@@ -454,45 +425,36 @@ public void setFieldsCanBeNull (boolean fieldsCanBeNull) {
454425
* {@link Field#setAccessible(boolean) set as accessible} if necessary (default). If false, only fields in the public
455426
* API will be serialized. */
456427
public void setFieldsAsAccessible (boolean setFieldsAsAccessible) {
457-
this.setFieldsAsAccessible = setFieldsAsAccessible;
458-
if (TRACE) trace("kryo", "setFieldsAsAccessible: " + setFieldsAsAccessible);
428+
config.setFieldsAsAccessible(setFieldsAsAccessible);
459429
rebuildCachedFields();
460430
}
461431

462432
/** Controls if synthetic fields are serialized. Default is true. Calling this method resets the {@link #getFields() cached
463433
* fields}.
464434
* @param ignoreSyntheticFields If true, only non-synthetic fields will be serialized. */
465435
public void setIgnoreSyntheticFields (boolean ignoreSyntheticFields) {
466-
this.ignoreSyntheticFields = ignoreSyntheticFields;
467-
if (TRACE) trace("kryo", "setIgnoreSyntheticFields: " + ignoreSyntheticFields);
436+
config.setIgnoreSyntheticFields(ignoreSyntheticFields);
468437
rebuildCachedFields();
469438
}
470439

471440
/** Sets the default value for {@link CachedField#setClass(Class)} to the field's declared type. This allows FieldSerializer to
472441
* be more efficient, since it knows field values will not be a subclass of their declared type. Default is false. Calling this
473442
* method resets the {@link #getFields() cached fields}. */
474443
public void setFixedFieldTypes (boolean fixedFieldTypes) {
475-
this.fixedFieldTypes = fixedFieldTypes;
476-
if (TRACE) trace("kryo", "setFixedFieldTypes: " + fixedFieldTypes);
444+
config.setFixedFieldTypes(fixedFieldTypes);
477445
rebuildCachedFields();
478446
}
479447

480448
/** Controls whether ASM should be used. Calling this method resets the {@link #getFields() cached fields}.
481449
* @param setUseAsm If true, ASM will be used for fast serialization. If false, Unsafe will be used (default) */
482450
public void setUseAsm (boolean setUseAsm) {
483-
useAsmEnabled = setUseAsm;
484-
if (!useAsmEnabled && !unsafeAvailable) {
485-
useAsmEnabled = true;
486-
if (TRACE) trace("kryo", "sun.misc.Unsafe is unavailable, using ASM.");
487-
}
488-
// optimizeInts = useAsmBackend;
489-
if (TRACE) trace("kryo", "setUseAsm: " + setUseAsm);
451+
config.setUseAsm(setUseAsm);
490452
rebuildCachedFields();
491453
}
492454

493455
// Enable/disable copying of transient fields
494456
public void setCopyTransient (boolean setCopyTransient) {
495-
copyTransient = setCopyTransient;
457+
config.setCopyTransient(setCopyTransient);
496458
}
497459

498460
/** This method can be called for different fields having the same type. Even though the raw type is the same, if the type is
@@ -649,15 +611,15 @@ public Kryo getKryo () {
649611
}
650612

651613
public boolean getUseAsmEnabled () {
652-
return useAsmEnabled;
614+
return config.isUseAsm();
653615
}
654616

655617
public boolean getUseMemRegions () {
656618
return useMemRegions;
657619
}
658620

659621
public boolean getCopyTransient () {
660-
return copyTransient;
622+
return config.isCopyTransient();
661623
}
662624

663625
/** Used by {@link #copy(Kryo, Object)} to create the new object. This can be overridden to customize object creation, eg to
@@ -671,7 +633,7 @@ public T copy (Kryo kryo, T original) {
671633
kryo.reference(copy);
672634

673635
// Copy transient fields
674-
if (copyTransient) {
636+
if (config.isCopyTransient()) {
675637
for (int i = 0, n = transientFields.length; i < n; i++)
676638
transientFields[i].copy(original, copy);
677639
}

0 commit comments

Comments
 (0)