From cfcc75669d225130b307e83328ef098abae952fe Mon Sep 17 00:00:00 2001 From: Bukkit/Spigot Date: Sat, 6 Jan 2024 16:03:53 +1100 Subject: [PATCH] #933: Define native persistent data types for lists By: Bjarne Koll --- .../persistence/ListPersistentDataType.java | 22 ++ .../ListPersistentDataTypeProvider.java | 229 ++++++++++++++++++ .../persistence/PersistentDataContainer.java | 24 +- .../persistence/PersistentDataType.java | 66 +++-- 4 files changed, 309 insertions(+), 32 deletions(-) create mode 100644 paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataType.java create mode 100644 paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataTypeProvider.java diff --git a/paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataType.java b/paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataType.java new file mode 100644 index 0000000000..e6b38ed805 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataType.java @@ -0,0 +1,22 @@ +package org.bukkit.persistence; + +import java.util.List; +import org.jetbrains.annotations.NotNull; + +/** + * The list persistent data represents a data type that is capable of storing a + * list of other data types in a {@link PersistentDataContainer}. + * + * @param

the primitive type of the list element. + * @param the complex type of the list elements. + */ +public interface ListPersistentDataType extends PersistentDataType, List> { + + /** + * Provides the persistent data type of the elements found in the list. + * + * @return the persistent data type. + */ + @NotNull + PersistentDataType elementType(); +} diff --git a/paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataTypeProvider.java b/paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataTypeProvider.java new file mode 100644 index 0000000000..2cb6704027 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/persistence/ListPersistentDataTypeProvider.java @@ -0,0 +1,229 @@ +package org.bukkit.persistence; + +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import java.util.List; +import org.jetbrains.annotations.NotNull; + +/** + * A provider for list persistent data types that represent the known primitive + * types exposed by {@link PersistentDataType}. + */ +public final class ListPersistentDataTypeProvider { + + private static final ListPersistentDataType BYTE = new ListPersistentDataTypeImpl<>(PersistentDataType.BYTE); + private static final ListPersistentDataType SHORT = new ListPersistentDataTypeImpl<>(PersistentDataType.SHORT); + private static final ListPersistentDataType INTEGER = new ListPersistentDataTypeImpl<>(PersistentDataType.INTEGER); + private static final ListPersistentDataType LONG = new ListPersistentDataTypeImpl<>(PersistentDataType.LONG); + private static final ListPersistentDataType FLOAT = new ListPersistentDataTypeImpl<>(PersistentDataType.FLOAT); + private static final ListPersistentDataType DOUBLE = new ListPersistentDataTypeImpl<>(PersistentDataType.DOUBLE); + private static final ListPersistentDataType BOOLEAN = new ListPersistentDataTypeImpl<>(PersistentDataType.BOOLEAN); + private static final ListPersistentDataType STRING = new ListPersistentDataTypeImpl<>(PersistentDataType.STRING); + private static final ListPersistentDataType BYTE_ARRAY = new ListPersistentDataTypeImpl<>(PersistentDataType.BYTE_ARRAY); + private static final ListPersistentDataType INTEGER_ARRAY = new ListPersistentDataTypeImpl<>(PersistentDataType.INTEGER_ARRAY); + private static final ListPersistentDataType LONG_ARRAY = new ListPersistentDataTypeImpl<>(PersistentDataType.LONG_ARRAY); + private static final ListPersistentDataType DATA_CONTAINER = new ListPersistentDataTypeImpl<>( + PersistentDataType.TAG_CONTAINER + ); + + ListPersistentDataTypeProvider() { + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of bytes. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType bytes() { + return BYTE; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of shorts. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType shorts() { + return SHORT; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of integers. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType integers() { + return INTEGER; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of longs. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType longs() { + return LONG; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of floats. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType floats() { + return FLOAT; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of doubles. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType doubles() { + return DOUBLE; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of booleans. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType booleans() { + return BOOLEAN; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of strings. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType strings() { + return STRING; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of byte arrays. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType byteArrays() { + return BYTE_ARRAY; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of int arrays. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType integerArrays() { + return INTEGER_ARRAY; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * storing lists of long arrays. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType longArrays() { + return LONG_ARRAY; + } + + /** + * Provides a shared {@link ListPersistentDataType} that is capable of + * persistent data containers.. + * + * @return the persistent data type. + */ + @NotNull + public ListPersistentDataType dataContainers() { + return DATA_CONTAINER; + } + + /** + * Constructs a new list persistent data type given any persistent data type + * for its elements. + * + * @param elementType the persistent data type that is capable of + * writing/reading the elements of the list. + * @param

the generic type of the primitives stored in the list. + * @param the generic type of the complex values yielded back by the + * persistent data types. + * @return the created list persistent data type. + */ + @NotNull + public ListPersistentDataType listTypeFrom(@NotNull final PersistentDataType elementType) { + return new ListPersistentDataTypeImpl<>(elementType); + } + + /** + * A private implementation of the {@link ListPersistentDataType} that uses + * {@link Collections2} for conversion from/to the primitive list. + * + * @param

the generic type of the primitives stored in the list. + * @param the generic type of the complex values yielded back by the + * persistent data types. + */ + private static final class ListPersistentDataTypeImpl implements ListPersistentDataType { + + @NotNull + private final PersistentDataType innerType; + + private ListPersistentDataTypeImpl(@NotNull final PersistentDataType innerType) { + this.innerType = innerType; + } + + @NotNull + @Override + @SuppressWarnings("unchecked") + public Class> getPrimitiveType() { + return (Class>) (Object) List.class; + } + + @NotNull + @Override + @SuppressWarnings("unchecked") + public Class> getComplexType() { + return (Class>) (Object) List.class; + } + + @NotNull + @Override + public List

toPrimitive(@NotNull final List complex, @NotNull final PersistentDataAdapterContext context) { + return Lists.transform(complex, s -> innerType.toPrimitive(s, context)); + } + + @NotNull + @Override + public List fromPrimitive(@NotNull final List

primitive, @NotNull final PersistentDataAdapterContext context) { + return Lists.transform(primitive, s -> innerType.fromPrimitive(s, context)); + } + + @NotNull + @Override + public PersistentDataType elementType() { + return this.innerType; + } + } +} diff --git a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java index 6c156faf01..18fc4f1c71 100644 --- a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java +++ b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java @@ -22,8 +22,8 @@ public interface PersistentDataContainer { * @param key the key this value will be stored under * @param type the type this tag uses * @param value the value to store in the tag - * @param the generic java type of the tag value - * @param the generic type of the object to store + * @param

the generic java type of the tag value + * @param the generic type of the object to store * * @throws IllegalArgumentException if the key is null * @throws IllegalArgumentException if the type is null @@ -32,7 +32,7 @@ public interface PersistentDataContainer { * @throws IllegalArgumentException if no suitable adapter was found for * the {@link PersistentDataType#getPrimitiveType()} */ - void set(@NotNull NamespacedKey key, @NotNull PersistentDataType type, @NotNull Z value); + void set(@NotNull NamespacedKey key, @NotNull PersistentDataType type, @NotNull C value); /** * Returns if the persistent metadata provider has metadata registered @@ -54,8 +54,8 @@ public interface PersistentDataContainer { * * @param key the key the value is stored under * @param type the type the primative stored value has to match - * @param the generic type of the stored primitive - * @param the generic type of the eventually created complex object + * @param

the generic type of the stored primitive + * @param the generic type of the eventually created complex object * * @return if a value with the provided key and type exists * @@ -63,7 +63,7 @@ public interface PersistentDataContainer { * @throws IllegalArgumentException if the type to cast the found object to is * null */ - boolean has(@NotNull NamespacedKey key, @NotNull PersistentDataType type); + boolean has(@NotNull NamespacedKey key, @NotNull PersistentDataType type); /** * Returns if the persistent metadata provider has metadata registered matching @@ -90,8 +90,8 @@ public interface PersistentDataContainer { * * @param key the key to look up in the custom tag map * @param type the type the value must have and will be casted to - * @param the generic type of the stored primitive - * @param the generic type of the eventually created complex object + * @param

the generic type of the stored primitive + * @param the generic type of the eventually created complex object * * @return the value or {@code null} if no value was mapped under the given * value @@ -106,7 +106,7 @@ public interface PersistentDataContainer { * PersistentDataType#getPrimitiveType()} */ @Nullable - Z get(@NotNull NamespacedKey key, @NotNull PersistentDataType type); + C get(@NotNull NamespacedKey key, @NotNull PersistentDataType type); /** * Returns the metadata value that is stored on the @@ -117,8 +117,8 @@ public interface PersistentDataContainer { * @param type the type the value must have and will be casted to * @param defaultValue the default value to return if no value was found for * the provided key - * @param the generic type of the stored primitive - * @param the generic type of the eventually created complex object + * @param

the generic type of the stored primitive + * @param the generic type of the eventually created complex object * * @return the value or the default value if no value was mapped under the * given key @@ -132,7 +132,7 @@ public interface PersistentDataContainer { * the {@link PersistentDataType#getPrimitiveType()} */ @NotNull - Z getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType type, @NotNull Z defaultValue); + C getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType type, @NotNull C defaultValue); /** * Get the set of keys present on this {@link PersistentDataContainer} diff --git a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java index b27f4568c2..f219d287e5 100644 --- a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java +++ b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java @@ -1,5 +1,6 @@ package org.bukkit.persistence; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** @@ -13,17 +14,17 @@ import org.jetbrains.annotations.NotNull; * {@code * public class UUIDTagType implements PersistentDataType { * - * {@literal @Override} + * @Override * public Class getPrimitiveType() { * return byte[].class; * } * - * {@literal @Override} + * @Override * public Class getComplexType() { * return UUID.class; * } * - * {@literal @Override} + * @Override * public byte[] toPrimitive(UUID complex, PersistentDataAdapterContext context) { * ByteBuffer bb = ByteBuffer.wrap(new byte[16]); * bb.putLong(complex.getMostSignificantBits()); @@ -31,19 +32,24 @@ import org.jetbrains.annotations.NotNull; * return bb.array(); * } * - * {@literal @Override} + * @Override * public UUID fromPrimitive(byte[] primitive, PersistentDataAdapterContext context) { * ByteBuffer bb = ByteBuffer.wrap(primitive); * long firstLong = bb.getLong(); * long secondLong = bb.getLong(); * return new UUID(firstLong, secondLong); * } - * }} + * } + *} * - * @param the primary object type that is stored in the given tag - * @param the retrieved object type when applying this tag type + * Any plugin owned implementation of this interface is required to define one + * of the existing primitive types found in this interface. Notably + * {@link #BOOLEAN} is not a primitive type but a convenience type. + * + * @param

the primary object type that is stored in the given tag + * @param the retrieved object type when applying this tag type */ -public interface PersistentDataType { +public interface PersistentDataType { /* The primitive one value types. @@ -80,6 +86,10 @@ public interface PersistentDataType { /* Complex Arrays. */ + /** + * @deprecated Use {@link #LIST}'s {@link ListPersistentDataTypeProvider#dataContainers()} instead. + */ + @ApiStatus.Obsolete PersistentDataType TAG_CONTAINER_ARRAY = new PrimitivePersistentDataType<>(PersistentDataContainer[].class); /* @@ -87,13 +97,29 @@ public interface PersistentDataType { */ PersistentDataType TAG_CONTAINER = new PrimitivePersistentDataType<>(PersistentDataContainer.class); + /** + * A data type provider type that itself cannot be used as a + * {@link PersistentDataType}. + * + * {@link ListPersistentDataTypeProvider} exposes shared persistent data + * types for storing lists of other data types, however. + *

+ * Its existence in the {@link PersistentDataType} interface does not permit + * {@link java.util.List} as a primitive type in combination with a plain + * {@link PersistentDataType}. {@link java.util.List}s are only valid + * primitive types when used via a {@link ListPersistentDataType}. + * + * @see ListPersistentDataTypeProvider + */ + ListPersistentDataTypeProvider LIST = new ListPersistentDataTypeProvider(); + /** * Returns the primitive data type of this tag. * * @return the class */ @NotNull - Class getPrimitiveType(); + Class

getPrimitiveType(); /** * Returns the complex object type the primitive value resembles. @@ -101,7 +127,7 @@ public interface PersistentDataType { * @return the class type */ @NotNull - Class getComplexType(); + Class getComplexType(); /** * Returns the primitive data that resembles the complex object passed to @@ -112,7 +138,7 @@ public interface PersistentDataType { * @return the primitive value */ @NotNull - T toPrimitive(@NotNull Z complex, @NotNull PersistentDataAdapterContext context); + P toPrimitive(@NotNull C complex, @NotNull PersistentDataAdapterContext context); /** * Creates a complex object based of the passed primitive value @@ -122,7 +148,7 @@ public interface PersistentDataType { * @return the complex object instance */ @NotNull - Z fromPrimitive(@NotNull T primitive, @NotNull PersistentDataAdapterContext context); + C fromPrimitive(@NotNull P primitive, @NotNull PersistentDataAdapterContext context); /** * A default implementation that simply exists to pass on the retrieved or @@ -131,37 +157,37 @@ public interface PersistentDataType { * This implementation does not add any kind of logic, but is used to * provide default implementations for the primitive types. * - * @param the generic type of the primitive objects + * @param

the generic type of the primitive objects */ - class PrimitivePersistentDataType implements PersistentDataType { + class PrimitivePersistentDataType

implements PersistentDataType { - private final Class primitiveType; + private final Class

primitiveType; - PrimitivePersistentDataType(@NotNull Class primitiveType) { + PrimitivePersistentDataType(@NotNull Class

primitiveType) { this.primitiveType = primitiveType; } @NotNull @Override - public Class getPrimitiveType() { + public Class

getPrimitiveType() { return primitiveType; } @NotNull @Override - public Class getComplexType() { + public Class

getComplexType() { return primitiveType; } @NotNull @Override - public T toPrimitive(@NotNull T complex, @NotNull PersistentDataAdapterContext context) { + public P toPrimitive(@NotNull P complex, @NotNull PersistentDataAdapterContext context) { return complex; } @NotNull @Override - public T fromPrimitive(@NotNull T primitive, @NotNull PersistentDataAdapterContext context) { + public P fromPrimitive(@NotNull P primitive, @NotNull PersistentDataAdapterContext context) { return primitive; } }