From 7a665d6f9c278847856ba7d9a05af001ce3c2e86 Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 1 Dec 2021 10:15:02 -0700 Subject: [PATCH] annotate Registry methods with nullability and contract --- .../terra/api/registry/CheckedRegistry.java | 5 ++- .../terra/api/registry/OpenRegistry.java | 6 ++- .../dfsek/terra/api/registry/Registry.java | 20 ++++++++-- .../exception/NoSuchEntryException.java | 11 +++++ .../terra/registry/CheckedRegistryImpl.java | 15 +++---- .../terra/registry/LockedRegistryImpl.java | 14 ++++--- .../terra/registry/OpenRegistryImpl.java | 40 ++++++++++++------- 7 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 common/api/registry/src/main/java/com/dfsek/terra/api/registry/exception/NoSuchEntryException.java diff --git a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/CheckedRegistry.java b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/CheckedRegistry.java index ce7f46e9e..b6ef6d53e 100644 --- a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/CheckedRegistry.java +++ b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/CheckedRegistry.java @@ -9,6 +9,8 @@ package com.dfsek.terra.api.registry; import com.dfsek.terra.api.registry.exception.DuplicateEntryException; +import org.jetbrains.annotations.NotNull; + public interface CheckedRegistry extends Registry { /** @@ -19,6 +21,5 @@ public interface CheckedRegistry extends Registry { * * @throws DuplicateEntryException If an entry with the same identifier is already present. */ - void register(String identifier, T value) throws DuplicateEntryException; - + void register(@NotNull String identifier, @NotNull T value) throws DuplicateEntryException; } diff --git a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/OpenRegistry.java b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/OpenRegistry.java index 4616ae34a..3420ca89d 100644 --- a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/OpenRegistry.java +++ b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/OpenRegistry.java @@ -9,6 +9,8 @@ package com.dfsek.terra.api.registry; import com.dfsek.terra.api.registry.exception.DuplicateEntryException; +import org.jetbrains.annotations.NotNull; + public interface OpenRegistry extends Registry { /** @@ -17,7 +19,7 @@ public interface OpenRegistry extends Registry { * @param identifier Identifier to assign value. * @param value Value to register. */ - boolean register(String identifier, T value); + boolean register(@NotNull String identifier, @NotNull T value); /** * Add a value to this registry, checking whether it is present first. @@ -27,7 +29,7 @@ public interface OpenRegistry extends Registry { * * @throws DuplicateEntryException If an entry with the same identifier is already present. */ - void registerChecked(String identifier, T value) throws DuplicateEntryException; + void registerChecked(@NotNull String identifier, @NotNull T value) throws DuplicateEntryException; /** * Clears all entries from the registry. diff --git a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/Registry.java b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/Registry.java index 1b1276417..8a34b9aab 100644 --- a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/Registry.java +++ b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/Registry.java @@ -9,6 +9,11 @@ package com.dfsek.terra.api.registry; import com.dfsek.tectonic.loading.TypeLoader; +import com.dfsek.terra.api.registry.exception.NoSuchEntryException; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + import java.util.Collection; import java.util.Set; import java.util.function.BiConsumer; @@ -23,7 +28,9 @@ public interface Registry extends TypeLoader { * * @return Value matching the identifier, {@code null} if no value is present. */ - T get(String identifier); + @NotNull + @Contract(pure = true) + T get(@NotNull String identifier) throws NoSuchEntryException; /** * Check if the registry contains a value. @@ -32,27 +39,30 @@ public interface Registry extends TypeLoader { * * @return Whether the registry contains the value. */ - boolean contains(String identifier); + @Contract(pure = true) + boolean contains(@NotNull String identifier); /** * Perform the given action for every value in the registry. * * @param consumer Action to perform on value. */ - void forEach(Consumer consumer); + void forEach(@NotNull Consumer consumer); /** * Perform an action for every key-value pair in the registry. * * @param consumer Action to perform on pair. */ - void forEach(BiConsumer consumer); + void forEach(@NotNull BiConsumer consumer); /** * Get the entries of this registry as a {@link Set}. * * @return Set containing all entries. */ + @NotNull + @Contract(pure = true) Collection entries(); /** @@ -60,5 +70,7 @@ public interface Registry extends TypeLoader { * * @return Keys in registry */ + @NotNull + @Contract(pure = true) Set keys(); } diff --git a/common/api/registry/src/main/java/com/dfsek/terra/api/registry/exception/NoSuchEntryException.java b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/exception/NoSuchEntryException.java new file mode 100644 index 000000000..ba0e627ff --- /dev/null +++ b/common/api/registry/src/main/java/com/dfsek/terra/api/registry/exception/NoSuchEntryException.java @@ -0,0 +1,11 @@ +package com.dfsek.terra.api.registry.exception; + +public class NoSuchEntryException extends RuntimeException { + public NoSuchEntryException(String message) { + super(message); + } + + public NoSuchEntryException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/CheckedRegistryImpl.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/CheckedRegistryImpl.java index 58bf61a4a..d172bfcac 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/CheckedRegistryImpl.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/CheckedRegistryImpl.java @@ -29,6 +29,7 @@ import java.util.function.Consumer; import com.dfsek.terra.api.registry.CheckedRegistry; import com.dfsek.terra.api.registry.OpenRegistry; import com.dfsek.terra.api.registry.exception.DuplicateEntryException; +import org.jetbrains.annotations.NotNull; /** @@ -44,37 +45,37 @@ public class CheckedRegistryImpl implements CheckedRegistry { } @Override - public void register(String identifier, T value) throws DuplicateEntryException { + public void register(@NotNull String identifier, @NotNull T value) throws DuplicateEntryException { registry.registerChecked(identifier, value); } @Override - public T get(String identifier) { + public @NotNull T get(@NotNull String identifier) { return registry.get(identifier); } @Override - public boolean contains(String identifier) { + public boolean contains(@NotNull String identifier) { return registry.contains(identifier); } @Override - public void forEach(Consumer consumer) { + public void forEach(@NotNull Consumer consumer) { registry.forEach(consumer); } @Override - public void forEach(BiConsumer consumer) { + public void forEach(@NotNull BiConsumer consumer) { registry.forEach(consumer); } @Override - public Collection entries() { + public @NotNull Collection entries() { return registry.entries(); } @Override - public Set keys() { + public @NotNull Set keys() { return registry.keys(); } diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/LockedRegistryImpl.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/LockedRegistryImpl.java index e82d27007..eb0751ecb 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/LockedRegistryImpl.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/LockedRegistryImpl.java @@ -28,6 +28,8 @@ import java.util.function.Consumer; import com.dfsek.terra.api.registry.Registry; +import org.jetbrains.annotations.NotNull; + /** * Wrapper for a registry that forbids all write access. @@ -42,32 +44,32 @@ public class LockedRegistryImpl implements Registry { } @Override - public T get(String identifier) { + public @NotNull T get(@NotNull String identifier) { return registry.get(identifier); } @Override - public boolean contains(String identifier) { + public boolean contains(@NotNull String identifier) { return registry.contains(identifier); } @Override - public void forEach(Consumer consumer) { + public void forEach(@NotNull Consumer consumer) { registry.forEach(consumer); } @Override - public void forEach(BiConsumer consumer) { + public void forEach(@NotNull BiConsumer consumer) { registry.forEach(consumer); } @Override - public Collection entries() { + public @NotNull Collection entries() { return registry.entries(); } @Override - public Set keys() { + public @NotNull Set keys() { return registry.keys(); } diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/registry/OpenRegistryImpl.java b/common/implementation/base/src/main/java/com/dfsek/terra/registry/OpenRegistryImpl.java index 04adb953c..59a0be1d7 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/registry/OpenRegistryImpl.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/registry/OpenRegistryImpl.java @@ -34,6 +34,10 @@ import java.util.stream.Collectors; import com.dfsek.terra.api.registry.OpenRegistry; import com.dfsek.terra.api.registry.exception.DuplicateEntryException; +import com.dfsek.terra.api.registry.exception.NoSuchEntryException; + +import org.jetbrains.annotations.NotNull; + /** * Registry implementation with read/write access. For internal use only. @@ -55,24 +59,26 @@ public class OpenRegistryImpl implements OpenRegistry { @Override public T load(AnnotatedType type, Object o, ConfigLoader configLoader) throws LoadException { - T obj = get((String) o); - String list = objects.keySet().stream().sorted().reduce("", (a, b) -> a + "\n - " + b); - - if(objects.isEmpty()) list = "[ ]"; - - if(obj == null) + T obj; + try { + obj = get((String) o); + } catch(NoSuchEntryException e) { + String list = objects.keySet().stream().sorted().reduce("", (a, b) -> a + "\n - " + b); + if(objects.isEmpty()) list = "[ ]"; throw new LoadException("No such " + type.getType().getTypeName() + " matching \"" + o + "\" was found in this registry. Registry contains items: " + list); + } + return obj; } @Override - public boolean register(String identifier, T value) { + public boolean register(@NotNull String identifier, @NotNull T value) { return register(identifier, new Entry<>(value)); } @Override - public void registerChecked(String identifier, T value) throws DuplicateEntryException { + public void registerChecked(@NotNull String identifier, @NotNull T value) throws DuplicateEntryException { if(objects.containsKey(identifier)) throw new DuplicateEntryException("Value with identifier \"" + identifier + "\" is already defined in registry."); register(identifier, value); @@ -95,32 +101,36 @@ public class OpenRegistryImpl implements OpenRegistry { @SuppressWarnings("unchecked") @Override - public T get(String identifier) { - return objects.getOrDefault(identifier, (Entry) NULL).getValue(); + public @NotNull T get(@NotNull String identifier) { + T value = objects.getOrDefault(identifier, (Entry) NULL).getValue(); + if(value == null) { + throw new NoSuchEntryException("Entry " + identifier + " is not present in registry."); + } + return value; } @Override - public boolean contains(String identifier) { + public boolean contains(@NotNull String identifier) { return objects.containsKey(identifier); } @Override - public void forEach(Consumer consumer) { + public void forEach(@NotNull Consumer consumer) { objects.forEach((id, obj) -> consumer.accept(obj.getRaw())); } @Override - public void forEach(BiConsumer consumer) { + public void forEach(@NotNull BiConsumer consumer) { objects.forEach((id, entry) -> consumer.accept(id, entry.getRaw())); } @Override - public Collection entries() { + public @NotNull Collection entries() { return objects.values().stream().map(Entry::getRaw).collect(Collectors.toList()); } @Override - public Set keys() { + public @NotNull Set keys() { return objects.keySet(); }