summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java
diff options
context:
space:
mode:
authorBrian S. O'Neill <bronee@gmail.com>2008-07-20 22:24:30 +0000
committerBrian S. O'Neill <bronee@gmail.com>2008-07-20 22:24:30 +0000
commit005101b7b1e7579b899c8a379f4516309e164c09 (patch)
treef5b1e9e51faa95d6957f05c3ba6dc6daa9fa02d2 /src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java
parent1b2638b5df6d11eef4d3a9bb81e7dd4307db0612 (diff)
Added normalization option for BigDecimal properties.
Diffstat (limited to 'src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java')
-rw-r--r--src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java128
1 files changed, 81 insertions, 47 deletions
diff --git a/src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java b/src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java
index c5417c4..e7a8ff9 100644
--- a/src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java
+++ b/src/main/java/com/amazon/carbonado/raw/GenericEncodingStrategy.java
@@ -25,6 +25,7 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.EnumSet;
import java.util.List;
import java.util.Map;
@@ -68,6 +69,26 @@ import com.amazon.carbonado.info.StorablePropertyAdapter;
* @author Brian S O'Neill
*/
public class GenericEncodingStrategy<S extends Storable> {
+ /**
+ * Defines extra encoding options.
+ *
+ * @since 1.2
+ */
+ public static enum Option {
+ /**
+ * Access properties by public methods instead of protected fields.
+ * Option should be used if class being generated doesn't have access
+ * to these fields.
+ */
+ USE_METHODS,
+
+ /**
+ * Property values such as BigDecimal are normalized before being
+ * encoded.
+ */
+ NORMALIZE,
+ }
+
private static enum Mode { KEY, DATA, SERIAL }
private final Class<S> mType;
@@ -144,9 +165,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* of a Storable instance.
* @param adapterInstanceClass class containing static references to
* adapter instances - defaults to instanceVar
- * @param useReadMethods when true, access properties by public read
- * methods instead of protected fields - should be used if class being
- * generated doesn't have access to these fields
+ * @param options optional encoding options
* @param partialStartVar optional variable for supporting partial key
* generation. It must be an int, whose runtime value must be less than the
* properties array length. It marks the range start of the partial
@@ -167,7 +186,7 @@ public class GenericEncodingStrategy<S extends Storable> {
OrderedProperty<S>[] properties,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
- boolean useReadMethods,
+ EnumSet<Option> options,
LocalVariable partialStartVar,
LocalVariable partialEndVar)
throws SupportException
@@ -176,7 +195,7 @@ public class GenericEncodingStrategy<S extends Storable> {
return buildEncoding(Mode.KEY, assembler,
extractProperties(properties), extractDirections(properties),
instanceVar, adapterInstanceClass,
- useReadMethods,
+ options,
-1, // no generation support
partialStartVar, partialEndVar);
}
@@ -194,9 +213,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* of a Storable instance.
* @param adapterInstanceClass class containing static references to
* adapter instances - defaults to instanceVar
- * @param useWriteMethods when true, set properties by public write
- * methods instead of protected fields - should be used if class being
- * generated doesn't have access to these fields
+ * @param options optional encoding options
* @param encodedVar required variable, which must be a byte array. At
* runtime, it references an encoded key.
*
@@ -208,14 +225,14 @@ public class GenericEncodingStrategy<S extends Storable> {
OrderedProperty<S>[] properties,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
- boolean useWriteMethods,
+ EnumSet<Option> options,
LocalVariable encodedVar)
throws SupportException
{
properties = ensureKeyProperties(properties);
buildDecoding(Mode.KEY, assembler,
extractProperties(properties), extractDirections(properties),
- instanceVar, adapterInstanceClass, useWriteMethods,
+ instanceVar, adapterInstanceClass, options,
-1, null, // no generation support
encodedVar);
}
@@ -235,8 +252,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* of a Storable instance.
* @param adapterInstanceClass class containing static references to
* adapter instances - defaults to instanceVar
- * @param useReadMethods when true, access properties by public read
- * methods instead of protected fields
+ * @param options optional encoding options
* @param generation when non-negative, write a storable layout generation
* value in one or four bytes. Generation 0..127 is encoded in one byte, and
* 128..max is encoded in four bytes, with the most significant bit set.
@@ -251,7 +267,7 @@ public class GenericEncodingStrategy<S extends Storable> {
StorableProperty<S>[] properties,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
- boolean useReadMethods,
+ EnumSet<Option> options,
int generation)
throws SupportException
{
@@ -259,7 +275,7 @@ public class GenericEncodingStrategy<S extends Storable> {
return buildEncoding(Mode.DATA, assembler,
properties, null,
instanceVar, adapterInstanceClass,
- useReadMethods, generation, null, null);
+ options, generation, null, null);
}
/**
@@ -275,9 +291,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* of a Storable instance.
* @param adapterInstanceClass class containing static references to
* adapter instances - defaults to instanceVar
- * @param useWriteMethods when true, set properties by public write
- * methods instead of protected fields - should be used if class being
- * generated doesn't have access to these fields
+ * @param options optional encoding options
* @param generation when non-negative, decoder expects a storable layout
* generation value to match this value. Otherwise, it throws a
* CorruptEncodingException.
@@ -297,7 +311,7 @@ public class GenericEncodingStrategy<S extends Storable> {
StorableProperty<S>[] properties,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
- boolean useWriteMethods,
+ EnumSet<Option> options,
int generation,
Label altGenerationHandler,
LocalVariable encodedVar)
@@ -305,7 +319,7 @@ public class GenericEncodingStrategy<S extends Storable> {
{
properties = ensureDataProperties(properties);
buildDecoding(Mode.DATA, assembler, properties, null,
- instanceVar, adapterInstanceClass, useWriteMethods,
+ instanceVar, adapterInstanceClass, options,
generation, altGenerationHandler, encodedVar);
}
@@ -316,17 +330,19 @@ public class GenericEncodingStrategy<S extends Storable> {
* @param assembler code assembler to receive bytecode instructions
* @param properties specific properties to decode, defaults to all
* properties if null
+ * @param options optional encoding options
* @return local variable referencing a byte array with encoded data
* @throws SupportException if any property type is not supported
* @since 1.2
*/
public LocalVariable buildSerialEncoding(CodeAssembler assembler,
- StorableProperty<S>[] properties)
+ StorableProperty<S>[] properties,
+ EnumSet<Option> options)
throws SupportException
{
properties = ensureAllProperties(properties);
return buildEncoding
- (Mode.SERIAL, assembler, properties, null, null, null, false, -1, null, null);
+ (Mode.SERIAL, assembler, properties, null, null, null, options, -1, null, null);
}
/**
@@ -336,6 +352,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* @param assembler code assembler to receive bytecode instructions
* @param properties specific properties to decode, defaults to all
* properties if null
+ * @param options optional encoding options
* @param encodedVar required variable, which must be a byte array. At
* runtime, it references encoded data.
* @throws SupportException if any property type is not supported
@@ -344,12 +361,13 @@ public class GenericEncodingStrategy<S extends Storable> {
*/
public void buildSerialDecoding(CodeAssembler assembler,
StorableProperty<S>[] properties,
+ EnumSet<Option> options,
LocalVariable encodedVar)
throws SupportException
{
properties = ensureAllProperties(properties);
buildDecoding
- (Mode.SERIAL, assembler, properties, null, null, null, false, -1, null, encodedVar);
+ (Mode.SERIAL, assembler, properties, null, null, null, options, -1, null, encodedVar);
}
/**
@@ -618,7 +636,7 @@ public class GenericEncodingStrategy<S extends Storable> {
Direction[] directions,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
- boolean useReadMethods,
+ EnumSet<Option> options,
int generation,
LocalVariable partialStartVar,
LocalVariable partialEndVar)
@@ -697,7 +715,7 @@ public class GenericEncodingStrategy<S extends Storable> {
// property is optional, then a byte prefix is needed to
// identify a null reference.
- loadPropertyValue(a, info, 0, useReadMethods,
+ loadPropertyValue(a, info, 0, options,
instanceVar, adapterInstanceClass, partialStartVar);
boolean descending = mode == Mode.KEY
@@ -785,7 +803,10 @@ public class GenericEncodingStrategy<S extends Storable> {
hasVariableLength = true;
}
- if (info.getPropertyType() == info.getStorageType()) {
+ if (info.getPropertyType() == info.getStorageType() &&
+ // BigDecimal is adapted in this method, to strip trailing zeros.
+ info.getPropertyType() != TypeDesc.forClass(BigDecimal.class))
+ {
// Property won't be adapted, so loading it twice is no big deal.
continue;
}
@@ -940,7 +961,7 @@ public class GenericEncodingStrategy<S extends Storable> {
} else {
// Load property to test for null.
loadPropertyValue(stashedProperties, stashedFromInstances,
- a, info, i, useReadMethods,
+ a, info, i, options,
instanceVar, adapterInstanceClass, partialStartVar);
Label isNull = a.createLabel();
@@ -972,7 +993,7 @@ public class GenericEncodingStrategy<S extends Storable> {
propType.toClass() == BigDecimal.class)
{
loadPropertyValue(stashedProperties, stashedFromInstances,
- a, info, i, useReadMethods,
+ a, info, i, options,
instanceVar, adapterInstanceClass, partialStartVar);
String methodName;
@@ -1158,7 +1179,7 @@ public class GenericEncodingStrategy<S extends Storable> {
boolean fromInstance = loadPropertyValue
(stashedProperties, stashedFromInstances,
- a, info, i, useReadMethods,
+ a, info, i, options,
instanceVar, adapterInstanceClass, partialStartVar);
TypeDesc propType = info.getStorageType();
@@ -1258,8 +1279,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* @param info info for property to load
* @param ordinal zero-based property ordinal, used only if instanceVar
* refers to an object array.
- * @param useReadMethod when true, access property by public read method
- * instead of protected field
+ * @param options optional encoding options
* @param instanceVar local variable referencing Storable instance,
* defaults to "this" if null. If variable type is an Object array, then
* property values are read from the runtime value of this array instead
@@ -1277,7 +1297,7 @@ public class GenericEncodingStrategy<S extends Storable> {
Boolean[] stashedFromInstances,
CodeAssembler a,
StorablePropertyInfo info, int ordinal,
- boolean useReadMethod,
+ EnumSet<Option> options,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
LocalVariable partialStartVar)
@@ -1288,7 +1308,7 @@ public class GenericEncodingStrategy<S extends Storable> {
}
boolean fromInstance = loadPropertyValue
- (a, info, ordinal, useReadMethod, instanceVar, adapterInstanceClass, partialStartVar);
+ (a, info, ordinal, options, instanceVar, adapterInstanceClass, partialStartVar);
if (stashedProperties != null) {
LocalVariable propVar = stashedProperties[ordinal];
@@ -1309,8 +1329,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* @param info info for property to load
* @param ordinal zero-based property ordinal, used only if instanceVar
* refers to an object array.
- * @param useReadMethod when true, access property by public read method
- * instead of protected field
+ * @param options optional encoding options
* @param instanceVar local variable referencing Storable instance,
* defaults to "this" if null. If variable type is an Object array, then
* property values are read from the runtime value of this array instead
@@ -1326,7 +1345,7 @@ public class GenericEncodingStrategy<S extends Storable> {
*/
protected boolean loadPropertyValue(CodeAssembler a,
StorablePropertyInfo info, int ordinal,
- boolean useReadMethod,
+ EnumSet<Option> options,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
LocalVariable partialStartVar)
@@ -1337,9 +1356,11 @@ public class GenericEncodingStrategy<S extends Storable> {
final boolean isObjectArrayInstanceVar = instanceVar != null
&& instanceVar.getType() == TypeDesc.forClass(Object[].class);
+ final boolean useMethod = options != null && options.contains(Option.USE_METHODS);
+
final boolean useAdapterInstance = adapterInstanceClass != null
&& info.getToStorageAdapter() != null
- && (useReadMethod || isObjectArrayInstanceVar);
+ && (useMethod || isObjectArrayInstanceVar);
if (useAdapterInstance) {
// Push adapter instance to stack to be used later.
@@ -1352,7 +1373,7 @@ public class GenericEncodingStrategy<S extends Storable> {
if (instanceVar == null) {
a.loadThis();
- if (useReadMethod) {
+ if (useMethod) {
info.addInvokeReadMethod(a);
} else {
// Access property value directly from protected field of "this".
@@ -1365,7 +1386,7 @@ public class GenericEncodingStrategy<S extends Storable> {
}
} else if (!isObjectArrayInstanceVar) {
a.loadLocal(instanceVar);
- if (useReadMethod) {
+ if (useMethod) {
info.addInvokeReadMethod(a, instanceVar.getType());
} else {
// Access property value directly from protected field of
@@ -1399,6 +1420,18 @@ public class GenericEncodingStrategy<S extends Storable> {
if (useAdapterInstance) {
// Invoke adapter method on instance pushed earlier.
a.invoke(info.getToStorageAdapter());
+ } else {
+ if (options != null && options.contains(Option.NORMALIZE)) {
+ TypeDesc bdType = TypeDesc.forClass(BigDecimal.class);
+ if (type == bdType) {
+ // Normalize by stripping trailing zeros.
+ a.dup();
+ Label isNull = a.createLabel();
+ a.ifNullBranch(isNull, true);
+ a.invokeVirtual(bdType, "stripTrailingZeros", bdType, null);
+ isNull.setLocation();
+ }
+ }
}
return !isObjectArrayInstanceVar;
@@ -1798,7 +1831,7 @@ public class GenericEncodingStrategy<S extends Storable> {
Direction[] directions,
LocalVariable instanceVar,
Class<?> adapterInstanceClass,
- boolean useWriteMethods,
+ EnumSet<Option> options,
int generation,
Label altGenerationHandler,
LocalVariable encodedVar)
@@ -1903,7 +1936,7 @@ public class GenericEncodingStrategy<S extends Storable> {
// Just store raw property value.
}
- storePropertyValue(a, info, useWriteMethods, instanceVar, adapterInstanceClass);
+ storePropertyValue(a, info, options, instanceVar, adapterInstanceClass);
return;
}
}
@@ -2117,7 +2150,7 @@ public class GenericEncodingStrategy<S extends Storable> {
storePropertyLocation.setLocation();
- storePropertyValue(a, info, useWriteMethods, instanceVar, adapterInstanceClass);
+ storePropertyValue(a, info, options, instanceVar, adapterInstanceClass);
nextPropertyLocation.setLocation();
}
@@ -2337,8 +2370,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* array must also be on the operand stack.
*
* @param info info for property to store to
- * @param useWriteMethod when true, set property by public write method
- * instead of protected field
+ * @param options optional encoding options
* @param instanceVar local variable referencing Storable instance,
* defaults to "this" if null. If variable type is an Object array, then
* property values are written to the runtime value of this array instead
@@ -2348,7 +2380,7 @@ public class GenericEncodingStrategy<S extends Storable> {
* @see #pushDecodingInstanceVar pushDecodingInstanceVar
*/
protected void storePropertyValue(CodeAssembler a, StorablePropertyInfo info,
- boolean useWriteMethod,
+ EnumSet<Option> options,
LocalVariable instanceVar,
Class<?> adapterInstanceClass) {
TypeDesc type = info.getPropertyType();
@@ -2357,9 +2389,11 @@ public class GenericEncodingStrategy<S extends Storable> {
boolean isObjectArrayInstanceVar = instanceVar != null
&& instanceVar.getType() == TypeDesc.forClass(Object[].class);
+ final boolean useMethod = options != null && options.contains(Option.USE_METHODS);
+
boolean useAdapterInstance = adapterInstanceClass != null
&& info.getToStorageAdapter() != null
- && (useWriteMethod || isObjectArrayInstanceVar);
+ && (useMethod || isObjectArrayInstanceVar);
if (useAdapterInstance) {
// Push adapter instance to adapt property value. It must be on the
@@ -2382,7 +2416,7 @@ public class GenericEncodingStrategy<S extends Storable> {
}
if (instanceVar == null) {
- if (useWriteMethod) {
+ if (useMethod) {
info.addInvokeWriteMethod(a);
} else {
// Set property value directly to protected field of instance.
@@ -2465,7 +2499,7 @@ public class GenericEncodingStrategy<S extends Storable> {
return;
}
- if (useWriteMethod) {
+ if (useMethod) {
info.addInvokeWriteMethod(a, instanceVarType);
} else {
// Set property value directly to protected field of referenced