[weaver-pojo] Implement first prototype of POJO weaving
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -3,7 +3,6 @@ package de.siphalor.tweed5.core.api.container;
|
||||
public enum ConfigContainerSetupPhase {
|
||||
EXTENSIONS_SETUP,
|
||||
TREE_SETUP,
|
||||
SEALING_TREE,
|
||||
TREE_SEALED,
|
||||
READY,
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user