Move common bridging code 97/81897/1
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 5 May 2019 17:52:19 +0000 (19:52 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sun, 5 May 2019 17:53:32 +0000 (19:53 +0200)
Since we'll want to be bridging from multiple class generators,
move the common bridging code into a common interface.

JIRA: MDSAL-443
Change-Id: I1aa7d70ae302d737bb960c06629da5ffe0123fc0
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ClassGeneratorBridge.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CodecDataObjectGenerator.java

index cc6dcca7d776abcf9c52b1e16af6581dc9def813..d5791d7534981b063cd9b970d180105d9ae89835 100644 (file)
@@ -10,8 +10,10 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 import static com.google.common.base.Verify.verifyNotNull;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Supplier;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader.ClassGenerator;
 
 /**
  * Bridge for initializing generated instance constants during class loading time. This class is public only due to
@@ -19,21 +21,45 @@ import org.eclipse.jdt.annotation.Nullable;
  */
 @Beta
 public final class ClassGeneratorBridge {
-    interface BridgeProvider {
-
+    interface BridgeProvider<T> extends ClassGenerator<T> {
+        @Override
+        default Class<T> customizeLoading(final @NonNull Supplier<Class<T>> loader) {
+            final BridgeProvider<?> prev = ClassGeneratorBridge.setup(this);
+            try {
+                final Class<T> result = loader.get();
+
+                /*
+                 * This a bit of magic to support NodeContextSupplier constants. These constants need to be resolved
+                 * while we have the information needed to find them -- that information is being held in this instance
+                 * and we leak it to a thread-local variable held by CodecDataObjectBridge.
+                 *
+                 * By default the JVM will defer class initialization to first use, which unfortunately is too late for
+                 * us, and hence we need to force class to initialize.
+                 */
+                try {
+                    Class.forName(result.getName(), true, result.getClassLoader());
+                } catch (ClassNotFoundException e) {
+                    throw new LinkageError("Failed to find newly-defined " + result, e);
+                }
+
+                return result;
+            } finally {
+                ClassGeneratorBridge.tearDown(prev);
+            }
+        }
     }
 
-    interface LocalNameProvider extends BridgeProvider {
+    interface LocalNameProvider<T> extends BridgeProvider<T> {
 
         @NonNull String resolveLocalName(@NonNull String methodName);
     }
 
-    interface NodeContextSupplierProvider extends BridgeProvider {
+    interface NodeContextSupplierProvider<T> extends BridgeProvider<T> {
 
         @NonNull NodeContextSupplier resolveNodeContextSupplier(@NonNull String methodName);
     }
 
-    private static final ThreadLocal<BridgeProvider> CURRENT_CUSTOMIZER = new ThreadLocal<>();
+    private static final ThreadLocal<BridgeProvider<?>> CURRENT_CUSTOMIZER = new ThreadLocal<>();
 
     private ClassGeneratorBridge() {
 
@@ -47,13 +73,13 @@ public final class ClassGeneratorBridge {
         return current(LocalNameProvider.class).resolveLocalName(methodName);
     }
 
-    static @Nullable BridgeProvider setup(final @NonNull BridgeProvider next) {
-        final BridgeProvider prev = CURRENT_CUSTOMIZER.get();
+    static @Nullable BridgeProvider<?> setup(final @NonNull BridgeProvider<?> next) {
+        final BridgeProvider<?> prev = CURRENT_CUSTOMIZER.get();
         CURRENT_CUSTOMIZER.set(verifyNotNull(next));
         return prev;
     }
 
-    static void tearDown(final @Nullable BridgeProvider prev) {
+    static void tearDown(final @Nullable BridgeProvider<?> prev) {
         if (prev == null) {
             CURRENT_CUSTOMIZER.remove();
         } else {
@@ -61,7 +87,7 @@ public final class ClassGeneratorBridge {
         }
     }
 
-    private static <T extends BridgeProvider> @NonNull T current(final Class<T> requested) {
+    private static <T extends BridgeProvider<?>> @NonNull T current(final Class<T> requested) {
         return requested.cast(verifyNotNull(CURRENT_CUSTOMIZER.get(), "No customizer attached"));
     }
 }
index fd62b1be79cae77504e8bef3cfcd2889e1da4bb7..a1e3c9d25adc25549e1be0af2bffb847adb7f40d 100644 (file)
@@ -16,7 +16,6 @@ import static org.opendaylight.mdsal.binding.dom.codec.impl.ByteBuddyUtils.invok
 import static org.opendaylight.mdsal.binding.dom.codec.impl.ByteBuddyUtils.putField;
 
 import com.google.common.base.MoreObjects.ToStringHelper;
-import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import java.lang.reflect.Method;
@@ -52,9 +51,7 @@ import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
 import net.bytebuddy.jar.asm.Label;
 import net.bytebuddy.jar.asm.MethodVisitor;
 import net.bytebuddy.jar.asm.Opcodes;
-import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.BridgeProvider;
 import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.LocalNameProvider;
 import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.NodeContextSupplierProvider;
 import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader;
@@ -157,10 +154,10 @@ import org.slf4j.LoggerFactory;
  * This strategy works due to close cooperation with the target ClassLoader, as the entire code generation and loading
  * block runs with the class loading lock for this FQCN and the reference is not leaked until the process completes.
  */
-abstract class CodecDataObjectGenerator<T extends CodecDataObject<?>> implements ClassGenerator<T>, BridgeProvider {
+abstract class CodecDataObjectGenerator<T extends CodecDataObject<?>> implements ClassGenerator<T> {
     // Not reusable defintion: we can inline NodeContextSuppliers without a problem
     private static final class Fixed<T extends CodecDataObject<?>> extends CodecDataObjectGenerator<T>
-            implements NodeContextSupplierProvider {
+            implements NodeContextSupplierProvider<T> {
         private final ImmutableMap<Method, NodeContextSupplier> properties;
 
         Fixed(final Builder<?> template, final ImmutableMap<Method, NodeContextSupplier> properties,
@@ -198,7 +195,7 @@ abstract class CodecDataObjectGenerator<T extends CodecDataObject<?>> implements
 
     // Reusable definition: we have to rely on context lookups
     private static final class Reusable<T extends CodecDataObject<?>> extends CodecDataObjectGenerator<T>
-            implements LocalNameProvider {
+            implements LocalNameProvider<T> {
         private final ImmutableMap<Method, ValueNodeCodecContext> simpleProperties;
         private final Map<Method, Class<?>> daoProperties;
 
@@ -341,32 +338,6 @@ abstract class CodecDataObjectGenerator<T extends CodecDataObject<?>> implements
                 .make());
     }
 
-    @Override
-    public Class<T> customizeLoading(final @NonNull Supplier<Class<T>> loader) {
-        final BridgeProvider prev = ClassGeneratorBridge.setup(this);
-        try {
-            final Class<T> result = loader.get();
-
-            /*
-             * This a bit of magic to support NodeContextSupplier constants. These constants need to be resolved
-             * while we have the information needed to find them -- that information is being held in this instance
-             * and we leak it to a thread-local variable held by CodecDataObjectBridge.
-             *
-             * By default the JVM will defer class initialization to first use, which unfortunately is too late for
-             * us, and hence we need to force class to initialize.
-             */
-            try {
-                Class.forName(result.getName(), true, result.getClassLoader());
-            } catch (ClassNotFoundException e) {
-                throw new LinkageError("Failed to find newly-defined " + result, e);
-            }
-
-            return result;
-        } finally {
-            ClassGeneratorBridge.tearDown(prev);
-        }
-    }
-
     abstract Builder<T> generateGetters(Builder<T> builder);
 
     abstract ArrayList<Method> getterMethods();