[type-utils, weaver-pojo] Introduce a submodule focused on Java types for POJO weaving
This commit is contained in:
@@ -5,4 +5,5 @@ plugins {
|
||||
dependencies {
|
||||
api(project(":tweed5-core"))
|
||||
api(project(":tweed5-naming-format"))
|
||||
api(project(":tweed5-type-utils"))
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import java.lang.annotation.Target;
|
||||
* Marks this class as a class that should be woven as a {@link de.siphalor.tweed5.core.api.entry.CompoundConfigEntry}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Target({ElementType.TYPE, ElementType.TYPE_USE})
|
||||
public @interface CompoundWeaving {
|
||||
/**
|
||||
* The naming format to use for this POJO.
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents multi-level annotations across multiple Java elements.
|
||||
* E.g. annotations on a field overriding annotations declared on the field type.
|
||||
*/
|
||||
public class Annotations {
|
||||
private static final List<ElementType> ELEMENT_TYPE_ORDER = Arrays.asList(
|
||||
ElementType.TYPE_USE,
|
||||
ElementType.FIELD,
|
||||
ElementType.CONSTRUCTOR,
|
||||
ElementType.METHOD,
|
||||
ElementType.LOCAL_VARIABLE,
|
||||
ElementType.TYPE_PARAMETER,
|
||||
ElementType.TYPE,
|
||||
ElementType.ANNOTATION_TYPE,
|
||||
ElementType.PACKAGE
|
||||
);
|
||||
private final Map<ElementType, AnnotatedElement> elements = new EnumMap<>(ElementType.class);
|
||||
|
||||
public void addAnnotationsFrom(ElementType elementType, AnnotatedElement element) {
|
||||
elements.put(elementType, element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
|
||||
for (ElementType elementType : ELEMENT_TYPE_ORDER) {
|
||||
AnnotatedElement annotatedElement = elements.get(elementType);
|
||||
if (annotatedElement != null) {
|
||||
T annotation = annotatedElement.getAnnotation(annotationClass);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends Annotation> T getAnnotation(ElementType elementType, Class<T> annotationType) {
|
||||
AnnotatedElement annotatedElement = elements.get(elementType);
|
||||
if (annotatedElement == null) {
|
||||
return null;
|
||||
}
|
||||
return annotatedElement.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends Annotation> T[] getAnnotationHierarchy(Class<T> annotationClass) {
|
||||
List<T> hierarchy = new ArrayList<>(elements.size());
|
||||
for (ElementType elementType : ELEMENT_TYPE_ORDER) {
|
||||
AnnotatedElement element = elements.get(elementType);
|
||||
if (element != null) {
|
||||
T annotation = element.getAnnotation(annotationClass);
|
||||
if (annotation != null) {
|
||||
hierarchy.add(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return hierarchy.toArray((T[]) Array.newInstance(annotationClass, hierarchy.size()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) {
|
||||
for (ElementType elementType : ELEMENT_TYPE_ORDER) {
|
||||
AnnotatedElement annotatedElement = elements.get(elementType);
|
||||
if (annotatedElement != null) {
|
||||
T[] annotations = annotatedElement.getAnnotationsByType(annotationClass);
|
||||
if (annotations.length != 0) {
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (T[]) Array.newInstance(annotationClass, 0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends Annotation> T[] getAnnotations(ElementType elementType, Class<T> annotationType) {
|
||||
AnnotatedElement annotatedElement = elements.get(elementType);
|
||||
if (annotatedElement == null) {
|
||||
//noinspection unchecked
|
||||
return (T[]) Array.newInstance(annotationType, 0);
|
||||
}
|
||||
return annotatedElement.getAnnotationsByType(annotationType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends Annotation> T[][] getAnnotationsHierachy(Class<T> annotationClass) {
|
||||
List<T[]> hierarchy = new ArrayList<>(ELEMENT_TYPE_ORDER.size());
|
||||
for (ElementType elementType : ELEMENT_TYPE_ORDER) {
|
||||
AnnotatedElement annotatedElement = elements.get(elementType);
|
||||
if (annotatedElement != null) {
|
||||
T[] annotations = annotatedElement.getAnnotationsByType(annotationClass);
|
||||
if (annotations.length != 0) {
|
||||
hierarchy.add(annotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return hierarchy.toArray((T[][]) Array.newInstance(annotationClass, 0, 0));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Annotation[] getAllAnnotations() {
|
||||
Map<Class<? extends Annotation>, Annotation[]> annotations = new HashMap<>();
|
||||
for (ElementType elementType : ELEMENT_TYPE_ORDER) {
|
||||
AnnotatedElement annotatedElement = elements.get(elementType);
|
||||
if (annotatedElement != null) {
|
||||
for (Annotation annotation : annotatedElement.getAnnotations()) {
|
||||
annotations.putIfAbsent(annotation.annotationType(), new Annotation[]{annotation});
|
||||
|
||||
Repeatable repeatable = annotation.annotationType().getAnnotation(Repeatable.class);
|
||||
if (repeatable != null) {
|
||||
annotations.put(repeatable.value(), annotatedElement.getAnnotationsByType(repeatable.value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (annotations.isEmpty()) {
|
||||
return new Annotation[0];
|
||||
} else if (annotations.size() == 1) {
|
||||
return annotations.values().iterator().next();
|
||||
} else {
|
||||
return annotations.values().stream().flatMap(Arrays::stream).toArray(Annotation[]::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import de.siphalor.tweed5.namingformat.api.NamingFormatCollector;
|
||||
import de.siphalor.tweed5.namingformat.api.NamingFormats;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import de.siphalor.tweed5.typeutils.api.type.LayeredTypeAnnotations;
|
||||
import de.siphalor.tweed5.typeutils.api.type.TypeAnnotationLayer;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.entry.StaticPojoCompoundConfigEntry;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoClassIntrospector;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException;
|
||||
@@ -15,8 +18,8 @@ import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfi
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -40,7 +43,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable <T> ConfigEntry<T> weaveEntry(Class<T> valueClass, WeavingContext context) {
|
||||
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
if (context.annotations().getAnnotation(CompoundWeaving.class) == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -49,7 +52,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
WeavingContext.ExtensionsData newExtensionsData = context.extensionsData().copy();
|
||||
weavingConfigAccess.set(newExtensionsData, weavingConfig);
|
||||
|
||||
PojoClassIntrospector introspector = PojoClassIntrospector.forClass(valueClass);
|
||||
PojoClassIntrospector introspector = PojoClassIntrospector.forClass(valueType.declaredType());
|
||||
|
||||
WeavableCompoundConfigEntry<T> compoundEntry = instantiateCompoundEntry(introspector, weavingConfig);
|
||||
|
||||
@@ -62,7 +65,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
|
||||
return compoundEntry;
|
||||
} catch (Exception e) {
|
||||
throw new PojoWeavingException("Exception occurred trying to weave compound for class " + valueClass.getName(), e);
|
||||
throw new PojoWeavingException("Exception occurred trying to weave compound for class " + valueType, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,27 +85,8 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
return CompoundWeavingConfigImpl.withOverrides(parent, local);
|
||||
}
|
||||
|
||||
private WeavingContext createSubContextForProperty(
|
||||
PojoClassIntrospector.Property property,
|
||||
String name,
|
||||
WeavingContext.ExtensionsData newExtensionsData,
|
||||
WeavingContext parentContext
|
||||
) {
|
||||
return parentContext.subContextBuilder(name)
|
||||
.annotations(collectAnnotationsForField(property.field()))
|
||||
.extensionsData(newExtensionsData)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Annotations collectAnnotationsForField(Field field) {
|
||||
Annotations annotations = new Annotations();
|
||||
annotations.addAnnotationsFrom(ElementType.TYPE, field.getType());
|
||||
annotations.addAnnotationsFrom(ElementType.FIELD, field);
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CompoundWeavingConfig createWeavingConfigFromAnnotations(Annotations annotations) {
|
||||
private CompoundWeavingConfig createWeavingConfigFromAnnotations(@NotNull AnnotatedElement annotations) {
|
||||
CompoundWeaving annotation = annotations.getAnnotation(CompoundWeaving.class);
|
||||
if (annotation == null) {
|
||||
return null;
|
||||
@@ -163,7 +147,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException("Final config entries are not supported in weaving yet.");
|
||||
} else {
|
||||
subEntry = subContext.weaveEntry(property.field().getType(), subContext);
|
||||
subEntry = subContext.weaveEntry(ActualType.ofUsedType(property.field().getAnnotatedType()), subContext);
|
||||
}
|
||||
|
||||
return new StaticPojoCompoundConfigEntry.SubEntry(
|
||||
@@ -192,4 +176,24 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
}
|
||||
return namingFormat;
|
||||
}
|
||||
|
||||
private WeavingContext createSubContextForProperty(
|
||||
PojoClassIntrospector.Property property,
|
||||
String name,
|
||||
WeavingContext.ExtensionsData newExtensionsData,
|
||||
WeavingContext parentContext
|
||||
) {
|
||||
return parentContext.subContextBuilder(name)
|
||||
.annotations(collectAnnotationsForField(property.field()))
|
||||
.extensionsData(newExtensionsData)
|
||||
.build();
|
||||
}
|
||||
|
||||
private AnnotatedElement collectAnnotationsForField(Field field) {
|
||||
LayeredTypeAnnotations annotations = new LayeredTypeAnnotations();
|
||||
annotations.appendLayerFrom(TypeAnnotationLayer.TYPE_DECLARATION, field.getType());
|
||||
annotations.appendLayerFrom(TypeAnnotationLayer.TYPE_USE, field);
|
||||
annotations.appendLayerFrom(TypeAnnotationLayer.TYPE_USE, field.getAnnotatedType());
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TrivialPojoWeaver implements TweedPojoWeaver {
|
||||
@@ -11,7 +12,7 @@ public class TrivialPojoWeaver implements TweedPojoWeaver {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable <T> ConfigEntry<T> weaveEntry(Class<T> valueClass, WeavingContext context) {
|
||||
return new SimpleConfigEntryImpl<>(valueClass);
|
||||
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
return new SimpleConfigEntryImpl<>(valueType.declaredType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -12,7 +13,7 @@ public interface TweedPojoWeavingFunction {
|
||||
* @return The resulting, sealed config entry or {@code null}, if the weaving function is not applicable to the given parameters.
|
||||
*/
|
||||
@Nullable
|
||||
<T> ConfigEntry<T> weaveEntry(Class<T> valueClass, WeavingContext context);
|
||||
<T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
|
||||
|
||||
@FunctionalInterface
|
||||
interface NonNull extends TweedPojoWeavingFunction {
|
||||
@@ -24,6 +25,6 @@ public interface TweedPojoWeavingFunction {
|
||||
* @throws RuntimeException when a valid config entry could not be resolved.
|
||||
*/
|
||||
@Override
|
||||
@NotNull <T> ConfigEntry<T> weaveEntry(Class<T> valueClass, WeavingContext context);
|
||||
@NotNull <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,13 @@ package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import lombok.*;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Value
|
||||
@@ -24,7 +26,7 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
|
||||
@NotNull
|
||||
ExtensionsData extensionsData;
|
||||
@NotNull
|
||||
Annotations annotations;
|
||||
AnnotatedElement annotations;
|
||||
|
||||
public static Builder builder(TweedPojoWeavingFunction.NonNull weavingFunction, ConfigContainer<?> configContainer) {
|
||||
return new Builder(null, weavingFunction, configContainer, new String[0]);
|
||||
@@ -41,8 +43,8 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> ConfigEntry<T> weaveEntry(Class<T> valueClass, WeavingContext context) {
|
||||
return weavingFunction.weaveEntry(valueClass, context);
|
||||
public @NotNull <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
return weavingFunction.weaveEntry(valueType, context);
|
||||
}
|
||||
|
||||
public interface ExtensionsData extends Patchwork<ExtensionsData> {}
|
||||
@@ -57,7 +59,7 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
|
||||
private final ConfigContainer<?> configContainer;
|
||||
private final String[] path;
|
||||
private ExtensionsData extensionsData;
|
||||
private Annotations annotations;
|
||||
private AnnotatedElement annotations;
|
||||
|
||||
public WeavingContext build() {
|
||||
return new WeavingContext(
|
||||
|
||||
@@ -8,10 +8,8 @@ import de.siphalor.tweed5.patchwork.api.PatchworkClassCreator;
|
||||
import de.siphalor.tweed5.patchwork.impl.PatchworkClass;
|
||||
import de.siphalor.tweed5.patchwork.impl.PatchworkClassGenerator;
|
||||
import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart;
|
||||
import de.siphalor.tweed5.utils.api.collection.ClassToInstancesMultimap;
|
||||
import de.siphalor.tweed5.utils.api.collection.InheritanceMap;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.Annotations;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.WeavingContext;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
|
||||
@@ -20,7 +18,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -168,7 +165,7 @@ public class TweedPojoWeaverBootstrapper<T> {
|
||||
setupWeavers();
|
||||
WeavingContext weavingContext = createWeavingContext();
|
||||
|
||||
ConfigEntry<T> rootEntry = this.weaveEntry(pojoClass, weavingContext);
|
||||
ConfigEntry<T> rootEntry = this.weaveEntry(ActualType.ofClass(pojoClass), weavingContext);
|
||||
configContainer.attachAndSealTree(rootEntry);
|
||||
|
||||
return configContainer;
|
||||
@@ -214,19 +211,16 @@ public class TweedPojoWeaverBootstrapper<T> {
|
||||
try {
|
||||
WeavingContext.ExtensionsData extensionsData = (WeavingContext.ExtensionsData) contextExtensionsDataClass.constructor().invoke();
|
||||
|
||||
Annotations annotations = new Annotations();
|
||||
annotations.addAnnotationsFrom(ElementType.TYPE, pojoClass);
|
||||
|
||||
return WeavingContext.builder(this::weaveEntry, configContainer)
|
||||
.extensionsData(extensionsData)
|
||||
.annotations(annotations)
|
||||
.annotations(pojoClass)
|
||||
.build();
|
||||
} catch (Throwable e) {
|
||||
throw new PojoWeavingException("Failed to create weaving context's extension data");
|
||||
}
|
||||
}
|
||||
|
||||
private <U> ConfigEntry<U> weaveEntry(Class<U> dataClass, WeavingContext context) {
|
||||
private <U> ConfigEntry<U> weaveEntry(ActualType<U> dataClass, WeavingContext context) {
|
||||
for (TweedPojoWeaver weaver : weavers) {
|
||||
ConfigEntry<U> configEntry = weaver.weaveEntry(dataClass, context);
|
||||
if (configEntry != null) {
|
||||
@@ -238,7 +232,7 @@ public class TweedPojoWeaverBootstrapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
throw new PojoWeavingException("Failed to weave " + dataClass.getName() + ": No matching weavers found");
|
||||
throw new PojoWeavingException("Failed to weave " + dataClass + ": No matching weavers found");
|
||||
}
|
||||
|
||||
private void applyPostProcessors(ConfigEntry<?> configEntry, WeavingContext context) {
|
||||
|
||||
@@ -7,14 +7,13 @@ import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.namingformat.api.NamingFormat;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfig;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
import static de.siphalor.tweed5.weaver.pojo.test.ConfigEntryAssertions.isCompoundEntryForClassWith;
|
||||
import static de.siphalor.tweed5.weaver.pojo.test.ConfigEntryAssertions.isSimpleEntryForClass;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -33,28 +32,25 @@ class CompoundPojoWeaverTest {
|
||||
}
|
||||
});
|
||||
|
||||
Annotations annotations = new Annotations();
|
||||
annotations.addAnnotationsFrom(ElementType.TYPE, Compound.class);
|
||||
|
||||
WeavingContext weavingContext = WeavingContext.builder(new TweedPojoWeavingFunction.NonNull() {
|
||||
@Override
|
||||
public @NotNull <T> ConfigEntry<T> weaveEntry(Class<T> valueClass, WeavingContext context) {
|
||||
ConfigEntry<T> entry = compoundWeaver.weaveEntry(valueClass, context);
|
||||
public @NotNull <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
ConfigEntry<T> entry = compoundWeaver.weaveEntry(valueType, context);
|
||||
if (entry != null) {
|
||||
return entry;
|
||||
} else {
|
||||
//noinspection unchecked
|
||||
ConfigEntry<T> configEntry = mock((Class<SimpleConfigEntry<T>>) (Class<?>) SimpleConfigEntry.class);
|
||||
when(configEntry.valueClass()).thenReturn(valueClass);
|
||||
when(configEntry.valueClass()).thenReturn(valueType.declaredType());
|
||||
return configEntry;
|
||||
}
|
||||
}
|
||||
}, mock(ConfigContainer.class))
|
||||
.extensionsData(new ExtensionsDataMock(null))
|
||||
.annotations(annotations)
|
||||
.annotations(Compound.class)
|
||||
.build();
|
||||
|
||||
ConfigEntry<Compound> resultEntry = compoundWeaver.weaveEntry(Compound.class, weavingContext);
|
||||
ConfigEntry<Compound> resultEntry = compoundWeaver.weaveEntry(ActualType.ofClass(Compound.class), weavingContext);
|
||||
|
||||
assertThat(resultEntry).satisfies(isCompoundEntryForClassWith(Compound.class, compoundEntry -> assertThat(compoundEntry.subEntries())
|
||||
.hasEntrySatisfying("an-integer", isSimpleEntryForClass(int.class))
|
||||
|
||||
@@ -12,21 +12,25 @@ import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
public class ConfigEntryAssertions {
|
||||
public static Consumer<Object> isSimpleEntryForClass(Class<?> valueClass) {
|
||||
return object -> assertThat(object)
|
||||
.as("Should be a simple config entry for class " + valueClass.getName())
|
||||
.asInstanceOf(type(SimpleConfigEntry.class))
|
||||
.extracting(ConfigEntry::valueClass)
|
||||
.isEqualTo(valueClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Consumer<Object> isCompoundEntryForClassWith(
|
||||
Class<T> compoundClass,
|
||||
Consumer<CompoundConfigEntry<T>> condition
|
||||
) {
|
||||
return object -> assertThat(object)
|
||||
.as("Should be a compound config entry for class " + compoundClass.getSimpleName())
|
||||
.asInstanceOf(type(CompoundConfigEntry.class))
|
||||
.satisfies(compoundEntry -> {
|
||||
assertThat(compoundEntry.valueClass()).isEqualTo(compoundClass);
|
||||
condition.accept(compoundEntry);
|
||||
});
|
||||
.as("Compound entry for class " + compoundClass.getSimpleName())
|
||||
.satisfies(
|
||||
compoundEntry -> assertThat(compoundEntry.valueClass())
|
||||
.as("Value class of compound entry should match")
|
||||
.isEqualTo(compoundClass),
|
||||
condition::accept
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user