diff --git a/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/annotation/CoherentCollectionWeaving.java b/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/annotation/CoherentCollectionWeaving.java
new file mode 100644
index 0000000..7685143
--- /dev/null
+++ b/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/annotation/CoherentCollectionWeaving.java
@@ -0,0 +1,14 @@
+package de.siphalor.tweed5.weaver.pojo.api.annotation;
+
+import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCoherentCollectionConfigEntry;
+
+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.TYPE_USE})
+public @interface CoherentCollectionWeaving {
+ Class extends WeavableCoherentCollectionConfigEntry> entryClass() default WeavableCoherentCollectionConfigEntry.class;
+}
diff --git a/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/entry/WeavableCoherentCollectionConfigEntry.java b/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/entry/WeavableCoherentCollectionConfigEntry.java
new file mode 100644
index 0000000..c6831b6
--- /dev/null
+++ b/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/entry/WeavableCoherentCollectionConfigEntry.java
@@ -0,0 +1,40 @@
+package de.siphalor.tweed5.weaver.pojo.api.entry;
+
+import de.siphalor.tweed5.core.api.entry.CoherentCollectionConfigEntry;
+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;
+
+/**
+ * {@inheritDoc}
+ *
+ * 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 WeavableCoherentCollectionConfigEntry>
+ extends CoherentCollectionConfigEntry {
+ static , C extends WeavableCoherentCollectionConfigEntry> C instantiate(
+ Class weavableClass, Class valueClass, IntFunction constructor
+ ) throws PojoWeavingException {
+ try {
+ Constructor 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
+ );
+ }
+ }
+
+ void elementEntry(ConfigEntry elementEntry);
+}
diff --git a/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/weaving/CoherentCollectionPojoWeaver.java b/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/weaving/CoherentCollectionPojoWeaver.java
new file mode 100644
index 0000000..e3757e9
--- /dev/null
+++ b/tweed5-weaver-pojo/src/main/java/de/siphalor/tweed5/weaver/pojo/api/weaving/CoherentCollectionPojoWeaver.java
@@ -0,0 +1,125 @@
+package de.siphalor.tweed5.weaver.pojo.api.weaving;
+
+import de.siphalor.tweed5.core.api.entry.ConfigEntry;
+import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
+import de.siphalor.tweed5.typeutils.api.type.ActualType;
+import de.siphalor.tweed5.weaver.pojo.api.annotation.CoherentCollectionWeaving;
+import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCoherentCollectionConfigEntry;
+import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException;
+import de.siphalor.tweed5.weaver.pojo.impl.weaving.coherentcollection.CoherentCollectionWeavingConfig;
+import de.siphalor.tweed5.weaver.pojo.impl.weaving.coherentcollection.CoherentCollectionWeavingConfigImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.AnnotatedElement;
+import java.util.*;
+import java.util.function.IntFunction;
+
+public class CoherentCollectionPojoWeaver implements TweedPojoWeaver {
+ private static final CoherentCollectionWeavingConfig DEFAULT_WEAVING_CONFIG = CoherentCollectionWeavingConfigImpl.builder()
+ .coherentCollectionEntryClass(de.siphalor.tweed5.weaver.pojo.impl.entry.CoherentCollectionConfigEntryImpl.class)
+ .build();
+
+ private RegisteredExtensionData weavingConfigAccess;
+
+ @Override
+ public void setup(SetupContext context) {
+ this.weavingConfigAccess = context.registerWeavingContextExtensionData(CoherentCollectionWeavingConfig.class);
+ }
+
+ @Override
+ public @Nullable ConfigEntry weaveEntry(ActualType valueType, WeavingContext context) {
+ List> collectionTypeParams = valueType.getTypesOfSuperArguments(Collection.class);
+ if (collectionTypeParams == null) {
+ return null;
+ }
+ try {
+ CoherentCollectionWeavingConfig weavingConfig = getOrCreateWeavingConfig(context);
+ WeavingContext.ExtensionsData newExtensionsData = context.extensionsData().copy();
+ weavingConfigAccess.set(newExtensionsData, weavingConfig);
+
+ IntFunction> constructor = getCollectionConstructor(valueType);
+
+ //noinspection unchecked,rawtypes
+ WeavableCoherentCollectionConfigEntry configEntry = WeavableCoherentCollectionConfigEntry.instantiate(
+ (Class) weavingConfig.coherentCollectionEntryClass(),
+ (Class) valueType.declaredType(),
+ constructor
+ );
+
+ configEntry.elementEntry(context.weaveEntry(
+ collectionTypeParams.get(0),
+ context.subContextBuilder("element")
+ .annotations(collectionTypeParams.get(0))
+ .extensionsData(newExtensionsData)
+ .build()
+ ));
+ configEntry.seal(context.configContainer());
+
+ return configEntry;
+ } catch (Exception e) {
+ throw new PojoWeavingException("Exception occurred trying to weave collectoin for class " + valueType, e);
+ }
+ }
+
+ private CoherentCollectionWeavingConfig getOrCreateWeavingConfig(WeavingContext context) {
+ CoherentCollectionWeavingConfig parent;
+ if (context.extensionsData().isPatchworkPartSet(CoherentCollectionWeavingConfig.class)) {
+ parent = (CoherentCollectionWeavingConfig) context.extensionsData();
+ } else {
+ parent = DEFAULT_WEAVING_CONFIG;
+ }
+
+ CoherentCollectionWeavingConfig local = createWeavingConfigFromAnnotations(context.annotations());
+ if (local == null) {
+ return parent;
+ }
+
+ return CoherentCollectionWeavingConfigImpl.withOverrides(parent, local);
+ }
+
+ private CoherentCollectionWeavingConfig createWeavingConfigFromAnnotations(@NotNull AnnotatedElement annotations) {
+ CoherentCollectionWeaving annotation = annotations.getAnnotation(CoherentCollectionWeaving.class);
+ if (annotation == null) {
+ return null;
+ }
+
+ CoherentCollectionWeavingConfigImpl.CoherentCollectionWeavingConfigImplBuilder builder = CoherentCollectionWeavingConfigImpl.builder();
+ if (annotation.entryClass() != null) {
+ builder.coherentCollectionEntryClass(annotation.entryClass());
+ }
+
+ return builder.build();
+ }
+
+ public IntFunction> getCollectionConstructor(ActualType> type) {
+ if (type.declaredType() == List.class) {
+ return ArrayList::new;
+ } else if (type.declaredType() == Set.class) {
+ return capacity -> new HashSet<>((int) Math.ceil(capacity * 1.4), 0.75F);
+ }
+ try {
+ return findCompatibleConstructor(type);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new PojoWeavingException("could not find no args constructor for " + type, e);
+ }
+ }
+
+ public IntFunction> findCompatibleConstructor(ActualType> type) throws
+ NoSuchMethodException,
+ IllegalAccessException {
+ MethodHandles.Lookup lookup = MethodHandles.publicLookup();
+ MethodHandle constructor = lookup.findConstructor(type.declaredType(), MethodType.methodType(Void.class));
+ return capacity -> {
+ try {
+ //noinspection unchecked
+ return (Collection