[weaver-pojo*] Refactor POJO weaver extensibility
This commit is contained in:
@@ -4,12 +4,14 @@ import de.siphalor.tweed5.annotationinheritance.impl.AnnotationInheritanceResolv
|
||||
import de.siphalor.tweed5.typeutils.api.annotations.AnnotationRepeatType;
|
||||
import de.siphalor.tweed5.utils.api.collection.ClassToInstanceMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.var;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class AnnotationInheritanceAwareAnnotatedElement implements AnnotatedElement {
|
||||
@@ -48,6 +50,28 @@ public class AnnotationInheritanceAwareAnnotatedElement implements AnnotatedElem
|
||||
return getOrResolveAnnotations().get(annotationClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull <T extends Annotation> @NotNull T[] getAnnotationsByType(@NonNull Class<T> annotationClass) {
|
||||
T annotation = getOrResolveAnnotations().get(annotationClass);
|
||||
if (annotation != null) {
|
||||
//noinspection unchecked
|
||||
T[] array = (T[]) Array.newInstance(annotationClass, 1);
|
||||
array[0] = annotation;
|
||||
return array;
|
||||
}
|
||||
|
||||
AnnotationRepeatType repeatType = AnnotationRepeatType.getType(annotationClass);
|
||||
if (repeatType instanceof AnnotationRepeatType.Repeatable) {
|
||||
var containerRepeatType = ((AnnotationRepeatType.Repeatable) repeatType).containerRepeatType();
|
||||
Annotation containerAnnotation = getOrResolveAnnotations().get(containerRepeatType.annotationClass());
|
||||
if (containerAnnotation != null) {
|
||||
return containerRepeatType.elements(containerAnnotation);
|
||||
}
|
||||
}
|
||||
//noinspection unchecked
|
||||
return (T[]) Array.newInstance(annotationClass, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Annotation[] getAnnotations() {
|
||||
return getOrResolveAnnotations().values().toArray(new Annotation[0]);
|
||||
|
||||
@@ -27,7 +27,7 @@ public class AnnotationInheritanceResolver {
|
||||
public ClassToInstanceMap<Annotation> resolve() {
|
||||
resolve(main, Collections.emptySet());
|
||||
|
||||
ClassToInstanceMap<Annotation> resolvedAnnotations = new ClassToInstanceMap<>();
|
||||
ClassToInstanceMap<Annotation> resolvedAnnotations = ClassToInstanceMap.backedBy(new LinkedHashMap<>());
|
||||
|
||||
List<Aggregator> aggregatorList = new ArrayList<>(aggregators.values());
|
||||
for (int i = aggregatorList.size() - 1; i >= 0; i--) {
|
||||
|
||||
@@ -18,6 +18,15 @@ class AnnotationInheritanceAwareAnnotatedElementTest {
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationsByTypeAForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
assertThat(element.getAnnotationsByType(A.class))
|
||||
.singleElement()
|
||||
.extracting(A::value)
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationBForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
@@ -27,6 +36,15 @@ class AnnotationInheritanceAwareAnnotatedElementTest {
|
||||
.isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationsByTypeBForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
assertThat(element.getAnnotationsByType(B.class))
|
||||
.singleElement()
|
||||
.extracting(B::value)
|
||||
.isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationCForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
@@ -36,12 +54,33 @@ class AnnotationInheritanceAwareAnnotatedElementTest {
|
||||
.isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationsByTypeCForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
assertThat(element.getAnnotationsByType(C.class))
|
||||
.singleElement()
|
||||
.extracting(C::value)
|
||||
.isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationRForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
assertThat(element.getAnnotation(R.class)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationsByTypeRForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
assertThat(element.getAnnotationsByType(R.class))
|
||||
.satisfiesExactly(
|
||||
r -> assertThat(r.value()).isEqualTo(4),
|
||||
r -> assertThat(r.value()).isEqualTo(2),
|
||||
r -> assertThat(r.value()).isEqualTo(3),
|
||||
r -> assertThat(r.value()).isEqualTo(10)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationRsForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
@@ -58,6 +97,21 @@ class AnnotationInheritanceAwareAnnotatedElementTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationsByTypeRsForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
assertThat(element.getAnnotationsByType(Rs.class))
|
||||
.singleElement()
|
||||
.extracting(Rs::value)
|
||||
.asInstanceOf(array(R[].class))
|
||||
.satisfiesExactly(
|
||||
r -> assertThat(r.value()).isEqualTo(4),
|
||||
r -> assertThat(r.value()).isEqualTo(2),
|
||||
r -> assertThat(r.value()).isEqualTo(3),
|
||||
r -> assertThat(r.value()).isEqualTo(10)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAnnotationsForTarget1() {
|
||||
var element = new AnnotationInheritanceAwareAnnotatedElement(Target1.class);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package de.siphalor.tweed5.patchwork.api;
|
||||
|
||||
import org.jetbrains.annotations.CheckReturnValue;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -10,7 +9,6 @@ public interface Patchwork {
|
||||
@Contract(mutates = "this")
|
||||
<T extends @Nullable Object> void set(PatchworkPartAccess<T> access, T value) throws InvalidPatchworkAccessException;
|
||||
|
||||
@CheckReturnValue
|
||||
@Contract(pure = true)
|
||||
Patchwork copy();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ClassToInstanceMap<T extends @NonNull Object> implements Iterable<T
|
||||
return delegate.containsValue(value);
|
||||
}
|
||||
|
||||
public <V extends T> V get(Class<V> key) {
|
||||
public <V extends T> @Nullable V get(Class<V> key) {
|
||||
return (V) delegate.get(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package de.siphalor.tweed5.weaver.pojoext.serde.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedReaderWriterProvider;
|
||||
import de.siphalor.tweed5.data.extension.impl.TweedEntryReaderWriterImpls;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeavingExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.WeavingContext;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
|
||||
import de.siphalor.tweed5.weaver.pojoext.serde.impl.SerdePojoReaderWriterSpec;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -18,11 +20,21 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
@CommonsLog
|
||||
public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor {
|
||||
public class ReadWritePojoWeavingProcessor implements TweedPojoWeavingExtension {
|
||||
private final Map<String, TweedReaderWriterProvider.ReaderWriterFactory<TweedEntryReader<?, ?>>> readerFactories = new HashMap<>();
|
||||
private final Map<String, TweedReaderWriterProvider.ReaderWriterFactory<TweedEntryWriter<?, ?>>> writerFactories = new HashMap<>();
|
||||
private final ReadWriteExtension readWriteExtension;
|
||||
|
||||
public ReadWritePojoPostProcessor() {
|
||||
public ReadWritePojoWeavingProcessor(ConfigContainer<?> configContainer) {
|
||||
this.readWriteExtension = configContainer.extension(ReadWriteExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
"You must register a " + ReadWriteExtension.class.getSimpleName()
|
||||
+ " to use the " + getClass().getSimpleName()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(SetupContext context) {
|
||||
loadProviders();
|
||||
}
|
||||
|
||||
@@ -63,18 +75,12 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(ConfigEntry<?> configEntry, WeavingContext context) {
|
||||
public <T> void afterWeaveEntry(ActualType<T> valueType, ConfigEntry<T> configEntry, WeavingContext context) {
|
||||
EntryReadWriteConfig entryConfig = context.annotations().getAnnotation(EntryReadWriteConfig.class);
|
||||
if (entryConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReadWriteExtension readWriteExtension = context.configContainer().extension(ReadWriteExtension.class).orElse(null);
|
||||
if (readWriteExtension == null && log.isErrorEnabled()) {
|
||||
log.error("You must not use " + getClass().getName() + " without the " + ReadWriteExtension.class.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
//noinspection rawtypes,unchecked
|
||||
readWriteExtension.setEntryReaderWriter(
|
||||
(ConfigEntry) configEntry,
|
||||
@@ -1,4 +1,4 @@
|
||||
package de.siphalor.tweed5.weaver.pojoext.serde;
|
||||
package de.siphalor.tweed5.weaver.pojoext.serde.api;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
@@ -10,11 +10,12 @@ import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.DefaultWeavingExtensions;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeavingExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.TweedPojoWeaverBootstrapper;
|
||||
import de.siphalor.tweed5.weaver.pojoext.serde.api.EntryReadWriteConfig;
|
||||
import de.siphalor.tweed5.weaver.pojoext.serde.api.ReadWritePojoPostProcessor;
|
||||
import lombok.*;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.StringReader;
|
||||
@@ -22,12 +23,13 @@ import java.io.StringWriter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WeaverPojoSerdeExtensionTest {
|
||||
class ReadWritePojoWeavingProcessorTest {
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void testAnnotated() {
|
||||
TweedPojoWeaverBootstrapper<AnnotatedConfig> weaverBootstrapper = TweedPojoWeaverBootstrapper.create(AnnotatedConfig.class);
|
||||
TweedPojoWeaverBootstrapper<AnnotatedConfig> weaverBootstrapper = TweedPojoWeaverBootstrapper.create(
|
||||
AnnotatedConfig.class);
|
||||
|
||||
ConfigContainer<AnnotatedConfig> configContainer = weaverBootstrapper.weave();
|
||||
configContainer.initialize();
|
||||
@@ -38,12 +40,27 @@ class WeaverPojoSerdeExtensionTest {
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
HjsonWriter hjsonWriter = new HjsonWriter(stringWriter, new HjsonWriter.Options());
|
||||
readWriteExtension.write(hjsonWriter, config, configContainer.rootEntry(), readWriteExtension.createReadWriteContextExtensionsData());
|
||||
readWriteExtension.write(
|
||||
hjsonWriter,
|
||||
config,
|
||||
configContainer.rootEntry(),
|
||||
readWriteExtension.createReadWriteContextExtensionsData()
|
||||
);
|
||||
|
||||
assertThat(stringWriter).hasToString("{\n\tanInt: 123\n\ttext: test\n\ttest: my cool custom writer\n}\n");
|
||||
assertThat(stringWriter).hasToString("""
|
||||
{
|
||||
\tanInt: 123
|
||||
\ttext: test
|
||||
\ttest: my cool custom writer
|
||||
}
|
||||
""");
|
||||
|
||||
HjsonReader reader = new HjsonReader(new HjsonLexer(new StringReader(
|
||||
"{\n\tanInt: 987\n\ttext: abdef\n\ttest: { inner: 29 }\n}"
|
||||
HjsonReader reader = new HjsonReader(new HjsonLexer(new StringReader("""
|
||||
{
|
||||
\tanInt: 987
|
||||
\ttext: abdef
|
||||
\ttest: { inner: 29 }
|
||||
}"""
|
||||
)));
|
||||
assertThat(readWriteExtension.read(
|
||||
reader,
|
||||
@@ -59,10 +76,10 @@ class WeaverPojoSerdeExtensionTest {
|
||||
context.registerWriterFactory("tweed5.test.dummy", delegates -> new TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>() {
|
||||
@Override
|
||||
public void write(
|
||||
@NonNull TweedDataVisitor writer,
|
||||
Object value,
|
||||
TweedDataVisitor writer,
|
||||
@Nullable Object value,
|
||||
ConfigEntry<Object> entry,
|
||||
@NonNull TweedWriteContext context
|
||||
TweedWriteContext context
|
||||
) throws TweedDataWriteException {
|
||||
writer.visitString("my cool custom writer");
|
||||
}
|
||||
@@ -70,9 +87,12 @@ class WeaverPojoSerdeExtensionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@PojoWeaving(extensions = ReadWriteExtension.class, postProcessors = ReadWritePojoPostProcessor.class)
|
||||
@PojoWeaving(extensions = ReadWriteExtension.class)
|
||||
@DefaultWeavingExtensions
|
||||
@PojoWeavingExtension(de.siphalor.tweed5.weaver.pojoext.serde.api.ReadWritePojoWeavingProcessor.class)
|
||||
@CompoundWeaving
|
||||
@EntryReadWriteConfig("tweed5.compound")
|
||||
// lombok
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.siphalor.tweed5.weaver.pojoext.serde.impl;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
@@ -52,7 +53,7 @@ class SerdePojoReaderWriterSpecTest {
|
||||
"abc..def;5;.",
|
||||
})
|
||||
@SneakyThrows
|
||||
void parseError(String input, int index, String codePoint) {
|
||||
void parseError(String input, int index, @Nullable String codePoint) {
|
||||
assertThatThrownBy(() -> SerdePojoReaderWriterSpec.parse(input))
|
||||
.asInstanceOf(type(SerdePojoReaderWriterSpec.ParseException.class))
|
||||
.isInstanceOf(SerdePojoReaderWriterSpec.ParseException.class)
|
||||
|
||||
@@ -4,6 +4,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation(project(":tweed5-construct"))
|
||||
api(project(":tweed5-annotation-inheritance"))
|
||||
api(project(":tweed5-core"))
|
||||
api(project(":tweed5-naming-format"))
|
||||
api(project(":tweed5-type-utils"))
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.annotation;
|
||||
|
||||
import de.siphalor.tweed5.annotationinheritance.api.AnnotationInheritance;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.CompoundPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TrivialPojoWeaver;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@AnnotationInheritance(passOn = PojoWeavingExtension.class)
|
||||
@PojoWeavingExtension(CompoundPojoWeaver.class)
|
||||
@PojoWeavingExtension(TrivialPojoWeaver.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
public @interface DefaultWeavingExtensions {
|
||||
}
|
||||
@@ -5,8 +5,7 @@ import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.CompoundPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TrivialPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeavingExtension;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -14,16 +13,9 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
public @interface PojoWeaving {
|
||||
Class<? extends ConfigContainer> container() default DefaultConfigContainer.class;
|
||||
|
||||
Class<? extends TweedPojoWeaver>[] weavers() default {
|
||||
CompoundPojoWeaver.class,
|
||||
TrivialPojoWeaver.class,
|
||||
};
|
||||
|
||||
Class<? extends TweedPojoWeavingPostProcessor>[] postProcessors() default {};
|
||||
|
||||
Class<? extends TweedExtension>[] extensions() default {};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.annotation;
|
||||
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeavingExtension;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Repeatable(PojoWeavingExtensions.class)
|
||||
public @interface PojoWeavingExtension {
|
||||
Class<? extends TweedPojoWeavingExtension> value();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
public @interface PojoWeavingExtensions {
|
||||
PojoWeavingExtension[] value();
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.*;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
public class CollectionPojoWeaver implements TweedPojoWeaver {
|
||||
public class CollectionPojoWeaver implements TweedPojoWeavingExtension {
|
||||
private static final CollectionWeavingConfig DEFAULT_WEAVING_CONFIG = CollectionWeavingConfigImpl.builder()
|
||||
.collectionEntryClass(CollectionConfigEntryImpl.class)
|
||||
.build();
|
||||
@@ -51,10 +51,8 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
|
||||
|
||||
ConfigEntry<?> elementEntry = context.weaveEntry(
|
||||
collectionTypeParams.get(0),
|
||||
context.subContextBuilder("element")
|
||||
.annotations(collectionTypeParams.get(0))
|
||||
.extensionsData(newExtensionsData)
|
||||
.build()
|
||||
newExtensionsData,
|
||||
ProtoWeavingContext.subContextFor(context, "element", collectionTypeParams.get(0))
|
||||
);
|
||||
|
||||
return WeavableCollectionConfigEntry.FACTORY
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* A weaver that weaves classes with the {@link CompoundWeaving} annotation as compound entries.
|
||||
*/
|
||||
public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
public class CompoundPojoWeaver implements TweedPojoWeavingExtension {
|
||||
private static final CompoundWeavingConfig DEFAULT_WEAVING_CONFIG = CompoundWeavingConfigImpl.builder()
|
||||
.compoundSourceNamingFormat(NamingFormats.camelCase())
|
||||
.compoundTargetNamingFormat(NamingFormats.camelCase())
|
||||
@@ -147,21 +147,28 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
private WeavableCompoundConfigEntry.SubEntry weaveCompoundSubEntry(
|
||||
PojoClassIntrospector.Property property,
|
||||
Patchwork newExtensionsData,
|
||||
WeavingContext parentContext
|
||||
WeavingContext context
|
||||
) {
|
||||
assert weavingConfigAccess != null;
|
||||
CompoundWeavingConfig weavingConfig = newExtensionsData.get(weavingConfigAccess);
|
||||
assert weavingConfig != null;
|
||||
|
||||
String name = convertName(property.field().getName(), weavingConfig);
|
||||
WeavingContext subContext = createSubContextForProperty(property, name, newExtensionsData, parentContext);
|
||||
|
||||
ConfigEntry<?> subEntry;
|
||||
if (property.isFinal()) {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException("Final config entries are not supported in weaving yet.");
|
||||
} else {
|
||||
subEntry = subContext.weaveEntry(ActualType.ofUsedType(property.field().getAnnotatedType()), subContext);
|
||||
subEntry = context.weaveEntry(
|
||||
ActualType.ofUsedType(property.field().getAnnotatedType()),
|
||||
newExtensionsData,
|
||||
ProtoWeavingContext.subContextFor(
|
||||
context,
|
||||
property.field().getName(),
|
||||
collectAnnotationsForField(property.field())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new StaticPojoCompoundConfigEntry.SubEntry(
|
||||
@@ -193,18 +200,6 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
||||
return namingFormat;
|
||||
}
|
||||
|
||||
private WeavingContext createSubContextForProperty(
|
||||
PojoClassIntrospector.Property property,
|
||||
String name,
|
||||
Patchwork 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());
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Value
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ProtoWeavingContext {
|
||||
@Nullable WeavingContext parent;
|
||||
ConfigContainer<?> configContainer;
|
||||
String[] path;
|
||||
AnnotatedElement annotations;
|
||||
|
||||
public static ProtoWeavingContext subContextFor(
|
||||
WeavingContext weavingContext,
|
||||
String subPathName,
|
||||
AnnotatedElement annotations
|
||||
) {
|
||||
String[] path = Arrays.copyOf(weavingContext.path(), weavingContext.path().length + 1, String[].class);
|
||||
path[path.length - 1] = subPathName;
|
||||
return new ProtoWeavingContext(
|
||||
weavingContext,
|
||||
weavingContext.configContainer(),
|
||||
path,
|
||||
annotations
|
||||
);
|
||||
}
|
||||
|
||||
public static ProtoWeavingContext create(ConfigContainer<?> configContainer, AnnotatedElement annotations) {
|
||||
return new ProtoWeavingContext(
|
||||
null,
|
||||
configContainer,
|
||||
new String[0],
|
||||
annotations
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
|
||||
public class TrivialPojoWeaver implements TweedPojoWeaver {
|
||||
public class TrivialPojoWeaver implements TweedPojoWeavingExtension {
|
||||
@Override
|
||||
public void setup(SetupContext context) {
|
||||
// nothing to set up here
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkFactory;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
public interface TweedPojoWeaver extends TweedPojoWeavingFunction {
|
||||
TweedConstructFactory<TweedPojoWeaver> FACTORY = TweedConstructFactory.builder(TweedPojoWeaver.class).build();
|
||||
|
||||
@ApiStatus.OverrideOnly
|
||||
void setup(SetupContext context);
|
||||
|
||||
interface SetupContext {
|
||||
<E> PatchworkPartAccess<E> registerWeavingContextExtensionData(Class<E> dataClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
|
||||
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.patchwork.api.PatchworkPartAccess;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public interface TweedPojoWeavingExtension extends TweedPojoWeavingFunction {
|
||||
TweedConstructFactory<TweedPojoWeavingExtension> FACTORY =
|
||||
TweedConstructFactory.builder(TweedPojoWeavingExtension.class)
|
||||
.typedArg(ConfigContainer.class)
|
||||
.build();
|
||||
|
||||
@ApiStatus.OverrideOnly
|
||||
void setup(SetupContext context);
|
||||
|
||||
default <T> void beforeWeaveEntry(ActualType<T> valueType, Patchwork extensionsData, ProtoWeavingContext context) {}
|
||||
|
||||
@Override
|
||||
default @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default <T> void afterWeaveEntry(ActualType<T> valueType, ConfigEntry<T> configEntry, WeavingContext context) {}
|
||||
|
||||
interface SetupContext {
|
||||
<E> PatchworkPartAccess<E> registerWeavingContextExtensionData(Class<E> dataClass);
|
||||
}
|
||||
}
|
||||
@@ -4,63 +4,30 @@ 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 lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Value
|
||||
public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
|
||||
@Builder
|
||||
public class WeavingContext {
|
||||
@Nullable WeavingContext parent;
|
||||
@Getter(AccessLevel.NONE)
|
||||
TweedPojoWeavingFunction.NonNull weavingFunction;
|
||||
WeavingFn weavingFunction;
|
||||
ConfigContainer<?> configContainer;
|
||||
String[] path;
|
||||
Patchwork extensionsData;
|
||||
AnnotatedElement annotations;
|
||||
|
||||
public static Builder builder(TweedPojoWeavingFunction.NonNull weavingFunction, ConfigContainer<?> configContainer) {
|
||||
return new Builder(null, weavingFunction, configContainer, new String[0]);
|
||||
public <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, Patchwork extensionsData, ProtoWeavingContext context) {
|
||||
return weavingFunction.weaveEntry(valueType, extensionsData, context);
|
||||
}
|
||||
|
||||
public static Builder builder(TweedPojoWeavingFunction.NonNull weavingFunction, ConfigContainer<?> configContainer, String baseName) {
|
||||
return new Builder(null, weavingFunction, configContainer, new String[]{ baseName });
|
||||
}
|
||||
|
||||
public Builder subContextBuilder(String subPathName) {
|
||||
String[] newPath = Arrays.copyOf(path, path.length + 1);
|
||||
newPath[path.length] = subPathName;
|
||||
return new Builder(this, weavingFunction, configContainer, newPath).extensionsData(extensionsData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
return weavingFunction.weaveEntry(valueType, context);
|
||||
}
|
||||
|
||||
@Accessors(fluent = true, chain = true)
|
||||
@Setter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class Builder {
|
||||
@Nullable
|
||||
private final WeavingContext parent;
|
||||
private final TweedPojoWeavingFunction.NonNull weavingFunction;
|
||||
private final ConfigContainer<?> configContainer;
|
||||
private final String[] path;
|
||||
private Patchwork extensionsData;
|
||||
private AnnotatedElement annotations;
|
||||
|
||||
public WeavingContext build() {
|
||||
return new WeavingContext(
|
||||
parent,
|
||||
weavingFunction,
|
||||
configContainer,
|
||||
path,
|
||||
extensionsData,
|
||||
annotations
|
||||
);
|
||||
}
|
||||
public interface WeavingFn {
|
||||
<T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, Patchwork extensionsData, ProtoWeavingContext context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
@NullMarked
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -1,20 +1,23 @@
|
||||
package de.siphalor.tweed5.weaver.pojo.impl.weaving;
|
||||
|
||||
import de.siphalor.tweed5.annotationinheritance.api.AnnotationInheritanceAwareAnnotatedElement;
|
||||
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.patchwork.api.PatchworkFactory;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeavingExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.ProtoWeavingContext;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TweedPojoWeavingExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.WeavingContext;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -27,36 +30,43 @@ import java.util.stream.Collectors;
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TweedPojoWeaverBootstrapper<T> {
|
||||
private final Class<T> pojoClass;
|
||||
private final AnnotatedElement pojoAnnotations;
|
||||
private final ConfigContainer<T> configContainer;
|
||||
private final Collection<TweedPojoWeaver> weavers;
|
||||
private final Collection<TweedPojoWeavingPostProcessor> postProcessors;
|
||||
private final Collection<TweedPojoWeavingExtension> weavingExtensions;
|
||||
@Nullable
|
||||
private PatchworkFactory contextExtensionsPatchworkFactory;
|
||||
private PatchworkFactory weavingExtensionsPatchworkFactory;
|
||||
|
||||
public static <T> TweedPojoWeaverBootstrapper<T> create(Class<T> pojoClass) {
|
||||
PojoWeaving rootWeavingConfig = expectAnnotation(pojoClass, PojoWeaving.class);
|
||||
AnnotatedElement pojoAnnotations = new AnnotationInheritanceAwareAnnotatedElement(pojoClass);
|
||||
PojoWeaving rootWeavingConfig = expectAnnotation(pojoAnnotations, PojoWeaving.class);
|
||||
PojoWeavingExtension[] extensionAnnotations = pojoAnnotations.getAnnotationsByType(PojoWeavingExtension.class);
|
||||
|
||||
//noinspection unchecked
|
||||
ConfigContainer<T> configContainer = (ConfigContainer<T>) createConfigContainer((Class<? extends ConfigContainer<?>>) rootWeavingConfig.container());
|
||||
|
||||
Collection<TweedPojoWeaver> weavers = loadWeavers(Arrays.asList(rootWeavingConfig.weavers()));
|
||||
Collection<TweedPojoWeavingPostProcessor> postProcessors = loadPostProcessors(Arrays.asList(rootWeavingConfig.postProcessors()));
|
||||
ConfigContainer<T>
|
||||
configContainer
|
||||
= (ConfigContainer<T>) createConfigContainer((Class<? extends ConfigContainer<?>>) rootWeavingConfig.container());
|
||||
|
||||
configContainer.registerExtensions(rootWeavingConfig.extensions());
|
||||
configContainer.finishExtensionSetup();
|
||||
|
||||
return new TweedPojoWeaverBootstrapper<>(pojoClass, configContainer, weavers, postProcessors);
|
||||
Collection<TweedPojoWeavingExtension> extensions = loadWeavingExtensions(
|
||||
Arrays.stream(extensionAnnotations).map(PojoWeavingExtension::value).collect(Collectors.toList()),
|
||||
configContainer
|
||||
);
|
||||
|
||||
return new TweedPojoWeaverBootstrapper<>(pojoClass, pojoAnnotations, configContainer, extensions);
|
||||
}
|
||||
|
||||
private static Collection<TweedPojoWeaver> loadWeavers(Collection<Class<? extends TweedPojoWeaver>> weaverClasses) {
|
||||
private static Collection<TweedPojoWeavingExtension> loadWeavingExtensions(
|
||||
Collection<Class<? extends TweedPojoWeavingExtension>> weaverClasses,
|
||||
ConfigContainer<?> configContainer
|
||||
) {
|
||||
return weaverClasses.stream()
|
||||
.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 -> TweedPojoWeavingPostProcessor.FACTORY.construct(postProcessorClass).finish())
|
||||
.map(weaverClass ->
|
||||
TweedPojoWeavingExtension.FACTORY.construct(weaverClass)
|
||||
.typedArg(ConfigContainer.class, configContainer)
|
||||
.finish()
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -68,69 +78,107 @@ public class TweedPojoWeaverBootstrapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private static <A extends Annotation> A expectAnnotation(Class<?> clazz, Class<A> annotationClass) {
|
||||
A annotation = clazz.getAnnotation(annotationClass);
|
||||
private static <A extends Annotation> A expectAnnotation(AnnotatedElement element, Class<A> annotationClass) {
|
||||
A annotation = element.getAnnotation(annotationClass);
|
||||
if (annotation == null) {
|
||||
throw new PojoWeavingException("Annotation " + annotationClass.getName() + " must be defined on class " + clazz);
|
||||
throw new PojoWeavingException("Annotation "
|
||||
+ annotationClass.getName()
|
||||
+ " must be defined on class "
|
||||
+ element);
|
||||
} else {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigContainer<T> weave() {
|
||||
setupWeavers();
|
||||
WeavingContext weavingContext = createWeavingContext();
|
||||
setupWeavingExtensions();
|
||||
|
||||
assert weavingExtensionsPatchworkFactory != null;
|
||||
|
||||
ConfigEntry<T> rootEntry = this.weaveEntry(
|
||||
ActualType.ofClass(pojoClass),
|
||||
weavingExtensionsPatchworkFactory.create(),
|
||||
ProtoWeavingContext.create(configContainer, pojoAnnotations)
|
||||
);
|
||||
|
||||
ConfigEntry<T> rootEntry = this.weaveEntry(ActualType.ofClass(pojoClass), weavingContext);
|
||||
configContainer.attachTree(rootEntry);
|
||||
|
||||
return configContainer;
|
||||
}
|
||||
|
||||
private void setupWeavers() {
|
||||
PatchworkFactory.Builder contextExtensionsPatchworkFactoryBuilder = PatchworkFactory.builder();
|
||||
private void setupWeavingExtensions() {
|
||||
PatchworkFactory.Builder weavingExtensionsPatchworkFactoryBuilder = PatchworkFactory.builder();
|
||||
|
||||
TweedPojoWeaver.SetupContext setupContext = contextExtensionsPatchworkFactoryBuilder::registerPart;
|
||||
TweedPojoWeavingExtension.SetupContext setupContext = weavingExtensionsPatchworkFactoryBuilder::registerPart;
|
||||
|
||||
for (TweedPojoWeaver weaver : weavers) {
|
||||
for (TweedPojoWeavingExtension weaver : weavingExtensions) {
|
||||
weaver.setup(setupContext);
|
||||
}
|
||||
|
||||
contextExtensionsPatchworkFactory = contextExtensionsPatchworkFactoryBuilder.build();
|
||||
weavingExtensionsPatchworkFactory = weavingExtensionsPatchworkFactoryBuilder.build();
|
||||
}
|
||||
|
||||
private WeavingContext createWeavingContext() {
|
||||
try {
|
||||
assert contextExtensionsPatchworkFactory != null;
|
||||
Patchwork extensionsData = contextExtensionsPatchworkFactory.create();
|
||||
private <U> ConfigEntry<U> weaveEntry(
|
||||
ActualType<U> dataClass,
|
||||
Patchwork extensionsData,
|
||||
ProtoWeavingContext protoContext
|
||||
) {
|
||||
extensionsData = extensionsData.copy();
|
||||
|
||||
return WeavingContext.builder(this::weaveEntry, configContainer)
|
||||
runBeforeWeaveHooks(dataClass, extensionsData, protoContext);
|
||||
|
||||
WeavingContext context = WeavingContext.builder()
|
||||
.parent(protoContext.parent())
|
||||
.weavingFunction(this::weaveEntry)
|
||||
.configContainer(configContainer)
|
||||
.path(protoContext.path())
|
||||
.extensionsData(extensionsData)
|
||||
.annotations(pojoClass)
|
||||
.annotations(new AnnotationInheritanceAwareAnnotatedElement(protoContext.annotations()))
|
||||
.build();
|
||||
} catch (Throwable e) {
|
||||
throw new PojoWeavingException("Failed to create weaving context's extension data");
|
||||
}
|
||||
}
|
||||
|
||||
private <U> ConfigEntry<U> weaveEntry(ActualType<U> dataClass, WeavingContext context) {
|
||||
for (TweedPojoWeaver weaver : weavers) {
|
||||
ConfigEntry<U> configEntry = weaver.weaveEntry(dataClass, context);
|
||||
for (TweedPojoWeavingExtension weavingExtension : weavingExtensions) {
|
||||
try {
|
||||
ConfigEntry<U> configEntry = weavingExtension.weaveEntry(dataClass, context);
|
||||
if (configEntry != null) {
|
||||
applyPostProcessors(configEntry, context);
|
||||
runAfterWeaveHooks(dataClass, configEntry, context);
|
||||
return configEntry;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to run Tweed POJO weaver (" + weavingExtension.getClass().getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
throw new PojoWeavingException("Failed to weave " + dataClass + ": No matching weavers found");
|
||||
}
|
||||
|
||||
private void applyPostProcessors(ConfigEntry<?> configEntry, WeavingContext context) {
|
||||
for (TweedPojoWeavingPostProcessor postProcessor : postProcessors) {
|
||||
private <U> void runBeforeWeaveHooks(
|
||||
ActualType<U> dataClass,
|
||||
Patchwork extensionsData,
|
||||
ProtoWeavingContext protoContext
|
||||
) {
|
||||
for (TweedPojoWeavingExtension weavingExtension : weavingExtensions) {
|
||||
try {
|
||||
postProcessor.apply(configEntry, context);
|
||||
weavingExtension.beforeWeaveEntry(dataClass, extensionsData, protoContext);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to apply Tweed POJO weaver post processor", e);
|
||||
log.error(
|
||||
"Failed to apply Tweed POJO weaver before weave hook ("
|
||||
+ weavingExtension.getClass().getName() + ")",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <U> void runAfterWeaveHooks(ActualType<U> dataClass, ConfigEntry<U> configEntry, WeavingContext context) {
|
||||
for (TweedPojoWeavingExtension weavingExtension : weavingExtensions) {
|
||||
try {
|
||||
weavingExtension.afterWeaveEntry(dataClass, configEntry, context);
|
||||
} catch (Exception e) {
|
||||
log.error(
|
||||
"Failed to apply Tweed POJO weaver after weave hook ("
|
||||
+ weavingExtension.getClass().getName() + ")",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,15 @@ 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.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkFactory;
|
||||
import de.siphalor.tweed5.typeutils.api.type.ActualType;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullUnmarked;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
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;
|
||||
@@ -28,19 +30,31 @@ class CompoundPojoWeaverTest {
|
||||
|
||||
PatchworkFactory weavingContextExtensionDataFactory = weavingContextExtensionDataFactoryBuilder.build();
|
||||
|
||||
WeavingContext weavingContext = WeavingContext.builder(new TweedPojoWeavingFunction.NonNull() {
|
||||
WeavingContext weavingContext = WeavingContext.builder()
|
||||
.weavingFunction(new WeavingContext.WeavingFn() {
|
||||
@Override
|
||||
public @NotNull <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||
ConfigEntry<T> entry = compoundWeaver.weaveEntry(valueType, context);
|
||||
if (entry != null) {
|
||||
return entry;
|
||||
} else {
|
||||
return new SimpleConfigEntryImpl<>(context.configContainer(), valueType.declaredType());
|
||||
public <T> ConfigEntry<T> weaveEntry(
|
||||
ActualType<T> valueType,
|
||||
Patchwork extensionsData,
|
||||
ProtoWeavingContext protoContext
|
||||
) {
|
||||
WeavingContext context = WeavingContext.builder()
|
||||
.configContainer(protoContext.configContainer())
|
||||
.annotations(valueType)
|
||||
.extensionsData(extensionsData.copy())
|
||||
.path(protoContext.path())
|
||||
.weavingFunction(protoContext.parent()::weaveEntry)
|
||||
.build();
|
||||
return Objects.requireNonNullElseGet(
|
||||
compoundWeaver.weaveEntry(valueType, context),
|
||||
() -> new SimpleConfigEntryImpl<>(context.configContainer(), valueType.declaredType())
|
||||
);
|
||||
}
|
||||
}
|
||||
}, mock(ConfigContainer.class))
|
||||
})
|
||||
.extensionsData(weavingContextExtensionDataFactory.create())
|
||||
.annotations(Compound.class)
|
||||
.path(new String[0])
|
||||
.configContainer(mock(ConfigContainer.class))
|
||||
.build();
|
||||
|
||||
ConfigEntry<Compound> resultEntry = compoundWeaver.weaveEntry(ActualType.ofClass(Compound.class), weavingContext);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
@NullMarked
|
||||
|
||||
package de.siphalor.tweed5.weaver.pojo.api.weaving;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -4,10 +4,10 @@ import com.google.auto.service.AutoService;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.DefaultWeavingExtensions;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeavingExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.CollectionPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.CompoundPojoWeaver;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.weaving.TrivialPojoWeaver;
|
||||
import lombok.Data;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -65,6 +65,7 @@ class TweedPojoWeaverBootstrapperTest {
|
||||
}
|
||||
|
||||
@PojoWeaving(extensions = {DummyExtension.class})
|
||||
@DefaultWeavingExtensions
|
||||
@CompoundWeaving(namingFormat = "camel_case")
|
||||
@Data
|
||||
public static class MainCompound {
|
||||
@@ -88,7 +89,9 @@ class TweedPojoWeaverBootstrapperTest {
|
||||
boolean somethingElse;
|
||||
}
|
||||
|
||||
@PojoWeaving(weavers = {CompoundPojoWeaver.class, CollectionPojoWeaver.class, TrivialPojoWeaver.class})
|
||||
@PojoWeaving
|
||||
@PojoWeavingExtension(CollectionPojoWeaver.class)
|
||||
@DefaultWeavingExtensions
|
||||
@CompoundWeaving(namingFormat = "camel_case")
|
||||
@Data
|
||||
public static class CompoundWithList {
|
||||
|
||||
Reference in New Issue
Block a user