[*] Migrate to jspecify annotations

This commit is contained in:
2025-04-24 21:52:33 +02:00
parent cef5227bf1
commit c97f711c0b
100 changed files with 553 additions and 369 deletions

View File

@@ -35,7 +35,10 @@ dependencies {
testCompileOnly(libs.autoservice.annotations) testCompileOnly(libs.autoservice.annotations)
testAnnotationProcessor(libs.autoservice.processor) testAnnotationProcessor(libs.autoservice.processor)
implementation(libs.jetbrains.annotations) compileOnly(libs.jetbrains.annotations)
testImplementation(libs.jetbrains.annotations)
compileOnly(libs.jspecify.annotations)
testImplementation(libs.jspecify.annotations)
implementation(libs.slf4j.api) implementation(libs.slf4j.api)
"localRuntimeOnly"(libs.slf4j.rt) "localRuntimeOnly"(libs.slf4j.rt)

View File

@@ -4,6 +4,7 @@ asm = "9.7"
autoservice = "1.1.1" autoservice = "1.1.1"
java = "8" java = "8"
jetbrains-annotations = "26.0.1" jetbrains-annotations = "26.0.1"
jspecify = "1.0.0"
junit = "5.12.0" junit = "5.12.0"
lombok = "1.18.34" lombok = "1.18.34"
mockito = "5.14.2" mockito = "5.14.2"
@@ -19,6 +20,7 @@ asm-core = { group = "org.ow2.asm", name = "asm", version.ref = "asm" }
autoservice-annotations = { group = "com.google.auto.service", name = "auto-service-annotations", version.ref = "autoservice" } autoservice-annotations = { group = "com.google.auto.service", name = "auto-service-annotations", version.ref = "autoservice" }
autoservice-processor = { group = "com.google.auto.service", name = "auto-service", version.ref = "autoservice" } autoservice-processor = { group = "com.google.auto.service", name = "auto-service", version.ref = "autoservice" }
jetbrains-annotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrains-annotations" } jetbrains-annotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrains-annotations" }
jspecify-annotations = { group = "org.jspecify", name = "jspecify", version.ref = "jspecify" }
junit-platform = { group = "org.junit", name = "junit-bom", version.ref = "junit" } junit-platform = { group = "org.junit", name = "junit-bom", version.ref = "junit" }
junit-core = { group = "org.junit.jupiter", name = "junit-jupiter" } junit-core = { group = "org.junit.jupiter", name = "junit-jupiter" }
junit-launcher = { group = "org.junit.platform", name = "junit-platform-launcher" } junit-launcher = { group = "org.junit.platform", name = "junit-platform-launcher" }

View File

@@ -3,8 +3,7 @@ package de.siphalor.tweed5.construct.api;
import de.siphalor.tweed5.construct.impl.TweedConstructFactoryImpl; import de.siphalor.tweed5.construct.impl.TweedConstructFactoryImpl;
import org.jetbrains.annotations.CheckReturnValue; import org.jetbrains.annotations.CheckReturnValue;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
/** /**
* A factory that allows to construct instances of subclasses of a specific type. * A factory that allows to construct instances of subclasses of a specific type.
@@ -20,7 +19,7 @@ public interface TweedConstructFactory<T> {
/** /**
* Starts building a new factory for the given base class. * Starts building a new factory for the given base class.
*/ */
static <T> TweedConstructFactory.@NotNull FactoryBuilder<T> builder(Class<T> baseClass) { static <T> TweedConstructFactory.FactoryBuilder<T> builder(Class<T> baseClass) {
return TweedConstructFactoryImpl.builder(baseClass); return TweedConstructFactoryImpl.builder(baseClass);
} }
@@ -30,7 +29,7 @@ public interface TweedConstructFactory<T> {
*/ */
@CheckReturnValue @CheckReturnValue
@Contract(pure = true) @Contract(pure = true)
<C extends T> @NotNull Construct<C> construct(@NotNull Class<C> subClass); <C extends T> Construct<C> construct(Class<C> subClass);
/** /**
* Builder for the factory. * Builder for the factory.
@@ -40,19 +39,19 @@ public interface TweedConstructFactory<T> {
* Defines a new typed argument of the given type. * Defines a new typed argument of the given type.
*/ */
@Contract(mutates = "this", value = "_ -> this") @Contract(mutates = "this", value = "_ -> this")
<A> @NotNull FactoryBuilder<T> typedArg(@NotNull Class<A> argType); <A> FactoryBuilder<T> typedArg(Class<A> argType);
/** /**
* Defines a new named argument with the given name and value type. * Defines a new named argument with the given name and value type.
*/ */
@Contract(mutates = "this", value = "_, _ -> this") @Contract(mutates = "this", value = "_, _ -> this")
<A> @NotNull FactoryBuilder<T> namedArg(@NotNull String name, @NotNull Class<A> argType); <A> FactoryBuilder<T> namedArg(String name, Class<A> argType);
/** /**
* Builds the factory. * Builds the factory.
*/ */
@Contract(pure = true) @Contract(pure = true)
@NotNull TweedConstructFactory<T> build(); TweedConstructFactory<T> build();
} }
/** /**
@@ -71,7 +70,7 @@ public interface TweedConstructFactory<T> {
* @see #namedArg(String, Object) * @see #namedArg(String, Object)
*/ */
@Contract(mutates = "this", value = "_ -> this") @Contract(mutates = "this", value = "_ -> this")
<A> @NotNull Construct<C> typedArg(@NotNull A value); <A> Construct<C> typedArg(A value);
/** /**
* Binds a value to a typed argument of the given type. * Binds a value to a typed argument of the given type.
@@ -81,19 +80,19 @@ public interface TweedConstructFactory<T> {
* @see #namedArg(String, Object) * @see #namedArg(String, Object)
*/ */
@Contract(mutates = "this", value = "_, _ -> this") @Contract(mutates = "this", value = "_, _ -> this")
<A> @NotNull Construct<C> typedArg(@NotNull Class<? super A> argType, @Nullable A value); <A> Construct<C> typedArg(Class<? super A> argType, @Nullable A value);
/** /**
* Binds a value to a named argument. * Binds a value to a named argument.
* @see #typedArg(Object) * @see #typedArg(Object)
*/ */
@Contract(mutates = "this", value = "_, _ -> this") @Contract(mutates = "this", value = "_, _ -> this")
<A> @NotNull Construct<C> namedArg(@NotNull String name, @Nullable A value); <A> Construct<C> namedArg(String name, @Nullable A value);
/** /**
* Finishes the binding and actually constructs the class. * Finishes the binding and actually constructs the class.
*/ */
@Contract(pure = true) @Contract(pure = true)
@NotNull C finish(); C finish();
} }
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.construct.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -4,8 +4,7 @@ import de.siphalor.tweed5.construct.api.ConstructParameter;
import de.siphalor.tweed5.construct.api.TweedConstruct; import de.siphalor.tweed5.construct.api.TweedConstruct;
import de.siphalor.tweed5.construct.api.TweedConstructFactory; import de.siphalor.tweed5.construct.api.TweedConstructFactory;
import lombok.*; import lombok.*;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@@ -37,11 +36,11 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
} }
@Override @Override
public <C extends T> TweedConstructFactory.@NotNull Construct<C> construct(@NotNull Class<C> subClass) { public <C extends T> TweedConstructFactory.Construct<C> construct(Class<C> subClass) {
return new Construct<>(getConstructTarget(subClass)); return new Construct<>(getConstructTarget(subClass));
} }
private <C extends T> @NotNull ConstructTarget<C> getConstructTarget(Class<C> type) { private <C extends T> ConstructTarget<C> getConstructTarget(Class<C> type) {
ConstructTarget<C> cachedConstructTarget = readConstructTargetFromCache(type); ConstructTarget<C> cachedConstructTarget = readConstructTargetFromCache(type);
if (cachedConstructTarget != null) { if (cachedConstructTarget != null) {
return cachedConstructTarget; return cachedConstructTarget;
@@ -164,7 +163,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
return new ConstructTarget<>(type, argOrder, createInvokerFromCandidate(type, executable)); return new ConstructTarget<>(type, argOrder, createInvokerFromCandidate(type, executable));
} }
private <C> Function<Object[], C> createInvokerFromCandidate(Class<C> type, Executable executable) { private <C> Function<@Nullable Object[], C> createInvokerFromCandidate(Class<C> type, Executable executable) {
MethodHandle handle; MethodHandle handle;
try { try {
if (executable instanceof Method) { if (executable instanceof Method) {
@@ -263,7 +262,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
private final Map<String, Class<?>> namedArgs = new HashMap<>(); private final Map<String, Class<?>> namedArgs = new HashMap<>();
@Override @Override
public <A> TweedConstructFactory.@NotNull FactoryBuilder<T> typedArg(@NotNull Class<A> argType) { public <A> TweedConstructFactory.FactoryBuilder<T> typedArg(Class<A> argType) {
argType = boxClass(argType); argType = boxClass(argType);
if (typedArgs.contains(argType)) { if (typedArgs.contains(argType)) {
throw new IllegalArgumentException("Argument for type " + argType + " has already been registered"); throw new IllegalArgumentException("Argument for type " + argType + " has already been registered");
@@ -273,10 +272,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
} }
@Override @Override
public <A> TweedConstructFactory.@NotNull FactoryBuilder<T> namedArg( public <A> TweedConstructFactory.FactoryBuilder<T> namedArg(String name, Class<A> argType) {
@NotNull String name,
@NotNull Class<A> argType
) {
Class<?> existingArgType = namedArgs.get(name); Class<?> existingArgType = namedArgs.get(name);
if (existingArgType != null) { if (existingArgType != null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@@ -290,7 +286,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
} }
@Override @Override
public @NotNull TweedConstructFactory<T> build() { public TweedConstructFactory<T> build() {
return new TweedConstructFactoryImpl<>( return new TweedConstructFactoryImpl<>(
constructBaseClass, constructBaseClass,
typedArgs, typedArgs,
@@ -302,18 +298,18 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
@RequiredArgsConstructor @RequiredArgsConstructor
private class Construct<C> implements TweedConstructFactory.Construct<C> { private class Construct<C> implements TweedConstructFactory.Construct<C> {
private final ConstructTarget<C> target; private final ConstructTarget<C> target;
private final Map<Class<?>, Object> typedArgValues = new HashMap<>(); private final Map<Class<?>, @Nullable Object> typedArgValues = new HashMap<>();
private final Map<String, Object> namedArgValues = new HashMap<>(); private final Map<String, @Nullable Object> namedArgValues = new HashMap<>();
@Override @Override
public <A> TweedConstructFactory.@NotNull Construct<C> typedArg(@NotNull A value) { public <A> TweedConstructFactory.Construct<C> typedArg(A value) {
requireTypedArgExists(value.getClass(), value); requireTypedArgExists(value.getClass(), value);
typedArgValues.put(value.getClass(), value); typedArgValues.put(value.getClass(), value);
return this; return this;
} }
@Override @Override
public <A> TweedConstructFactory.@NotNull Construct<C> typedArg(@NotNull Class<? super A> argType, @Nullable A value) { public <A> TweedConstructFactory.Construct<C> typedArg(Class<? super A> argType, @Nullable A value) {
argType = boxClass(argType); argType = boxClass(argType);
if (value != null && !argType.isAssignableFrom(value.getClass())) { if (value != null && !argType.isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@@ -327,7 +323,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
return this; return this;
} }
private <A> void requireTypedArgExists(@NotNull Class<?> type, @Nullable A value) { private <A> void requireTypedArgExists(Class<?> type, @Nullable A value) {
if (!typedArgs.contains(type)) { if (!typedArgs.contains(type)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Typed argument for type " + type.getName() + " does not exist, value: " + value "Typed argument for type " + type.getName() + " does not exist, value: " + value
@@ -336,7 +332,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
} }
@Override @Override
public <A> TweedConstructFactory.@NotNull Construct<C> namedArg(@NotNull String name, @Nullable A value) { public <A> TweedConstructFactory.Construct<C> namedArg(String name, @Nullable A value) {
Class<?> argType = namedArgs.get(name); Class<?> argType = namedArgs.get(name);
if (argType == null) { if (argType == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
@@ -353,10 +349,10 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
} }
@Override @Override
public @NotNull C finish() { public C finish() {
checkAllArgsFilled(); checkAllArgsFilled();
Object[] argValues = new Object[target.argOrder.length]; @Nullable Object[] argValues = new Object[target.argOrder.length];
for (int i = 0; i < target.argOrder.length; i++) { for (int i = 0; i < target.argOrder.length; i++) {
Object arg = target.argOrder[i]; Object arg = target.argOrder[i];
if (arg instanceof Class<?>) { if (arg instanceof Class<?>) {
@@ -459,6 +455,6 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
private static class ConstructTarget<C> { private static class ConstructTarget<C> {
Class<?> type; Class<?> type;
Object[] argOrder; Object[] argOrder;
Function<Object[], C> invoker; Function<@Nullable Object[], C> invoker;
} }
} }

View File

@@ -1,4 +1,6 @@
@ApiStatus.Internal @ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.construct.impl; package de.siphalor.tweed5.construct.impl;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -5,7 +5,7 @@ import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData; import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.core.api.extension.TweedExtension; import de.siphalor.tweed5.core.api.extension.TweedExtension;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;

View File

@@ -4,13 +4,11 @@ import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData; import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
public abstract class BaseConfigEntry<T> implements ConfigEntry<T> { public abstract class BaseConfigEntry<T> implements ConfigEntry<T> {
@NotNull
private final Class<T> valueClass; private final Class<T> valueClass;
private ConfigContainer<?> container; private ConfigContainer<?> container;
private EntryExtensionsData extensionsData; private EntryExtensionsData extensionsData;

View File

@@ -2,7 +2,6 @@ package de.siphalor.tweed5.core.api.entry;
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData; import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import de.siphalor.tweed5.core.api.container.ConfigContainer; import de.siphalor.tweed5.core.api.container.ConfigContainer;
import org.jetbrains.annotations.NotNull;
public interface ConfigEntry<T> { public interface ConfigEntry<T> {
Class<T> valueClass(); Class<T> valueClass();
@@ -15,6 +14,5 @@ public interface ConfigEntry<T> {
void visitInOrder(ConfigEntryVisitor visitor); void visitInOrder(ConfigEntryVisitor visitor);
void visitInOrder(ConfigEntryValueVisitor visitor, T value); void visitInOrder(ConfigEntryValueVisitor visitor, T value);
@NotNull T deepCopy(T value);
T deepCopy(@NotNull T value);
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.core.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -12,11 +12,13 @@ import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart;
import de.siphalor.tweed5.utils.api.collection.InheritanceMap; import de.siphalor.tweed5.utils.api.collection.InheritanceMap;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.*; import java.util.*;
@NullUnmarked
public class DefaultConfigContainer<T> implements ConfigContainer<T> { public class DefaultConfigContainer<T> implements ConfigContainer<T> {
@Getter @Getter
private ConfigContainerSetupPhase setupPhase = ConfigContainerSetupPhase.EXTENSIONS_SETUP; private ConfigContainerSetupPhase setupPhase = ConfigContainerSetupPhase.EXTENSIONS_SETUP;

View File

@@ -1,7 +1,6 @@
package de.siphalor.tweed5.core.impl.entry; package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.*; import de.siphalor.tweed5.core.api.entry.*;
import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
import java.util.function.IntFunction; import java.util.function.IntFunction;
@@ -52,7 +51,7 @@ public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseC
} }
@Override @Override
public @NotNull T deepCopy(@NotNull T value) { public T deepCopy(T value) {
T copy = collectionConstructor.apply(value.size()); T copy = collectionConstructor.apply(value.size());
for (E element : value) { for (E element : value) {
copy.add(elementEntry().deepCopy(element)); copy.add(elementEntry().deepCopy(element));

View File

@@ -4,7 +4,6 @@ import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor; import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor; import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry; import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
import org.jetbrains.annotations.NotNull;
public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements SimpleConfigEntry<T> { public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements SimpleConfigEntry<T> {
public SimpleConfigEntryImpl(Class<T> valueClass) { public SimpleConfigEntryImpl(Class<T> valueClass) {
@@ -22,8 +21,7 @@ public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements Simp
} }
@Override @Override
@NotNull public T deepCopy(T value) {
public T deepCopy(@NotNull T value) {
return value; return value;
} }
} }

View File

@@ -1,7 +1,6 @@
package de.siphalor.tweed5.core.impl.entry; package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.*; import de.siphalor.tweed5.core.api.entry.*;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@@ -11,7 +10,7 @@ public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> ext
private final IntFunction<T> mapConstructor; private final IntFunction<T> mapConstructor;
private final Map<String, ConfigEntry<?>> compoundEntries = new LinkedHashMap<>(); private final Map<String, ConfigEntry<?>> compoundEntries = new LinkedHashMap<>();
public StaticMapCompoundConfigEntryImpl(@NotNull Class<T> valueClass, IntFunction<T> mapConstructor) { public StaticMapCompoundConfigEntryImpl(Class<T> valueClass, IntFunction<T> mapConstructor) {
super(valueClass); super(valueClass);
this.mapConstructor = mapConstructor; this.mapConstructor = mapConstructor;
} }
@@ -80,7 +79,7 @@ public class StaticMapCompoundConfigEntryImpl<T extends Map<String, Object>> ext
} }
@Override @Override
public @NotNull T deepCopy(@NotNull T value) { public T deepCopy(T value) {
T copy = instantiateCompoundValue(); T copy = instantiateCompoundValue();
value.forEach((String key, Object element) -> { value.forEach((String key, Object element) -> {
//noinspection unchecked //noinspection unchecked

View File

@@ -1 +1,4 @@
package de.siphalor.tweed5.core.impl; @NullMarked
package de.siphalor.tweed5.core.impl;
import org.jspecify.annotations.NullMarked;

View File

@@ -2,7 +2,7 @@ package de.siphalor.tweed5.defaultextensions.comment.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.TweedExtension; import de.siphalor.tweed5.core.api.extension.TweedExtension;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
public interface CommentExtension extends TweedExtension { public interface CommentExtension extends TweedExtension {
@Nullable String getFullComment(ConfigEntry<?> configEntry); @Nullable String getFullComment(ConfigEntry<?> configEntry);

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.defaultextensions.comment.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -13,9 +13,12 @@ import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension
import de.siphalor.tweed5.defaultextensions.comment.api.*; import de.siphalor.tweed5.defaultextensions.comment.api.*;
import lombok.Getter; import lombok.Getter;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
@AutoService(CommentExtension.class) @AutoService(CommentExtension.class)
@NullUnmarked
public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentExtension { public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentExtension {
@Getter @Getter
private RegisteredExtensionData<EntryExtensionsData, InternalCommentEntryData> internalEntryDataExtension; private RegisteredExtensionData<EntryExtensionsData, InternalCommentEntryData> internalEntryDataExtension;
@@ -62,8 +65,7 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
} }
@Override @Override
@Nullable public @Nullable String getFullComment(@NonNull ConfigEntry<?> configEntry) {
public String getFullComment(ConfigEntry<?> configEntry) {
String comment = ((InternalCommentEntryData) configEntry.extensionsData()).commentProducer().createComment(configEntry); String comment = ((InternalCommentEntryData) configEntry.extensionsData()).commentProducer().createComment(configEntry);
return comment.isEmpty() ? null : comment; return comment.isEmpty() ? null : comment;
} }

View File

@@ -6,8 +6,8 @@ import de.siphalor.tweed5.core.api.middleware.Middleware;
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter; import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor; import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> { class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
public static final TweedEntryWriterCommentMiddleware INSTANCE = new TweedEntryWriterCommentMiddleware(); public static final TweedEntryWriterCommentMiddleware INSTANCE = new TweedEntryWriterCommentMiddleware();
@@ -20,8 +20,8 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
@Override @Override
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) { public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
//noinspection unchecked //noinspection unchecked
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, ConfigEntry<Object>>) inner; TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedEntryWriter<Object, ConfigEntry<Object>>) (writer, value, entry, context) -> { return (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) (writer, value, entry, context) -> {
if (writer instanceof CompoundDataVisitor) { if (writer instanceof CompoundDataVisitor) {
// Comment is already written in front of the key by the CompoundDataWriter, // Comment is already written in front of the key by the CompoundDataWriter,
// so we don't have to write it here. // so we don't have to write it here.
@@ -94,7 +94,7 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
} }
@Override @Override
public void visitString(@NotNull String value) { public void visitString(String value) {
delegate.visitString(value); delegate.visitString(value);
} }

View File

@@ -1,4 +1,6 @@
@ApiStatus.Internal @ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.defaultextensions.comment.impl; package de.siphalor.tweed5.defaultextensions.comment.impl;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,5 +1,7 @@
package de.siphalor.tweed5.defaultextensions.pather.api; package de.siphalor.tweed5.defaultextensions.pather.api;
import org.jspecify.annotations.Nullable;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Deque; import java.util.Deque;
@@ -9,7 +11,7 @@ public class PathTracking implements PatherData {
private final Deque<String> pathParts = new ArrayDeque<>(50); private final Deque<String> pathParts = new ArrayDeque<>(50);
private final Deque<Integer> listIndexes = new ArrayDeque<>(10); private final Deque<Integer> listIndexes = new ArrayDeque<>(10);
public Context currentContext() { public @Nullable Context currentContext() {
return contextStack.peek(); return contextStack.peek();
} }

View File

@@ -2,7 +2,6 @@ package de.siphalor.tweed5.defaultextensions.pather.api;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor; import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor @RequiredArgsConstructor
public class PathTrackingDataVisitor implements TweedDataVisitor { public class PathTrackingDataVisitor implements TweedDataVisitor {
@@ -58,7 +57,7 @@ public class PathTrackingDataVisitor implements TweedDataVisitor {
} }
@Override @Override
public void visitString(@NotNull String value) { public void visitString(String value) {
delegate.visitString(value); delegate.visitString(value);
valueVisited(); valueVisited();
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.defaultextensions.pather.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -15,10 +15,13 @@ import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataReader; import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataReader;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataVisitor; import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataVisitor;
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension; import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
import org.jetbrains.annotations.NotNull; import lombok.val;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
@AutoService(PatherExtension.class) @AutoService(PatherExtension.class)
@NullUnmarked
public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension { public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension {
private static final String PATHER_ID = "pather"; private static final String PATHER_ID = "pather";
@@ -39,7 +42,7 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
entryWriterMiddleware = createEntryWriterMiddleware(); entryWriterMiddleware = createEntryWriterMiddleware();
} }
private @NotNull Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() { private @NonNull Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() {
return new Middleware<TweedEntryReader<?, ?>>() { return new Middleware<TweedEntryReader<?, ?>>() {
@Override @Override
public String id() { public String id() {
@@ -49,7 +52,7 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
@Override @Override
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) { public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
//noinspection unchecked //noinspection unchecked
TweedEntryReader<Object, ConfigEntry<Object>> castedInner = (TweedEntryReader<Object, ConfigEntry<Object>>) inner; val castedInner = (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) -> { return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) -> {
if (context.extensionsData().isPatchworkPartSet(PathTracking.class)) { if (context.extensionsData().isPatchworkPartSet(PathTracking.class)) {
@@ -74,7 +77,7 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
@Override @Override
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) { public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
//noinspection unchecked //noinspection unchecked
TweedEntryWriter<Object, ConfigEntry<Object>> castedInner = (TweedEntryWriter<Object, ConfigEntry<Object>>) inner; val castedInner = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext context) -> { return (TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext context) -> {
if (context.extensionsData().isPatchworkPartSet(PathTracking.class)) { if (context.extensionsData().isPatchworkPartSet(PathTracking.class)) {

View File

@@ -0,0 +1,6 @@
@ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.defaultextensions.pather.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -2,11 +2,10 @@ package de.siphalor.tweed5.defaultextensions.validation.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
public interface ConfigEntryValidator { public interface ConfigEntryValidator {
<T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value); <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value);
@NotNull
<T> String description(ConfigEntry<T> configEntry); <T> String description(ConfigEntry<T> configEntry);
} }

View File

@@ -3,7 +3,8 @@ package de.siphalor.tweed5.defaultextensions.validation.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.TweedExtension; import de.siphalor.tweed5.core.api.extension.TweedExtension;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
import org.jspecify.annotations.Nullable;
public interface ValidationExtension extends TweedExtension { public interface ValidationExtension extends TweedExtension {
<T> ValidationIssues validate(ConfigEntry<T> entry, T value); <T extends @Nullable Object> ValidationIssues validate(ConfigEntry<T> entry, T value);
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.defaultextensions.validation.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -3,7 +3,6 @@ package de.siphalor.tweed5.defaultextensions.validation.api.result;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -14,7 +13,6 @@ import java.util.function.Function;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidationResult<T> { public class ValidationResult<T> {
private final T value; private final T value;
@NotNull
private final Collection<ValidationIssue> issues; private final Collection<ValidationIssue> issues;
private final boolean hasError; private final boolean hasError;
@@ -22,7 +20,7 @@ public class ValidationResult<T> {
return new ValidationResult<>(value, Collections.emptyList(), false); return new ValidationResult<>(value, Collections.emptyList(), false);
} }
public static <T> ValidationResult<T> withIssues(T value, @NotNull Collection<ValidationIssue> issues) { public static <T> ValidationResult<T> withIssues(T value, Collection<ValidationIssue> issues) {
return new ValidationResult<>(value, issues, issuesContainError(issues)); return new ValidationResult<>(value, issues, issuesContainError(issues));
} }

View File

@@ -5,13 +5,13 @@ import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import java.util.Collections; import java.util.Collections;
public class NonNullValidator implements ConfigEntryValidator { public class NonNullValidator implements ConfigEntryValidator {
@Override @Override
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) { public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
if (value == null) { if (value == null) {
return ValidationResult.withIssues(null, Collections.singleton( return ValidationResult.withIssues(null, Collections.singleton(
new ValidationIssue("Value must not be null", ValidationIssueLevel.ERROR) new ValidationIssue("Value must not be null", ValidationIssueLevel.ERROR)
@@ -21,7 +21,7 @@ public class NonNullValidator implements ConfigEntryValidator {
} }
@Override @Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) { public <T> String description(ConfigEntry<T> configEntry) {
return "Must be set (not null)."; return "Must be set (not null).";
} }
} }

View File

@@ -7,23 +7,20 @@ import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssu
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.Collections; import java.util.Collections;
@Value @Value
@AllArgsConstructor @AllArgsConstructor
public class NumberRangeValidator<N extends Number> implements ConfigEntryValidator { public class NumberRangeValidator<N extends @NonNull Number> implements ConfigEntryValidator {
@NotNull
Class<N> numberClass; Class<N> numberClass;
@Nullable @Nullable N minimum;
N minimum; @Nullable N maximum;
@Nullable
N maximum;
@Override @Override
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) { public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
if (!(value instanceof Number)) { if (!(value instanceof Number)) {
return ValidationResult.withIssues(value, Collections.singleton( return ValidationResult.withIssues(value, Collections.singleton(
new ValidationIssue("Value must be numeric", ValidationIssueLevel.ERROR) new ValidationIssue("Value must be numeric", ValidationIssueLevel.ERROR)
@@ -56,7 +53,7 @@ public class NumberRangeValidator<N extends Number> implements ConfigEntryValida
return ValidationResult.ok(value); return ValidationResult.ok(value);
} }
private int compare(@NotNull Number a, @NotNull Number b) { private int compare(Number a, Number b) {
if (numberClass == Byte.class) { if (numberClass == Byte.class) {
return Byte.compare(a.byteValue(), b.byteValue()); return Byte.compare(a.byteValue(), b.byteValue());
} else if (numberClass == Short.class) { } else if (numberClass == Short.class) {
@@ -73,7 +70,7 @@ public class NumberRangeValidator<N extends Number> implements ConfigEntryValida
} }
@Override @Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) { public <T> String description(ConfigEntry<T> configEntry) {
if (minimum == null) { if (minimum == null) {
if (maximum == null) { if (maximum == null) {
return ""; return "";

View File

@@ -6,7 +6,7 @@ import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
@@ -18,12 +18,12 @@ public class SimpleValidatorMiddleware implements Middleware<ConfigEntryValidato
public ConfigEntryValidator process(ConfigEntryValidator inner) { public ConfigEntryValidator process(ConfigEntryValidator inner) {
return new ConfigEntryValidator() { return new ConfigEntryValidator() {
@Override @Override
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) { public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
return inner.validate(configEntry, value).andThen(v -> validator.validate(configEntry, v)); return inner.validate(configEntry, value).andThen(v -> validator.validate(configEntry, v));
} }
@Override @Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) { public <T extends @Nullable Object> String description(ConfigEntry<T> configEntry) {
String description = validator.description(configEntry); String description = validator.description(configEntry);
if (description.isEmpty()) { if (description.isEmpty()) {
return inner.description(configEntry); return inner.description(configEntry);

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.defaultextensions.validation.api.validators;
import org.jspecify.annotations.NullMarked;

View File

@@ -35,11 +35,13 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.util.*; import java.util.*;
@AutoService(ValidationExtension.class) @AutoService(ValidationExtension.class)
@NullUnmarked
public class ValidationExtensionImpl implements ReadWriteRelatedExtension, ValidationExtension, CommentModifyingExtension { public class ValidationExtensionImpl implements ReadWriteRelatedExtension, ValidationExtension, CommentModifyingExtension {
private static final ValidationResult<?> PRIMITIVE_IS_NULL_RESULT = ValidationResult.withIssues( private static final ValidationResult<?> PRIMITIVE_IS_NULL_RESULT = ValidationResult.withIssues(
null, null,
@@ -47,7 +49,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
); );
private static final ConfigEntryValidator PRIMITIVE_VALIDATOR = new ConfigEntryValidator() { private static final ConfigEntryValidator PRIMITIVE_VALIDATOR = new ConfigEntryValidator() {
@Override @Override
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) { public <T> ValidationResult<T> validate(@NotNull ConfigEntry<T> configEntry, @Nullable T value) {
if (value == null) { if (value == null) {
//noinspection unchecked //noinspection unchecked
return (ValidationResult<T>) PRIMITIVE_IS_NULL_RESULT; return (ValidationResult<T>) PRIMITIVE_IS_NULL_RESULT;
@@ -56,18 +58,18 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
} }
@Override @Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) { public <T> String description(@NotNull ConfigEntry<T> configEntry) {
return "Value must not be null."; return "Value must not be null.";
} }
}; };
private static final ConfigEntryValidator NOOP_VALIDATOR = new ConfigEntryValidator() { private static final ConfigEntryValidator NOOP_VALIDATOR = new ConfigEntryValidator() {
@Override @Override
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) { public <T> ValidationResult<T> validate(@NotNull ConfigEntry<T> configEntry, @Nullable T value) {
return ValidationResult.ok(value); return ValidationResult.ok(value);
} }
@Override @Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) { public <T> String description(@NotNull ConfigEntry<T> configEntry) {
return ""; return "";
} }
}; };
@@ -166,7 +168,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
} }
@Override @Override
public <T> ValidationIssues validate(ConfigEntry<T> entry, T value) { public <T> ValidationIssues validate(@NotNull ConfigEntry<T> entry, @Nullable T value) {
PathTracking pathTracking = new PathTracking(); PathTracking pathTracking = new PathTracking();
ValidatingConfigEntryVisitor validatingVisitor = new ValidatingConfigEntryVisitor(pathTracking); ValidatingConfigEntryVisitor validatingVisitor = new ValidatingConfigEntryVisitor(pathTracking);

View File

@@ -0,0 +1,6 @@
@ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.defaultextensions.validation.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,5 +1,7 @@
package de.siphalor.tweed5.defaultextensions.validationfallback.api; package de.siphalor.tweed5.defaultextensions.validationfallback.api;
import org.jspecify.annotations.Nullable;
public interface ValidationFallbackValue { public interface ValidationFallbackValue {
Object validationFallbackValue(); @Nullable Object validationFallbackValue();
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.defaultextensions.validationfallback.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -11,7 +11,7 @@ import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssu
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult; import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension; import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackValue; import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackValue;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -55,7 +55,7 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
public ConfigEntryValidator process(ConfigEntryValidator inner) { public ConfigEntryValidator process(ConfigEntryValidator inner) {
return new ConfigEntryValidator() { return new ConfigEntryValidator() {
@Override @Override
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) { public <T extends @Nullable Object> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
ValidationResult<T> result = inner.validate(configEntry, value); ValidationResult<T> result = inner.validate(configEntry, value);
if (!result.hasError()) { if (!result.hasError()) {
return result; return result;
@@ -90,7 +90,7 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
} }
@Override @Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) { public <T> String description(ConfigEntry<T> configEntry) {
if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) { if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) {
return inner.description(configEntry); return inner.description(configEntry);
} }

View File

@@ -0,0 +1,6 @@
@ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.defaultextensions.validationfallback.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.namingformat.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,5 +1,6 @@
@ApiStatus.Internal @ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.namingformat.impl; package de.siphalor.tweed5.namingformat.impl;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -4,7 +4,10 @@ import de.siphalor.tweed5.patchwork.impl.ByteArrayClassLoader;
import de.siphalor.tweed5.patchwork.impl.PatchworkClass; import de.siphalor.tweed5.patchwork.impl.PatchworkClass;
import de.siphalor.tweed5.patchwork.impl.PatchworkClassGenerator; import de.siphalor.tweed5.patchwork.impl.PatchworkClassGenerator;
import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart; import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart;
import lombok.*; import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.Value;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@@ -16,17 +19,18 @@ import java.util.stream.Collectors;
@Value @Value
public class PatchworkClassCreator<P extends Patchwork<P>> { public class PatchworkClassCreator<P extends Patchwork<P>> {
@NonNull
Class<P> patchworkInterface; Class<P> patchworkInterface;
@NonNull
PatchworkClassGenerator.Config generatorConfig; PatchworkClassGenerator.Config generatorConfig;
public static <P extends Patchwork<P>> Builder<P> builder() { public static <P extends Patchwork<P>> Builder<P> builder() {
return new Builder<>(); return new Builder<>();
} }
public PatchworkClass<P> createClass(Collection<Class<?>> partInterfaces) throws PatchworkClassGenerator.GenerationException { public PatchworkClass<P> createClass(Collection<Class<?>> partInterfaces) throws
List<PatchworkClassPart> parts = partInterfaces.stream().map(PatchworkClassPart::new).collect(Collectors.toList()); PatchworkClassGenerator.GenerationException {
List<PatchworkClassPart> parts = partInterfaces.stream()
.map(PatchworkClassPart::new)
.collect(Collectors.toList());
PatchworkClassGenerator generator = new PatchworkClassGenerator(generatorConfig, parts); PatchworkClassGenerator generator = new PatchworkClassGenerator(generatorConfig, parts);
try { try {
@@ -45,7 +49,10 @@ public class PatchworkClassCreator<P extends Patchwork<P>> {
MethodHandle setterHandle = lookup.findSetter(patchworkClass, part.fieldName(), part.partInterface()); MethodHandle setterHandle = lookup.findSetter(patchworkClass, part.fieldName(), part.partInterface());
part.fieldSetter(setterHandle); part.fieldSetter(setterHandle);
} catch (NoSuchFieldException | IllegalAccessException e) { } catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException("Failed to access setter for patchwork part " + part.partInterface().getName(), e); throw new IllegalStateException(
"Failed to access setter for patchwork part " + part.partInterface().getName(),
e
);
} }
} }
try { try {
@@ -67,9 +74,7 @@ public class PatchworkClassCreator<P extends Patchwork<P>> {
@Setter @Setter
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Builder<P extends Patchwork<P>> { public static class Builder<P extends Patchwork<P>> {
@NonNull
private Class<P> patchworkInterface; private Class<P> patchworkInterface;
@NonNull
private String classPackage; private String classPackage;
private String classPrefix = ""; private String classPrefix = "";

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.patchwork.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,8 +1,10 @@
package de.siphalor.tweed5.patchwork.impl; package de.siphalor.tweed5.patchwork.impl;
import org.jspecify.annotations.Nullable;
public class ByteArrayClassLoader extends ClassLoader { public class ByteArrayClassLoader extends ClassLoader {
public static Class<?> loadClass(String binaryClassName, byte[] byteCode) { public static Class<?> loadClass(@Nullable String binaryClassName, byte[] byteCode) {
return new ByteArrayClassLoader(ByteArrayClassLoader.class.getClassLoader()) return new ByteArrayClassLoader(ByteArrayClassLoader.class.getClassLoader())
.createClass(binaryClassName, byteCode); .createClass(binaryClassName, byteCode);
} }
@@ -11,7 +13,7 @@ public class ByteArrayClassLoader extends ClassLoader {
super(parent); super(parent);
} }
public Class<?> createClass(String binaryClassName, byte[] byteCode) { public Class<?> createClass(@Nullable String binaryClassName, byte[] byteCode) {
Class<?> clazz = defineClass(binaryClassName, byteCode, 0, byteCode.length); Class<?> clazz = defineClass(binaryClassName, byteCode, 0, byteCode.length);
resolveClass(clazz); resolveClass(clazz);
return clazz; return clazz;

View File

@@ -4,6 +4,8 @@ import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.patchwork.api.PatchworkPartIsNullException; import de.siphalor.tweed5.patchwork.api.PatchworkPartIsNullException;
import de.siphalor.tweed5.patchwork.impl.util.StreamUtils; import de.siphalor.tweed5.patchwork.impl.util.StreamUtils;
import lombok.*; import lombok.*;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.objectweb.asm.*; import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.GeneratorAdapter;
@@ -21,7 +23,8 @@ public class PatchworkClassGenerator {
*/ */
private static final int CLASS_VERSION = Opcodes.V1_8; private static final int CLASS_VERSION = Opcodes.V1_8;
private static final String TARGET_PACKAGE = "de.siphalor.tweed5.core.generated.contextextensions"; private static final String TARGET_PACKAGE = "de.siphalor.tweed5.core.generated.contextextensions";
private static final List<Type> DEFAULT_PATHWORK_INTERFACES = Collections.singletonList(Type.getType(Patchwork.class)); private static final List<Type> DEFAULT_PATHWORK_INTERFACES
= Collections.singletonList(Type.getType(Patchwork.class));
private static final String INNER_EQUALS_METHOD_NAME = "patchwork$innerEquals"; private static final String INNER_EQUALS_METHOD_NAME = "patchwork$innerEquals";
@@ -458,7 +461,13 @@ public class PatchworkClassGenerator {
} }
// </editor-fold> // </editor-fold>
private GeneratorAdapter createMethod(int access, String name, String desc, String signature, String[] exceptions) { private GeneratorAdapter createMethod(
int access,
String name,
String desc,
@Nullable String signature,
String @Nullable [] exceptions
) {
MethodVisitor methodVisitor = classWriter.visitMethod(access, name, desc, signature, exceptions); MethodVisitor methodVisitor = classWriter.visitMethod(access, name, desc, signature, exceptions);
return new GeneratorAdapter(methodVisitor, access, name, desc); return new GeneratorAdapter(methodVisitor, access, name, desc);
} }
@@ -502,7 +511,13 @@ public class PatchworkClassGenerator {
} }
@Override @Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { public MethodVisitor visitMethod(
int access,
String name,
String descriptor,
String signature,
String[] exceptions
) {
GeneratorAdapter methodWriter = createMethod(Opcodes.ACC_PUBLIC, name, descriptor, signature, exceptions); GeneratorAdapter methodWriter = createMethod(Opcodes.ACC_PUBLIC, name, descriptor, signature, exceptions);
return new PartMethodVisitor(api, methodWriter, descriptor, extensionClass); return new PartMethodVisitor(api, methodWriter, descriptor, extensionClass);
} }
@@ -513,7 +528,12 @@ public class PatchworkClassGenerator {
private final String methodDescriptor; private final String methodDescriptor;
private final PatchworkClassPart patchworkPart; private final PatchworkClassPart patchworkPart;
protected PartMethodVisitor(int api, GeneratorAdapter methodWriter, String methodDescriptor, PatchworkClassPart patchworkPart) { protected PartMethodVisitor(
int api,
GeneratorAdapter methodWriter,
String methodDescriptor,
PatchworkClassPart patchworkPart
) {
super(api); super(api);
this.methodWriter = methodWriter; this.methodWriter = methodWriter;
this.patchworkPart = patchworkPart; this.patchworkPart = patchworkPart;
@@ -531,7 +551,12 @@ public class PatchworkClassGenerator {
methodWriter.visitCode(); methodWriter.visitCode();
methodWriter.visitVarInsn(Opcodes.ALOAD, 0); methodWriter.visitVarInsn(Opcodes.ALOAD, 0);
methodWriter.visitFieldInsn(Opcodes.GETFIELD, internalClassName(), patchworkPart.fieldName(), Type.getDescriptor(patchworkPart.partInterface())); methodWriter.visitFieldInsn(
Opcodes.GETFIELD,
internalClassName(),
patchworkPart.fieldName(),
Type.getDescriptor(patchworkPart.partInterface())
);
methodWriter.dup(); methodWriter.dup();
methodWriter.ifNull(nullLabel); methodWriter.ifNull(nullLabel);
methodWriter.loadArgs(); methodWriter.loadArgs();
@@ -563,11 +588,9 @@ public class PatchworkClassGenerator {
@Data @Data
public static class Config { public static class Config {
@NonNull @lombok.NonNull
private String classPackage; private @NonNull String classPackage;
@NonNull
private String classPrefix = ""; private String classPrefix = "";
@NonNull
private Collection<Class<?>> markerInterfaces = Collections.emptyList(); private Collection<Class<?>> markerInterfaces = Collections.emptyList();
} }
@@ -594,12 +617,16 @@ public class PatchworkClassGenerator {
transient Collection<Method> signatures; transient Collection<Method> signatures;
private DuplicateMethodsException(Collection<Method> methods) { private DuplicateMethodsException(Collection<Method> methods) {
super("Duplicate method signatures:\n" + methods.stream().map(DuplicateMethodsException::getMethodMessage).collect(Collectors.joining("\n"))); super("Duplicate method signatures:\n" + methods.stream()
.map(DuplicateMethodsException::getMethodMessage)
.collect(Collectors.joining("\n")));
this.signatures = methods; this.signatures = methods;
} }
private static String getMethodMessage(Method method) { private static String getMethodMessage(Method method) {
StringBuilder stringBuilder = new StringBuilder("\t- " + method.getDeclaringClass().getCanonicalName() + "#("); StringBuilder stringBuilder = new StringBuilder("\t- "
+ method.getDeclaringClass().getCanonicalName()
+ "#(");
for (Class<?> parameterType : method.getParameterTypes()) { for (Class<?> parameterType : method.getParameterTypes()) {
stringBuilder.append(parameterType.getCanonicalName()); stringBuilder.append(parameterType.getCanonicalName());
stringBuilder.append(", "); stringBuilder.append(", ");

View File

@@ -0,0 +1,6 @@
@ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.patchwork.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -3,7 +3,7 @@ package de.siphalor.tweed5.dataapi.api;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
@Getter @Getter
public class TweedDataReadException extends RuntimeException { public class TweedDataReadException extends RuntimeException {
@@ -28,8 +28,7 @@ public class TweedDataReadException extends RuntimeException {
private String message; private String message;
private Throwable cause; private Throwable cause;
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
@Nullable private @Nullable TweedDataReaderRecoverMode recoverMode;
private TweedDataReaderRecoverMode recoverMode;
public TweedDataReadException build() { public TweedDataReadException build() {
return new TweedDataReadException(message, cause, recoverMode); return new TweedDataReadException(message, cause, recoverMode);

View File

@@ -1,7 +1,5 @@
package de.siphalor.tweed5.dataapi.api; package de.siphalor.tweed5.dataapi.api;
import org.jetbrains.annotations.NotNull;
public interface TweedDataVisitor { public interface TweedDataVisitor {
void visitNull(); void visitNull();
void visitBoolean(boolean value); void visitBoolean(boolean value);
@@ -11,7 +9,7 @@ public interface TweedDataVisitor {
void visitLong(long value); void visitLong(long value);
void visitFloat(float value); void visitFloat(float value);
void visitDouble(double value); void visitDouble(double value);
void visitString(@NotNull String value); void visitString(String value);
default void visitEmptyList() { default void visitEmptyList() {
visitListStart(); visitListStart();

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.dataapi.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -5,13 +5,23 @@ import de.siphalor.tweed5.core.api.extension.TweedExtension;
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteContextExtensionsData; import de.siphalor.tweed5.data.extension.api.extension.ReadWriteContextExtensionsData;
import de.siphalor.tweed5.dataapi.api.TweedDataReader; import de.siphalor.tweed5.dataapi.api.TweedDataReader;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor; import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import org.jspecify.annotations.Nullable;
public interface ReadWriteExtension extends TweedExtension { public interface ReadWriteExtension extends TweedExtension {
void setEntryReaderWriterDefinition(ConfigEntry<?> entry, EntryReaderWriterDefinition readerWriterDefinition); void setEntryReaderWriterDefinition(ConfigEntry<?> entry, EntryReaderWriterDefinition readerWriterDefinition);
ReadWriteContextExtensionsData createReadWriteContextExtensionsData(); ReadWriteContextExtensionsData createReadWriteContextExtensionsData();
<T> T read(TweedDataReader reader, ConfigEntry<T> entry, ReadWriteContextExtensionsData contextExtensionsData) throws TweedEntryReadException; <T extends @Nullable Object> T read(
TweedDataReader reader,
ConfigEntry<T> entry,
ReadWriteContextExtensionsData contextExtensionsData
) throws TweedEntryReadException;
<T> void write(TweedDataVisitor writer, T value, ConfigEntry<T> entry, ReadWriteContextExtensionsData contextExtensionsData) throws TweedEntryWriteException; <T extends @Nullable Object> void write(
TweedDataVisitor writer,
T value,
ConfigEntry<T> entry,
ReadWriteContextExtensionsData contextExtensionsData
) throws TweedEntryWriteException;
} }

View File

@@ -3,8 +3,11 @@ package de.siphalor.tweed5.data.extension.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.dataapi.api.TweedDataReadException; import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
import de.siphalor.tweed5.dataapi.api.TweedDataReader; import de.siphalor.tweed5.dataapi.api.TweedDataReader;
import org.jspecify.annotations.Nullable;
@FunctionalInterface @FunctionalInterface
public interface TweedEntryReader<T, C extends ConfigEntry<T>> { public interface TweedEntryReader<T extends @Nullable Object, C extends ConfigEntry<T>> {
T read(TweedDataReader reader, C entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException; T read(TweedDataReader reader, C entry, TweedReadContext context) throws
TweedEntryReadException,
TweedDataReadException;
} }

View File

@@ -3,8 +3,9 @@ package de.siphalor.tweed5.data.extension.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException; import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor; import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import org.jspecify.annotations.Nullable;
@FunctionalInterface @FunctionalInterface
public interface TweedEntryWriter<T, C extends ConfigEntry<T>> { public interface TweedEntryWriter<T extends @Nullable Object, C extends ConfigEntry<T>> {
void write(TweedDataVisitor writer, T value, C entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException; void write(TweedDataVisitor writer, @Nullable T value, C entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException;
} }

View File

@@ -3,7 +3,7 @@ package de.siphalor.tweed5.data.extension.api.extension;
import de.siphalor.tweed5.core.api.middleware.Middleware; import de.siphalor.tweed5.core.api.middleware.Middleware;
import de.siphalor.tweed5.data.extension.api.TweedEntryReader; import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter; import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
public interface ReadWriteRelatedExtension { public interface ReadWriteRelatedExtension {
default void setupReadWriteExtension(ReadWriteExtensionSetupContext context) { default void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.data.extension.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -8,6 +8,7 @@ import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
import de.siphalor.tweed5.data.extension.impl.TweedEntryReaderWriterImpls; import de.siphalor.tweed5.data.extension.impl.TweedEntryReaderWriterImpls;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.jspecify.annotations.NonNull;
import java.util.Collection; import java.util.Collection;
@@ -55,11 +56,11 @@ public class TweedEntryReaderWriters {
public static <T, C extends Collection<T>> TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> collectionReaderWriter() { public static <T, C extends Collection<T>> TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> collectionReaderWriter() {
//noinspection unchecked //noinspection unchecked
return (TweedEntryReaderWriter<C, CollectionConfigEntry<T,C>>)(TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.COLLECTION_READER_WRITER; return (TweedEntryReaderWriter<C, @NonNull CollectionConfigEntry<T, C>>) (TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.COLLECTION_READER_WRITER;
} }
public static <T> TweedEntryReaderWriter<T, CompoundConfigEntry<T>> compoundReaderWriter() { public static <T> TweedEntryReaderWriter<T, CompoundConfigEntry<T>> compoundReaderWriter() {
//noinspection unchecked //noinspection unchecked
return (TweedEntryReaderWriter<T, CompoundConfigEntry<T>>)(TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.COMPOUND_READER_WRITER; return (TweedEntryReaderWriter<T, @NonNull CompoundConfigEntry<T>>) (TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.COMPOUND_READER_WRITER;
} }
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.data.extension.api.readwrite;
import org.jspecify.annotations.NullMarked;

View File

@@ -22,6 +22,10 @@ import de.siphalor.tweed5.patchwork.impl.PatchworkClassGenerator;
import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart; import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart;
import lombok.Setter; import lombok.Setter;
import lombok.Value; import lombok.Value;
import lombok.val;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.Collection; import java.util.Collection;
@@ -29,14 +33,16 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
@AutoService(ReadWriteExtension.class) @AutoService(ReadWriteExtension.class)
@NullUnmarked
public class ReadWriteExtensionImpl implements ReadWriteExtension { public class ReadWriteExtensionImpl implements ReadWriteExtension {
private RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition> readerWriterDefinitionExtension; private RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition> readerWriterDefinitionExtension;
private RegisteredExtensionData<EntryExtensionsData, ReadWriteEntryDataExtension> readWriteEntryDataExtension; private RegisteredExtensionData<EntryExtensionsData, ReadWriteEntryDataExtension> readWriteEntryDataExtension;
private DefaultMiddlewareContainer<TweedEntryReader<?, ?>> entryReaderMiddlewareContainer; private DefaultMiddlewareContainer<TweedEntryReader<?, ?>> entryReaderMiddlewareContainer;
private DefaultMiddlewareContainer<TweedEntryWriter<?, ?>> entryWriterMiddlewareContainer; private DefaultMiddlewareContainer<TweedEntryWriter<?, ?>> entryWriterMiddlewareContainer;
private Map<Class<?>, RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?>> readWriteContextExtensionsDataClasses; private Map<Class<?>, RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?>>
private PatchworkClass<ReadWriteContextExtensionsData> readWriteContextExtensionsDataPatchwork; readWriteContextExtensionsDataClasses;
private PatchworkClass<@NonNull ReadWriteContextExtensionsData> readWriteContextExtensionsDataPatchwork;
@Override @Override
public String getId() { public String getId() {
@@ -54,11 +60,17 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
ReadWriteExtensionSetupContext setupContext = new ReadWriteExtensionSetupContext() { ReadWriteExtensionSetupContext setupContext = new ReadWriteExtensionSetupContext() {
@Override @Override
public <E> RegisteredExtensionData<ReadWriteContextExtensionsData, E> registerReadWriteContextExtensionData(Class<E> extensionDataClass) { public <E> RegisteredExtensionData<ReadWriteContextExtensionsData, E> registerReadWriteContextExtensionData(
Class<E> extensionDataClass
) {
if (readWriteContextExtensionsDataClasses.containsKey(extensionDataClass)) { if (readWriteContextExtensionsDataClasses.containsKey(extensionDataClass)) {
throw new IllegalArgumentException("Context extension " + extensionDataClass.getName() + " is already registered"); throw new IllegalArgumentException("Context extension "
+ extensionDataClass.getName()
+ " is already registered");
} }
RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, E> registeredExtensionData = new RegisteredExtensionDataImpl<>(); RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, E>
registeredExtensionData
= new RegisteredExtensionDataImpl<>();
readWriteContextExtensionsDataClasses.put(extensionDataClass, registeredExtensionData); readWriteContextExtensionsDataClasses.put(extensionDataClass, registeredExtensionData);
return registeredExtensionData; return registeredExtensionData;
} }
@@ -73,11 +85,13 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
rwExtension.setupReadWriteExtension(setupContext); rwExtension.setupReadWriteExtension(setupContext);
if (rwExtension.entryReaderMiddleware() != null) { val readerMiddleware = rwExtension.entryReaderMiddleware();
entryReaderMiddlewareContainer.register(rwExtension.entryReaderMiddleware()); if (readerMiddleware != null) {
entryReaderMiddlewareContainer.register(readerMiddleware);
} }
if (rwExtension.entryWriterMiddleware() != null) { val writerMiddleware = rwExtension.entryWriterMiddleware();
entryWriterMiddlewareContainer.register(rwExtension.entryWriterMiddleware()); if (writerMiddleware != null) {
entryWriterMiddlewareContainer.register(writerMiddleware);
} }
} }
} }
@@ -85,20 +99,26 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
entryReaderMiddlewareContainer.seal(); entryReaderMiddlewareContainer.seal();
entryWriterMiddlewareContainer.seal(); entryWriterMiddlewareContainer.seal();
PatchworkClassCreator<ReadWriteContextExtensionsData> patchworkClassCreator = PatchworkClassCreator.<ReadWriteContextExtensionsData>builder() val patchworkClassCreator = PatchworkClassCreator.<ReadWriteContextExtensionsData>builder()
.patchworkInterface(ReadWriteContextExtensionsData.class) .patchworkInterface(ReadWriteContextExtensionsData.class)
.classPackage("de.siphalor.tweed5.data.extension.generated") .classPackage("de.siphalor.tweed5.data.extension.generated")
.classPrefix("ReadWriteContextExtensionsData$") .classPrefix("ReadWriteContextExtensionsData$")
.build(); .build();
try { try {
readWriteContextExtensionsDataPatchwork = patchworkClassCreator.createClass(readWriteContextExtensionsDataClasses.keySet()); readWriteContextExtensionsDataPatchwork =
patchworkClassCreator.createClass(readWriteContextExtensionsDataClasses.keySet());
for (PatchworkClassPart patchworkClassPart : readWriteContextExtensionsDataPatchwork.parts()) { for (PatchworkClassPart patchworkClassPart : readWriteContextExtensionsDataPatchwork.parts()) {
RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?> registeredExtension = readWriteContextExtensionsDataClasses.get(patchworkClassPart.partInterface()); RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?>
registeredExtension
= readWriteContextExtensionsDataClasses.get(patchworkClassPart.partInterface());
registeredExtension.setter = patchworkClassPart.fieldSetter(); registeredExtension.setter = patchworkClassPart.fieldSetter();
} }
} catch (PatchworkClassGenerator.GenerationException e) { } catch (PatchworkClassGenerator.GenerationException e) {
throw new IllegalStateException("Failed to generate read write context extensions' data patchwork class", e); throw new IllegalStateException(
"Failed to generate read write context extensions' data patchwork class",
e
);
} }
} }
@@ -115,14 +135,19 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
baseWriter = TweedEntryReaderWriterImpls.NOOP_READER_WRITER; baseWriter = TweedEntryReaderWriterImpls.NOOP_READER_WRITER;
} }
readWriteEntryDataExtension.set(configEntry.extensionsData(), new ReadWriteEntryDataExtensionImpl( readWriteEntryDataExtension.set(
entryReaderMiddlewareContainer.process(baseReader), configEntry.extensionsData(), new ReadWriteEntryDataExtensionImpl(
entryWriterMiddlewareContainer.process(baseWriter) entryReaderMiddlewareContainer.process(baseReader),
)); entryWriterMiddlewareContainer.process(baseWriter)
)
);
} }
@Override @Override
public void setEntryReaderWriterDefinition(ConfigEntry<?> entry, EntryReaderWriterDefinition readerWriterDefinition) { public void setEntryReaderWriterDefinition(
@NonNull ConfigEntry<?> entry,
@NonNull EntryReaderWriterDefinition readerWriterDefinition
) {
readerWriterDefinitionExtension.set(entry.extensionsData(), readerWriterDefinition); readerWriterDefinitionExtension.set(entry.extensionsData(), readerWriterDefinition);
} }
@@ -136,7 +161,11 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
} }
@Override @Override
public <T> T read(TweedDataReader reader, ConfigEntry<T> entry, ReadWriteContextExtensionsData contextExtensionsData) throws TweedEntryReadException { public <T> T read(
@NonNull TweedDataReader reader,
@NonNull ConfigEntry<T> entry,
@NonNull ReadWriteContextExtensionsData contextExtensionsData
) throws TweedEntryReadException {
try { try {
return getReaderChain(entry).read(reader, entry, new TweedReadWriteContextImpl(contextExtensionsData)); return getReaderChain(entry).read(reader, entry, new TweedReadWriteContextImpl(contextExtensionsData));
} catch (TweedDataReadException e) { } catch (TweedDataReadException e) {
@@ -145,7 +174,12 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
} }
@Override @Override
public <T> void write(TweedDataVisitor writer, T value, ConfigEntry<T> entry, ReadWriteContextExtensionsData contextExtensionsData) throws TweedEntryWriteException { public <T> void write(
@NonNull TweedDataVisitor writer,
@Nullable T value,
@NonNull ConfigEntry<T> entry,
@NonNull ReadWriteContextExtensionsData contextExtensionsData
) throws TweedEntryWriteException {
try { try {
getWriterChain(entry).write(writer, value, entry, new TweedReadWriteContextImpl(contextExtensionsData)); getWriterChain(entry).write(writer, value, entry, new TweedReadWriteContextImpl(contextExtensionsData));
} catch (TweedDataWriteException e) { } catch (TweedDataWriteException e) {
@@ -160,7 +194,8 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
} }
@Setter @Setter
private static class RegisteredExtensionDataImpl<U extends Patchwork<U>, E> implements RegisteredExtensionData<U, E> { private static class RegisteredExtensionDataImpl<U extends Patchwork<@NonNull U>, E>
implements RegisteredExtensionData<U, E> {
private MethodHandle setter; private MethodHandle setter;
@Override @Override
@@ -173,13 +208,13 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
} }
} }
static <T> TweedEntryReader<T, ConfigEntry<T>> getReaderChain(ConfigEntry<T> elementEntry) { static <T> TweedEntryReader<T, @NonNull ConfigEntry<T>> getReaderChain(ConfigEntry<T> elementEntry) {
//noinspection unchecked //noinspection unchecked
return (TweedEntryReader<T, ConfigEntry<T>>) ((ReadWriteEntryDataExtension) elementEntry.extensionsData()).entryReaderChain(); return (TweedEntryReader<T, @NonNull ConfigEntry<T>>) ((ReadWriteEntryDataExtension) elementEntry.extensionsData()).entryReaderChain();
} }
static <T> TweedEntryWriter<T, ConfigEntry<T>> getWriterChain(ConfigEntry<T> elementEntry) { static <T> TweedEntryWriter<T, @NonNull ConfigEntry<T>> getWriterChain(ConfigEntry<T> elementEntry) {
//noinspection unchecked //noinspection unchecked
return (TweedEntryWriter<T, ConfigEntry<T>>) ((ReadWriteEntryDataExtension) elementEntry.extensionsData()).entryWriterChain(); return (TweedEntryWriter<T, @NonNull ConfigEntry<T>>) ((ReadWriteEntryDataExtension) elementEntry.extensionsData()).entryWriterChain();
} }
} }

View File

@@ -9,6 +9,9 @@ import de.siphalor.tweed5.dataapi.api.*;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@@ -32,7 +35,7 @@ public class TweedEntryReaderWriterImpls {
public static final TweedEntryReaderWriter<Object, ConfigEntry<Object>> NOOP_READER_WRITER = new NoopReaderWriter(); public static final TweedEntryReaderWriter<Object, ConfigEntry<Object>> NOOP_READER_WRITER = new NoopReaderWriter();
@RequiredArgsConstructor @RequiredArgsConstructor
public static class NullableReader<T, C extends ConfigEntry<T>> implements TweedEntryReader<T, C> { public static class NullableReader<T extends @Nullable Object, C extends ConfigEntry<T>> implements TweedEntryReader<T, C> {
private final TweedEntryReader<T, C> delegate; private final TweedEntryReader<T, C> delegate;
@Override @Override
@@ -46,7 +49,7 @@ public class TweedEntryReaderWriterImpls {
} }
@RequiredArgsConstructor @RequiredArgsConstructor
public static class NullableWriter<T, C extends ConfigEntry<T>> implements TweedEntryWriter<T, C> { public static class NullableWriter<T extends @Nullable Object, C extends ConfigEntry<T>> implements TweedEntryWriter<T, C> {
private final TweedEntryWriter<T, C> delegate; private final TweedEntryWriter<T, C> delegate;
@Override @Override
@@ -60,7 +63,7 @@ public class TweedEntryReaderWriterImpls {
} }
@RequiredArgsConstructor @RequiredArgsConstructor
private static class PrimitiveReaderWriter<T> implements TweedEntryReaderWriter<T, ConfigEntry<T>> { private static class PrimitiveReaderWriter<T extends @NonNull Object> implements TweedEntryReaderWriter<T, ConfigEntry<T>> {
private final Function<TweedDataToken, T> readerCall; private final Function<TweedDataToken, T> readerCall;
private final BiConsumer<TweedDataVisitor, T> writerCall; private final BiConsumer<TweedDataVisitor, T> writerCall;
@@ -70,13 +73,13 @@ public class TweedEntryReaderWriterImpls {
} }
@Override @Override
public void write(TweedDataVisitor writer, T value, ConfigEntry<T> entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException { public void write(TweedDataVisitor writer, @Nullable T value, ConfigEntry<T> entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException {
requireNonNullWriteValue(value); requireNonNullWriteValue(value);
writerCall.accept(writer, value); writerCall.accept(writer, value);
} }
} }
public static class CollectionReaderWriter<T, C extends Collection<T>> implements TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> { public static class CollectionReaderWriter<T extends @NonNull Object, C extends Collection<T>> implements TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> {
@Override @Override
public C read(TweedDataReader reader, CollectionConfigEntry<T, C> entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException { public C read(TweedDataReader reader, CollectionConfigEntry<T, C> entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException {
assertIsToken(reader.readToken(), TweedDataToken::isListStart, "Expected list start"); assertIsToken(reader.readToken(), TweedDataToken::isListStart, "Expected list start");
@@ -126,7 +129,7 @@ public class TweedEntryReaderWriterImpls {
} }
} }
public static class CompoundReaderWriter<T> implements TweedEntryReaderWriter<T, CompoundConfigEntry<T>> { public static class CompoundReaderWriter<T extends @NonNull Object> implements TweedEntryReaderWriter<T, CompoundConfigEntry<T>> {
@Override @Override
public T read(TweedDataReader reader, CompoundConfigEntry<T> entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException { public T read(TweedDataReader reader, CompoundConfigEntry<T> entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException {
assertIsToken(reader.readToken(), TweedDataToken::isMapStart, "Expected map start"); assertIsToken(reader.readToken(), TweedDataToken::isMapStart, "Expected map start");
@@ -143,10 +146,8 @@ public class TweedEntryReaderWriterImpls {
//noinspection unchecked //noinspection unchecked
ConfigEntry<Object> subEntry = (ConfigEntry<Object>) compoundEntries.get(key); ConfigEntry<Object> subEntry = (ConfigEntry<Object>) compoundEntries.get(key);
TweedEntryReader<Object, ConfigEntry<Object>> subEntryReaderChain = ReadWriteExtensionImpl.getReaderChain(subEntry); TweedEntryReader<Object, ConfigEntry<Object>> subEntryReaderChain = ReadWriteExtensionImpl.getReaderChain(subEntry);
if (subEntryReaderChain != null) { Object subEntryValue = subEntryReaderChain.read(reader, subEntry, context);
Object subEntryValue = subEntryReaderChain.read(reader, subEntry, context); entry.set(compoundValue, key, subEntryValue);
entry.set(compoundValue, key, subEntryValue);
}
} else { } else {
throw new TweedEntryReadException("Unexpected token " + token + ": Expected map key or map end"); throw new TweedEntryReadException("Unexpected token " + token + ": Expected map key or map end");
} }
@@ -155,7 +156,7 @@ public class TweedEntryReaderWriterImpls {
} }
@Override @Override
public void write(TweedDataVisitor writer, T value, CompoundConfigEntry<T> entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException { public void write(TweedDataVisitor writer, @Nullable T value, CompoundConfigEntry<T> entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException {
requireNonNullWriteValue(value); requireNonNullWriteValue(value);
writer.visitMapStart(); writer.visitMapStart();
@@ -168,19 +169,17 @@ public class TweedEntryReaderWriterImpls {
TweedEntryWriter<Object, ConfigEntry<Object>> subEntryWriterChain = ReadWriteExtensionImpl.getWriterChain(subEntry); TweedEntryWriter<Object, ConfigEntry<Object>> subEntryWriterChain = ReadWriteExtensionImpl.getWriterChain(subEntry);
if (subEntryWriterChain != null) { writer.visitMapEntryKey(key);
writer.visitMapEntryKey(key); subEntryWriterChain.write(writer, entry.get(value, key), subEntry, context);
subEntryWriterChain.write(writer, entry.get(value, key), subEntry, context);
}
} }
writer.visitMapEnd(); writer.visitMapEnd();
} }
} }
public static class NoopReaderWriter implements TweedEntryReaderWriter<Object, ConfigEntry<Object>> { public static class NoopReaderWriter implements TweedEntryReaderWriter<@Nullable Object, ConfigEntry<Object>> {
@Override @Override
public Object read(TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) throws TweedDataReadException { public @Nullable Object read(TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) throws TweedDataReadException {
TweedDataToken token = reader.readToken(); TweedDataToken token = reader.readToken();
if (!token.isListStart() && !token.isMapStart()) { if (!token.isListStart() && !token.isMapStart()) {
return null; return null;
@@ -209,7 +208,7 @@ public class TweedEntryReaderWriterImpls {
} }
@Override @Override
public void write(TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext context) throws TweedDataWriteException { public void write(TweedDataVisitor writer, @Nullable Object value, ConfigEntry<Object> entry, TweedWriteContext context) throws TweedDataWriteException {
writer.visitNull(); writer.visitNull();
} }
@@ -218,7 +217,8 @@ public class TweedEntryReaderWriterImpls {
} }
} }
private static <T> void requireNonNullWriteValue(T value) throws TweedEntryWriteException { @Contract("null -> fail")
private static <T> void requireNonNullWriteValue(@Nullable T value) throws TweedEntryWriteException {
if (value == null) { if (value == null) {
throw new TweedEntryWriteException("Unable to write null value"); throw new TweedEntryWriteException("Unable to write null value");
} }

View File

@@ -1,4 +1,6 @@
@ApiStatus.Internal @ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.data.extension.impl; package de.siphalor.tweed5.data.extension.impl;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -3,7 +3,7 @@ package de.siphalor.tweed5.data.hjson;
import de.siphalor.tweed5.dataapi.api.TweedDataReadException; import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@@ -58,8 +58,7 @@ public class HjsonLexer {
} }
} }
@Nullable private HjsonLexerToken.@Nullable Type getTerminalTokenType(int codePoint) {
private HjsonLexerToken.Type getTerminalTokenType(int codePoint) {
switch (codePoint) { switch (codePoint) {
case -1: return HjsonLexerToken.Type.EOF; case -1: return HjsonLexerToken.Type.EOF;
case '[': return HjsonLexerToken.Type.BRACKET_OPEN; case '[': return HjsonLexerToken.Type.BRACKET_OPEN;
@@ -78,8 +77,7 @@ public class HjsonLexer {
return new HjsonLexerToken(tokenType, position, position, null); return new HjsonLexerToken(tokenType, position, position, null);
} }
@Nullable private @Nullable HjsonLexerToken tryReadQuotedString(int codePoint) throws TweedDataReadException {
private HjsonLexerToken tryReadQuotedString(int codePoint) throws TweedDataReadException {
if (codePoint == '"') { if (codePoint == '"') {
return readJsonQuotedString('"'); return readJsonQuotedString('"');
} else if (codePoint == '\'') { } else if (codePoint == '\'') {

View File

@@ -3,7 +3,7 @@ package de.siphalor.tweed5.data.hjson;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
@ApiStatus.Internal @ApiStatus.Internal
@Value @Value
@@ -12,12 +12,10 @@ public class HjsonLexerToken {
HjsonReadPosition begin; HjsonReadPosition begin;
HjsonReadPosition end; HjsonReadPosition end;
@EqualsAndHashCode.Exclude @EqualsAndHashCode.Exclude
@Nullable @Nullable CharSequence content;
CharSequence content;
@EqualsAndHashCode.Include @EqualsAndHashCode.Include
@Nullable public @Nullable String contentString() {
public String contentString() {
return content == null ? null : content.toString(); return content == null ? null : content.toString();
} }

View File

@@ -1,6 +1,8 @@
package de.siphalor.tweed5.data.hjson; package de.siphalor.tweed5.data.hjson;
import de.siphalor.tweed5.dataapi.api.*; import de.siphalor.tweed5.dataapi.api.*;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -10,9 +12,9 @@ public class HjsonReader implements TweedDataReader {
private final Deque<Context> contexts; private final Deque<Context> contexts;
private State state = State.BEFORE_VALUE; private State state = State.BEFORE_VALUE;
private HjsonLexerToken peekedLexerToken; private @Nullable HjsonLexerToken peekedLexerToken;
private TweedDataToken peekedToken; private @Nullable TweedDataToken peekedToken;
public HjsonReader(HjsonLexer lexer) { public HjsonReader(HjsonLexer lexer) {
this.lexer = lexer; this.lexer = lexer;
@@ -204,6 +206,7 @@ public class HjsonReader implements TweedDataReader {
}; };
} }
@NullUnmarked
private TweedDataToken createNumberToken(HjsonLexerToken lexerToken) { private TweedDataToken createNumberToken(HjsonLexerToken lexerToken) {
assert lexerToken.content() != null; assert lexerToken.content() != null;
return new TweedDataToken() { return new TweedDataToken() {
@@ -318,7 +321,7 @@ public class HjsonReader implements TweedDataReader {
tryLong = 0L; tryLong = 0L;
boolean inFraction = false; boolean inFraction = false;
do { do {
tryLong = Math.addExact(Math.multiplyExact(tryLong, 10L), (long) (codePoint - '0')); tryLong = Math.addExact(Math.multiplyExact(tryLong, 10L), codePoint - '0');
if (inFraction) { if (inFraction) {
fractionDigits++; fractionDigits++;
} }
@@ -513,7 +516,7 @@ public class HjsonReader implements TweedDataReader {
@Override @Override
public String readAsString() throws TweedDataReadException { public String readAsString() throws TweedDataReadException {
if (lexerToken.type() == HjsonLexerToken.Type.QUOTELESS_STRING || lexerToken.type() == HjsonLexerToken.Type.MULTILINE_STRING) { if (lexerToken.type() == HjsonLexerToken.Type.QUOTELESS_STRING || lexerToken.type() == HjsonLexerToken.Type.MULTILINE_STRING) {
return lexerToken.contentString(); return Objects.requireNonNull(lexerToken.contentString());
} else if (lexerToken.type() == HjsonLexerToken.Type.JSON_STRING) { } else if (lexerToken.type() == HjsonLexerToken.Type.JSON_STRING) {
return readJsonString(lexerToken.content()); return readJsonString(lexerToken.content());
} }
@@ -623,6 +626,7 @@ public class HjsonReader implements TweedDataReader {
} }
private Context currentContext() { private Context currentContext() {
assert contexts.peek() != null;
return contexts.peek(); return contexts.peek();
} }

View File

@@ -4,19 +4,17 @@ import de.siphalor.tweed5.dataapi.api.TweedDataReader;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor; import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import de.siphalor.tweed5.dataapi.api.TweedSerde; import de.siphalor.tweed5.dataapi.api.TweedSerde;
import java.io.IOException; import java.io.*;
import java.io.InputStream;
import java.io.OutputStream;
public class HjsonSerde implements TweedSerde { public class HjsonSerde implements TweedSerde {
@Override @Override
public TweedDataReader createReader(InputStream inputStream) { public TweedDataReader createReader(InputStream inputStream) {
return null; return new HjsonReader(new HjsonLexer(new InputStreamReader(inputStream)));
} }
@Override @Override
public TweedDataVisitor createWriter(OutputStream outputStream) throws IOException { public TweedDataVisitor createWriter(OutputStream outputStream) throws IOException {
return null; return new HjsonWriter(new OutputStreamWriter(outputStream), new HjsonWriter.Options());
} }
@Override @Override

View File

@@ -3,7 +3,6 @@ package de.siphalor.tweed5.data.hjson;
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException; import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor; import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import lombok.Data; import lombok.Data;
import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
@@ -90,7 +89,7 @@ public class HjsonWriter implements TweedDataVisitor {
} }
@Override @Override
public void visitString(@NotNull String value) { public void visitString(String value) {
beforeValueWrite(); beforeValueWrite();
writeStringValue(getValueStringStringType(value), value); writeStringValue(getValueStringStringType(value), value);
afterValueWrite(); afterValueWrite();

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.data.hjson;
import org.jspecify.annotations.NullMarked;

View File

@@ -3,8 +3,7 @@ package de.siphalor.tweed5.typeutils.api.type;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
@@ -27,13 +26,11 @@ public class ActualType<T> implements AnnotatedElement {
* The {@link AnnotatedType} that represents the type that is actually in use (without parameters). * The {@link AnnotatedType} that represents the type that is actually in use (without parameters).
*/ */
@Getter(AccessLevel.PROTECTED) @Getter(AccessLevel.PROTECTED)
@Nullable private final @Nullable AnnotatedType usedType;
private final AnnotatedType usedType;
/** /**
* The {@link AnnotatedParameterizedType} that represents the type that is actually in use with parameters. * The {@link AnnotatedParameterizedType} that represents the type that is actually in use with parameters.
*/ */
@Nullable private final @Nullable AnnotatedParameterizedType usedParameterizedType;
private final AnnotatedParameterizedType usedParameterizedType;
/** /**
* A representation of the layered annotations of this type. * A representation of the layered annotations of this type.
@@ -45,7 +42,7 @@ public class ActualType<T> implements AnnotatedElement {
* Internal cache for the resolved actual type parameters. * Internal cache for the resolved actual type parameters.
*/ */
@Nullable @Nullable
private List<@NotNull ActualType<?>> resolvedParameters; private List<ActualType<?>> resolvedParameters;
/** /**
* Creates a basic actual type from just a declared class. * Creates a basic actual type from just a declared class.
@@ -64,7 +61,7 @@ public class ActualType<T> implements AnnotatedElement {
* *
* @throws UnsupportedOperationException when the given annotated type is not yet supported by this class * @throws UnsupportedOperationException when the given annotated type is not yet supported by this class
*/ */
public static ActualType<?> ofUsedType(@NotNull AnnotatedType annotatedType) throws UnsupportedOperationException { public static ActualType<?> ofUsedType(AnnotatedType annotatedType) throws UnsupportedOperationException {
Class<?> clazz = getDeclaredClassForUsedType(annotatedType); Class<?> clazz = getDeclaredClassForUsedType(annotatedType);
LayeredTypeAnnotations layeredTypeAnnotations = new LayeredTypeAnnotations(); LayeredTypeAnnotations layeredTypeAnnotations = new LayeredTypeAnnotations();
@@ -83,7 +80,7 @@ public class ActualType<T> implements AnnotatedElement {
* *
* @throws UnsupportedOperationException if the given parameter is not supported yet * @throws UnsupportedOperationException if the given parameter is not supported yet
*/ */
private static @NotNull Class<?> getDeclaredClassForUsedType(@NotNull AnnotatedType annotatedType) throws UnsupportedOperationException { private static Class<?> getDeclaredClassForUsedType(AnnotatedType annotatedType) throws UnsupportedOperationException {
if (annotatedType.getType() instanceof Class) { if (annotatedType.getType() instanceof Class) {
return (Class<?>) annotatedType.getType(); return (Class<?>) annotatedType.getType();
} else if (annotatedType.getType() instanceof ParameterizedType) { } else if (annotatedType.getType() instanceof ParameterizedType) {
@@ -102,24 +99,24 @@ public class ActualType<T> implements AnnotatedElement {
} }
@Override @Override
public <A extends Annotation> A getAnnotation(@NotNull Class<A> annotationClass) { public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
return layeredTypeAnnotations.getAnnotation(annotationClass); return layeredTypeAnnotations.getAnnotation(annotationClass);
} }
@Override @Override
public @NotNull Annotation @NotNull [] getAnnotations() { public Annotation[] getAnnotations() {
return layeredTypeAnnotations.getAnnotations(); return layeredTypeAnnotations.getAnnotations();
} }
@Override @Override
public @NotNull Annotation @NotNull [] getDeclaredAnnotations() { public Annotation[] getDeclaredAnnotations() {
return layeredTypeAnnotations.getDeclaredAnnotations(); return layeredTypeAnnotations.getDeclaredAnnotations();
} }
/** /**
* Resolves the type parameters of this type as {@link ActualType}s. * Resolves the type parameters of this type as {@link ActualType}s.
*/ */
public @NotNull List<@NotNull ActualType<?>> parameters() { public List<ActualType<?>> parameters() {
if (resolvedParameters != null) { if (resolvedParameters != null) {
return resolvedParameters; return resolvedParameters;
} else if (usedParameterizedType == null) { } else if (usedParameterizedType == null) {
@@ -145,7 +142,7 @@ public class ActualType<T> implements AnnotatedElement {
* @param targetClass the class to check * @param targetClass the class to check
* @return the list of type parameters if the given class is assignable from this type or {@code null} if not * @return the list of type parameters if the given class is assignable from this type or {@code null} if not
*/ */
public @Nullable List<ActualType<?>> getTypesOfSuperArguments(@NotNull Class<?> targetClass) { public @Nullable List<ActualType<?>> getTypesOfSuperArguments(Class<?> targetClass) {
if (targetClass.getTypeParameters().length == 0) { if (targetClass.getTypeParameters().length == 0) {
if (targetClass.isAssignableFrom(declaredType)) { if (targetClass.isAssignableFrom(declaredType)) {
return Collections.emptyList(); return Collections.emptyList();
@@ -170,7 +167,7 @@ public class ActualType<T> implements AnnotatedElement {
return currentType; return currentType;
} }
List<@NotNull ActualType<?>> currentParameters = currentType.parameters(); List<ActualType<?>> currentParameters = currentType.parameters();
Map<String, AnnotatedType> paramMap; Map<String, AnnotatedType> paramMap;
if (currentParameters.isEmpty()) { if (currentParameters.isEmpty()) {
@@ -178,6 +175,8 @@ public class ActualType<T> implements AnnotatedElement {
} else { } else {
paramMap = new HashMap<>(); paramMap = new HashMap<>();
for (int i = 0; i < currentParameters.size(); i++) { for (int i = 0; i < currentParameters.size(); i++) {
// used types are always known in resolved parameters
//noinspection DataFlowIssue
paramMap.put(currentClass.getTypeParameters()[i].getName(), currentParameters.get(i).usedType()); paramMap.put(currentClass.getTypeParameters()[i].getName(), currentParameters.get(i).usedType());
} }
} }
@@ -185,7 +184,7 @@ public class ActualType<T> implements AnnotatedElement {
if (targetClass.isInterface()) { if (targetClass.isInterface()) {
for (AnnotatedType annotatedInterface : currentClass.getAnnotatedInterfaces()) { for (AnnotatedType annotatedInterface : currentClass.getAnnotatedInterfaces()) {
ActualType<?> interfaceType = resolveTypeWithParameters(annotatedInterface, paramMap); ActualType<?> interfaceType = resolveTypeWithParameters(annotatedInterface, paramMap);
@Nullable ActualType<?> resultType = getViewOnSuperType(targetClass, interfaceType); ActualType<?> resultType = getViewOnSuperType(targetClass, interfaceType);
if (resultType != null) { if (resultType != null) {
return resultType; return resultType;
} }
@@ -193,7 +192,7 @@ public class ActualType<T> implements AnnotatedElement {
} }
if (currentClass != Object.class && !currentClass.isInterface()) { if (currentClass != Object.class && !currentClass.isInterface()) {
ActualType<?> superType = resolveTypeWithParameters(currentClass.getAnnotatedSuperclass(), paramMap); ActualType<?> superType = resolveTypeWithParameters(currentClass.getAnnotatedSuperclass(), paramMap);
@Nullable ActualType<?> resultType = getViewOnSuperType(targetClass, superType); ActualType<?> resultType = getViewOnSuperType(targetClass, superType);
if (resultType != null) { if (resultType != null) {
return resultType; return resultType;
} }
@@ -243,10 +242,10 @@ public class ActualType<T> implements AnnotatedElement {
appendAnnotationsToString(sb, usedType.getAnnotations()); appendAnnotationsToString(sb, usedType.getAnnotations());
} }
sb.append(declaredType.getName()); sb.append(declaredType.getName());
List<@NotNull ActualType<?>> parameters = parameters(); List<ActualType<?>> parameters = parameters();
if (!parameters.isEmpty()) { if (!parameters.isEmpty()) {
sb.append("<"); sb.append("<");
for (@NotNull ActualType<?> parameter : parameters) { for (ActualType<?> parameter : parameters) {
sb.append(parameter); sb.append(parameter);
sb.append(", "); sb.append(", ");
} }
@@ -256,8 +255,8 @@ public class ActualType<T> implements AnnotatedElement {
return sb.toString(); return sb.toString();
} }
private void appendAnnotationsToString(@NotNull StringBuilder sb, @NotNull Annotation[] annotations) { private void appendAnnotationsToString(StringBuilder sb, Annotation[] annotations) {
for (@NotNull Annotation annotation : annotations) { for (Annotation annotation : annotations) {
sb.append(annotation); sb.append(annotation);
sb.append(' '); sb.append(' ');
} }

View File

@@ -2,12 +2,11 @@ package de.siphalor.tweed5.typeutils.api.type;
import de.siphalor.tweed5.typeutils.impl.type.AnnotationRepeatTypeResolver; import de.siphalor.tweed5.typeutils.impl.type.AnnotationRepeatTypeResolver;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
public interface AnnotationRepeatType { public interface AnnotationRepeatType {
static AnnotationRepeatType getType(@NotNull Class<? extends Annotation> annotationClass) { static AnnotationRepeatType getType(Class<? extends Annotation> annotationClass) {
return AnnotationRepeatTypeResolver.getType(annotationClass); return AnnotationRepeatTypeResolver.getType(annotationClass);
} }

View File

@@ -1,8 +1,7 @@
package de.siphalor.tweed5.typeutils.api.type; package de.siphalor.tweed5.typeutils.api.type;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
@@ -11,7 +10,7 @@ import java.util.*;
public class LayeredTypeAnnotations implements AnnotatedElement { public class LayeredTypeAnnotations implements AnnotatedElement {
private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0]; private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
public static LayeredTypeAnnotations of(@NotNull TypeAnnotationLayer layer, @NotNull AnnotatedElement annotatedElement) { public static LayeredTypeAnnotations of(TypeAnnotationLayer layer, AnnotatedElement annotatedElement) {
LayeredTypeAnnotations annotations = new LayeredTypeAnnotations(); LayeredTypeAnnotations annotations = new LayeredTypeAnnotations();
annotations.layers.add(new Layer(layer, annotatedElement)); annotations.layers.add(new Layer(layer, annotatedElement));
return annotations; return annotations;
@@ -19,7 +18,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
private final List<Layer> layers = new ArrayList<>(); private final List<Layer> layers = new ArrayList<>();
public void appendLayerFrom(@NotNull TypeAnnotationLayer layer, @NotNull AnnotatedElement annotatedElement) { public void appendLayerFrom(TypeAnnotationLayer layer, AnnotatedElement annotatedElement) {
int i; int i;
for (i = 0; i < layers.size(); i++) { for (i = 0; i < layers.size(); i++) {
if (layer.compareTo(layers.get(i).layer()) > 0) { if (layer.compareTo(layers.get(i).layer()) > 0) {
@@ -29,7 +28,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
layers.add(i, new Layer(layer, annotatedElement)); layers.add(i, new Layer(layer, annotatedElement));
} }
public void prependLayerFrom(@NotNull TypeAnnotationLayer layer, @NotNull AnnotatedElement annotatedElement) { public void prependLayerFrom(TypeAnnotationLayer layer, AnnotatedElement annotatedElement) {
int i; int i;
for (i = 0; i < layers.size(); i++) { for (i = 0; i < layers.size(); i++) {
if (layer.compareTo(layers.get(i).layer()) >= 0) { if (layer.compareTo(layers.get(i).layer()) >= 0) {
@@ -40,7 +39,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
} }
@Override @Override
public <T extends Annotation> T getAnnotation(@NotNull Class<T> annotationClass) { public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
if (layers.isEmpty()) { if (layers.isEmpty()) {
return null; return null;
} else if (layers.size() == 1) { } else if (layers.size() == 1) {
@@ -62,7 +61,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
} }
@Override @Override
public @NotNull Annotation @NotNull [] getAnnotations() { public Annotation[] getAnnotations() {
if (layers.isEmpty()) { if (layers.isEmpty()) {
return EMPTY_ANNOTATIONS; return EMPTY_ANNOTATIONS;
} else if (layers.size() == 1) { } else if (layers.size() == 1) {
@@ -87,7 +86,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
} }
@Override @Override
public @NotNull Annotation @NotNull [] getDeclaredAnnotations() { public Annotation[] getDeclaredAnnotations() {
if (layers.isEmpty()) { if (layers.isEmpty()) {
return EMPTY_ANNOTATIONS; return EMPTY_ANNOTATIONS;
} else if (layers.size() == 1) { } else if (layers.size() == 1) {
@@ -111,7 +110,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
return annotations.values().toArray(new Annotation[0]); return annotations.values().toArray(new Annotation[0]);
} }
private static <T extends Annotation> @Nullable Class<? extends Annotation> getRepeatAlternativeAnnotation(@NotNull Class<T> annotationClass) { private static <T extends Annotation> @Nullable Class<? extends Annotation> getRepeatAlternativeAnnotation(Class<T> annotationClass) {
AnnotationRepeatType annotationRepeatType = AnnotationRepeatType.getType(annotationClass); AnnotationRepeatType annotationRepeatType = AnnotationRepeatType.getType(annotationClass);
Class<? extends Annotation> altAnnotationClass = null; Class<? extends Annotation> altAnnotationClass = null;
if (annotationRepeatType instanceof AnnotationRepeatType.Repeatable) { if (annotationRepeatType instanceof AnnotationRepeatType.Repeatable) {

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.typeutils.api.type;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,5 +1,6 @@
@ApiStatus.Internal @ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.typeutils.impl; package de.siphalor.tweed5.typeutils.impl;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,8 +1,7 @@
package de.siphalor.tweed5.typeutils.impl.type; package de.siphalor.tweed5.typeutils.impl.type;
import de.siphalor.tweed5.typeutils.api.type.AnnotationRepeatType; import de.siphalor.tweed5.typeutils.api.type.AnnotationRepeatType;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable; import java.lang.annotation.Repeatable;
@@ -16,7 +15,7 @@ public class AnnotationRepeatTypeResolver {
private static final Map<Class<? extends Annotation>, AnnotationRepeatType> CACHE = new HashMap<>(); private static final Map<Class<? extends Annotation>, AnnotationRepeatType> CACHE = new HashMap<>();
private static final ReadWriteLock CACHE_LOCK = new ReentrantReadWriteLock(); private static final ReadWriteLock CACHE_LOCK = new ReentrantReadWriteLock();
public static AnnotationRepeatType getType(@NotNull Class<? extends Annotation> annotationClass) { public static AnnotationRepeatType getType(Class<? extends Annotation> annotationClass) {
CACHE_LOCK.readLock().lock(); CACHE_LOCK.readLock().lock();
try { try {
AnnotationRepeatType cachedValue = CACHE.get(annotationClass); AnnotationRepeatType cachedValue = CACHE.get(annotationClass);
@@ -29,7 +28,7 @@ public class AnnotationRepeatTypeResolver {
return determineType(annotationClass); return determineType(annotationClass);
} }
private static AnnotationRepeatType determineType(@NotNull Class<? extends Annotation> annotationClass) { private static AnnotationRepeatType determineType(Class<? extends Annotation> annotationClass) {
Class<? extends Annotation> container = getRepeatableContainerFromComponentAnnotation(annotationClass); Class<? extends Annotation> container = getRepeatableContainerFromComponentAnnotation(annotationClass);
if (container != null) { if (container != null) {
CACHE_LOCK.writeLock().lock(); CACHE_LOCK.writeLock().lock();
@@ -64,8 +63,7 @@ public class AnnotationRepeatTypeResolver {
return AnnotationRepeatType.NonRepeatable.instance(); return AnnotationRepeatType.NonRepeatable.instance();
} }
@Nullable private static @Nullable Class<? extends Annotation> getRepeatableContainerFromComponentAnnotation(
private static Class<? extends Annotation> getRepeatableContainerFromComponentAnnotation(
Class<? extends Annotation> annotationClass Class<? extends Annotation> annotationClass
) { ) {
Repeatable repeatableDeclaration = annotationClass.getAnnotation(Repeatable.class); Repeatable repeatableDeclaration = annotationClass.getAnnotation(Repeatable.class);
@@ -75,8 +73,7 @@ public class AnnotationRepeatTypeResolver {
return repeatableDeclaration.value(); return repeatableDeclaration.value();
} }
@Nullable private static @Nullable Class<? extends Annotation> getRepeatableComponentFromContainerAnnotation(
private static Class<? extends Annotation> getRepeatableComponentFromContainerAnnotation(
Class<? extends Annotation> annotationClass Class<? extends Annotation> annotationClass
) { ) {
try { try {

View File

@@ -3,17 +3,18 @@ package de.siphalor.tweed5.utils.api.collection;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.*; import java.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@EqualsAndHashCode @EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PROTECTED) @RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class ClassToInstanceMap<T> implements Iterable<T> { public class ClassToInstanceMap<T extends @NonNull Object> implements Iterable<T> {
private final Map<Class<? extends T>, T> delegate; private final Map<Class<? extends T>, T> delegate;
public static <T> ClassToInstanceMap<T> backedBy(Map<Class<? extends T>, T> delegate) { public static <T extends @NonNull Object> ClassToInstanceMap<T> backedBy(Map<Class<? extends T>, T> delegate) {
return new ClassToInstanceMap<>(delegate); return new ClassToInstanceMap<>(delegate);
} }
@@ -41,11 +42,11 @@ public class ClassToInstanceMap<T> implements Iterable<T> {
return (V) delegate.get(key); return (V) delegate.get(key);
} }
public <V extends T> V put(@NotNull V value) { public <V extends T> @Nullable V put(V value) {
return (V) delegate.put((Class<? extends T>) value.getClass(), value); return (V) delegate.put((Class<? extends T>) value.getClass(), value);
} }
public <V extends T> V remove(Class<V> key) { public <V extends T> @Nullable V remove(Class<V> key) {
return (V) delegate.remove(key); return (V) delegate.remove(key);
} }
@@ -60,7 +61,7 @@ public class ClassToInstanceMap<T> implements Iterable<T> {
public Set<T> values() { public Set<T> values() {
return new AbstractSet<T>() { return new AbstractSet<T>() {
@Override @Override
public @NotNull Iterator<T> iterator() { public Iterator<T> iterator() {
Iterator<Map.Entry<Class<? extends T>, T>> entryIterator = delegate.entrySet().iterator(); Iterator<Map.Entry<Class<? extends T>, T>> entryIterator = delegate.entrySet().iterator();
return new Iterator<T>() { return new Iterator<T>() {
@Override @Override
@@ -88,7 +89,7 @@ public class ClassToInstanceMap<T> implements Iterable<T> {
} }
@Override @Override
public @NotNull Iterator<T> iterator() { public Iterator<T> iterator() {
return values().iterator(); return values().iterator();
} }
} }

View File

@@ -1,7 +1,7 @@
package de.siphalor.tweed5.utils.api.collection; package de.siphalor.tweed5.utils.api.collection;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.*; import java.util.*;
@@ -33,7 +33,7 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public boolean contains(@NotNull Object o) { public boolean contains(Object o) {
return delegate.getOrDefault(o.getClass(), Collections.emptyList()).contains(o); return delegate.getOrDefault(o.getClass(), Collections.emptyList()).contains(o);
} }
@@ -42,10 +42,10 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public @NotNull Iterator<T> iterator() { public Iterator<T> iterator() {
return new Iterator<T>() { return new Iterator<T>() {
private final Iterator<Map.Entry<Class<? extends T>, Collection<T>>> classIterator = delegate.entrySet().iterator(); private final Iterator<Map.Entry<Class<? extends T>, Collection<T>>> classIterator = delegate.entrySet().iterator();
private Iterator<? extends T> listIterator; private @Nullable Iterator<? extends T> listIterator;
private boolean keptElement; private boolean keptElement;
private boolean keptAnyElementInList; private boolean keptAnyElementInList;
@@ -82,14 +82,12 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
@NotNull public Object[] toArray() {
public Object @NotNull [] toArray() {
return delegate.values().stream().flatMap(Collection::stream).toArray(); return delegate.values().stream().flatMap(Collection::stream).toArray();
} }
@Override @Override
@NotNull public <S> S[] toArray(S[] array) {
public <S> S @NotNull [] toArray(@NotNull S @NotNull [] array) {
Class<?> clazz = array.getClass().getComponentType(); Class<?> clazz = array.getClass().getComponentType();
return delegate.values().stream() return delegate.values().stream()
.flatMap(Collection::stream) .flatMap(Collection::stream)
@@ -97,12 +95,12 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public boolean add(@NotNull T value) { public boolean add(T value) {
return delegate.computeIfAbsent(((Class<T>) value.getClass()), clazz -> collectionSupplier.get()).add(value); return delegate.computeIfAbsent(((Class<T>) value.getClass()), clazz -> collectionSupplier.get()).add(value);
} }
@Override @Override
public boolean remove(@NotNull Object value) { public boolean remove(Object value) {
Collection<T> values = delegate.get(value.getClass()); Collection<T> values = delegate.get(value.getClass());
if (values == null) { if (values == null) {
return false; return false;
@@ -116,19 +114,17 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
return false; return false;
} }
@NotNull
public <U extends T> Collection<U> getAll(Class<U> clazz) { public <U extends T> Collection<U> getAll(Class<U> clazz) {
return (Collection<U>) Collections.unmodifiableCollection(delegate.getOrDefault(clazz, Collections.emptyList())); return (Collection<U>) Collections.unmodifiableCollection(delegate.getOrDefault(clazz, Collections.emptyList()));
} }
@NotNull
public Collection<T> removeAll(Class<? extends T> clazz) { public Collection<T> removeAll(Class<? extends T> clazz) {
Collection<T> removed = delegate.remove(clazz); Collection<T> removed = delegate.remove(clazz);
return removed == null ? Collections.emptyList() : Collections.unmodifiableCollection(removed); return removed == null ? Collections.emptyList() : Collections.unmodifiableCollection(removed);
} }
@Override @Override
public boolean containsAll(@NotNull Collection<?> values) { public boolean containsAll(Collection<?> values) {
for (Object value : values) { for (Object value : values) {
if (!contains(value)) { if (!contains(value)) {
return false; return false;
@@ -138,7 +134,7 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public boolean addAll(@NotNull Collection<? extends T> values) { public boolean addAll(Collection<? extends T> values) {
boolean changed = false; boolean changed = false;
for (T value : values) { for (T value : values) {
changed = add(value) || changed; changed = add(value) || changed;
@@ -147,7 +143,7 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public boolean removeAll(@NotNull Collection<?> values) { public boolean removeAll(Collection<?> values) {
boolean changed = false; boolean changed = false;
for (Object value : values) { for (Object value : values) {
changed = remove(value) || changed; changed = remove(value) || changed;
@@ -156,7 +152,7 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public boolean retainAll(@NotNull Collection<?> values) { public boolean retainAll(Collection<?> values) {
Map<Class<?>, ? extends List<?>> valuesByClass = values.stream() Map<Class<?>, ? extends List<?>> valuesByClass = values.stream()
.collect(Collectors.groupingBy(Object::getClass)); .collect(Collectors.groupingBy(Object::getClass));
delegate.putAll((Map<Class<? extends T>, List<T>>)(Object) valuesByClass); delegate.putAll((Map<Class<? extends T>, List<T>>)(Object) valuesByClass);
@@ -178,37 +174,37 @@ public class ClassToInstancesMultimap<T> implements Collection<T> {
} }
@Override @Override
public @NotNull Iterator<T> iterator() { public Iterator<T> iterator() {
return delegate.values().stream().flatMap(Collection::stream).iterator(); return delegate.values().stream().flatMap(Collection::stream).iterator();
} }
@Override @Override
public boolean add(@NotNull T value) { public boolean add(T value) {
throw createUnsupportedOperationException(); throw createUnsupportedOperationException();
} }
@Override @Override
public boolean remove(@NotNull Object value) { public boolean remove(Object value) {
throw createUnsupportedOperationException(); throw createUnsupportedOperationException();
} }
@Override @Override
public @NotNull Collection<T> removeAll(Class<? extends T> clazz) { public Collection<T> removeAll(Class<? extends T> clazz) {
throw createUnsupportedOperationException(); throw createUnsupportedOperationException();
} }
@Override @Override
public boolean addAll(@NotNull Collection<? extends T> values) { public boolean addAll(Collection<? extends T> values) {
throw createUnsupportedOperationException(); throw createUnsupportedOperationException();
} }
@Override @Override
public boolean removeAll(@NotNull Collection<?> values) { public boolean removeAll(Collection<?> values) {
throw createUnsupportedOperationException(); throw createUnsupportedOperationException();
} }
@Override @Override
public boolean retainAll(@NotNull Collection<?> values) { public boolean retainAll(Collection<?> values) {
throw createUnsupportedOperationException(); throw createUnsupportedOperationException();
} }

View File

@@ -2,22 +2,24 @@ package de.siphalor.tweed5.utils.api.collection;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.*; import java.util.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@AllArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED)
public class InheritanceMap<T> { public class InheritanceMap<T extends @NonNull Object> {
private static final InheritanceMap<Object> EMPTY = unmodifiable(new InheritanceMap<>(Object.class)); private static final InheritanceMap<Object> EMPTY = unmodifiable(new InheritanceMap<>(Object.class));
private final Class<T> baseClass; private final Class<T> baseClass;
private final Map<T, Collection<Class<? extends T>>> instanceToClasses; private final Map<T, Collection<Class<? extends T>>> instanceToClasses;
private final Map<Class<? extends T>, Collection<T>> classToInstances; private final Map<Class<? extends T>, Collection<T>> classToInstances;
public static <T> InheritanceMap<T> empty() { public static <T extends @NonNull Object> InheritanceMap<T> empty() {
return (InheritanceMap<T>) EMPTY; return (InheritanceMap<T>) EMPTY;
} }
public static <T> InheritanceMap<T> unmodifiable(InheritanceMap<T> map) { public static <T extends @NonNull Object> InheritanceMap<T> unmodifiable(InheritanceMap<T> map) {
return new Unmodifiable<>(map); return new Unmodifiable<>(map);
} }
@@ -49,7 +51,7 @@ public class InheritanceMap<T> {
return (Collection<V>) classToInstances.getOrDefault(clazz, Collections.emptyList()); return (Collection<V>) classToInstances.getOrDefault(clazz, Collections.emptyList());
} }
public <V extends T> V getSingleInstance(Class<V> clazz) throws NonUniqueResultException { public <V extends T> @Nullable V getSingleInstance(Class<V> clazz) throws NonUniqueResultException {
Collection<T> instances = classToInstances.getOrDefault(clazz, Collections.emptyList()); Collection<T> instances = classToInstances.getOrDefault(clazz, Collections.emptyList());
if (instances.isEmpty()) { if (instances.isEmpty()) {
return null; return null;
@@ -87,7 +89,7 @@ public class InheritanceMap<T> {
} }
} }
public <V extends T> V removeInstance(V instance) { public <V extends T> @Nullable V removeInstance(V instance) {
if (!instanceToClasses.containsKey(instance)) { if (!instanceToClasses.containsKey(instance)) {
return null; return null;
} }
@@ -153,7 +155,7 @@ public class InheritanceMap<T> {
} }
} }
private static class Unmodifiable<T> extends InheritanceMap<T> { private static class Unmodifiable<T extends @NonNull Object> extends InheritanceMap<T> {
public Unmodifiable(InheritanceMap<T> delegate) { public Unmodifiable(InheritanceMap<T> delegate) {
super(delegate.baseClass, delegate.instanceToClasses, delegate.classToInstances); super(delegate.baseClass, delegate.instanceToClasses, delegate.classToInstances);
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.utils.api.collection;
import org.jspecify.annotations.NullMarked;

View File

@@ -7,7 +7,7 @@ import de.siphalor.tweed5.weaver.pojo.api.weaving.WeavingContext;
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor; import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
import de.siphalor.tweed5.weaver.pojoext.serde.impl.SerdePojoReaderWriterSpec; import de.siphalor.tweed5.weaver.pojoext.serde.impl.SerdePojoReaderWriterSpec;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@@ -80,8 +80,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
} }
} }
@Nullable private @Nullable EntryReaderWriterDefinition createDefinitionFromEntryConfig(EntryReadWriteConfig entryConfig, WeavingContext context) {
private EntryReaderWriterDefinition createDefinitionFromEntryConfig(EntryReadWriteConfig entryConfig, WeavingContext context) {
String readerSpecText = entryConfig.reader().isEmpty() ? entryConfig.value() : entryConfig.reader(); String readerSpecText = entryConfig.reader().isEmpty() ? entryConfig.value() : entryConfig.reader();
String writerSpecText = entryConfig.writer().isEmpty() ? entryConfig.value() : entryConfig.writer(); String writerSpecText = entryConfig.writer().isEmpty() ? entryConfig.value() : entryConfig.writer();
@@ -98,14 +97,14 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
return null; return null;
} }
//noinspection unchecked //noinspection unchecked,rawtypes
TweedEntryReader<?, ?> reader = readerSpec == null TweedEntryReader<?, ?> reader = Optional.ofNullable(readerSpec)
? TweedEntryReaderWriterImpls.NOOP_READER_WRITER .map((spec) -> resolveReaderWriterFromSpec((Class<TweedEntryReader<?, ?>>)(Object) TweedEntryReader.class, readerFactories, spec, context))
: resolveReaderWriterFromSpec((Class<TweedEntryReader<?, ?>>)(Object) TweedEntryReader.class, readerFactories, readerSpec, context); .orElse(((TweedEntryReader) TweedEntryReaderWriterImpls.NOOP_READER_WRITER));
//noinspection unchecked //noinspection unchecked,rawtypes
TweedEntryWriter<?, ?> writer = writerSpec == null TweedEntryWriter<?, ?> writer = Optional.ofNullable(writerSpec)
? TweedEntryReaderWriterImpls.NOOP_READER_WRITER .map((spec) -> resolveReaderWriterFromSpec((Class<TweedEntryWriter<?, ?>>)(Object) TweedEntryWriter.class, writerFactories, spec, context))
: resolveReaderWriterFromSpec((Class<TweedEntryWriter<?, ?>>)(Object) TweedEntryWriter.class, writerFactories, writerSpec, context); .orElse(((TweedEntryWriter) TweedEntryReaderWriterImpls.NOOP_READER_WRITER));
return new EntryReaderWriterDefinition() { return new EntryReaderWriterDefinition() {
@Override @Override
@@ -120,8 +119,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
}; };
} }
@Nullable private @Nullable SerdePojoReaderWriterSpec specFromText(String specText, WeavingContext context) {
private SerdePojoReaderWriterSpec specFromText(String specText, WeavingContext context) {
if (specText.isEmpty()) { if (specText.isEmpty()) {
return null; return null;
} }
@@ -137,7 +135,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
} }
} }
private <T> T resolveReaderWriterFromSpec( private <T> @Nullable T resolveReaderWriterFromSpec(
Class<T> baseClass, Class<T> baseClass,
Map<String, TweedReaderWriterProvider.ReaderWriterFactory<T>> factories, Map<String, TweedReaderWriterProvider.ReaderWriterFactory<T>> factories,
SerdePojoReaderWriterSpec spec, SerdePojoReaderWriterSpec spec,
@@ -152,17 +150,18 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
TweedReaderWriterProvider.ReaderWriterFactory<T> factory = factories.get(spec.identifier()); TweedReaderWriterProvider.ReaderWriterFactory<T> factory = factories.get(spec.identifier());
T instance; T instance;
if (factory != null) { try {
instance = factory.create(arguments); if (factory != null) {
} else { instance = factory.create(arguments);
instance = loadClassIfExists(baseClass, spec.identifier(), arguments); } else {
} instance = loadClassIfExists(baseClass, spec.identifier(), arguments);
}
if (instance == null) { } catch (Exception e) {
log.warn( log.warn(
"Failed to resolve reader or writer factory \"{}\" for entry {}, entry will not be included in serde", "Failed to resolve reader or writer factory \"{}\" for entry {}, entry will not be included in serde",
spec.identifier(), spec.identifier(),
context.path() context.path(),
e
); );
return null; return null;
} }
@@ -170,7 +169,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
return instance; return instance;
} }
private <T> T loadClassIfExists(Class<T> baseClass, String className, T[] arguments) { private <T> @Nullable T loadClassIfExists(Class<T> baseClass, String className, T[] arguments) {
try { try {
Class<?> clazz = Class.forName(className); Class<?> clazz = Class.forName(className);
Class<?>[] argClasses = new Class<?>[arguments.length]; Class<?>[] argClasses = new Class<?>[arguments.length];

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojoext.serde.api;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojoext.serde.impl;
import org.jspecify.annotations.NullMarked;

View File

@@ -57,13 +57,13 @@ class WeaverPojoSerdeExtensionTest {
public static class TestWriterProvider implements TweedReaderWriterProvider { public static class TestWriterProvider implements TweedReaderWriterProvider {
@Override @Override
public void provideReaderWriters(ProviderContext context) { public void provideReaderWriters(ProviderContext context) {
context.registerWriterFactory("tweed5.test.dummy", delegates -> new TweedEntryWriter<Object, ConfigEntry<Object>>() { context.registerWriterFactory("tweed5.test.dummy", delegates -> new TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>() {
@Override @Override
public void write( public void write(
TweedDataVisitor writer, @NonNull TweedDataVisitor writer,
Object value, Object value,
ConfigEntry<Object> entry, ConfigEntry<Object> entry,
TweedWriteContext context @NonNull TweedWriteContext context
) throws TweedDataWriteException { ) throws TweedDataWriteException {
writer.visitString("my cool custom writer"); writer.visitString("my cool custom writer");
} }

View File

@@ -5,7 +5,7 @@ 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 lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -28,9 +28,9 @@ public interface WeavableCompoundConfigEntry<T> extends CompoundConfigEntry<T> {
@Value @Value
@RequiredArgsConstructor @RequiredArgsConstructor
class SubEntry { class SubEntry {
@NotNull String name; String name;
@NotNull ConfigEntry<?> configEntry; ConfigEntry<?> configEntry;
@NotNull MethodHandle getter; @Nullable MethodHandle getter;
@NotNull MethodHandle setter; @Nullable MethodHandle setter;
} }
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.api.entry;
import org.jspecify.annotations.NullMarked;

View File

@@ -9,8 +9,7 @@ import de.siphalor.tweed5.weaver.pojo.impl.entry.CollectionConfigEntryImpl;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException; import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.collection.CollectionWeavingConfig; import de.siphalor.tweed5.weaver.pojo.impl.weaving.collection.CollectionWeavingConfig;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.collection.CollectionWeavingConfigImpl; import de.siphalor.tweed5.weaver.pojo.impl.weaving.collection.CollectionWeavingConfigImpl;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@@ -33,7 +32,7 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
@Override @Override
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) { public <T> @Nullable ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
List<ActualType<?>> collectionTypeParams = valueType.getTypesOfSuperArguments(Collection.class); List<ActualType<?>> collectionTypeParams = valueType.getTypesOfSuperArguments(Collection.class);
if (collectionTypeParams == null) { if (collectionTypeParams == null) {
return null; return null;
@@ -82,7 +81,7 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
return CollectionWeavingConfigImpl.withOverrides(parent, local); return CollectionWeavingConfigImpl.withOverrides(parent, local);
} }
private CollectionWeavingConfig createWeavingConfigFromAnnotations(@NotNull AnnotatedElement annotations) { private @Nullable CollectionWeavingConfig createWeavingConfigFromAnnotations(AnnotatedElement annotations) {
CollectionWeaving annotation = annotations.getAnnotation(CollectionWeaving.class); CollectionWeaving annotation = annotations.getAnnotation(CollectionWeaving.class);
if (annotation == null) { if (annotation == null) {
return null; return null;

View File

@@ -15,8 +15,7 @@ import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoClassIntrospector;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException; import de.siphalor.tweed5.weaver.pojo.impl.weaving.PojoWeavingException;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfig; import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfig;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfigImpl; import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfigImpl;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
@@ -44,7 +43,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
} }
@Override @Override
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) { public <T> @Nullable ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
if (context.annotations().getAnnotation(CompoundWeaving.class) == null) { if (context.annotations().getAnnotation(CompoundWeaving.class) == null) {
return null; return null;
} }
@@ -88,8 +87,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
return CompoundWeavingConfigImpl.withOverrides(parent, local); return CompoundWeavingConfigImpl.withOverrides(parent, local);
} }
@Nullable private @Nullable CompoundWeavingConfig createWeavingConfigFromAnnotations(AnnotatedElement annotations) {
private CompoundWeavingConfig createWeavingConfigFromAnnotations(@NotNull AnnotatedElement annotations) {
CompoundWeaving annotation = annotations.getAnnotation(CompoundWeaving.class); CompoundWeaving annotation = annotations.getAnnotation(CompoundWeaving.class);
if (annotation == null) { if (annotation == null) {
return null; return null;
@@ -127,7 +125,6 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
//noinspection rawtypes //noinspection rawtypes
Class<? extends WeavableCompoundConfigEntry> annotationEntryClass = weavingConfig.compoundEntryClass(); Class<? extends WeavableCompoundConfigEntry> annotationEntryClass = weavingConfig.compoundEntryClass();
@NotNull
Class<WeavableCompoundConfigEntry<C>> weavableEntryClass = (Class<WeavableCompoundConfigEntry<C>>) ( Class<WeavableCompoundConfigEntry<C>> weavableEntryClass = (Class<WeavableCompoundConfigEntry<C>>) (
annotationEntryClass != null annotationEntryClass != null
? annotationEntryClass ? annotationEntryClass
@@ -143,7 +140,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
return property.getter() != null && (property.setter() != null || property.isFinal()); return property.getter() != null && (property.setter() != null || property.isFinal());
} }
private @NotNull WeavableCompoundConfigEntry.SubEntry weaveCompoundSubEntry( private WeavableCompoundConfigEntry.SubEntry weaveCompoundSubEntry(
PojoClassIntrospector.Property property, PojoClassIntrospector.Property property,
WeavingContext.ExtensionsData newExtensionsData, WeavingContext.ExtensionsData newExtensionsData,
WeavingContext parentContext WeavingContext parentContext
@@ -167,7 +164,9 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
); );
} }
private @NotNull String convertName(String name, CompoundWeavingConfig weavingConfig) { private String convertName(String name, CompoundWeavingConfig weavingConfig) {
// Always non-null at this point, since null values were already defaulted
//noinspection DataFlowIssue
return NamingFormat.convert( return NamingFormat.convert(
name, name,
weavingConfig.compoundSourceNamingFormat(), weavingConfig.compoundSourceNamingFormat(),
@@ -175,7 +174,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
); );
} }
private @NotNull NamingFormat getNamingFormatById(String id) { private NamingFormat getNamingFormatById(String id) {
NamingFormat namingFormat = namingFormatCollector.namingFormats().get(id); NamingFormat namingFormat = namingFormatCollector.namingFormats().get(id);
if (namingFormat == null) { if (namingFormat == null) {
throw new PojoWeavingException( throw new PojoWeavingException(

View File

@@ -3,7 +3,6 @@ package de.siphalor.tweed5.weaver.pojo.api.weaving;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
import de.siphalor.tweed5.typeutils.api.type.ActualType; import de.siphalor.tweed5.typeutils.api.type.ActualType;
import org.jetbrains.annotations.Nullable;
public class TrivialPojoWeaver implements TweedPojoWeaver { public class TrivialPojoWeaver implements TweedPojoWeaver {
@Override @Override
@@ -12,7 +11,7 @@ public class TrivialPojoWeaver implements TweedPojoWeaver {
} }
@Override @Override
public @Nullable <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) { public <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
SimpleConfigEntryImpl<T> entry = new SimpleConfigEntryImpl<>(valueType.declaredType()); SimpleConfigEntryImpl<T> entry = new SimpleConfigEntryImpl<>(valueType.declaredType());
entry.seal(context.configContainer()); entry.seal(context.configContainer());
return entry; return entry;

View File

@@ -2,8 +2,7 @@ package de.siphalor.tweed5.weaver.pojo.api.weaving;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.typeutils.api.type.ActualType; import de.siphalor.tweed5.typeutils.api.type.ActualType;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
@FunctionalInterface @FunctionalInterface
public interface TweedPojoWeavingFunction { public interface TweedPojoWeavingFunction {
@@ -12,8 +11,7 @@ public interface TweedPojoWeavingFunction {
* The returned config entry must be sealed. * The returned config entry must be sealed.
* @return The resulting, sealed config entry or {@code null}, if the weaving function is not applicable to the given parameters. * @return The resulting, sealed config entry or {@code null}, if the weaving function is not applicable to the given parameters.
*/ */
@Nullable <T> @Nullable ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
<T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
@FunctionalInterface @FunctionalInterface
interface NonNull extends TweedPojoWeavingFunction { interface NonNull extends TweedPojoWeavingFunction {
@@ -25,6 +23,6 @@ public interface TweedPojoWeavingFunction {
* @throws RuntimeException when a valid config entry could not be resolved. * @throws RuntimeException when a valid config entry could not be resolved.
*/ */
@Override @Override
@NotNull <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context); <T> @org.jspecify.annotations.NonNull ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
} }
} }

View File

@@ -6,26 +6,19 @@ import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.typeutils.api.type.ActualType; import de.siphalor.tweed5.typeutils.api.type.ActualType;
import lombok.*; import lombok.*;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
import java.util.Arrays; import java.util.Arrays;
@Value @Value
public class WeavingContext implements TweedPojoWeavingFunction.NonNull { public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
@Nullable @Nullable WeavingContext parent;
WeavingContext parent;
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
@NotNull
TweedPojoWeavingFunction.NonNull weavingFunction; TweedPojoWeavingFunction.NonNull weavingFunction;
@NotNull
ConfigContainer<?> configContainer; ConfigContainer<?> configContainer;
@NotNull
String[] path; String[] path;
@NotNull
ExtensionsData extensionsData; ExtensionsData extensionsData;
@NotNull
AnnotatedElement annotations; AnnotatedElement annotations;
public static Builder builder(TweedPojoWeavingFunction.NonNull weavingFunction, ConfigContainer<?> configContainer) { public static Builder builder(TweedPojoWeavingFunction.NonNull weavingFunction, ConfigContainer<?> configContainer) {
@@ -36,14 +29,14 @@ 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(@NotNull String subPathName) { public Builder subContextBuilder(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);
} }
@Override @Override
public @NotNull <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) { public <T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context) {
return weavingFunction.weaveEntry(valueType, context); return weavingFunction.weaveEntry(valueType, context);
} }

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.api.weaving;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess;
import org.jspecify.annotations.NullMarked;

View File

@@ -9,6 +9,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.function.IntFunction; import java.util.function.IntFunction;
@@ -18,7 +19,7 @@ import java.util.function.IntFunction;
@ToString(callSuper = true) @ToString(callSuper = true)
public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements WeavableCollectionConfigEntry<E, T> { public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements WeavableCollectionConfigEntry<E, T> {
private final IntFunction<T> constructor; private final IntFunction<T> constructor;
private ConfigEntry<E> elementEntry; private @Nullable ConfigEntry<E> elementEntry;
public CollectionConfigEntryImpl(@NotNull Class<T> valueClass, IntFunction<T> constructor) { public CollectionConfigEntryImpl(@NotNull Class<T> valueClass, IntFunction<T> constructor) {
super(valueClass); super(valueClass);

View File

@@ -5,7 +5,6 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor; import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor; import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry; import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
import org.jetbrains.annotations.NotNull;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -17,7 +16,7 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
private final Map<String, SubEntry> subEntries = new LinkedHashMap<>(); private final Map<String, SubEntry> subEntries = new LinkedHashMap<>();
private final Map<String, ConfigEntry<?>> subConfigEntries = new LinkedHashMap<>(); private final Map<String, ConfigEntry<?>> subConfigEntries = new LinkedHashMap<>();
public StaticPojoCompoundConfigEntry(@NotNull Class<T> valueClass, @NotNull Supplier<T> noArgsConstructor) { public StaticPojoCompoundConfigEntry(Class<T> valueClass, Supplier<T> noArgsConstructor) {
super(valueClass); super(valueClass);
this.noArgsConstructor = noArgsConstructor; this.noArgsConstructor = noArgsConstructor;
} }
@@ -91,7 +90,7 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
subEntries.forEach((key, entry) -> { subEntries.forEach((key, entry) -> {
if (visitor.enterCompoundSubEntry(key)) { if (visitor.enterCompoundSubEntry(key)) {
try { try {
Object subValue = entry.getter().invokeExact(value); Object subValue = entry.getter().invoke(value);
//noinspection unchecked //noinspection unchecked
visitor.visitEntry((ConfigEntry<Object>) entry.configEntry(), subValue); visitor.visitEntry((ConfigEntry<Object>) entry.configEntry(), subValue);
} catch (Throwable e) { } catch (Throwable e) {
@@ -103,11 +102,11 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
} }
@Override @Override
public @NotNull T deepCopy(@NotNull T value) { public T deepCopy(T value) {
T copy = instantiateCompoundValue(); T copy = instantiateCompoundValue();
for (SubEntry subEntry : subEntries.values()) { for (SubEntry subEntry : subEntries.values()) {
try { try {
Object subValue = subEntry.getter().invokeExact(value); Object subValue = subEntry.getter().invoke(value);
subEntry.setter().invoke(copy, subValue); subEntry.setter().invoke(copy, subValue);
} catch (Throwable e) { } catch (Throwable e) {
throw new RuntimeException("Failed to copy value of sub entry \"" + subEntry.name() + "\"", e); throw new RuntimeException("Failed to copy value of sub entry \"" + subEntry.name() + "\"", e);

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.impl.entry;
import org.jspecify.annotations.NullMarked;

View File

@@ -5,7 +5,7 @@ import lombok.Builder;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Value; import lombok.Value;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
@@ -23,7 +23,7 @@ public class PojoClassIntrospector {
private final Class<?> clazz; private final Class<?> clazz;
private final MethodHandles.Lookup lookup = MethodHandles.publicLookup(); private final MethodHandles.Lookup lookup = MethodHandles.publicLookup();
private Map<String, Property> properties; private @Nullable Map<String, Property> properties;
public static PojoClassIntrospector forClass(Class<?> clazz) { public static PojoClassIntrospector forClass(Class<?> clazz) {
if ((clazz.getModifiers() & Modifier.PUBLIC) == 0) { if ((clazz.getModifiers() & Modifier.PUBLIC) == 0) {

View File

@@ -15,7 +15,7 @@ import de.siphalor.tweed5.weaver.pojo.api.weaving.WeavingContext;
import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor; import de.siphalor.tweed5.weaver.pojo.api.weaving.postprocess.TweedPojoWeavingPostProcessor;
import lombok.*; import lombok.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;

View File

@@ -1,10 +1,9 @@
package de.siphalor.tweed5.weaver.pojo.impl.weaving.collection; package de.siphalor.tweed5.weaver.pojo.impl.weaving.collection;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCollectionConfigEntry; import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCollectionConfigEntry;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
public interface CollectionWeavingConfig { public interface CollectionWeavingConfig {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Nullable @Nullable Class<? extends WeavableCollectionConfigEntry> collectionEntryClass();
Class<? extends WeavableCollectionConfigEntry> collectionEntryClass();
} }

View File

@@ -3,15 +3,14 @@ package de.siphalor.tweed5.weaver.pojo.impl.weaving.collection;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCollectionConfigEntry; import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCollectionConfigEntry;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
@Builder @Builder
@Value @Value
public class CollectionWeavingConfigImpl implements CollectionWeavingConfig { public class CollectionWeavingConfigImpl implements CollectionWeavingConfig {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Nullable @Nullable Class<? extends WeavableCollectionConfigEntry> collectionEntryClass;
Class<? extends WeavableCollectionConfigEntry> collectionEntryClass;
public static CollectionWeavingConfigImpl withOverrides(CollectionWeavingConfig self, CollectionWeavingConfig overrides) { public static CollectionWeavingConfigImpl withOverrides(CollectionWeavingConfig self, CollectionWeavingConfig overrides) {
return CollectionWeavingConfigImpl.builder() return CollectionWeavingConfigImpl.builder()

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.impl.weaving.collection;
import org.jspecify.annotations.NullMarked;

View File

@@ -2,14 +2,13 @@ package de.siphalor.tweed5.weaver.pojo.impl.weaving.compound;
import de.siphalor.tweed5.namingformat.api.NamingFormat; import de.siphalor.tweed5.namingformat.api.NamingFormat;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry; import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
public interface CompoundWeavingConfig { public interface CompoundWeavingConfig {
NamingFormat compoundSourceNamingFormat(); @Nullable NamingFormat compoundSourceNamingFormat();
NamingFormat compoundTargetNamingFormat(); @Nullable NamingFormat compoundTargetNamingFormat();
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Nullable @Nullable Class<? extends WeavableCompoundConfigEntry> compoundEntryClass();
Class<? extends WeavableCompoundConfigEntry> compoundEntryClass();
} }

View File

@@ -4,17 +4,16 @@ import de.siphalor.tweed5.namingformat.api.NamingFormat;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry; import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
import lombok.Builder; import lombok.Builder;
import lombok.Value; import lombok.Value;
import org.jetbrains.annotations.Nullable; import org.jspecify.annotations.Nullable;
@Builder @Builder
@Value @Value
public class CompoundWeavingConfigImpl implements CompoundWeavingConfig { public class CompoundWeavingConfigImpl implements CompoundWeavingConfig {
NamingFormat compoundSourceNamingFormat; @Nullable NamingFormat compoundSourceNamingFormat;
NamingFormat compoundTargetNamingFormat; @Nullable NamingFormat compoundTargetNamingFormat;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Nullable @Nullable Class<? extends WeavableCompoundConfigEntry> compoundEntryClass;
Class<? extends WeavableCompoundConfigEntry> compoundEntryClass;
public static CompoundWeavingConfigImpl withOverrides(CompoundWeavingConfig self, CompoundWeavingConfig overrides) { public static CompoundWeavingConfigImpl withOverrides(CompoundWeavingConfig self, CompoundWeavingConfig overrides) {
return CompoundWeavingConfigImpl.builder() return CompoundWeavingConfigImpl.builder()

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.impl.weaving.compound;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.weaver.pojo.impl.weaving;
import org.jspecify.annotations.NullMarked;