[weaver-pojo] Implement first prototype of POJO weaving

This commit is contained in:
2024-10-20 21:30:00 +02:00
parent 37d64502ad
commit 002f59ebd0
40 changed files with 2144 additions and 31 deletions

View File

@@ -0,0 +1,224 @@
package de.siphalor.tweed5.core.api.collection;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
@RequiredArgsConstructor
public class TypedMultimap<T> implements Collection<T> {
private static final TypedMultimap<Object> EMPTY = unmodifiable(new TypedMultimap<>(Collections.emptyMap(), ArrayList::new));
protected final Map<Class<? extends T>, Collection<T>> delegate;
protected final Supplier<Collection<T>> collectionSupplier;
public static <T> TypedMultimap<T> unmodifiable(TypedMultimap<T> map) {
return new Unmodifiable<>(map.delegate, map.collectionSupplier);
}
public static <T> TypedMultimap<T> empty() {
return (TypedMultimap<T>) EMPTY;
}
public int size() {
return (int) delegate.values().stream().mapToLong(Collection::size).sum();
}
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(@NotNull Object o) {
return delegate.getOrDefault(o.getClass(), Collections.emptyList()).contains(o);
}
public Set<Class<? extends T>> classes() {
return delegate.keySet();
}
@Override
public @NotNull Iterator<T> iterator() {
return new Iterator<T>() {
private final Iterator<Map.Entry<Class<? extends T>, Collection<T>>> classIterator = delegate.entrySet().iterator();
private Iterator<? extends T> listIterator;
private boolean keptElement;
private boolean keptAnyElementInList;
@Override
public boolean hasNext() {
return classIterator.hasNext() || (listIterator != null && listIterator.hasNext());
}
@Override
public T next() {
if (keptElement) {
keptAnyElementInList = true;
}
if (listIterator == null || !listIterator.hasNext()) {
if (!keptAnyElementInList) {
classIterator.remove();
}
listIterator = classIterator.next().getValue().iterator();
keptAnyElementInList = false;
}
keptElement = true;
return listIterator.next();
}
@Override
public void remove() {
if (listIterator == null) {
throw new IllegalStateException("Iterator has not been called");
}
keptElement = false;
listIterator.remove();
}
};
}
@Override
@NotNull
public Object @NotNull [] toArray() {
return delegate.values().stream().flatMap(Collection::stream).toArray();
}
@Override
@NotNull
public <S> S @NotNull [] toArray(@NotNull S @NotNull [] array) {
Class<?> clazz = array.getClass().getComponentType();
return delegate.values().stream()
.flatMap(Collection::stream)
.toArray(size -> (S[]) Array.newInstance(clazz, size));
}
@Override
public boolean add(@NotNull T value) {
return delegate.computeIfAbsent(((Class<T>) value.getClass()), clazz -> collectionSupplier.get()).add(value);
}
@Override
public boolean remove(@NotNull Object value) {
Collection<T> values = delegate.get(value.getClass());
if (values == null) {
return false;
}
if (values.remove(value)) {
if (values.isEmpty()) {
delegate.remove(value.getClass());
}
return true;
}
return false;
}
@NotNull
public <U extends T> Collection<U> getAll(Class<U> clazz) {
return (Collection<U>) Collections.unmodifiableCollection(delegate.getOrDefault(clazz, Collections.emptyList()));
}
@NotNull
public Collection<T> removeAll(Class<? extends T> clazz) {
Collection<T> removed = delegate.remove(clazz);
return removed == null ? Collections.emptyList() : Collections.unmodifiableCollection(removed);
}
@Override
public boolean containsAll(@NotNull Collection<?> values) {
for (Object value : values) {
if (!contains(value)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(@NotNull Collection<? extends T> values) {
boolean changed = false;
for (T value : values) {
changed = add(value) || changed;
}
return changed;
}
@Override
public boolean removeAll(@NotNull Collection<?> values) {
boolean changed = false;
for (Object value : values) {
changed = remove(value) || changed;
}
return changed;
}
@Override
public boolean retainAll(@NotNull Collection<?> values) {
Map<? extends Class<?>, ? extends List<?>> valuesByClass = values.stream()
.collect(Collectors.groupingBy(Object::getClass));
delegate.putAll((Map<Class<? extends T>, List<T>>) valuesByClass);
delegate.keySet().removeIf(key -> !valuesByClass.containsKey(key));
return true;
}
@Override
public void clear() {
delegate.clear();
}
protected static class Unmodifiable<T> extends TypedMultimap<T> {
public Unmodifiable(
Map<Class<? extends T>, Collection<T>> delegate,
Supplier<Collection<T>> collectionSupplier
) {
super(delegate, collectionSupplier);
}
@Override
public @NotNull Iterator<T> iterator() {
return delegate.values().stream().flatMap(Collection::stream).iterator();
}
@Override
public boolean add(@NotNull T value) {
throw createUnsupportedOperationException();
}
@Override
public boolean remove(@NotNull Object value) {
throw createUnsupportedOperationException();
}
@Override
public @NotNull Collection<T> removeAll(Class<? extends T> clazz) {
throw createUnsupportedOperationException();
}
@Override
public boolean addAll(@NotNull Collection<? extends T> values) {
throw createUnsupportedOperationException();
}
@Override
public boolean removeAll(@NotNull Collection<?> values) {
throw createUnsupportedOperationException();
}
@Override
public boolean retainAll(@NotNull Collection<?> values) {
throw createUnsupportedOperationException();
}
@Override
public void clear() {
throw createUnsupportedOperationException();
}
protected UnsupportedOperationException createUnsupportedOperationException() {
return new UnsupportedOperationException("Map is unmodifiable");
}
}
}

View File

@@ -8,12 +8,24 @@ import de.siphalor.tweed5.core.api.extension.TweedExtension;
import java.util.Collection;
import java.util.Map;
/**
* The main wrapper for a config tree.<br />
* Holds certain global metadata like registered extensions and manages the initialization phases.
* @param <T> The class that the config tree represents
* @see ConfigContainerSetupPhase
*/
public interface ConfigContainer<T> {
ConfigContainerSetupPhase setupPhase();
default boolean isReady() {
return setupPhase() == ConfigContainerSetupPhase.READY;
}
default void registerExtensions(TweedExtension... extensions) {
for (TweedExtension extension : extensions) {
registerExtension(extension);
}
}
void registerExtension(TweedExtension extension);
void finishExtensionSetup();

View File

@@ -3,7 +3,6 @@ package de.siphalor.tweed5.core.api.container;
public enum ConfigContainerSetupPhase {
EXTENSIONS_SETUP,
TREE_SETUP,
SEALING_TREE,
TREE_SEALED,
READY,
}

View File

@@ -1,7 +1,6 @@
package de.siphalor.tweed5.core.impl.entry;
package de.siphalor.tweed5.core.api.entry;
import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -9,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor
@Getter
abstract class BaseConfigEntryImpl<T> implements ConfigEntry<T> {
public abstract class BaseConfigEntry<T> implements ConfigEntry<T> {
@NotNull
private final Class<T> valueClass;

View File

@@ -110,16 +110,18 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
}
private void finishEntrySetup() {
setupPhase = ConfigContainerSetupPhase.SEALING_TREE;
rootEntry.visitInOrder(entry -> entry.seal(DefaultConfigContainer.this));
rootEntry.visitInOrder(entry -> {
if (!entry.sealed()) {
entry.seal(DefaultConfigContainer.this);
}
});
setupPhase = ConfigContainerSetupPhase.TREE_SEALED;
}
@Override
public EntryExtensionsData createExtensionsData() {
requireSetupPhase(ConfigContainerSetupPhase.SEALING_TREE);
requireSetupPhase(ConfigContainerSetupPhase.TREE_SETUP);
try {
return (EntryExtensionsData) entryExtensionsDataPatchworkClass.constructor().invoke();

View File

@@ -1,15 +1,12 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.CoherentCollectionConfigEntry;
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.core.api.entry.*;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.IntFunction;
public class CoherentCollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntryImpl<T> implements CoherentCollectionConfigEntry<E, T> {
public class CoherentCollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements CoherentCollectionConfigEntry<E, T> {
private final IntFunction<T> collectionConstructor;
private ConfigEntry<E> elementEntry;

View File

@@ -1,9 +1,6 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
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.core.api.entry.*;
import lombok.Getter;
import lombok.Value;
import org.jetbrains.annotations.NotNull;
@@ -16,7 +13,7 @@ import java.util.Map;
import java.util.stream.Collectors;
@Getter
public class ReflectiveCompoundConfigEntryImpl<T> extends BaseConfigEntryImpl<T> implements CompoundConfigEntry<T> {
public class ReflectiveCompoundConfigEntryImpl<T> extends BaseConfigEntry<T> implements CompoundConfigEntry<T> {
private final Constructor<T> noArgsConstructor;
private final Map<String, CompoundEntry> compoundEntries;

View File

@@ -1,11 +1,12 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
import org.jetbrains.annotations.NotNull;
public class SimpleConfigEntryImpl<T> extends BaseConfigEntryImpl<T> implements SimpleConfigEntry<T> {
public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements SimpleConfigEntry<T> {
public SimpleConfigEntryImpl(Class<T> valueClass) {
super(valueClass);
}

View File

@@ -1,16 +1,13 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
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.core.api.entry.*;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.IntFunction;
public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> extends BaseConfigEntryImpl<T> implements CompoundConfigEntry<T> {
public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> extends BaseConfigEntry<T> implements CompoundConfigEntry<T> {
private final IntFunction<T> mapConstructor;
private final Map<String, ConfigEntry<?>> compoundEntries = new LinkedHashMap<>();