[construct, core, weaver-pojo] Replace simple class injections with more sophisticated construction
This commit is contained in:
@@ -3,7 +3,8 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":tweed5-construct"))
|
||||
api(project(":tweed5-core"))
|
||||
api(project(":tweed5-naming-format"))
|
||||
api(project(":tweed5-type-utils"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.entry;
|
||||
|
||||
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
|
||||
import de.siphalor.tweed5.core.api.entry.CollectionConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collection;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
@@ -15,26 +13,13 @@ import java.util.function.IntFunction;
|
||||
* A constructor taking the value {@link Class}
|
||||
* and a {@link java.util.function.IntFunction} that allows to instantiate the value class with a single capacity argument.
|
||||
*/
|
||||
public interface WeavableCollectionConfigEntry<E, T extends Collection<E>>
|
||||
extends CollectionConfigEntry<E, T> {
|
||||
static <E, T extends Collection<E>, C extends WeavableCollectionConfigEntry<E, T>> C instantiate(
|
||||
Class<C> weavableClass, Class<T> valueClass, IntFunction<T> constructor
|
||||
) throws PojoWeavingException {
|
||||
try {
|
||||
Constructor<C> weavableEntryConstructor = weavableClass.getConstructor(Class.class, IntFunction.class);
|
||||
return weavableEntryConstructor.newInstance(valueClass, constructor);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new PojoWeavingException(
|
||||
"Class " + weavableClass.getName() + " must have constructor with value class and value constructor",
|
||||
e
|
||||
);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new PojoWeavingException(
|
||||
"Failed to instantiate class for weavable collection entry " + weavableClass.getName(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
public interface WeavableCollectionConfigEntry<E, T extends Collection<E>> extends CollectionConfigEntry<E, T> {
|
||||
@SuppressWarnings("rawtypes")
|
||||
TweedConstructFactory<WeavableCollectionConfigEntry> FACTORY =
|
||||
TweedConstructFactory.builder(WeavableCollectionConfigEntry.class)
|
||||
.typedArg(Class.class) // value class
|
||||
.typedArg(IntFunction.class) // value class constructor with capacity
|
||||
.build();
|
||||
|
||||
void elementEntry(ConfigEntry<E> elementEntry);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,27 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.entry;
|
||||
|
||||
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
|
||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <br />
|
||||
* A constructor taking the value {@link Class} and a {@link MethodHandle} that allows to instantiate the value Class with no arguments.
|
||||
* A constructor taking the value {@link Class} and a {@link Supplier} that allows to instantiate the value Class with no arguments.
|
||||
*/
|
||||
public interface WeavableCompoundConfigEntry<T> extends CompoundConfigEntry<T> {
|
||||
static <T, C extends WeavableCompoundConfigEntry<T>> C instantiate(
|
||||
Class<C> weavableClass, Class<T> valueClass, MethodHandle constructorHandle
|
||||
) throws PojoWeavingException {
|
||||
try {
|
||||
Constructor<C> weavableEntryConstructor = weavableClass.getConstructor(Class.class, MethodHandle.class);
|
||||
return weavableEntryConstructor.newInstance(valueClass, constructorHandle);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new PojoWeavingException(
|
||||
"Class " + weavableClass.getName() + " must have constructor with value class and value constructor",
|
||||
e
|
||||
);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new PojoWeavingException(
|
||||
"Failed to instantiate class for weavable compound entry " + weavableClass.getName(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("rawtypes")
|
||||
TweedConstructFactory<WeavableCompoundConfigEntry> FACTORY =
|
||||
TweedConstructFactory.builder(WeavableCompoundConfigEntry.class)
|
||||
.typedArg(Class.class) // the value class
|
||||
.typedArg(Supplier.class) // constructor for the value class
|
||||
.build();
|
||||
|
||||
void registerSubEntry(SubEntry subEntry);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
|
||||
this.weavingConfigAccess = context.registerWeavingContextExtensionData(CollectionWeavingConfig.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
List<ActualType<?>> collectionTypeParams = valueType.getTypesOfSuperArguments(Collection.class);
|
||||
@@ -44,12 +45,11 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
|
||||
|
||||
IntFunction<Collection<Object>> constructor = getCollectionConstructor(valueType);
|
||||
|
||||
//noinspection unchecked,rawtypes
|
||||
WeavableCollectionConfigEntry configEntry = WeavableCollectionConfigEntry.instantiate(
|
||||
(Class) weavingConfig.collectionEntryClass(),
|
||||
(Class) valueType.declaredType(),
|
||||
constructor
|
||||
);
|
||||
WeavableCollectionConfigEntry configEntry = WeavableCollectionConfigEntry.FACTORY
|
||||
.construct(Objects.requireNonNull(weavingConfig.collectionEntryClass()))
|
||||
.typedArg(valueType.declaredType())
|
||||
.typedArg(IntFunction.class, constructor)
|
||||
.finish();
|
||||
|
||||
configEntry.elementEntry(context.weaveEntry(
|
||||
collectionTypeParams.get(0),
|
||||
@@ -62,7 +62,7 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
|
||||
|
||||
return configEntry;
|
||||
} catch (Exception e) {
|
||||
throw new PojoWeavingException("Exception occurred trying to weave collectoin for class " + valueType, e);
|
||||
throw new PojoWeavingException("Exception occurred trying to weave collection for class " + valueType, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A weaver that weaves classes with the {@link CompoundWeaving} annotation as compound entries.
|
||||
@@ -112,10 +113,17 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
PojoClassIntrospector classIntrospector,
|
||||
CompoundWeavingConfig weavingConfig
|
||||
) {
|
||||
MethodHandle valueConstructor = classIntrospector.noArgsConstructor();
|
||||
if (valueConstructor == null) {
|
||||
MethodHandle valueConstructorHandle = classIntrospector.noArgsConstructor();
|
||||
if (valueConstructorHandle == null) {
|
||||
throw new PojoWeavingException("Class " + classIntrospector.type().getName() + " must have public no args constructor");
|
||||
}
|
||||
Supplier<?> valueConstructor = () -> {
|
||||
try {
|
||||
return valueConstructorHandle.invoke();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
|
||||
//noinspection rawtypes
|
||||
Class<? extends WeavableCompoundConfigEntry> annotationEntryClass = weavingConfig.compoundEntryClass();
|
||||
@@ -125,11 +133,10 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
? annotationEntryClass
|
||||
: StaticPojoCompoundConfigEntry.class
|
||||
);
|
||||
return WeavableCompoundConfigEntry.instantiate(
|
||||
weavableEntryClass,
|
||||
(Class<C>) classIntrospector.type(),
|
||||
valueConstructor
|
||||
);
|
||||
return WeavableCompoundConfigEntry.FACTORY.construct(weavableEntryClass)
|
||||
.typedArg(classIntrospector.type())
|
||||
.typedArg(Supplier.class, valueConstructor)
|
||||
.finish();
|
||||
}
|
||||
|
||||
private boolean shouldIncludeCompoundPropertyInWeaving(PojoClassIntrospector.Property property) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public interface TweedPojoWeaver extends TweedPojoWeavingFunction {
|
||||
TweedConstructFactory<TweedPojoWeaver> FACTORY = TweedConstructFactory.builder(TweedPojoWeaver.class).build();
|
||||
|
||||
@ApiStatus.OverrideOnly
|
||||
void setup(SetupContext context);
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess;
|
||||
|
||||
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.WeavingContext;
|
||||
|
||||
public interface TweedPojoWeavingPostProcessor {
|
||||
TweedConstructFactory<TweedPojoWeavingPostProcessor> FACTORY =
|
||||
TweedConstructFactory.builder(TweedPojoWeavingPostProcessor.class).build();
|
||||
|
||||
void apply(ConfigEntry<?> configEntry, WeavingContext context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,17 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> implements WeavableCompoundConfigEntry<T> {
|
||||
private final MethodHandle noArgsConstructor;
|
||||
private final Supplier<T> noArgsConstructor;
|
||||
private final Map<String, SubEntry> subEntries = new LinkedHashMap<>();
|
||||
private final Map<String, ConfigEntry<?>> subConfigEntries = new LinkedHashMap<>();
|
||||
|
||||
public StaticPojoCompoundConfigEntry(@NotNull Class<T> valueClass, @NotNull MethodHandle noArgsConstructor) {
|
||||
public StaticPojoCompoundConfigEntry(@NotNull Class<T> valueClass, @NotNull Supplier<T> noArgsConstructor) {
|
||||
super(valueClass);
|
||||
this.noArgsConstructor = noArgsConstructor;
|
||||
}
|
||||
@@ -66,8 +66,7 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
|
||||
@Override
|
||||
public T instantiateCompoundValue() {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return (T) noArgsConstructor.invoke();
|
||||
return noArgsConstructor.get();
|
||||
} catch (Throwable e) {
|
||||
throw new IllegalStateException("Failed to instantiate compound class", e);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -63,19 +61,19 @@ public class TweedPojoWeaverBootstrapper<T> {
|
||||
|
||||
private static Collection<TweedPojoWeaver> loadWeavers(Collection<Class<? extends TweedPojoWeaver>> weaverClasses) {
|
||||
return weaverClasses.stream()
|
||||
.map(weaverClass -> checkImplementsAndInstantiate(TweedPojoWeaver.class, weaverClass))
|
||||
.map(weaverClass -> TweedPojoWeaver.FACTORY.construct(weaverClass).finish())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Collection<TweedPojoWeavingPostProcessor> loadPostProcessors(Collection<Class<? extends TweedPojoWeavingPostProcessor>> postProcessorClasses) {
|
||||
return postProcessorClasses.stream()
|
||||
.map(postProcessorClass -> checkImplementsAndInstantiate(TweedPojoWeavingPostProcessor.class, postProcessorClass))
|
||||
.map(postProcessorClass -> TweedPojoWeavingPostProcessor.FACTORY.construct(postProcessorClass).finish())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static ConfigContainer<?> createConfigContainer(Class<? extends ConfigContainer<?>> containerClass) {
|
||||
try {
|
||||
return checkImplementsAndInstantiate(ConfigContainer.class, containerClass);
|
||||
return ConfigContainer.FACTORY.construct(containerClass).finish();
|
||||
} catch (Exception e) {
|
||||
throw new PojoWeavingException("Failed to instantiate config container");
|
||||
}
|
||||
@@ -144,23 +142,6 @@ public class TweedPojoWeaverBootstrapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T checkImplementsAndInstantiate(Class<T> superClass, Class<? extends T> clazz) {
|
||||
if (!superClass.isAssignableFrom(clazz)) {
|
||||
throw new PojoWeavingException("Class " + clazz.getName() + " must extend/implement " + superClass.getName());
|
||||
}
|
||||
return instantiate(clazz);
|
||||
}
|
||||
|
||||
private static <T> T instantiate(Class<T> clazz) {
|
||||
try {
|
||||
Constructor<T> constructor = clazz.getConstructor();
|
||||
return constructor.newInstance();
|
||||
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
|
||||
IllegalAccessException e) {
|
||||
throw new PojoWeavingException("Failed to instantiate class " + clazz.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigContainer<T> weave() {
|
||||
setupWeavers();
|
||||
WeavingContext weavingContext = createWeavingContext();
|
||||
|
||||
@@ -121,4 +121,4 @@ class CompoundPojoWeaverTest {
|
||||
return weavingConfig.compoundEntryClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user