-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.panda_lang.utilities.inject; | ||
|
||
import java.util.Map; | ||
|
||
final class CodegenCache { | ||
|
||
private CodegenCache() { } | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* Copyright (c) 2020 Dzikoysk | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.panda_lang.utilities.inject; | ||
|
||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Modifier; | ||
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 panda.utilities.ObjectUtils; | ||
|
||
final class CodegenConstructorInjector<T> implements ConstructorInjector<T> { | ||
|
||
private static final Object[] EMPTY = new Object[0]; | ||
Check warning on line 34 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L34
|
||
|
||
private static final AtomicInteger ID = new AtomicInteger(); | ||
Check warning on line 36 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L36
|
||
|
||
private final InjectorProcessor processor; | ||
private final Constructor<T> constructor; | ||
private final boolean empty; | ||
private final InjectorCache cache; | ||
|
||
private final Function<Object[], Object> generated; | ||
|
||
CodegenConstructorInjector(InjectorProcessor processor, Constructor<T> constructor) throws Exception { | ||
this.processor = processor; | ||
this.constructor = constructor; | ||
Check warning on line 47 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L45-L47
|
||
this.empty = constructor.getParameterCount() == 0; | ||
this.cache = InjectorCache.of(processor, constructor); | ||
Check warning on line 49 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L49
|
||
|
||
this.generated = generate(constructor); | ||
} | ||
Check warning on line 52 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L51-L52
|
||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public T newInstance(Object... injectorArgs) throws Exception { | ||
return (T) this.generated.apply( | ||
Check warning on line 57 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L57
|
||
this.empty | ||
? EMPTY | ||
: this.processor.fetchValues(this.cache, injectorArgs) | ||
Check warning on line 60 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L59-L60
|
||
); | ||
} | ||
|
||
private static Function<Object[], Object> generate(Constructor<?> constructor) throws Exception { | ||
Class<?> declaringClass = constructor.getDeclaringClass(); | ||
Check warning on line 65 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L65
|
||
if (!Modifier.isPublic(declaringClass.getModifiers())) { | ||
throw new IllegalStateException(declaringClass + " has to be public"); | ||
Check warning on line 67 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L67
|
||
} | ||
|
||
if (!Modifier.isPublic(constructor.getModifiers())) { | ||
throw new IllegalStateException(constructor + " has to be public"); | ||
Check warning on line 71 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L71
|
||
} | ||
|
||
ByteBuddy byteBuddy = new ByteBuddy(); | ||
DynamicType.Unloaded<?> classPackage = byteBuddy | ||
.makePackage(declaringClass.getPackage().getName()) | ||
.make(); | ||
Check warning on line 77 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L74-L77
|
||
|
||
Class<?> loaded = byteBuddy.subclass(Object.class) | ||
.implement(GeneratedFunction.class) | ||
.name(declaringClass.getName() + "$" + constructor.getName() + "$" + ID.incrementAndGet()) | ||
.method(ElementMatchers.named("apply")) | ||
.intercept(MethodCall.invoke(constructor) | ||
.onArgument(0) | ||
.withArgumentArrayElements(1) | ||
.withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)) | ||
.make() | ||
.include(classPackage) | ||
.load(declaringClass.getClassLoader()) | ||
.getLoaded(); | ||
Check warning on line 90 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L79-L90
|
||
|
||
return ObjectUtils.cast(loaded.getDeclaredConstructor().newInstance()); | ||
Check warning on line 92 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L92
|
||
} | ||
|
||
@Override | ||
public Constructor<T> getConstructor() { | ||
return this.constructor; | ||
Check warning on line 97 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenConstructorInjector.java#L97
|
||
} | ||
|
||
@FunctionalInterface | ||
public interface GeneratedFunction extends Function<Object[], Object> { | ||
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package org.panda_lang.utilities.inject; | ||
|
||
import java.io.File; | ||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Modifier; | ||
import java.lang.reflect.Type; | ||
import java.util.Arrays; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import java.util.function.BiConsumer; | ||
import net.bytebuddy.ByteBuddy; | ||
import net.bytebuddy.dynamic.DynamicType; | ||
import net.bytebuddy.implementation.FieldAccessor; | ||
import net.bytebuddy.implementation.MethodDelegation; | ||
import net.bytebuddy.implementation.bind.annotation.AllArguments; | ||
import net.bytebuddy.matcher.ElementMatchers; | ||
import panda.utilities.ArrayUtils; | ||
|
||
public class CodegenFieldsInjector<T> implements FieldsInjector<T> { | ||
|
||
private static final AtomicInteger ID = new AtomicInteger(); | ||
|
||
private final InjectorProcessor processor; | ||
private final ConstructorInjector<T> constructorInjector; | ||
private final Class<?> declaringClass; | ||
|
||
private final BiConsumer<Object, Object[]> generated; | ||
|
||
CodegenFieldsInjector(InjectorProcessor processor, ConstructorInjector<T> constructorInjector) throws Exception { | ||
this.processor = processor; | ||
this.constructorInjector = constructorInjector; | ||
this.declaringClass = constructorInjector.getConstructor().getDeclaringClass(); | ||
Check warning on line 32 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L29-L32
|
||
|
||
this.generated = generate(this.declaringClass); | ||
} | ||
Check warning on line 35 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L34-L35
|
||
|
||
@Override | ||
public T newInstance(Object... injectorArgs) throws Exception { | ||
T instance = this.constructorInjector.newInstance(injectorArgs); | ||
|
||
Field[] fields = ClassCache.getInjectorFields(this.declaringClass); | ||
Object[] values = new Object[fields.length]; | ||
Check warning on line 42 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L41-L42
|
||
for (int i = 0; i < fields.length; i++) { | ||
values[i] = this.processor.fetchValue(new PropertyField(fields[i]), injectorArgs); | ||
} | ||
this.generated.accept(instance, values); | ||
|
||
return instance; | ||
} | ||
|
||
@Override | ||
public Constructor<T> getConstructor() { | ||
return this.constructorInjector.getConstructor(); | ||
} | ||
|
||
private static BiConsumer<Object, Object[]> generate(Class<?> declaringClass) throws Exception { | ||
if (!Modifier.isPublic(declaringClass.getModifiers())) { | ||
throw new IllegalStateException(declaringClass + " has to be public"); | ||
} | ||
|
||
Field[] fields = ClassCache.getInjectorFields(declaringClass); | ||
for (Field field : fields) { | ||
int modifiers = field.getModifiers(); | ||
if (!Modifier.isPublic(modifiers)) { | ||
throw new IllegalStateException(field + " has to be public"); | ||
} else if (Modifier.isFinal(modifiers)) { | ||
throw new IllegalStateException(field + " cannot be final"); | ||
} | ||
} | ||
|
||
ByteBuddy byteBuddy = new ByteBuddy(); | ||
DynamicType.Unloaded<?> classPackage = byteBuddy | ||
.makePackage(declaringClass.getPackage().getName()) | ||
.make(); | ||
Check warning on line 74 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L71-L74
|
||
|
||
|
||
/*DynamicType.Builder.MethodDefinition.ExceptionDefinition<Object> init = byteBuddy.subclass(Object.class) | ||
.implement(GeneratedConsumer.class) | ||
.name(declaringClass.getName() + "$init$" + ID.incrementAndGet()) | ||
.method(ElementMatchers.named("accept")) | ||
.withoutCode() | ||
.defineMethod("init", void.class, Modifier.PUBLIC) | ||
.withParameters(ArrayUtils.merge(new Type[]{declaringClass}, Arrays.stream(fields).map(Field::getType).toArray(Class[]::new))) | ||
.intercept(FieldAccessor.ofField("instance").setsArgumentAt(0)); | ||
DynamicType.Unloaded<Object> unloaded = init | ||
.intercept(MethodDelegation.to(FieldAccessor.ofField("instance"))) | ||
.make();*/ | ||
|
||
return (instance, values) -> { | ||
|
||
}; | ||
} | ||
|
||
public static class Interceptor { | ||
|
||
private final Field[] fields; | ||
|
||
public Interceptor(Field[] fields) { | ||
this.fields = fields; | ||
} | ||
Check warning on line 101 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L99-L101
|
||
|
||
public void intercept(@AllArguments Object[] args) throws IllegalAccessException { | ||
Object instance = args[0]; | ||
Object[] values = Arrays.copyOfRange(args, 1, args.length); | ||
Check warning on line 105 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L104-L105
|
||
|
||
for (int i = 0; i < values.length; i++) { | ||
Field field = this.fields[i]; | ||
field.setAccessible(true); | ||
field.set(instance, values[i]); | ||
Check warning on line 110 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L108-L110
|
||
} | ||
|
||
} | ||
Check warning on line 113 in di-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java Codecov / codecov/patchdi-codegen/src/main/java/org/panda_lang/utilities/inject/CodegenFieldsInjector.java#L113
|
||
|
||
} | ||
|
||
@FunctionalInterface | ||
public interface GeneratedConsumer extends BiConsumer<Object, Object[]> { } | ||
|
||
} |