From 7977fcd381e17c4e3bdfebfbf7ca4c0d90cdba1f Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sun, 10 Jun 2007 04:22:34 +0000 Subject: Added methods to access Storable properties by name. --- .../amazon/carbonado/gen/CommonMethodNames.java | 2 + .../amazon/carbonado/gen/StorableGenerator.java | 174 +++++++++++++++------ 2 files changed, 129 insertions(+), 47 deletions(-) (limited to 'src/main/java/com/amazon/carbonado/gen') diff --git a/src/main/java/com/amazon/carbonado/gen/CommonMethodNames.java b/src/main/java/com/amazon/carbonado/gen/CommonMethodNames.java index d9db47c..f0262ea 100644 --- a/src/main/java/com/amazon/carbonado/gen/CommonMethodNames.java +++ b/src/main/java/com/amazon/carbonado/gen/CommonMethodNames.java @@ -52,6 +52,8 @@ public class CommonMethodNames { IS_PROPERTY_DIRTY = "isPropertyDirty", IS_PROPERTY_CLEAN = "isPropertyClean", IS_PROPERTY_SUPPORTED = "isPropertySupported", + GET_PROPERTY_VALUE = "getPropertyValue", + SET_PROPERTY_VALUE = "setPropertyValue", TO_STRING_KEY_ONLY_METHOD_NAME = "toStringKeyOnly", TO_STRING_METHOD_NAME = "toString", HASHCODE_METHOD_NAME = "hashCode", diff --git a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java index 5f473cb..28dbd9e 100644 --- a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java +++ b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java @@ -189,6 +189,9 @@ public final class StorableGenerator { private static final String UPDATE_OP = "Update"; private static final String DELETE_OP = "Delete"; + // Different uses for generated property switch statements. + private static final int SWITCH_FOR_STATE = 1, SWITCH_FOR_GET = 2, SWITCH_FOR_SET = 3; + /** * Returns an abstract implementation of the given Storable type, which is * fully thread-safe. The Storable type itself may be an interface or a @@ -1863,6 +1866,10 @@ public final class StorableGenerator { b.returnValue(TypeDesc.BOOLEAN); } + // Define reflection-like method for manipulating property by name. + addGetPropertyValueMethod(); + addSetPropertyValueMethod(); + // Define standard object methods. addHashCodeMethod(); addEqualsMethod(EQUAL_FULL); @@ -2733,8 +2740,11 @@ public final class StorableGenerator { MethodInfo mi = mClassFile.addMethod(Modifiers.PRIVATE, PROPERTY_STATE_EXTRACT_METHOD_NAME, TypeDesc.INT, new TypeDesc[] {TypeDesc.STRING}); - CodeBuilder b = new CodeBuilder(mi); + + addPropertySwitch(new CodeBuilder(mi), SWITCH_FOR_STATE); + } + private void addPropertySwitch(CodeBuilder b, int switchFor) { // Generate big switch statement that operates on Strings. See also // org.cojen.util.BeanPropertyAccessor, which also generates this kind of // switch. @@ -2795,6 +2805,8 @@ public final class StorableGenerator { Label derivedMatch = null; Label joinMatch = null; + Label unreadable = null; + Label unwritable = null; for (int i=0; i> matches = caseMatches[i]; @@ -2824,29 +2836,59 @@ public final class StorableGenerator { b.ifZeroComparisonBranch(notEqual, "=="); } - if (prop.isDerived()) { - if (derivedMatch == null) { - derivedMatch = b.createLabel(); + if (switchFor == SWITCH_FOR_STATE) { + if (prop.isDerived()) { + if (derivedMatch == null) { + derivedMatch = b.createLabel(); + } + b.branch(derivedMatch); + } else if (prop.isJoin()) { + if (joinMatch == null) { + joinMatch = b.createLabel(); + } + b.branch(joinMatch); + } else { + int ordinal = ordinalMap.get(prop); + + b.loadThis(); + b.loadField(PROPERTY_STATE_FIELD_NAME + (ordinal >> 4), TypeDesc.INT); + int shift = (ordinal & 0xf) * 2; + if (shift != 0) { + b.loadConstant(shift); + b.math(Opcode.ISHR); + } + b.loadConstant(PROPERTY_STATE_MASK); + b.math(Opcode.IAND); + b.returnValue(TypeDesc.INT); } - b.branch(derivedMatch); - } else if (prop.isJoin()) { - if (joinMatch == null) { - joinMatch = b.createLabel(); + } else if (switchFor == SWITCH_FOR_GET) { + if (prop.getReadMethod() == null) { + if (unreadable == null) { + unreadable = b.createLabel(); + } + b.branch(unreadable); + } else { + b.loadThis(); + b.invoke(prop.getReadMethod()); + TypeDesc type = TypeDesc.forClass(prop.getType()); + b.convert(type, type.toObjectType()); + b.returnValue(TypeDesc.OBJECT); } - b.branch(joinMatch); - } else { - int ordinal = ordinalMap.get(prop); - - b.loadThis(); - b.loadField(PROPERTY_STATE_FIELD_NAME + (ordinal >> 4), TypeDesc.INT); - int shift = (ordinal & 0xf) * 2; - if (shift != 0) { - b.loadConstant(shift); - b.math(Opcode.ISHR); + } else if (switchFor == SWITCH_FOR_SET) { + if (prop.getWriteMethod() == null) { + if (unwritable == null) { + unwritable = b.createLabel(); + } + b.branch(unwritable); + } else { + b.loadThis(); + b.loadLocal(b.getParameter(1)); + TypeDesc type = TypeDesc.forClass(prop.getType()); + b.checkCast(type.toObjectType()); + b.convert(type.toObjectType(), type); + b.invoke(prop.getWriteMethod()); + b.returnVoid(); } - b.loadConstant(PROPERTY_STATE_MASK); - b.math(Opcode.IAND); - b.returnValue(TypeDesc.INT); } if (notEqual != null) { @@ -2855,42 +2897,44 @@ public final class StorableGenerator { } } - TypeDesc exceptionType = TypeDesc.forClass(IllegalArgumentException.class); - params = new TypeDesc[] {TypeDesc.STRING}; - noMatch.setLocation(); - - b.newObject(exceptionType); - b.dup(); - b.loadConstant("Unknown property: "); - b.loadLocal(b.getParameter(0)); - b.invokeVirtual(TypeDesc.STRING, "concat", TypeDesc.STRING, params); - b.invokeConstructor(exceptionType, params); - b.throwObject(); + throwIllegalArgException(b, "Unknown property: ", b.getParameter(0)); if (derivedMatch != null) { derivedMatch.setLocation(); - - b.newObject(exceptionType); - b.dup(); - b.loadConstant("Cannot get state for derived property: "); - b.loadLocal(b.getParameter(0)); - b.invokeVirtual(TypeDesc.STRING, "concat", TypeDesc.STRING, params); - b.invokeConstructor(exceptionType, params); - b.throwObject(); + throwIllegalArgException + (b, "Cannot get state for derived property: ", b.getParameter(0)); } if (joinMatch != null) { joinMatch.setLocation(); + throwIllegalArgException(b, "Cannot get state for join property: ", b.getParameter(0)); + } - b.newObject(exceptionType); - b.dup(); - b.loadConstant("Cannot get state for join property: "); - b.loadLocal(b.getParameter(0)); - b.invokeVirtual(TypeDesc.STRING, "concat", TypeDesc.STRING, params); - b.invokeConstructor(exceptionType, params); - b.throwObject(); + if (unreadable != null) { + unreadable.setLocation(); + throwIllegalArgException(b, "Property cannot be read: ", b.getParameter(0)); } + + if (unwritable != null) { + unwritable.setLocation(); + throwIllegalArgException(b, "Property cannot be written: ", b.getParameter(0)); + } + } + + private static void throwIllegalArgException(CodeBuilder b, String message, + LocalVariable concatStr) + { + TypeDesc exceptionType = TypeDesc.forClass(IllegalArgumentException.class); + TypeDesc[] params = {TypeDesc.STRING}; + + b.newObject(exceptionType); + b.dup(); + b.loadConstant(message); + b.loadLocal(concatStr); + b.invokeVirtual(TypeDesc.STRING, "concat", TypeDesc.STRING, params); + b.invokeConstructor(exceptionType, params); + b.throwObject(); } /** @@ -2955,6 +2999,42 @@ public final class StorableGenerator { b.returnValue(TypeDesc.BOOLEAN); } + private void addGetPropertyValueMethod() { + MethodInfo mi = addMethodIfNotFinal(Modifiers.PUBLIC, GET_PROPERTY_VALUE, + TypeDesc.OBJECT, new TypeDesc[] {TypeDesc.STRING}); + + if (mi == null) { + return; + } + + CodeBuilder b = new CodeBuilder(mi); + + if (mGenMode == GEN_WRAPPED) { + callWrappedStorable(mi, b); + return; + } + + addPropertySwitch(b, SWITCH_FOR_GET); + } + + private void addSetPropertyValueMethod() { + MethodInfo mi = addMethodIfNotFinal(Modifiers.PUBLIC, SET_PROPERTY_VALUE, null, + new TypeDesc[] {TypeDesc.STRING, TypeDesc.OBJECT}); + + if (mi == null) { + return; + } + + CodeBuilder b = new CodeBuilder(mi); + + if (mGenMode == GEN_WRAPPED) { + callWrappedStorable(mi, b); + return; + } + + addPropertySwitch(b, SWITCH_FOR_SET); + } + /** * Defines a hashCode method. */ -- cgit v1.2.3