-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
176 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 111 additions & 1 deletion
112
di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenCache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,119 @@ | ||
package org.panda_lang.utilities.inject; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Modifier; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import java.util.function.BiFunction; | ||
import java.util.function.Function; | ||
import net.bytebuddy.ByteBuddy; | ||
import net.bytebuddy.dynamic.DynamicType; | ||
import net.bytebuddy.implementation.MethodCall; | ||
import net.bytebuddy.implementation.bytecode.assign.Assigner; | ||
import net.bytebuddy.matcher.ElementMatchers; | ||
import org.jetbrains.annotations.ApiStatus; | ||
import panda.utilities.ObjectUtils; | ||
|
||
@ApiStatus.Internal | ||
final class CodegenCache { | ||
|
||
private CodegenCache() { } | ||
private static final AtomicInteger CONSTRUCTORS_ID = new AtomicInteger(); | ||
private static final Map<Constructor<?>, Function<Object[], Object>> CONSTRUCTOR_INVOKERS = new ConcurrentHashMap<>(); | ||
|
||
private static final AtomicInteger METHODS_ID = new AtomicInteger(); | ||
private static final Map<Method, BiFunction<Object, Object[], Object>> METHOD_INVOKERS = new ConcurrentHashMap<>(); | ||
|
||
private CodegenCache() { | ||
} | ||
|
||
public static Function<Object[], Object> getConstructorInvoker(Constructor<?> constructor) { | ||
return CONSTRUCTOR_INVOKERS.computeIfAbsent(constructor, key -> { | ||
Class<?> declaringClass = constructor.getDeclaringClass(); | ||
if (!Modifier.isPublic(declaringClass.getModifiers())) { | ||
throw new IllegalStateException(declaringClass + " has to be public"); | ||
} | ||
|
||
if (!Modifier.isPublic(constructor.getModifiers())) { | ||
throw new IllegalStateException(constructor + " has to be public"); | ||
} | ||
|
||
ByteBuddy byteBuddy = new ByteBuddy(); | ||
DynamicType.Unloaded<?> classPackage = byteBuddy | ||
.makePackage(declaringClass.getPackage().getName()) | ||
.make(); | ||
|
||
Class<?> loaded = byteBuddy.subclass(Object.class) | ||
.implement(GeneratedFunction.class) | ||
.name(declaringClass.getName() + "$" + constructor.getName() + "$" + CONSTRUCTORS_ID.incrementAndGet()) | ||
.method(ElementMatchers.named("apply")) | ||
.intercept(MethodCall.construct(constructor) | ||
.withArgumentArrayElements(0) | ||
.withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)) | ||
.make() | ||
.include(classPackage) | ||
.load(declaringClass.getClassLoader()) | ||
.getLoaded(); | ||
|
||
try { | ||
return ObjectUtils.cast(loaded.getDeclaredConstructor().newInstance()); | ||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | | ||
NoSuchMethodException ex) { | ||
throw new DependencyInjectionException("Failed to generate codegen constructor invoker", ex); | ||
} | ||
}); | ||
} | ||
|
||
public static BiFunction<Object, Object[], Object> getMethodInvoker(Method method) { | ||
return METHOD_INVOKERS.computeIfAbsent(method, key -> { | ||
Class<?> declaringClass = method.getDeclaringClass(); | ||
if (!Modifier.isPublic(declaringClass.getModifiers())) { | ||
throw new IllegalStateException(declaringClass + " has to be public"); | ||
} | ||
|
||
if (!Modifier.isPublic(method.getModifiers())) { | ||
throw new IllegalStateException(method + " has to be public"); | ||
} | ||
|
||
ByteBuddy byteBuddy = new ByteBuddy(); | ||
DynamicType.Unloaded<?> classPackage = byteBuddy | ||
.makePackage(declaringClass.getPackage().getName()) | ||
.make(); | ||
|
||
Class<?> loaded = byteBuddy.subclass(Object.class) | ||
.implement(GeneratedBiFunction.class) | ||
.name(declaringClass.getName() + "$" + method.getName() + "$" + METHODS_ID.incrementAndGet()) | ||
.method(ElementMatchers.named("apply")) | ||
.intercept(MethodCall.invoke(method) | ||
.onArgument(0) | ||
.withArgumentArrayElements(1) | ||
.withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)) | ||
.make() | ||
.include(classPackage) | ||
.load(declaringClass.getClassLoader()) | ||
.getLoaded(); | ||
|
||
try { | ||
return ObjectUtils.cast(loaded.getDeclaredConstructor().newInstance()); | ||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | | ||
NoSuchMethodException ex) { | ||
throw new DependencyInjectionException("Failed to generate codegen method invoker", ex); | ||
} | ||
}); | ||
} | ||
|
||
@ApiStatus.Internal | ||
@FunctionalInterface | ||
public interface GeneratedFunction extends Function<Object[], Object> { | ||
|
||
} | ||
|
||
@ApiStatus.Internal | ||
@FunctionalInterface | ||
public interface GeneratedBiFunction extends BiFunction<Object, Object[], Object> { | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
...egen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjectorFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.panda_lang.utilities.inject; | ||
|
||
import java.lang.reflect.Constructor; | ||
|
||
public class CodegenConstructorInjectorFactory<T> implements ConstructorInjectorFactory<T> { | ||
|
||
@Override | ||
public ConstructorInjector<T> createConstructorInjector(InjectorProcessor processor, Constructor<T> constructor) { | ||
return new CodegenConstructorInjector<>(processor, constructor); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
...in/resources/META-INF/services/org.panda_lang.utilities.inject.ConstructorInjectorFactory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
org.panda_lang.utilities.inject.CodegenConstructorInjectorFactory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
di/src/main/java/org/panda_lang/utilities/inject/ConstructorInjectorFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.panda_lang.utilities.inject; | ||
|
||
import java.lang.reflect.Constructor; | ||
import org.jetbrains.annotations.ApiStatus; | ||
|
||
@ApiStatus.Internal | ||
interface ConstructorInjectorFactory<T> { | ||
|
||
ConstructorInjector<T> createConstructorInjector(InjectorProcessor processor, Constructor<T> constructor); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.