[*] 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)
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)
"localRuntimeOnly"(libs.slf4j.rt)

View File

@@ -4,6 +4,7 @@ asm = "9.7"
autoservice = "1.1.1"
java = "8"
jetbrains-annotations = "26.0.1"
jspecify = "1.0.0"
junit = "5.12.0"
lombok = "1.18.34"
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-processor = { group = "com.google.auto.service", name = "auto-service", version.ref = "autoservice" }
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-core = { group = "org.junit.jupiter", name = "junit-jupiter" }
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 org.jetbrains.annotations.CheckReturnValue;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
/**
* 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.
*/
static <T> TweedConstructFactory.@NotNull FactoryBuilder<T> builder(Class<T> baseClass) {
static <T> TweedConstructFactory.FactoryBuilder<T> builder(Class<T> baseClass) {
return TweedConstructFactoryImpl.builder(baseClass);
}
@@ -30,7 +29,7 @@ public interface TweedConstructFactory<T> {
*/
@CheckReturnValue
@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.
@@ -40,19 +39,19 @@ public interface TweedConstructFactory<T> {
* Defines a new typed argument of the given type.
*/
@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.
*/
@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.
*/
@Contract(pure = true)
@NotNull TweedConstructFactory<T> build();
TweedConstructFactory<T> build();
}
/**
@@ -71,7 +70,7 @@ public interface TweedConstructFactory<T> {
* @see #namedArg(String, Object)
*/
@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.
@@ -81,19 +80,19 @@ public interface TweedConstructFactory<T> {
* @see #namedArg(String, Object)
*/
@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.
* @see #typedArg(Object)
*/
@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.
*/
@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.TweedConstructFactory;
import lombok.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -37,11 +36,11 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
}
@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));
}
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);
if (cachedConstructTarget != null) {
return cachedConstructTarget;
@@ -164,7 +163,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
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;
try {
if (executable instanceof Method) {
@@ -263,7 +262,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
private final Map<String, Class<?>> namedArgs = new HashMap<>();
@Override
public <A> TweedConstructFactory.@NotNull FactoryBuilder<T> typedArg(@NotNull Class<A> argType) {
public <A> TweedConstructFactory.FactoryBuilder<T> typedArg(Class<A> argType) {
argType = boxClass(argType);
if (typedArgs.contains(argType)) {
throw new IllegalArgumentException("Argument for type " + argType + " has already been registered");
@@ -273,10 +272,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
}
@Override
public <A> TweedConstructFactory.@NotNull FactoryBuilder<T> namedArg(
@NotNull String name,
@NotNull Class<A> argType
) {
public <A> TweedConstructFactory.FactoryBuilder<T> namedArg(String name, Class<A> argType) {
Class<?> existingArgType = namedArgs.get(name);
if (existingArgType != null) {
throw new IllegalArgumentException(
@@ -290,7 +286,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
}
@Override
public @NotNull TweedConstructFactory<T> build() {
public TweedConstructFactory<T> build() {
return new TweedConstructFactoryImpl<>(
constructBaseClass,
typedArgs,
@@ -302,18 +298,18 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
@RequiredArgsConstructor
private class Construct<C> implements TweedConstructFactory.Construct<C> {
private final ConstructTarget<C> target;
private final Map<Class<?>, Object> typedArgValues = new HashMap<>();
private final Map<String, Object> namedArgValues = new HashMap<>();
private final Map<Class<?>, @Nullable Object> typedArgValues = new HashMap<>();
private final Map<String, @Nullable Object> namedArgValues = new HashMap<>();
@Override
public <A> TweedConstructFactory.@NotNull Construct<C> typedArg(@NotNull A value) {
public <A> TweedConstructFactory.Construct<C> typedArg(A value) {
requireTypedArgExists(value.getClass(), value);
typedArgValues.put(value.getClass(), value);
return this;
}
@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);
if (value != null && !argType.isAssignableFrom(value.getClass())) {
throw new IllegalArgumentException(
@@ -327,7 +323,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
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)) {
throw new IllegalArgumentException(
"Typed argument for type " + type.getName() + " does not exist, value: " + value
@@ -336,7 +332,7 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
}
@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);
if (argType == null) {
throw new IllegalArgumentException(
@@ -353,10 +349,10 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
}
@Override
public @NotNull C finish() {
public C finish() {
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++) {
Object arg = target.argOrder[i];
if (arg instanceof Class<?>) {
@@ -459,6 +455,6 @@ public class TweedConstructFactoryImpl<T> implements TweedConstructFactory<T> {
private static class ConstructTarget<C> {
Class<?> type;
Object[] argOrder;
Function<Object[], C> invoker;
Function<@Nullable Object[], C> invoker;
}
}

View File

@@ -1,4 +1,6 @@
@ApiStatus.Internal
@NullMarked
package de.siphalor.tweed5.construct.impl;
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.extension.RegisteredExtensionData;
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.Map;

View File

@@ -4,13 +4,11 @@ import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor
@Getter
public abstract class BaseConfigEntry<T> implements ConfigEntry<T> {
@NotNull
private final Class<T> valueClass;
private ConfigContainer<?> container;
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.container.ConfigContainer;
import org.jetbrains.annotations.NotNull;
public interface ConfigEntry<T> {
Class<T> valueClass();
@@ -15,6 +14,5 @@ public interface ConfigEntry<T> {
void visitInOrder(ConfigEntryVisitor visitor);
void visitInOrder(ConfigEntryValueVisitor visitor, T value);
@NotNull
T deepCopy(@NotNull T value);
T deepCopy(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 lombok.Getter;
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.util.*;
@NullUnmarked
public class DefaultConfigContainer<T> implements ConfigContainer<T> {
@Getter
private ConfigContainerSetupPhase setupPhase = ConfigContainerSetupPhase.EXTENSIONS_SETUP;

View File

@@ -1,7 +1,6 @@
package de.siphalor.tweed5.core.impl.entry;
import de.siphalor.tweed5.core.api.entry.*;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.function.IntFunction;
@@ -52,7 +51,7 @@ public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseC
}
@Override
public @NotNull T deepCopy(@NotNull T value) {
public T deepCopy(T value) {
T copy = collectionConstructor.apply(value.size());
for (E element : value) {
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.ConfigEntryVisitor;
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
import org.jetbrains.annotations.NotNull;
public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements SimpleConfigEntry<T> {
public SimpleConfigEntryImpl(Class<T> valueClass) {
@@ -22,8 +21,7 @@ public class SimpleConfigEntryImpl<T> extends BaseConfigEntry<T> implements Simp
}
@Override
@NotNull
public T deepCopy(@NotNull T value) {
public T deepCopy(T value) {
return value;
}
}

View File

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

View File

@@ -1 +1,4 @@
@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.extension.TweedExtension;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
public interface CommentExtension extends TweedExtension {
@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 lombok.Getter;
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)
@NullUnmarked
public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentExtension {
@Getter
private RegisteredExtensionData<EntryExtensionsData, InternalCommentEntryData> internalEntryDataExtension;
@@ -62,8 +65,7 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
}
@Override
@Nullable
public String getFullComment(ConfigEntry<?> configEntry) {
public @Nullable String getFullComment(@NonNull ConfigEntry<?> configEntry) {
String comment = ((InternalCommentEntryData) configEntry.extensionsData()).commentProducer().createComment(configEntry);
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.dataapi.api.TweedDataVisitor;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
public static final TweedEntryWriterCommentMiddleware INSTANCE = new TweedEntryWriterCommentMiddleware();
@@ -20,8 +20,8 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
@Override
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
//noinspection unchecked
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, ConfigEntry<Object>>) inner;
return (TweedEntryWriter<Object, ConfigEntry<Object>>) (writer, value, entry, context) -> {
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) (writer, value, entry, context) -> {
if (writer instanceof CompoundDataVisitor) {
// Comment is already written in front of the key by the CompoundDataWriter,
// so we don't have to write it here.
@@ -94,7 +94,7 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
}
@Override
public void visitString(@NotNull String value) {
public void visitString(String value) {
delegate.visitString(value);
}

View File

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

View File

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

View File

@@ -2,7 +2,6 @@ package de.siphalor.tweed5.defaultextensions.pather.api;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
@RequiredArgsConstructor
public class PathTrackingDataVisitor implements TweedDataVisitor {
@@ -58,7 +57,7 @@ public class PathTrackingDataVisitor implements TweedDataVisitor {
}
@Override
public void visitString(@NotNull String value) {
public void visitString(String value) {
delegate.visitString(value);
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.PathTrackingDataVisitor;
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import lombok.val;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
@AutoService(PatherExtension.class)
@NullUnmarked
public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension {
private static final String PATHER_ID = "pather";
@@ -39,7 +42,7 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
entryWriterMiddleware = createEntryWriterMiddleware();
}
private @NotNull Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() {
private @NonNull Middleware<TweedEntryReader<?, ?>> createEntryReaderMiddleware() {
return new Middleware<TweedEntryReader<?, ?>>() {
@Override
public String id() {
@@ -49,7 +52,7 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
@Override
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
//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) -> {
if (context.extensionsData().isPatchworkPartSet(PathTracking.class)) {
@@ -74,7 +77,7 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
@Override
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
//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) -> {
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.defaultextensions.validation.api.result.ValidationResult;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
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);
}

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.extension.TweedExtension;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
import org.jspecify.annotations.Nullable;
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.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
@@ -14,7 +13,6 @@ import java.util.function.Function;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidationResult<T> {
private final T value;
@NotNull
private final Collection<ValidationIssue> issues;
private final boolean hasError;
@@ -22,7 +20,7 @@ public class ValidationResult<T> {
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));
}

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.ValidationIssueLevel;
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import java.util.Collections;
public class NonNullValidator implements ConfigEntryValidator {
@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) {
return ValidationResult.withIssues(null, Collections.singleton(
new ValidationIssue("Value must not be null", ValidationIssueLevel.ERROR)
@@ -21,7 +21,7 @@ public class NonNullValidator implements ConfigEntryValidator {
}
@Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
public <T> String description(ConfigEntry<T> configEntry) {
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 lombok.AllArgsConstructor;
import lombok.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.Collections;
@Value
@AllArgsConstructor
public class NumberRangeValidator<N extends Number> implements ConfigEntryValidator {
@NotNull
public class NumberRangeValidator<N extends @NonNull Number> implements ConfigEntryValidator {
Class<N> numberClass;
@Nullable
N minimum;
@Nullable
N maximum;
@Nullable N minimum;
@Nullable N maximum;
@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)) {
return ValidationResult.withIssues(value, Collections.singleton(
new ValidationIssue("Value must be numeric", ValidationIssueLevel.ERROR)
@@ -56,7 +53,7 @@ public class NumberRangeValidator<N extends Number> implements ConfigEntryValida
return ValidationResult.ok(value);
}
private int compare(@NotNull Number a, @NotNull Number b) {
private int compare(Number a, Number b) {
if (numberClass == Byte.class) {
return Byte.compare(a.byteValue(), b.byteValue());
} else if (numberClass == Short.class) {
@@ -73,7 +70,7 @@ public class NumberRangeValidator<N extends Number> implements ConfigEntryValida
}
@Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
public <T> String description(ConfigEntry<T> configEntry) {
if (minimum == null) {
if (maximum == null) {
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 lombok.AllArgsConstructor;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
@Getter
@AllArgsConstructor
@@ -18,12 +18,12 @@ public class SimpleValidatorMiddleware implements Middleware<ConfigEntryValidato
public ConfigEntryValidator process(ConfigEntryValidator inner) {
return new ConfigEntryValidator() {
@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));
}
@Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
public <T extends @Nullable Object> String description(ConfigEntry<T> configEntry) {
String description = validator.description(configEntry);
if (description.isEmpty()) {
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.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.util.*;
@AutoService(ValidationExtension.class)
@NullUnmarked
public class ValidationExtensionImpl implements ReadWriteRelatedExtension, ValidationExtension, CommentModifyingExtension {
private static final ValidationResult<?> PRIMITIVE_IS_NULL_RESULT = ValidationResult.withIssues(
null,
@@ -47,7 +49,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
);
private static final ConfigEntryValidator PRIMITIVE_VALIDATOR = new ConfigEntryValidator() {
@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) {
//noinspection unchecked
return (ValidationResult<T>) PRIMITIVE_IS_NULL_RESULT;
@@ -56,18 +58,18 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
}
@Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
public <T> String description(@NotNull ConfigEntry<T> configEntry) {
return "Value must not be null.";
}
};
private static final ConfigEntryValidator NOOP_VALIDATOR = new ConfigEntryValidator() {
@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);
}
@Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
public <T> String description(@NotNull ConfigEntry<T> configEntry) {
return "";
}
};
@@ -166,7 +168,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
}
@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();
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;
import org.jspecify.annotations.Nullable;
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.validationfallback.api.ValidationFallbackExtension;
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.Collections;
@@ -55,7 +55,7 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
public ConfigEntryValidator process(ConfigEntryValidator inner) {
return new ConfigEntryValidator() {
@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);
if (!result.hasError()) {
return result;
@@ -90,7 +90,7 @@ public class ValidationFallbackExtensionImpl implements ValidationFallbackExtens
}
@Override
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
public <T> String description(ConfigEntry<T> configEntry) {
if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) {
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
@NullMarked
package de.siphalor.tweed5.namingformat.impl;
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.PatchworkClassGenerator;
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.MethodHandles;
@@ -16,17 +19,18 @@ import java.util.stream.Collectors;
@Value
public class PatchworkClassCreator<P extends Patchwork<P>> {
@NonNull
Class<P> patchworkInterface;
@NonNull
PatchworkClassGenerator.Config generatorConfig;
public static <P extends Patchwork<P>> Builder<P> builder() {
return new Builder<>();
}
public PatchworkClass<P> createClass(Collection<Class<?>> partInterfaces) throws PatchworkClassGenerator.GenerationException {
List<PatchworkClassPart> parts = partInterfaces.stream().map(PatchworkClassPart::new).collect(Collectors.toList());
public PatchworkClass<P> createClass(Collection<Class<?>> partInterfaces) throws
PatchworkClassGenerator.GenerationException {
List<PatchworkClassPart> parts = partInterfaces.stream()
.map(PatchworkClassPart::new)
.collect(Collectors.toList());
PatchworkClassGenerator generator = new PatchworkClassGenerator(generatorConfig, parts);
try {
@@ -45,7 +49,10 @@ public class PatchworkClassCreator<P extends Patchwork<P>> {
MethodHandle setterHandle = lookup.findSetter(patchworkClass, part.fieldName(), part.partInterface());
part.fieldSetter(setterHandle);
} 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 {
@@ -67,9 +74,7 @@ public class PatchworkClassCreator<P extends Patchwork<P>> {
@Setter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Builder<P extends Patchwork<P>> {
@NonNull
private Class<P> patchworkInterface;
@NonNull
private String classPackage;
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;
import org.jspecify.annotations.Nullable;
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())
.createClass(binaryClassName, byteCode);
}
@@ -11,7 +13,7 @@ public class ByteArrayClassLoader extends ClassLoader {
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);
resolveClass(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.impl.util.StreamUtils;
import lombok.*;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.objectweb.asm.*;
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 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";
@@ -458,7 +461,13 @@ public class PatchworkClassGenerator {
}
// </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);
return new GeneratorAdapter(methodVisitor, access, name, desc);
}
@@ -502,7 +511,13 @@ public class PatchworkClassGenerator {
}
@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);
return new PartMethodVisitor(api, methodWriter, descriptor, extensionClass);
}
@@ -513,7 +528,12 @@ public class PatchworkClassGenerator {
private final String methodDescriptor;
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);
this.methodWriter = methodWriter;
this.patchworkPart = patchworkPart;
@@ -531,7 +551,12 @@ public class PatchworkClassGenerator {
methodWriter.visitCode();
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.ifNull(nullLabel);
methodWriter.loadArgs();
@@ -563,11 +588,9 @@ public class PatchworkClassGenerator {
@Data
public static class Config {
@NonNull
private String classPackage;
@NonNull
@lombok.NonNull
private @NonNull String classPackage;
private String classPrefix = "";
@NonNull
private Collection<Class<?>> markerInterfaces = Collections.emptyList();
}
@@ -594,12 +617,16 @@ public class PatchworkClassGenerator {
transient Collection<Method> signatures;
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;
}
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()) {
stringBuilder.append(parameterType.getCanonicalName());
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.Getter;
import lombok.Setter;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
@Getter
public class TweedDataReadException extends RuntimeException {
@@ -28,8 +28,7 @@ public class TweedDataReadException extends RuntimeException {
private String message;
private Throwable cause;
@Setter(AccessLevel.NONE)
@Nullable
private TweedDataReaderRecoverMode recoverMode;
private @Nullable TweedDataReaderRecoverMode recoverMode;
public TweedDataReadException build() {
return new TweedDataReadException(message, cause, recoverMode);

View File

@@ -1,7 +1,5 @@
package de.siphalor.tweed5.dataapi.api;
import org.jetbrains.annotations.NotNull;
public interface TweedDataVisitor {
void visitNull();
void visitBoolean(boolean value);
@@ -11,7 +9,7 @@ public interface TweedDataVisitor {
void visitLong(long value);
void visitFloat(float value);
void visitDouble(double value);
void visitString(@NotNull String value);
void visitString(String value);
default void visitEmptyList() {
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.dataapi.api.TweedDataReader;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import org.jspecify.annotations.Nullable;
public interface ReadWriteExtension extends TweedExtension {
void setEntryReaderWriterDefinition(ConfigEntry<?> entry, EntryReaderWriterDefinition readerWriterDefinition);
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.dataapi.api.TweedDataReadException;
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
import org.jspecify.annotations.Nullable;
@FunctionalInterface
public interface TweedEntryReader<T, C extends ConfigEntry<T>> {
T read(TweedDataReader reader, C entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException;
public interface TweedEntryReader<T extends @Nullable Object, C extends ConfigEntry<T>> {
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.dataapi.api.TweedDataWriteException;
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
import org.jspecify.annotations.Nullable;
@FunctionalInterface
public interface TweedEntryWriter<T, C extends ConfigEntry<T>> {
void write(TweedDataVisitor writer, T value, C entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException;
public interface TweedEntryWriter<T extends @Nullable Object, C extends ConfigEntry<T>> {
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.data.extension.api.TweedEntryReader;
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
public interface ReadWriteRelatedExtension {
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 lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.jspecify.annotations.NonNull;
import java.util.Collection;
@@ -55,11 +56,11 @@ public class TweedEntryReaderWriters {
public static <T, C extends Collection<T>> TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> collectionReaderWriter() {
//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() {
//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 lombok.Setter;
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.util.Collection;
@@ -29,14 +33,16 @@ import java.util.HashMap;
import java.util.Map;
@AutoService(ReadWriteExtension.class)
@NullUnmarked
public class ReadWriteExtensionImpl implements ReadWriteExtension {
private RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition> readerWriterDefinitionExtension;
private RegisteredExtensionData<EntryExtensionsData, ReadWriteEntryDataExtension> readWriteEntryDataExtension;
private DefaultMiddlewareContainer<TweedEntryReader<?, ?>> entryReaderMiddlewareContainer;
private DefaultMiddlewareContainer<TweedEntryWriter<?, ?>> entryWriterMiddlewareContainer;
private Map<Class<?>, RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?>> readWriteContextExtensionsDataClasses;
private PatchworkClass<ReadWriteContextExtensionsData> readWriteContextExtensionsDataPatchwork;
private Map<Class<?>, RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?>>
readWriteContextExtensionsDataClasses;
private PatchworkClass<@NonNull ReadWriteContextExtensionsData> readWriteContextExtensionsDataPatchwork;
@Override
public String getId() {
@@ -54,11 +60,17 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
ReadWriteExtensionSetupContext setupContext = new ReadWriteExtensionSetupContext() {
@Override
public <E> RegisteredExtensionData<ReadWriteContextExtensionsData, E> registerReadWriteContextExtensionData(Class<E> extensionDataClass) {
public <E> RegisteredExtensionData<ReadWriteContextExtensionsData, E> registerReadWriteContextExtensionData(
Class<E> 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);
return registeredExtensionData;
}
@@ -73,11 +85,13 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
rwExtension.setupReadWriteExtension(setupContext);
if (rwExtension.entryReaderMiddleware() != null) {
entryReaderMiddlewareContainer.register(rwExtension.entryReaderMiddleware());
val readerMiddleware = rwExtension.entryReaderMiddleware();
if (readerMiddleware != null) {
entryReaderMiddlewareContainer.register(readerMiddleware);
}
if (rwExtension.entryWriterMiddleware() != null) {
entryWriterMiddlewareContainer.register(rwExtension.entryWriterMiddleware());
val writerMiddleware = rwExtension.entryWriterMiddleware();
if (writerMiddleware != null) {
entryWriterMiddlewareContainer.register(writerMiddleware);
}
}
}
@@ -85,20 +99,26 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
entryReaderMiddlewareContainer.seal();
entryWriterMiddlewareContainer.seal();
PatchworkClassCreator<ReadWriteContextExtensionsData> patchworkClassCreator = PatchworkClassCreator.<ReadWriteContextExtensionsData>builder()
val patchworkClassCreator = PatchworkClassCreator.<ReadWriteContextExtensionsData>builder()
.patchworkInterface(ReadWriteContextExtensionsData.class)
.classPackage("de.siphalor.tweed5.data.extension.generated")
.classPrefix("ReadWriteContextExtensionsData$")
.build();
try {
readWriteContextExtensionsDataPatchwork = patchworkClassCreator.createClass(readWriteContextExtensionsDataClasses.keySet());
readWriteContextExtensionsDataPatchwork =
patchworkClassCreator.createClass(readWriteContextExtensionsDataClasses.keySet());
for (PatchworkClassPart patchworkClassPart : readWriteContextExtensionsDataPatchwork.parts()) {
RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?> registeredExtension = readWriteContextExtensionsDataClasses.get(patchworkClassPart.partInterface());
RegisteredExtensionDataImpl<ReadWriteContextExtensionsData, ?>
registeredExtension
= readWriteContextExtensionsDataClasses.get(patchworkClassPart.partInterface());
registeredExtension.setter = patchworkClassPart.fieldSetter();
}
} 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;
}
readWriteEntryDataExtension.set(configEntry.extensionsData(), new ReadWriteEntryDataExtensionImpl(
readWriteEntryDataExtension.set(
configEntry.extensionsData(), new ReadWriteEntryDataExtensionImpl(
entryReaderMiddlewareContainer.process(baseReader),
entryWriterMiddlewareContainer.process(baseWriter)
));
)
);
}
@Override
public void setEntryReaderWriterDefinition(ConfigEntry<?> entry, EntryReaderWriterDefinition readerWriterDefinition) {
public void setEntryReaderWriterDefinition(
@NonNull ConfigEntry<?> entry,
@NonNull EntryReaderWriterDefinition readerWriterDefinition
) {
readerWriterDefinitionExtension.set(entry.extensionsData(), readerWriterDefinition);
}
@@ -136,7 +161,11 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
}
@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 {
return getReaderChain(entry).read(reader, entry, new TweedReadWriteContextImpl(contextExtensionsData));
} catch (TweedDataReadException e) {
@@ -145,7 +174,12 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
}
@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 {
getWriterChain(entry).write(writer, value, entry, new TweedReadWriteContextImpl(contextExtensionsData));
} catch (TweedDataWriteException e) {
@@ -160,7 +194,8 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
}
@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;
@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
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
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.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.*;
import java.util.function.BiConsumer;
@@ -32,7 +35,7 @@ public class TweedEntryReaderWriterImpls {
public static final TweedEntryReaderWriter<Object, ConfigEntry<Object>> NOOP_READER_WRITER = new NoopReaderWriter();
@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;
@Override
@@ -46,7 +49,7 @@ public class TweedEntryReaderWriterImpls {
}
@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;
@Override
@@ -60,7 +63,7 @@ public class TweedEntryReaderWriterImpls {
}
@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 BiConsumer<TweedDataVisitor, T> writerCall;
@@ -70,13 +73,13 @@ public class TweedEntryReaderWriterImpls {
}
@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);
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
public C read(TweedDataReader reader, CollectionConfigEntry<T, C> entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException {
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
public T read(TweedDataReader reader, CompoundConfigEntry<T> entry, TweedReadContext context) throws TweedEntryReadException, TweedDataReadException {
assertIsToken(reader.readToken(), TweedDataToken::isMapStart, "Expected map start");
@@ -143,10 +146,8 @@ public class TweedEntryReaderWriterImpls {
//noinspection unchecked
ConfigEntry<Object> subEntry = (ConfigEntry<Object>) compoundEntries.get(key);
TweedEntryReader<Object, ConfigEntry<Object>> subEntryReaderChain = ReadWriteExtensionImpl.getReaderChain(subEntry);
if (subEntryReaderChain != null) {
Object subEntryValue = subEntryReaderChain.read(reader, subEntry, context);
entry.set(compoundValue, key, subEntryValue);
}
} else {
throw new TweedEntryReadException("Unexpected token " + token + ": Expected map key or map end");
}
@@ -155,7 +156,7 @@ public class TweedEntryReaderWriterImpls {
}
@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);
writer.visitMapStart();
@@ -168,19 +169,17 @@ public class TweedEntryReaderWriterImpls {
TweedEntryWriter<Object, ConfigEntry<Object>> subEntryWriterChain = ReadWriteExtensionImpl.getWriterChain(subEntry);
if (subEntryWriterChain != null) {
writer.visitMapEntryKey(key);
subEntryWriterChain.write(writer, entry.get(value, key), subEntry, context);
}
}
writer.visitMapEnd();
}
}
public static class NoopReaderWriter implements TweedEntryReaderWriter<Object, ConfigEntry<Object>> {
public static class NoopReaderWriter implements TweedEntryReaderWriter<@Nullable Object, ConfigEntry<Object>> {
@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();
if (!token.isListStart() && !token.isMapStart()) {
return null;
@@ -209,7 +208,7 @@ public class TweedEntryReaderWriterImpls {
}
@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();
}
@@ -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) {
throw new TweedEntryWriteException("Unable to write null value");
}

View File

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

View File

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

View File

@@ -1,6 +1,8 @@
package de.siphalor.tweed5.data.hjson;
import de.siphalor.tweed5.dataapi.api.*;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import java.util.*;
import java.util.stream.Collectors;
@@ -10,9 +12,9 @@ public class HjsonReader implements TweedDataReader {
private final Deque<Context> contexts;
private State state = State.BEFORE_VALUE;
private HjsonLexerToken peekedLexerToken;
private @Nullable HjsonLexerToken peekedLexerToken;
private TweedDataToken peekedToken;
private @Nullable TweedDataToken peekedToken;
public HjsonReader(HjsonLexer lexer) {
this.lexer = lexer;
@@ -204,6 +206,7 @@ public class HjsonReader implements TweedDataReader {
};
}
@NullUnmarked
private TweedDataToken createNumberToken(HjsonLexerToken lexerToken) {
assert lexerToken.content() != null;
return new TweedDataToken() {
@@ -318,7 +321,7 @@ public class HjsonReader implements TweedDataReader {
tryLong = 0L;
boolean inFraction = false;
do {
tryLong = Math.addExact(Math.multiplyExact(tryLong, 10L), (long) (codePoint - '0'));
tryLong = Math.addExact(Math.multiplyExact(tryLong, 10L), codePoint - '0');
if (inFraction) {
fractionDigits++;
}
@@ -513,7 +516,7 @@ public class HjsonReader implements TweedDataReader {
@Override
public String readAsString() throws TweedDataReadException {
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) {
return readJsonString(lexerToken.content());
}
@@ -623,6 +626,7 @@ public class HjsonReader implements TweedDataReader {
}
private Context currentContext() {
assert contexts.peek() != null;
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.TweedSerde;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
public class HjsonSerde implements TweedSerde {
@Override
public TweedDataReader createReader(InputStream inputStream) {
return null;
return new HjsonReader(new HjsonLexer(new InputStreamReader(inputStream)));
}
@Override
public TweedDataVisitor createWriter(OutputStream outputStream) throws IOException {
return null;
return new HjsonWriter(new OutputStreamWriter(outputStream), new HjsonWriter.Options());
}
@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.TweedDataVisitor;
import lombok.Data;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.Writer;
@@ -90,7 +89,7 @@ public class HjsonWriter implements TweedDataVisitor {
}
@Override
public void visitString(@NotNull String value) {
public void visitString(String value) {
beforeValueWrite();
writeStringValue(getValueStringStringType(value), value);
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.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.annotation.Annotation;
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).
*/
@Getter(AccessLevel.PROTECTED)
@Nullable
private final AnnotatedType usedType;
private final @Nullable AnnotatedType usedType;
/**
* The {@link AnnotatedParameterizedType} that represents the type that is actually in use with parameters.
*/
@Nullable
private final AnnotatedParameterizedType usedParameterizedType;
private final @Nullable AnnotatedParameterizedType usedParameterizedType;
/**
* 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.
*/
@Nullable
private List<@NotNull ActualType<?>> resolvedParameters;
private List<ActualType<?>> resolvedParameters;
/**
* 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
*/
public static ActualType<?> ofUsedType(@NotNull AnnotatedType annotatedType) throws UnsupportedOperationException {
public static ActualType<?> ofUsedType(AnnotatedType annotatedType) throws UnsupportedOperationException {
Class<?> clazz = getDeclaredClassForUsedType(annotatedType);
LayeredTypeAnnotations layeredTypeAnnotations = new LayeredTypeAnnotations();
@@ -83,7 +80,7 @@ public class ActualType<T> implements AnnotatedElement {
*
* @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) {
return (Class<?>) annotatedType.getType();
} else if (annotatedType.getType() instanceof ParameterizedType) {
@@ -102,24 +99,24 @@ public class ActualType<T> implements AnnotatedElement {
}
@Override
public <A extends Annotation> A getAnnotation(@NotNull Class<A> annotationClass) {
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
return layeredTypeAnnotations.getAnnotation(annotationClass);
}
@Override
public @NotNull Annotation @NotNull [] getAnnotations() {
public Annotation[] getAnnotations() {
return layeredTypeAnnotations.getAnnotations();
}
@Override
public @NotNull Annotation @NotNull [] getDeclaredAnnotations() {
public Annotation[] getDeclaredAnnotations() {
return layeredTypeAnnotations.getDeclaredAnnotations();
}
/**
* Resolves the type parameters of this type as {@link ActualType}s.
*/
public @NotNull List<@NotNull ActualType<?>> parameters() {
public List<ActualType<?>> parameters() {
if (resolvedParameters != null) {
return resolvedParameters;
} else if (usedParameterizedType == null) {
@@ -145,7 +142,7 @@ public class ActualType<T> implements AnnotatedElement {
* @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
*/
public @Nullable List<ActualType<?>> getTypesOfSuperArguments(@NotNull Class<?> targetClass) {
public @Nullable List<ActualType<?>> getTypesOfSuperArguments(Class<?> targetClass) {
if (targetClass.getTypeParameters().length == 0) {
if (targetClass.isAssignableFrom(declaredType)) {
return Collections.emptyList();
@@ -170,7 +167,7 @@ public class ActualType<T> implements AnnotatedElement {
return currentType;
}
List<@NotNull ActualType<?>> currentParameters = currentType.parameters();
List<ActualType<?>> currentParameters = currentType.parameters();
Map<String, AnnotatedType> paramMap;
if (currentParameters.isEmpty()) {
@@ -178,6 +175,8 @@ public class ActualType<T> implements AnnotatedElement {
} else {
paramMap = new HashMap<>();
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());
}
}
@@ -185,7 +184,7 @@ public class ActualType<T> implements AnnotatedElement {
if (targetClass.isInterface()) {
for (AnnotatedType annotatedInterface : currentClass.getAnnotatedInterfaces()) {
ActualType<?> interfaceType = resolveTypeWithParameters(annotatedInterface, paramMap);
@Nullable ActualType<?> resultType = getViewOnSuperType(targetClass, interfaceType);
ActualType<?> resultType = getViewOnSuperType(targetClass, interfaceType);
if (resultType != null) {
return resultType;
}
@@ -193,7 +192,7 @@ public class ActualType<T> implements AnnotatedElement {
}
if (currentClass != Object.class && !currentClass.isInterface()) {
ActualType<?> superType = resolveTypeWithParameters(currentClass.getAnnotatedSuperclass(), paramMap);
@Nullable ActualType<?> resultType = getViewOnSuperType(targetClass, superType);
ActualType<?> resultType = getViewOnSuperType(targetClass, superType);
if (resultType != null) {
return resultType;
}
@@ -243,10 +242,10 @@ public class ActualType<T> implements AnnotatedElement {
appendAnnotationsToString(sb, usedType.getAnnotations());
}
sb.append(declaredType.getName());
List<@NotNull ActualType<?>> parameters = parameters();
List<ActualType<?>> parameters = parameters();
if (!parameters.isEmpty()) {
sb.append("<");
for (@NotNull ActualType<?> parameter : parameters) {
for (ActualType<?> parameter : parameters) {
sb.append(parameter);
sb.append(", ");
}
@@ -256,8 +255,8 @@ public class ActualType<T> implements AnnotatedElement {
return sb.toString();
}
private void appendAnnotationsToString(@NotNull StringBuilder sb, @NotNull Annotation[] annotations) {
for (@NotNull Annotation annotation : annotations) {
private void appendAnnotationsToString(StringBuilder sb, Annotation[] annotations) {
for (Annotation annotation : annotations) {
sb.append(annotation);
sb.append(' ');
}

View File

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

View File

@@ -1,8 +1,7 @@
package de.siphalor.tweed5.typeutils.api.type;
import lombok.Value;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
@@ -11,7 +10,7 @@ import java.util.*;
public class LayeredTypeAnnotations implements AnnotatedElement {
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();
annotations.layers.add(new Layer(layer, annotatedElement));
return annotations;
@@ -19,7 +18,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
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;
for (i = 0; i < layers.size(); i++) {
if (layer.compareTo(layers.get(i).layer()) > 0) {
@@ -29,7 +28,7 @@ public class LayeredTypeAnnotations implements 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;
for (i = 0; i < layers.size(); i++) {
if (layer.compareTo(layers.get(i).layer()) >= 0) {
@@ -40,7 +39,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
}
@Override
public <T extends Annotation> T getAnnotation(@NotNull Class<T> annotationClass) {
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
if (layers.isEmpty()) {
return null;
} else if (layers.size() == 1) {
@@ -62,7 +61,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
}
@Override
public @NotNull Annotation @NotNull [] getAnnotations() {
public Annotation[] getAnnotations() {
if (layers.isEmpty()) {
return EMPTY_ANNOTATIONS;
} else if (layers.size() == 1) {
@@ -87,7 +86,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
}
@Override
public @NotNull Annotation @NotNull [] getDeclaredAnnotations() {
public Annotation[] getDeclaredAnnotations() {
if (layers.isEmpty()) {
return EMPTY_ANNOTATIONS;
} else if (layers.size() == 1) {
@@ -111,7 +110,7 @@ public class LayeredTypeAnnotations implements AnnotatedElement {
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);
Class<? extends Annotation> altAnnotationClass = null;
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
@NullMarked
package de.siphalor.tweed5.typeutils.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;

View File

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

View File

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

View File

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

View File

@@ -2,22 +2,24 @@ package de.siphalor.tweed5.utils.api.collection;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.*;
@SuppressWarnings("unchecked")
@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 final Class<T> baseClass;
private final Map<T, Collection<Class<? extends T>>> instanceToClasses;
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;
}
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);
}
@@ -49,7 +51,7 @@ public class InheritanceMap<T> {
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());
if (instances.isEmpty()) {
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)) {
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) {
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.pojoext.serde.impl.SerdePojoReaderWriterSpec;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
@@ -80,8 +80,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
}
}
@Nullable
private EntryReaderWriterDefinition createDefinitionFromEntryConfig(EntryReadWriteConfig entryConfig, WeavingContext context) {
private @Nullable EntryReaderWriterDefinition createDefinitionFromEntryConfig(EntryReadWriteConfig entryConfig, WeavingContext context) {
String readerSpecText = entryConfig.reader().isEmpty() ? entryConfig.value() : entryConfig.reader();
String writerSpecText = entryConfig.writer().isEmpty() ? entryConfig.value() : entryConfig.writer();
@@ -98,14 +97,14 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
return null;
}
//noinspection unchecked
TweedEntryReader<?, ?> reader = readerSpec == null
? TweedEntryReaderWriterImpls.NOOP_READER_WRITER
: resolveReaderWriterFromSpec((Class<TweedEntryReader<?, ?>>)(Object) TweedEntryReader.class, readerFactories, readerSpec, context);
//noinspection unchecked
TweedEntryWriter<?, ?> writer = writerSpec == null
? TweedEntryReaderWriterImpls.NOOP_READER_WRITER
: resolveReaderWriterFromSpec((Class<TweedEntryWriter<?, ?>>)(Object) TweedEntryWriter.class, writerFactories, writerSpec, context);
//noinspection unchecked,rawtypes
TweedEntryReader<?, ?> reader = Optional.ofNullable(readerSpec)
.map((spec) -> resolveReaderWriterFromSpec((Class<TweedEntryReader<?, ?>>)(Object) TweedEntryReader.class, readerFactories, spec, context))
.orElse(((TweedEntryReader) TweedEntryReaderWriterImpls.NOOP_READER_WRITER));
//noinspection unchecked,rawtypes
TweedEntryWriter<?, ?> writer = Optional.ofNullable(writerSpec)
.map((spec) -> resolveReaderWriterFromSpec((Class<TweedEntryWriter<?, ?>>)(Object) TweedEntryWriter.class, writerFactories, spec, context))
.orElse(((TweedEntryWriter) TweedEntryReaderWriterImpls.NOOP_READER_WRITER));
return new EntryReaderWriterDefinition() {
@Override
@@ -120,8 +119,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
};
}
@Nullable
private SerdePojoReaderWriterSpec specFromText(String specText, WeavingContext context) {
private @Nullable SerdePojoReaderWriterSpec specFromText(String specText, WeavingContext context) {
if (specText.isEmpty()) {
return null;
}
@@ -137,7 +135,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
}
}
private <T> T resolveReaderWriterFromSpec(
private <T> @Nullable T resolveReaderWriterFromSpec(
Class<T> baseClass,
Map<String, TweedReaderWriterProvider.ReaderWriterFactory<T>> factories,
SerdePojoReaderWriterSpec spec,
@@ -152,17 +150,18 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
TweedReaderWriterProvider.ReaderWriterFactory<T> factory = factories.get(spec.identifier());
T instance;
try {
if (factory != null) {
instance = factory.create(arguments);
} else {
instance = loadClassIfExists(baseClass, spec.identifier(), arguments);
}
if (instance == null) {
} catch (Exception e) {
log.warn(
"Failed to resolve reader or writer factory \"{}\" for entry {}, entry will not be included in serde",
spec.identifier(),
context.path()
context.path(),
e
);
return null;
}
@@ -170,7 +169,7 @@ public class ReadWritePojoPostProcessor implements TweedPojoWeavingPostProcessor
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 {
Class<?> clazz = Class.forName(className);
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 {
@Override
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
public void write(
TweedDataVisitor writer,
@NonNull TweedDataVisitor writer,
Object value,
ConfigEntry<Object> entry,
TweedWriteContext context
@NonNull TweedWriteContext context
) throws TweedDataWriteException {
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 lombok.RequiredArgsConstructor;
import lombok.Value;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.util.function.Supplier;
@@ -28,9 +28,9 @@ public interface WeavableCompoundConfigEntry<T> extends CompoundConfigEntry<T> {
@Value
@RequiredArgsConstructor
class SubEntry {
@NotNull String name;
@NotNull ConfigEntry<?> configEntry;
@NotNull MethodHandle getter;
@NotNull MethodHandle setter;
String name;
ConfigEntry<?> configEntry;
@Nullable MethodHandle getter;
@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.collection.CollectionWeavingConfig;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.collection.CollectionWeavingConfigImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -33,7 +32,7 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
@SuppressWarnings({"rawtypes", "unchecked"})
@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);
if (collectionTypeParams == null) {
return null;
@@ -82,7 +81,7 @@ public class CollectionPojoWeaver implements TweedPojoWeaver {
return CollectionWeavingConfigImpl.withOverrides(parent, local);
}
private CollectionWeavingConfig createWeavingConfigFromAnnotations(@NotNull AnnotatedElement annotations) {
private @Nullable CollectionWeavingConfig createWeavingConfigFromAnnotations(AnnotatedElement annotations) {
CollectionWeaving annotation = annotations.getAnnotation(CollectionWeaving.class);
if (annotation == 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.compound.CompoundWeavingConfig;
import de.siphalor.tweed5.weaver.pojo.impl.weaving.compound.CompoundWeavingConfigImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.AnnotatedElement;
@@ -44,7 +43,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
}
@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) {
return null;
}
@@ -88,8 +87,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
return CompoundWeavingConfigImpl.withOverrides(parent, local);
}
@Nullable
private CompoundWeavingConfig createWeavingConfigFromAnnotations(@NotNull AnnotatedElement annotations) {
private @Nullable CompoundWeavingConfig createWeavingConfigFromAnnotations(AnnotatedElement annotations) {
CompoundWeaving annotation = annotations.getAnnotation(CompoundWeaving.class);
if (annotation == null) {
return null;
@@ -127,7 +125,6 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
//noinspection rawtypes
Class<? extends WeavableCompoundConfigEntry> annotationEntryClass = weavingConfig.compoundEntryClass();
@NotNull
Class<WeavableCompoundConfigEntry<C>> weavableEntryClass = (Class<WeavableCompoundConfigEntry<C>>) (
annotationEntryClass != null
? annotationEntryClass
@@ -143,7 +140,7 @@ public class CompoundPojoWeaver implements TweedPojoWeaver {
return property.getter() != null && (property.setter() != null || property.isFinal());
}
private @NotNull WeavableCompoundConfigEntry.SubEntry weaveCompoundSubEntry(
private WeavableCompoundConfigEntry.SubEntry weaveCompoundSubEntry(
PojoClassIntrospector.Property property,
WeavingContext.ExtensionsData newExtensionsData,
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(
name,
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);
if (namingFormat == null) {
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.impl.entry.SimpleConfigEntryImpl;
import de.siphalor.tweed5.typeutils.api.type.ActualType;
import org.jetbrains.annotations.Nullable;
public class TrivialPojoWeaver implements TweedPojoWeaver {
@Override
@@ -12,7 +11,7 @@ public class TrivialPojoWeaver implements TweedPojoWeaver {
}
@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());
entry.seal(context.configContainer());
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.typeutils.api.type.ActualType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
@FunctionalInterface
public interface TweedPojoWeavingFunction {
@@ -12,8 +11,7 @@ public interface TweedPojoWeavingFunction {
* 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.
*/
@Nullable
<T> ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
<T> @Nullable ConfigEntry<T> weaveEntry(ActualType<T> valueType, WeavingContext context);
@FunctionalInterface
interface NonNull extends TweedPojoWeavingFunction {
@@ -25,6 +23,6 @@ public interface TweedPojoWeavingFunction {
* @throws RuntimeException when a valid config entry could not be resolved.
*/
@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 lombok.*;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
@Value
public class WeavingContext implements TweedPojoWeavingFunction.NonNull {
@Nullable
WeavingContext parent;
@Nullable WeavingContext parent;
@Getter(AccessLevel.NONE)
@NotNull
TweedPojoWeavingFunction.NonNull weavingFunction;
@NotNull
ConfigContainer<?> configContainer;
@NotNull
String[] path;
@NotNull
ExtensionsData extensionsData;
@NotNull
AnnotatedElement annotations;
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 });
}
public Builder subContextBuilder(@NotNull String subPathName) {
public Builder subContextBuilder(String subPathName) {
String[] newPath = Arrays.copyOf(path, path.length + 1);
newPath[path.length] = subPathName;
return new Builder(this, weavingFunction, configContainer, newPath).extensionsData(extensionsData);
}
@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);
}

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.ToString;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import java.util.Collection;
import java.util.function.IntFunction;
@@ -18,7 +19,7 @@ import java.util.function.IntFunction;
@ToString(callSuper = true)
public class CollectionConfigEntryImpl<E, T extends Collection<E>> extends BaseConfigEntry<T> implements WeavableCollectionConfigEntry<E, T> {
private final IntFunction<T> constructor;
private ConfigEntry<E> elementEntry;
private @Nullable ConfigEntry<E> elementEntry;
public CollectionConfigEntryImpl(@NotNull Class<T> valueClass, IntFunction<T> constructor) {
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.ConfigEntryVisitor;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
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, ConfigEntry<?>> subConfigEntries = new LinkedHashMap<>();
public StaticPojoCompoundConfigEntry(@NotNull Class<T> valueClass, @NotNull Supplier<T> noArgsConstructor) {
public StaticPojoCompoundConfigEntry(Class<T> valueClass, Supplier<T> noArgsConstructor) {
super(valueClass);
this.noArgsConstructor = noArgsConstructor;
}
@@ -91,7 +90,7 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
subEntries.forEach((key, entry) -> {
if (visitor.enterCompoundSubEntry(key)) {
try {
Object subValue = entry.getter().invokeExact(value);
Object subValue = entry.getter().invoke(value);
//noinspection unchecked
visitor.visitEntry((ConfigEntry<Object>) entry.configEntry(), subValue);
} catch (Throwable e) {
@@ -103,11 +102,11 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
}
@Override
public @NotNull T deepCopy(@NotNull T value) {
public T deepCopy(T value) {
T copy = instantiateCompoundValue();
for (SubEntry subEntry : subEntries.values()) {
try {
Object subValue = subEntry.getter().invokeExact(value);
Object subValue = subEntry.getter().invoke(value);
subEntry.setter().invoke(copy, subValue);
} catch (Throwable 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.Value;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -23,7 +23,7 @@ public class PojoClassIntrospector {
private final Class<?> clazz;
private final MethodHandles.Lookup lookup = MethodHandles.publicLookup();
private Map<String, Property> properties;
private @Nullable Map<String, Property> properties;
public static PojoClassIntrospector forClass(Class<?> clazz) {
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 lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;

View File

@@ -1,10 +1,9 @@
package de.siphalor.tweed5.weaver.pojo.impl.weaving.collection;
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCollectionConfigEntry;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
public interface CollectionWeavingConfig {
@SuppressWarnings("rawtypes")
@Nullable
Class<? extends WeavableCollectionConfigEntry> collectionEntryClass();
@Nullable 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 lombok.Builder;
import lombok.Value;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
@Builder
@Value
public class CollectionWeavingConfigImpl implements CollectionWeavingConfig {
@SuppressWarnings("rawtypes")
@Nullable
Class<? extends WeavableCollectionConfigEntry> collectionEntryClass;
@Nullable Class<? extends WeavableCollectionConfigEntry> collectionEntryClass;
public static CollectionWeavingConfigImpl withOverrides(CollectionWeavingConfig self, CollectionWeavingConfig overrides) {
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.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
public interface CompoundWeavingConfig {
NamingFormat compoundSourceNamingFormat();
@Nullable NamingFormat compoundSourceNamingFormat();
NamingFormat compoundTargetNamingFormat();
@Nullable NamingFormat compoundTargetNamingFormat();
@SuppressWarnings("rawtypes")
@Nullable
Class<? extends WeavableCompoundConfigEntry> compoundEntryClass();
@Nullable 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 lombok.Builder;
import lombok.Value;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
@Builder
@Value
public class CompoundWeavingConfigImpl implements CompoundWeavingConfig {
NamingFormat compoundSourceNamingFormat;
NamingFormat compoundTargetNamingFormat;
@Nullable NamingFormat compoundSourceNamingFormat;
@Nullable NamingFormat compoundTargetNamingFormat;
@SuppressWarnings("rawtypes")
@Nullable
Class<? extends WeavableCompoundConfigEntry> compoundEntryClass;
@Nullable Class<? extends WeavableCompoundConfigEntry> compoundEntryClass;
public static CompoundWeavingConfigImpl withOverrides(CompoundWeavingConfig self, CompoundWeavingConfig overrides) {
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;