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;
}
}