From d5954e1a511e4aa139548abf33c51d27e016f8c4 Mon Sep 17 00:00:00 2001 From: Jan Vales Date: Wed, 9 May 2018 04:51:05 +0200 Subject: [PATCH] [2.2.2] Transparent DI works. --- .../ass2/di/InjectionControllerFactory.java | 12 +++--- .../java/dst/ass2/di/agent/InjectorAgent.java | 43 ++++++++++++++++--- .../ass2/di/impl/InjectionControllerImpl.java | 18 ++++++-- 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java b/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java index f20b258..ca11b33 100644 --- a/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java +++ b/ass2-di/src/main/java/dst/ass2/di/InjectionControllerFactory.java @@ -7,6 +7,7 @@ import dst.ass2.di.impl.InjectionControllerImpl; */ public class InjectionControllerFactory { private static IInjectionController standalone = null; + private static IInjectionController transparent = null; /** * Returns the singleton {@link IInjectionController} instance.
@@ -29,8 +30,10 @@ public class InjectionControllerFactory { * @return the instance */ public static synchronized IInjectionController getTransparentInstance() { - // TODO - return null; + if (transparent == null) { + transparent = getNewTransparentInstance(); + } + return transparent; } /** @@ -39,7 +42,7 @@ public class InjectionControllerFactory { * @return the newly created instance */ public static IInjectionController getNewStandaloneInstance() { - return new InjectionControllerImpl(); + return new InjectionControllerImpl(false); } /** @@ -49,7 +52,6 @@ public class InjectionControllerFactory { * @return the instance */ public static IInjectionController getNewTransparentInstance() { - // TODO - return null; + return new InjectionControllerImpl(true); } } diff --git a/ass2-di/src/main/java/dst/ass2/di/agent/InjectorAgent.java b/ass2-di/src/main/java/dst/ass2/di/agent/InjectorAgent.java index d0b5298..e311a10 100644 --- a/ass2-di/src/main/java/dst/ass2/di/agent/InjectorAgent.java +++ b/ass2-di/src/main/java/dst/ass2/di/agent/InjectorAgent.java @@ -1,18 +1,51 @@ package dst.ass2.di.agent; +import dst.ass2.di.annotation.Component; +import javassist.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; import java.security.ProtectionDomain; public class InjectorAgent implements ClassFileTransformer { + public static void premain(String args, Instrumentation instrumentation) { + instrumentation.addTransformer(new InjectorAgent()); + } @Override public byte[] transform(ClassLoader loader, String className, - Class classBeingRedefined, ProtectionDomain protectionDomain, - byte[] classfileBuffer) throws IllegalClassFormatException { + Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) throws IllegalClassFormatException { + + ClassPool classPool = new ClassPool(); + classPool.appendClassPath(new LoaderClassPath(loader)); + try { + CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer)); - // TODO - return classfileBuffer; - } + // only @Components may continue. + if (!ctClass.hasAnnotation(Component.class)) { + return classfileBuffer; + } + + // insert our code into constructors + for (CtConstructor ctor : ctClass.getConstructors()) { + try { + ctor.insertAfter("dst.ass2.di.InjectionControllerFactory.getTransparentInstance().initialize(this);"); + } catch (CannotCompileException e) { + e.printStackTrace(); + return classfileBuffer; + } + } + + // output new bytecode. + return ctClass.toBytecode(); + } catch (IOException | CannotCompileException e) { + e.printStackTrace(); + return classfileBuffer; + } + } } diff --git a/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java b/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java index 18a2072..29fc287 100644 --- a/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java +++ b/ass2-di/src/main/java/dst/ass2/di/impl/InjectionControllerImpl.java @@ -16,7 +16,11 @@ import java.util.concurrent.atomic.AtomicLong; public class InjectionControllerImpl implements IInjectionController { private final Map, Object> singletons = new ConcurrentHashMap<>(); private final AtomicLong ids = new AtomicLong(0L); + private final boolean isTransparent; + public InjectionControllerImpl(boolean b) { + isTransparent = b; + } private void initializeClass(Object obj, Class clazz, Long id) throws IllegalAccessException { if (clazz == null || !clazz.isAnnotationPresent(Component.class)) { @@ -64,7 +68,10 @@ public class InjectionControllerImpl implements IInjectionController { } catch (InstantiationException e) { e.printStackTrace(); } - initialize(fieldObject); + // only do this in standalone mode. + if (!isTransparent) { + initialize(fieldObject); + } } boolean accessible = f.isAccessible(); @@ -84,7 +91,8 @@ public class InjectionControllerImpl implements IInjectionController { throw new InjectionException(clazz + " has no @ComponentID"); } - initializeClass(obj, clazz.getSuperclass(), id); + // only do this in standalone mode. + if (!isTransparent) initializeClass(obj, clazz.getSuperclass(), id); } @@ -125,7 +133,11 @@ public class InjectionControllerImpl implements IInjectionController { } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } - initialize(single); + + // only do this in standalone mode. + if (!isTransparent) { + initialize(single); + } } return single; } -- 2.43.0