From 1f8ac314930f8b2cb13b9623a1e79706b1bc8d79 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Mon, 7 Apr 2008 00:57:48 +0000 Subject: Add prepare method to Storable. --- .../com/amazon/carbonado/gen/CodeBuilderUtil.java | 102 ++++++++++++++++++++- .../carbonado/gen/DelegateStorableGenerator.java | 2 + 2 files changed, 99 insertions(+), 5 deletions(-) (limited to 'src/main/java/com/amazon/carbonado/gen') diff --git a/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java b/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java index 1f01872..a99ea56 100644 --- a/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java +++ b/src/main/java/com/amazon/carbonado/gen/CodeBuilderUtil.java @@ -125,8 +125,8 @@ public class CodeBuilderUtil { } /** - * Add copy bridge methods for all classes/interfaces between the leaf (genericised class) - * and the root (genericised baseclass). + * Add copy bridge methods for all classes/interfaces between the leaf + * (genericised class) and the root (genericised baseclass). * * @param cf file to which to add the copy bridge * @param leaf leaf class @@ -140,9 +140,9 @@ public class CodeBuilderUtil { } /** - * Add a copy bridge method to the classfile for the given type. This is needed to allow - * the genericised class make a copy itself -- which will be erased to the base type -- and - * return it as the correct type. + * Add a copy bridge method to the classfile for the given type. This is + * needed to allow the genericised class make a copy itself -- which will + * be erased to the base type -- and return it as the correct type. * * @param cf file to which to add the copy bridge * @param leaf leaf class @@ -164,6 +164,98 @@ public class CodeBuilderUtil { b.returnValue(returnType); } + /** + * Defines a Storable prepare method, which assumes that a support field + * exists and a single-argument constructor exists which accepts a support + * instance. + * + * @param cf file to which to add the prepare method + * @since 1.2 + */ + public static void definePrepareMethod(ClassFile cf, + Class storableClass, + TypeDesc supportCtorType) + { + definePrepareMethod(cf, storableClass, supportCtorType, + StorableGenerator.SUPPORT_FIELD_NAME, + TypeDesc.forClass(TriggerSupport.class)); + } + + /** + * Defines a Storable prepare method, which assumes that a support field + * exists and a single-argument constructor exists which accepts a support + * instance. + * + * @param cf file to which to add the prepare method + * @since 1.2 + */ + public static void definePrepareMethod(ClassFile cf, + Class storableClass, + TypeDesc supportCtorType, + String supportFieldName, + TypeDesc supportFieldType) + { + TypeDesc storableType = TypeDesc.forClass(storableClass); + + if (!isPublicMethodFinal(storableClass, PREPARE_METHOD_NAME, storableType, null)) { + MethodInfo mi = cf.addMethod + (Modifiers.PUBLIC, PREPARE_METHOD_NAME, cf.getType(), null); + + CodeBuilder b = new CodeBuilder(mi); + b.newObject(cf.getType()); + b.dup(); + b.loadThis(); + b.loadField(supportFieldName, supportFieldType); + if (supportFieldType != supportCtorType) { + b.checkCast(supportCtorType); + } + b.invokeConstructor(new TypeDesc[] {supportCtorType}); + b.returnValue(cf.getType()); + } + + definePrepareBridges(cf, storableClass); + } + + /** + * Add prepare bridge methods for all classes/interfaces between the leaf + * (genericised class) and the root (genericised baseclass). + * + * @param cf file to which to add the prepare bridge + * @param leaf leaf class + * @since 1.2 + */ + public static void definePrepareBridges(ClassFile cf, Class leaf) { + for (Class c : gatherAllBridgeTypes(new HashSet(), leaf)) { + if (c != Object.class) { + definePrepareBridge(cf, leaf, c); + } + } + } + + /** + * Add a prepare bridge method to the classfile for the given type. + * + * @param cf file to which to add the prepare bridge + * @param leaf leaf class + * @param returnClass type returned from generated bridge method + * @since 1.2 + */ + private static void definePrepareBridge(ClassFile cf, Class leaf, Class returnClass) { + TypeDesc returnType = TypeDesc.forClass(returnClass); + + if (isPublicMethodFinal(leaf, PREPARE_METHOD_NAME, returnType, null)) { + // Cannot override. + return; + } + + MethodInfo mi = cf.addMethod(Modifiers.PUBLIC.toBridge(true), + PREPARE_METHOD_NAME, returnType, null); + CodeBuilder b = new CodeBuilder(mi); + b.loadThis(); + b.invokeVirtual(PREPARE_METHOD_NAME, cf.getType(), null); + b.returnValue(returnType); + } + /** * Returns true if a public final method exists which matches the given * specification. diff --git a/src/main/java/com/amazon/carbonado/gen/DelegateStorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/DelegateStorableGenerator.java index 4de28bd..38b612c 100644 --- a/src/main/java/com/amazon/carbonado/gen/DelegateStorableGenerator.java +++ b/src/main/java/com/amazon/carbonado/gen/DelegateStorableGenerator.java @@ -113,6 +113,8 @@ public class DelegateStorableGenerator { b.returnVoid(); } + CodeBuilderUtil.definePrepareMethod(mClassFile, mStorableType, delegateSupportType); + // Implement abstract methods which all delegate to DelegateSupport instance. generateDelegatedMethod -- cgit v1.2.3