diff --git a/paper-api/src/main/java/org/bukkit/NamespacedKey.java b/paper-api/src/main/java/org/bukkit/NamespacedKey.java index 22eca2a18..803fa0019 100644 --- a/paper-api/src/main/java/org/bukkit/NamespacedKey.java +++ b/paper-api/src/main/java/org/bukkit/NamespacedKey.java @@ -6,6 +6,7 @@ import java.util.UUID; import java.util.regex.Pattern; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Represents a String based key which consists of two components - a namespace @@ -139,4 +140,76 @@ public final class NamespacedKey { public static NamespacedKey minecraft(@NotNull String key) { return new NamespacedKey(MINECRAFT, key); } + + /** + * Get a NamespacedKey from the supplied string with a default namespace if + * a namespace is not defined. This is a utility method meant to fetch a + * NamespacedKey from user input. Please note that casing does matter and + * any instance of uppercase characters will be considered invalid. The + * input contract is as follows: + *
+ * fromString("foo", plugin) -{@literal >} "plugin:foo"
+ * fromString("foo:bar", plugin) -{@literal >} "foo:bar"
+ * fromString(":foo", null) -{@literal >} "minecraft:foo"
+ * fromString("foo", null) -{@literal >} "minecraft:foo"
+ * fromString("Foo", plugin) -{@literal >} null
+ * fromString(":Foo", plugin) -{@literal >} null
+ * fromString("foo:bar:bazz", plugin) -{@literal >} null
+ * fromString("", plugin) -{@literal >} null
+ *
+ *
+ * @param string the string to convert to a NamespacedKey
+ * @param defaultNamespace the default namespace to use if none was
+ * supplied. If null, the {@code minecraft} namespace
+ * ({@link #minecraft(String)}) will be used
+ * @return the created NamespacedKey. null if invalid key
+ * @see #fromString(String)
+ */
+ @Nullable
+ public static NamespacedKey fromString(@NotNull String string, @Nullable Plugin defaultNamespace) {
+ Preconditions.checkArgument(string != null && !string.isEmpty(), "Input string must not be empty or null");
+
+ String[] components = string.split(":", 3);
+ if (components.length > 2) {
+ return null;
+ }
+
+ String key = (components.length == 2) ? components[1] : "";
+ if (components.length == 1) {
+ String value = components[0];
+ if (value.isEmpty() || !VALID_KEY.matcher(value).matches()) {
+ return null;
+ }
+
+ return (defaultNamespace != null) ? new NamespacedKey(defaultNamespace, value) : minecraft(value);
+ } else if (components.length == 2 && !VALID_KEY.matcher(key).matches()) {
+ return null;
+ }
+
+ String namespace = components[0];
+ if (namespace.isEmpty()) {
+ return (defaultNamespace != null) ? new NamespacedKey(defaultNamespace, key) : minecraft(key);
+ }
+
+ if (!VALID_KEY.matcher(namespace).matches()) {
+ return null;
+ }
+
+ return new NamespacedKey(namespace, key);
+ }
+
+ /**
+ * Get a NamespacedKey from the supplied string.
+ *
+ * The default namespace will be Minecraft's (i.e.
+ * {@link #minecraft(String)}).
+ *
+ * @param key the key to convert to a NamespacedKey
+ * @return the created NamespacedKey. null if invalid
+ * @see #fromString(String, Plugin)
+ */
+ @Nullable
+ public static NamespacedKey fromString(@NotNull String key) {
+ return fromString(key, null);
+ }
}
diff --git a/paper-api/src/test/java/org/bukkit/NamespacedKeyTest.java b/paper-api/src/test/java/org/bukkit/NamespacedKeyTest.java
index 8c5e5ca78..9f57889cb 100644
--- a/paper-api/src/test/java/org/bukkit/NamespacedKeyTest.java
+++ b/paper-api/src/test/java/org/bukkit/NamespacedKeyTest.java
@@ -14,6 +14,31 @@ public class NamespacedKeyTest {
Assert.assertEquals("minecraft:foo/bar_baz-qux.quux", new NamespacedKey("minecraft", "foo/bar_baz-qux.quux").toString());
}
+ @Test
+ public void testValidFromString() {
+ NamespacedKey expected = NamespacedKey.minecraft("foo");
+ Assert.assertEquals(expected, NamespacedKey.fromString("foo"));
+ Assert.assertEquals(expected, NamespacedKey.fromString(":foo"));
+ Assert.assertEquals(expected, NamespacedKey.fromString("minecraft:foo"));
+ Assert.assertEquals(new NamespacedKey("foo", "bar"), NamespacedKey.fromString("foo:bar"));
+
+ Assert.assertNull(NamespacedKey.fromString("fOO"));
+ Assert.assertNull(NamespacedKey.fromString(":Foo"));
+ Assert.assertNull(NamespacedKey.fromString("fOO:bar"));
+ Assert.assertNull(NamespacedKey.fromString("minecraft:fOO"));
+ Assert.assertNull(NamespacedKey.fromString("foo:bar:bazz"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFromStringEmptyInput() {
+ NamespacedKey.fromString("");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFromStringNullInput() {
+ NamespacedKey.fromString(null);
+ }
+
@Test(expected = IllegalArgumentException.class)
public void testEmptyNamespace() {
new NamespacedKey("", "foo").toString();