[patchwork, core, extensions] Hugely simplify Patchworks

This commit is contained in:
2025-06-13 22:04:16 +02:00
parent 694f993b8c
commit 6e5c9a23c2
72 changed files with 987 additions and 1977 deletions

View File

@@ -2,7 +2,8 @@ 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.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
import de.siphalor.tweed5.typeutils.api.type.ActualType;
import de.siphalor.tweed5.weaver.pojo.api.annotation.CollectionWeaving;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCollectionConfigEntry;
@@ -24,24 +25,27 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
.collectionEntryClass(CollectionConfigEntryImpl.class)
.build();
private RegisteredExtensionData<WeavingContext.ExtensionsData, CollectionWeavingConfig> weavingConfigAccess;
@Nullable
private PatchworkPartAccess<CollectionWeavingConfig> weavingConfigAccess;
@Override
public void setup(SetupContext context) {
this.weavingConfigAccess = context.registerWeavingContextExtensionData(CollectionWeavingConfig.class);
}
@SuppressWarnings({"rawtypes", "unchecked"})
@SuppressWarnings({"unchecked"})
@Override
public <T> @Nullable ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
assert weavingConfigAccess != null;
List<ActualType<?>> collectionTypeParams = valueType.getTypesOfSuperArguments(Collection.class);
if (collectionTypeParams == null) {
return null;
}
try {
CollectionWeavingConfig weavingConfig = getOrCreateWeavingConfig(context);
WeavingContext.ExtensionsData newExtensionsData = context.extensionsData().copy();
weavingConfigAccess.set(newExtensionsData, weavingConfig);
Patchwork newExtensionsData = context.extensionsData().copy();
newExtensionsData.set(weavingConfigAccess, weavingConfig);
IntFunction<Collection<Object>> constructor = getCollectionConstructor(valueType);
@@ -66,10 +70,10 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
}
private CollectionWeavingConfig getOrCreateWeavingConfig(WeavingContext context) {
CollectionWeavingConfig parent;
if (context.extensionsData().isPatchworkPartSet(CollectionWeavingConfig.class)) {
parent = (CollectionWeavingConfig) context.extensionsData();
} else {
assert weavingConfigAccess != null;
CollectionWeavingConfig parent = context.extensionsData().get(weavingConfigAccess);
if (parent == null) {
parent = DEFAULT_WEAVING_CONFIG;
}

View File

@@ -2,10 +2,11 @@ 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.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.namingformat.api.NamingFormat;
import de.siphalor.tweed5.namingformat.api.NamingFormatCollector;
import de.siphalor.tweed5.namingformat.api.NamingFormats;
import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
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;
@@ -22,7 +23,6 @@ import java.lang.invoke.MethodHandle;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -37,7 +37,8 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
.build();
private final NamingFormatCollector namingFormatCollector = new NamingFormatCollector();
private RegisteredExtensionData<WeavingContext.ExtensionsData, CompoundWeavingConfig> weavingConfigAccess;
@Nullable
private PatchworkPartAccess<CompoundWeavingConfig> weavingConfigAccess;
public void setup(SetupContext context) {
namingFormatCollector.setupFormats();
@@ -47,13 +48,15 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
@Override
public <T> @Nullable ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
assert weavingConfigAccess != null;
if (context.annotations().getAnnotation(CompoundWeaving.class) == null) {
return null;
}
try {
CompoundWeavingConfig weavingConfig = getOrCreateWeavingConfig(context);
WeavingContext.ExtensionsData newExtensionsData = context.extensionsData().copy();
weavingConfigAccess.set(newExtensionsData, weavingConfig);
Patchwork newExtensionsData = context.extensionsData().copy();
newExtensionsData.set(weavingConfigAccess, weavingConfig);
PojoClassIntrospector introspector = PojoClassIntrospector.forClass(valueType.declaredType());
@@ -69,10 +72,10 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
}
private CompoundWeavingConfig getOrCreateWeavingConfig(WeavingContext context) {
CompoundWeavingConfig parent;
if (context.extensionsData().isPatchworkPartSet(CompoundWeavingConfig.class)) {
parent = (CompoundWeavingConfig) context.extensionsData();
} else {
assert weavingConfigAccess != null;
CompoundWeavingConfig parent = context.extensionsData().get(weavingConfigAccess);
if (parent == null) {
parent = DEFAULT_WEAVING_CONFIG;
}
@@ -143,10 +146,14 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
private WeavableCompoundConfigEntry.SubEntry weaveCompoundSubEntry(
PojoClassIntrospector.Property property,
WeavingContext.ExtensionsData newExtensionsData,
Patchwork newExtensionsData,
WeavingContext parentContext
) {
String name = convertName(property.field().getName(), (CompoundWeavingConfig) newExtensionsData);
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;
@@ -189,7 +196,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
private WeavingContext createSubContextForProperty(
PojoClassIntrospector.Property property,
String name,
WeavingContext.ExtensionsData newExtensionsData,
Patchwork newExtensionsData,
WeavingContext parentContext
) {
return parentContext.subContextBuilder(name)

View File

@@ -1,7 +1,8 @@
package de.siphalor.tweed5.weaver.pojo.api.weaving;
import de.siphalor.tweed5.construct.api.TweedConstructFactory;
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.patchwork.api.PatchworkFactory;
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
import org.jetbrains.annotations.ApiStatus;
public interface TweedPojoWeaver extends TweedPojoWeavingFunction {
@@ -11,6 +12,6 @@ public interface TweedPojoWeaver extends TweedPojoWeavingFunction {
void setup(SetupContext context);
interface SetupContext {
<E> RegisteredExtensionData<WeavingContext.ExtensionsData, E> registerWeavingContextExtensionData(Class<E> dataClass);
<E> PatchworkPartAccess<E> registerWeavingContextExtensionData(Class<E> dataClass);
}
}

View File

@@ -18,7 +18,7 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
TweedPojoWeavingFunction.NonNull weavingFunction;
ConfigContainer<?> configContainer;
String[] path;
ExtensionsData extensionsData;
Patchwork extensionsData;
AnnotatedElement annotations;
public static Builder builder(TweedPojoWeavingFunction.NonNull weavingFunction, ConfigContainer<?> configContainer) {
@@ -40,8 +40,6 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
return weavingFunction.weaveEntry(valueType, context);
}
public interface ExtensionsData extends Patchwork<ExtensionsData> {}
@Accessors(fluent = true, chain = true)
@Setter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@@ -51,7 +49,7 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
private final TweedPojoWeavingFunction.NonNull weavingFunction;
private final ConfigContainer<?> configContainer;
private final String[] path;
private ExtensionsData extensionsData;
private Patchwork extensionsData;
private AnnotatedElement annotations;
public WeavingContext build() {

View File

@@ -62,7 +62,7 @@ public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseC
}
@Override
public @NotNull T deepCopy(@NotNull T value) {
public @NotNull T deepCopy(T value) {
T copy = instantiateCollection(value.size());
for (E element : value) {
copy.add(elementEntry.deepCopy(element));

View File

@@ -7,6 +7,7 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
import org.jspecify.annotations.Nullable;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -97,7 +98,7 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
}
@Override
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
public void visitInOrder(ConfigEntryValueVisitor visitor, @Nullable T value) {
if (visitor.enterCompoundEntry(this, value)) {
subEntries.forEach((key, entry) -> {
if (visitor.enterCompoundSubEntry(key)) {

View File

@@ -2,22 +2,21 @@ package de.siphalor.tweed5.weaver.pojo.impl.weaving;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
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.weaver.pojo.api.annotation.PojoWeaving;
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.weaving.WeavingContext;
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
import lombok.*;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.Nullable;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
/**
@@ -31,7 +30,8 @@ public class TweedPojoWeaverBootstrapper<T> {
private final ConfigContainer<T> configContainer;
private final Collection<TweedPojoWeaver> weavers;
private final Collection<TweedPojoWeavingPostProcessor> postProcessors;
private PatchworkClass<WeavingContext.ExtensionsData> contextExtensionsDataClass;
@Nullable
private PatchworkFactory contextExtensionsPatchworkFactory;
public static <T> TweedPojoWeaverBootstrapper<T> create(Class<T> pojoClass) {
PojoWeaving rootWeavingConfig = expectAnnotation(pojoClass, PojoWeaving.class);
@@ -88,44 +88,21 @@ public class TweedPojoWeaverBootstrapper<T> {
}
private void setupWeavers() {
Map<Class<?>, RegisteredExtensionDataImpl<?>> registeredExtensions = new HashMap<>();
PatchworkFactory.Builder contextExtensionsPatchworkFactoryBuilder = PatchworkFactory.builder();
TweedPojoWeaver.SetupContext setupContext = new TweedPojoWeaver.SetupContext() {
@Override
public <E> RegisteredExtensionData<WeavingContext.ExtensionsData, E> registerWeavingContextExtensionData(
Class<E> dataClass
) {
RegisteredExtensionDataImpl<E> registeredExtension = new RegisteredExtensionDataImpl<>();
registeredExtensions.put(dataClass, registeredExtension);
return registeredExtension;
}
};
TweedPojoWeaver.SetupContext setupContext = contextExtensionsPatchworkFactoryBuilder::registerPart;
for (TweedPojoWeaver weaver : weavers) {
weaver.setup(setupContext);
}
PatchworkClassCreator<WeavingContext.ExtensionsData> weavingContextCreator = PatchworkClassCreator.<WeavingContext.ExtensionsData>builder()
.classPackage(this.getClass().getPackage().getName() + ".generated")
.classPrefix("WeavingContext$")
.patchworkInterface(WeavingContext.ExtensionsData.class)
.build();
try {
this.contextExtensionsDataClass = weavingContextCreator.createClass(registeredExtensions.keySet());
for (PatchworkClassPart part : this.contextExtensionsDataClass.parts()) {
RegisteredExtensionDataImpl<?> registeredExtension = registeredExtensions.get(part.partInterface());
registeredExtension.setter(part.fieldSetter());
}
} catch (PatchworkClassGenerator.GenerationException e) {
throw new PojoWeavingException("Failed to create weaving context extensions data");
}
contextExtensionsPatchworkFactory = contextExtensionsPatchworkFactoryBuilder.build();
}
private WeavingContext createWeavingContext() {
try {
WeavingContext.ExtensionsData extensionsData = (WeavingContext.ExtensionsData) contextExtensionsDataClass.constructor().invoke();
assert contextExtensionsPatchworkFactory != null;
Patchwork extensionsData = contextExtensionsPatchworkFactory.create();
return WeavingContext.builder(this::weaveEntry, configContainer)
.extensionsData(extensionsData)
@@ -157,18 +134,4 @@ public class TweedPojoWeaverBootstrapper<T> {
}
}
}
@Setter
private static class RegisteredExtensionDataImpl<E> implements RegisteredExtensionData<WeavingContext.ExtensionsData, E> {
private MethodHandle setter;
@Override
public void set(WeavingContext.ExtensionsData patchwork, E extension) {
try {
setter.invokeWithArguments(patchwork, extension);
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
}
}

View File

@@ -2,24 +2,18 @@ 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.api.entry.SimpleConfigEntry;
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
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.patchwork.api.PatchworkFactory;
import de.siphalor.tweed5.typeutils.api.type.ActualType;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfig;
import lombok.AllArgsConstructor;
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullUnmarked;
import org.junit.jupiter.api.Test;
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;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
@SuppressWarnings("unused")
@NullUnmarked
@@ -27,13 +21,12 @@ class CompoundPojoWeaverTest {
@Test
void weave() {
PatchworkFactory.Builder weavingContextExtensionDataFactoryBuilder = PatchworkFactory.builder();
CompoundPojoWeaver compoundWeaver = new CompoundPojoWeaver();
compoundWeaver.setup(new TweedPojoWeaver.SetupContext() {
@Override
public <E> RegisteredExtensionData<WeavingContext.ExtensionsData, E> registerWeavingContextExtensionData(Class<E> dataClass) {
return (patchwork, extension) -> ((ExtensionsDataMock) patchwork).weavingConfig = (CompoundWeavingConfig) extension;
}
});
compoundWeaver.setup(weavingContextExtensionDataFactoryBuilder::registerPart);
PatchworkFactory weavingContextExtensionDataFactory = weavingContextExtensionDataFactoryBuilder.build();
WeavingContext weavingContext = WeavingContext.builder(new TweedPojoWeavingFunction.NonNull() {
@Override
@@ -46,7 +39,7 @@ class CompoundPojoWeaverTest {
}
}
}, mock(ConfigContainer.class))
.extensionsData(new ExtensionsDataMock(null))
.extensionsData(weavingContextExtensionDataFactory.create())
.annotations(Compound.class)
.build();
@@ -86,39 +79,4 @@ class CompoundPojoWeaverTest {
public static class InnerValue {
public Integer value;
}
@AllArgsConstructor
private static class ExtensionsDataMock implements WeavingContext.ExtensionsData, CompoundWeavingConfig {
private CompoundWeavingConfig weavingConfig;
@Override
public boolean isPatchworkPartDefined(Class<?> patchworkInterface) {
return patchworkInterface == CompoundWeavingConfig.class;
}
@Override
public boolean isPatchworkPartSet(Class<?> patchworkInterface) {
return weavingConfig != null;
}
@Override
public WeavingContext.ExtensionsData copy() {
return new ExtensionsDataMock(weavingConfig);
}
@Override
public NamingFormat compoundSourceNamingFormat() {
return weavingConfig.compoundSourceNamingFormat();
}
@Override
public NamingFormat compoundTargetNamingFormat() {
return weavingConfig.compoundTargetNamingFormat();
}
@Override
public @Nullable Class<? extends WeavableCompoundConfigEntry> compoundEntryClass() {
return weavingConfig.compoundEntryClass();
}
}
}