[weaver-pojo] Coherent collection weaving
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
* <br />
|
||||||
|
* 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<E, T extends Collection<E>>
|
||||||
|
extends CoherentCollectionConfigEntry<E, T> {
|
||||||
|
static <E, T extends Collection<E>, C extends WeavableCoherentCollectionConfigEntry<E, T>> C instantiate(
|
||||||
|
Class<C> weavableClass, Class<T> valueClass, IntFunction<T> constructor
|
||||||
|
) throws PojoWeavingException {
|
||||||
|
try {
|
||||||
|
Constructor<C> 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<E> elementEntry);
|
||||||
|
}
|
||||||
@@ -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<WeavingContext.ExtensionsData, CoherentCollectionWeavingConfig> weavingConfigAccess;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(SetupContext context) {
|
||||||
|
this.weavingConfigAccess = context.registerWeavingContextExtensionData(CoherentCollectionWeavingConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||||
|
List<ActualType<?>> 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<Collection<Object>> 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<Collection<Object>> 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<Collection<Object>> 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<Object>) constructor.invoke();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,6 +63,8 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
compoundEntry.seal(context.configContainer());
|
||||||
|
|
||||||
return compoundEntry;
|
return compoundEntry;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new PojoWeavingException("Exception occurred trying to weave compound for class " + valueType, e);
|
throw new PojoWeavingException("Exception occurred trying to weave compound for class " + valueType, e);
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ public class TrivialPojoWeaver implements TweedPojoWeaver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
|
||||||
return new SimpleConfigEntryImpl<>(valueType.declaredType());
|
SimpleConfigEntryImpl<T> entry = new SimpleConfigEntryImpl<>(valueType.declaredType());
|
||||||
|
entry.seal(context.configContainer());
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
|
|||||||
return new Builder(null, weavingFunction, configContainer, new String[]{ baseName });
|
return new Builder(null, weavingFunction, configContainer, new String[]{ baseName });
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder subContextBuilder(String subPathName) {
|
public Builder subContextBuilder(@NotNull String subPathName) {
|
||||||
String[] newPath = Arrays.copyOf(path, path.length + 1);
|
String[] newPath = Arrays.copyOf(path, path.length + 1);
|
||||||
newPath[path.length] = subPathName;
|
newPath[path.length] = subPathName;
|
||||||
return new Builder(this, weavingFunction, configContainer, newPath).extensionsData(extensionsData);
|
return new Builder(this, weavingFunction, configContainer, newPath).extensionsData(extensionsData);
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package de.siphalor.tweed5.weaver.pojo.impl.entry;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
|
||||||
|
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.WeavableCoherentCollectionConfigEntry;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class CoherentCollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements WeavableCoherentCollectionConfigEntry<E, T> {
|
||||||
|
private final IntFunction<T> constructor;
|
||||||
|
private ConfigEntry<E> elementEntry;
|
||||||
|
|
||||||
|
public CoherentCollectionConfigEntryImpl(@NotNull Class<T> valueClass, IntFunction<T> constructor) {
|
||||||
|
super(valueClass);
|
||||||
|
this.constructor = constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void elementEntry(ConfigEntry<E> elementEntry) {
|
||||||
|
this.elementEntry = elementEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T instantiateCollection(int size) {
|
||||||
|
try {
|
||||||
|
return constructor.apply(size);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new IllegalStateException("Failed to instantiate collection class", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInOrder(ConfigEntryVisitor visitor) {
|
||||||
|
if (visitor.enterCollectionEntry(this)) {
|
||||||
|
elementEntry.visitInOrder(visitor);
|
||||||
|
visitor.leaveCollectionEntry(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||||
|
if (visitor.enterCollectionEntry(this, value)) {
|
||||||
|
for (E element : value) {
|
||||||
|
elementEntry.visitInOrder(visitor, element);
|
||||||
|
}
|
||||||
|
visitor.leaveCollectionEntry(this, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull T deepCopy(@NotNull T value) {
|
||||||
|
T copy = instantiateCollection(value.size());
|
||||||
|
for (E element : value) {
|
||||||
|
copy.add(elementEntry.deepCopy(element));
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package de.siphalor.tweed5.weaver.pojo.impl.weaving.coherentcollection;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCoherentCollectionConfigEntry;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public interface CoherentCollectionWeavingConfig {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Nullable
|
||||||
|
Class<? extends WeavableCoherentCollectionConfigEntry> coherentCollectionEntryClass();
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package de.siphalor.tweed5.weaver.pojo.impl.weaving.coherentcollection;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCoherentCollectionConfigEntry;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Value;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Value
|
||||||
|
public class CoherentCollectionWeavingConfigImpl implements CoherentCollectionWeavingConfig {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Nullable
|
||||||
|
Class<? extends WeavableCoherentCollectionConfigEntry> coherentCollectionEntryClass;
|
||||||
|
|
||||||
|
public static CoherentCollectionWeavingConfigImpl withOverrides(CoherentCollectionWeavingConfig self, CoherentCollectionWeavingConfig overrides) {
|
||||||
|
return CoherentCollectionWeavingConfigImpl.builder()
|
||||||
|
.coherentCollectionEntryClass(overrides.coherentCollectionEntryClass() != null ? overrides.coherentCollectionEntryClass() : self.coherentCollectionEntryClass())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
@Builder
|
@Builder
|
||||||
@Value
|
@Value
|
||||||
public class CompoundWeavingConfigImpl implements CompoundWeavingConfig {
|
public class CompoundWeavingConfigImpl implements CompoundWeavingConfig {
|
||||||
private static final CompoundWeavingConfigImpl EMPTY = CompoundWeavingConfigImpl.builder().build();
|
|
||||||
|
|
||||||
NamingFormat compoundSourceNamingFormat;
|
NamingFormat compoundSourceNamingFormat;
|
||||||
NamingFormat compoundTargetNamingFormat;
|
NamingFormat compoundTargetNamingFormat;
|
||||||
|
|||||||
@@ -5,30 +5,35 @@ import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
|||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
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.CompoundWeaving;
|
||||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.weaving.CoherentCollectionPojoWeaver;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.weaving.CompoundPojoWeaver;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.weaving.TrivialPojoWeaver;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.weaver.pojo.test.ConfigEntryAssertions.isCompoundEntryForClassWith;
|
import java.util.List;
|
||||||
import static de.siphalor.tweed5.weaver.pojo.test.ConfigEntryAssertions.isSimpleEntryForClass;
|
|
||||||
|
import static de.siphalor.tweed5.weaver.pojo.test.ConfigEntryAssertions.*;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
class TweedPojoWeaverBootstrapperTest {
|
class TweedPojoWeaverBootstrapperTest {
|
||||||
@Test
|
@Test
|
||||||
void defaultWeaving() {
|
void defaultWeaving() {
|
||||||
TweedPojoWeaverBootstrapper<DefaultWeaving> bootstrapper = TweedPojoWeaverBootstrapper.create(DefaultWeaving.class);
|
TweedPojoWeaverBootstrapper<MainCompound> bootstrapper = TweedPojoWeaverBootstrapper.create(MainCompound.class);
|
||||||
ConfigContainer<DefaultWeaving> configContainer = bootstrapper.weave();
|
ConfigContainer<MainCompound> configContainer = bootstrapper.weave();
|
||||||
|
|
||||||
assertThat(configContainer.rootEntry()).satisfies(isCompoundEntryForClassWith(DefaultWeaving.class, rootCompound ->
|
assertThat(configContainer.rootEntry()).satisfies(isCompoundEntryForClassWith(MainCompound.class, rootCompound ->
|
||||||
assertThat(rootCompound.subEntries())
|
assertThat(rootCompound.subEntries())
|
||||||
.hasEntrySatisfying("primitiveInteger", isSimpleEntryForClass(int.class))
|
.hasEntrySatisfying("primitiveInteger", isSimpleEntryForClass(int.class))
|
||||||
.hasEntrySatisfying("boxedDouble", isSimpleEntryForClass(Double.class))
|
.hasEntrySatisfying("boxedDouble", isSimpleEntryForClass(Double.class))
|
||||||
.hasEntrySatisfying("value", isSimpleEntryForClass(InnerValue.class))
|
.hasEntrySatisfying("value", isSimpleEntryForClass(InnerValue.class))
|
||||||
.hasEntrySatisfying("compound", isCompoundEntryForClassWith(InnerCompound.class, innerCompound ->
|
.hasEntrySatisfying("list", isSimpleEntryForClass(List.class))
|
||||||
assertThat(innerCompound.subEntries())
|
.hasEntrySatisfying("compound", isCompoundEntryForClassWith(InnerCompound.class, innerCompound ->
|
||||||
.hasEntrySatisfying("string", isSimpleEntryForClass(String.class))
|
assertThat(innerCompound.subEntries())
|
||||||
.hasSize(1)))
|
.hasEntrySatisfying("string", isSimpleEntryForClass(String.class))
|
||||||
.hasSize(4)
|
.hasSize(1)))
|
||||||
|
.hasSize(5)
|
||||||
));
|
));
|
||||||
|
|
||||||
configContainer.initialize();
|
configContainer.initialize();
|
||||||
@@ -38,6 +43,21 @@ class TweedPojoWeaverBootstrapperTest {
|
|||||||
.hasSize(1);
|
.hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void weavingWithList() {
|
||||||
|
TweedPojoWeaverBootstrapper<CompoundWithList> bootstrapper = TweedPojoWeaverBootstrapper.create(CompoundWithList.class);
|
||||||
|
ConfigContainer<CompoundWithList> configContainer = bootstrapper.weave();
|
||||||
|
|
||||||
|
assertThat(configContainer.rootEntry()).satisfies(isCompoundEntryForClassWith(CompoundWithList.class, rootCompound ->
|
||||||
|
assertThat(rootCompound.subEntries())
|
||||||
|
.hasEntrySatisfying("strings", isCollectionEntryForClass(
|
||||||
|
List.class,
|
||||||
|
list -> assertThat(list.elementEntry()).satisfies(isSimpleEntryForClass(String.class))
|
||||||
|
|
||||||
|
))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@AutoService(DummyExtension.class)
|
@AutoService(DummyExtension.class)
|
||||||
public static class DummyExtension implements TweedExtension {
|
public static class DummyExtension implements TweedExtension {
|
||||||
@Override
|
@Override
|
||||||
@@ -49,10 +69,11 @@ class TweedPojoWeaverBootstrapperTest {
|
|||||||
@PojoWeaving(extensions = {DummyExtension.class})
|
@PojoWeaving(extensions = {DummyExtension.class})
|
||||||
@CompoundWeaving(namingFormat = "camel_case")
|
@CompoundWeaving(namingFormat = "camel_case")
|
||||||
@Data
|
@Data
|
||||||
public static class DefaultWeaving {
|
public static class MainCompound {
|
||||||
int primitiveInteger;
|
int primitiveInteger;
|
||||||
Double boxedDouble;
|
Double boxedDouble;
|
||||||
InnerValue value;
|
InnerValue value;
|
||||||
|
List<Integer> list;
|
||||||
|
|
||||||
InnerCompound compound;
|
InnerCompound compound;
|
||||||
}
|
}
|
||||||
@@ -68,4 +89,11 @@ class TweedPojoWeaverBootstrapperTest {
|
|||||||
int something;
|
int something;
|
||||||
boolean somethingElse;
|
boolean somethingElse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PojoWeaving(weavers = {CompoundPojoWeaver.class, CoherentCollectionPojoWeaver.class, TrivialPojoWeaver.class})
|
||||||
|
@CompoundWeaving(namingFormat = "camel_case")
|
||||||
|
@Data
|
||||||
|
public static class CompoundWithList {
|
||||||
|
List<String> strings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package de.siphalor.tweed5.weaver.pojo.test;
|
package de.siphalor.tweed5.weaver.pojo.test;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.CoherentCollectionConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
|
||||||
|
import de.siphalor.tweed5.weaver.pojo.api.weaving.CoherentCollectionPojoWeaver;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -33,4 +36,20 @@ public class ConfigEntryAssertions {
|
|||||||
condition::accept
|
condition::accept
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Consumer<Object> isCollectionEntryForClass(
|
||||||
|
Class<?> collectionClass,
|
||||||
|
Consumer<CoherentCollectionConfigEntry<?, ?>> condition
|
||||||
|
) {
|
||||||
|
return object -> assertThat(object)
|
||||||
|
.as("Should be a collection config entry for class " + collectionClass.getName())
|
||||||
|
.asInstanceOf(type(CoherentCollectionConfigEntry.class))
|
||||||
|
.as("Collection entry for class " + collectionClass.getSimpleName())
|
||||||
|
.satisfies(
|
||||||
|
listEntry -> assertThat(listEntry.valueClass())
|
||||||
|
.as("Value class of collection entry should match")
|
||||||
|
.isEqualTo(collectionClass),
|
||||||
|
condition::accept
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user