Refactor: Improved handling of unknown materials and issues during ItemData deserialization.

master
blablubbabc 2020-11-28 17:45:33 +01:00
parent cb843307da
commit 55ed27979e
6 changed files with 73 additions and 47 deletions

View File

@ -21,6 +21,7 @@ import com.nisovin.shopkeepers.config.annotation.WithValueType;
import com.nisovin.shopkeepers.config.annotation.WithValueTypeProvider;
import com.nisovin.shopkeepers.config.value.DefaultValueTypes;
import com.nisovin.shopkeepers.config.value.SettingLoadException;
import com.nisovin.shopkeepers.config.value.UnknownMaterialException;
import com.nisovin.shopkeepers.config.value.ValueType;
import com.nisovin.shopkeepers.config.value.ValueTypeProvider;
import com.nisovin.shopkeepers.config.value.ValueTypeRegistry;
@ -348,6 +349,9 @@ public abstract class Config {
protected <T> void onSettingLoadException(Field field, ConfigurationSection config, SettingLoadException e) throws ConfigLoadException {
String configKey = this.getConfigKey(field);
Log.warning(this.msgSettingLoadException(configKey, e));
if (e instanceof UnknownMaterialException) {
Log.warning(this.getLogPrefix() + "All valid material names can be found here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html");
}
}
protected String msgSettingLoadException(String configKey, SettingLoadException e) {

View File

@ -0,0 +1,19 @@
package com.nisovin.shopkeepers.config.value;
import org.bukkit.Material;
/**
* This exception is issued by {@link ValueType#load(Object)} when an unknown {@link Material} is encountered.
*/
public class UnknownMaterialException extends SettingLoadException {
private static final long serialVersionUID = 1653518607452366268L;
public UnknownMaterialException(String message) {
super(message);
}
public UnknownMaterialException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,8 +1,11 @@
package com.nisovin.shopkeepers.config.value.types;
import com.nisovin.shopkeepers.config.value.SettingLoadException;
import com.nisovin.shopkeepers.config.value.UnknownMaterialException;
import com.nisovin.shopkeepers.config.value.ValueType;
import com.nisovin.shopkeepers.util.ItemData;
import com.nisovin.shopkeepers.util.ItemData.ItemDataDeserializeException;
import com.nisovin.shopkeepers.util.ItemData.UnknownItemTypeException;
public class ItemDataValue extends ValueType<ItemData> {
@ -13,27 +16,14 @@ public class ItemDataValue extends ValueType<ItemData> {
@Override
public ItemData load(Object configValue) throws SettingLoadException {
ItemData itemData = null;
try {
// Returns null if the config value is null. Otherwise triggers a warning, which we translate into an
// exception.
itemData = ItemData.deserialize(configValue, (warning) -> {
String errorMsg = warning;
if (warning.contains("Unknown item type")) { // TODO this is ugly
errorMsg = warning + " (All valid material names can be found here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html)";
}
// We can only throw unchecked exceptions here, so we wrap the exception here and unwrap it again
// outside:
throw new RuntimeException(new SettingLoadException(errorMsg));
});
} catch (RuntimeException e) {
if (e.getCause() instanceof SettingLoadException) {
throw (SettingLoadException) e.getCause();
} else {
throw e;
}
// Returns null if the config value is null.
return ItemData.deserialize(configValue);
} catch (UnknownItemTypeException e) {
throw new UnknownMaterialException(e.getMessage(), e);
} catch (ItemDataDeserializeException e) {
throw new SettingLoadException(e.getMessage(), e);
}
return itemData;
}
@Override

View File

@ -3,6 +3,7 @@ package com.nisovin.shopkeepers.config.value.types;
import org.bukkit.Material;
import com.nisovin.shopkeepers.config.value.SettingLoadException;
import com.nisovin.shopkeepers.config.value.UnknownMaterialException;
import com.nisovin.shopkeepers.config.value.ValueType;
public class MaterialValue extends ValueType<Material> {
@ -21,8 +22,7 @@ public class MaterialValue extends ValueType<Material> {
// This assumes that legacy item conversion has already been performed:
Material material = Material.matchMaterial(materialName); // Can be null
if (material == null) {
throw new SettingLoadException("Unknown material: " + materialName
+ " (All valid material names can be found here: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html)");
throw new UnknownMaterialException("Unknown material: " + materialName);
}
return material;
}

View File

@ -5,7 +5,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Consumer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -18,8 +17,32 @@ import org.bukkit.inventory.meta.ItemMeta;
*/
public class ItemData implements Cloneable {
private static final Consumer<String> SILENT_WARNING_HANDLER = (warning) -> {
};
public static class ItemDataDeserializeException extends Exception {
private static final long serialVersionUID = -6637983932875623362L;
public ItemDataDeserializeException(String message) {
super(message);
}
public ItemDataDeserializeException(String message, Throwable cause) {
super(message, cause);
}
}
public static class UnknownItemTypeException extends ItemDataDeserializeException {
private static final long serialVersionUID = -6123823171023440870L;
public UnknownItemTypeException(String message) {
super(message);
}
public UnknownItemTypeException(String message, Throwable cause) {
super(message, cause);
}
}
private static final String META_TYPE_KEY = "meta-type";
private static final String DISPLAY_NAME_KEY = "display-name";
private static final String LORE_KEY = "lore";
@ -27,16 +50,8 @@ public class ItemData implements Cloneable {
// Special case: Omitting 'blockMaterial' for empty TILE_ENTITY item meta.
private static final String TILE_ENTITY_BLOCK_MATERIAL_KEY = "blockMaterial";
public static ItemData deserialize(Object dataObject) {
return deserialize(dataObject, null);
}
// Only returns null if the input data is null, or if the data cannot be loaded (in which case the warning handler
// is informed).
public static ItemData deserialize(Object dataObject, Consumer<String> warningHandler) {
if (warningHandler == null) {
warningHandler = SILENT_WARNING_HANDLER; // Ignore all warnings
}
// Only returns null if the input data is null.
public static ItemData deserialize(Object dataObject) throws ItemDataDeserializeException {
if (dataObject == null) return null;
String typeName = null;
@ -56,8 +71,7 @@ public class ItemData implements Cloneable {
dataMap.put(entry.getKey().toString(), entry.getValue());
}
} else {
warningHandler.accept("Unknown item data: " + dataObject);
return null;
throw new ItemDataDeserializeException("Unknown item data representation: " + dataObject);
}
assert dataMap != null; // Assert: dataMap is a (shallow) copy
@ -67,8 +81,7 @@ public class ItemData implements Cloneable {
}
if (typeName == null) {
// Missing item type information:
warningHandler.accept("Missing item type");
return null;
throw new ItemDataDeserializeException("Missing item type");
}
assert typeName != null;
@ -83,8 +96,7 @@ public class ItemData implements Cloneable {
Material type = Material.matchMaterial(typeName);
if (type == null) {
// Unknown item type:
warningHandler.accept("Unknown item type: " + typeName);
return null;
throw new UnknownItemTypeException("Unknown item type: " + typeName);
}
// Create item stack (still misses meta data):

View File

@ -25,10 +25,11 @@ import org.junit.Assert;
import org.junit.Test;
import com.nisovin.shopkeepers.testutil.AbstractBukkitTest;
import com.nisovin.shopkeepers.util.ItemData.ItemDataDeserializeException;
public class ItemDataTest extends AbstractBukkitTest {
private static void testDeserialization(ItemData originalItemData) {
private static void testDeserialization(ItemData originalItemData) throws ItemDataDeserializeException {
YamlConfiguration config = new YamlConfiguration();
Object serialized = originalItemData.serialize();
config.set("key", serialized);
@ -72,7 +73,7 @@ public class ItemDataTest extends AbstractBukkitTest {
}
@Test
public void testDeserializationSimple() {
public void testDeserializationSimple() throws ItemDataDeserializeException {
ItemStack itemStack = createItemStackSimple();
ItemData itemData = new ItemData(itemStack);
testDeserialization(itemData);
@ -110,7 +111,7 @@ public class ItemDataTest extends AbstractBukkitTest {
}
@Test
public void testDeserializationMinimal() {
public void testDeserializationMinimal() throws ItemDataDeserializeException {
ItemStack itemStack = createItemStackMinimal();
ItemData itemData = new ItemData(itemStack);
testDeserialization(itemData);
@ -209,7 +210,7 @@ public class ItemDataTest extends AbstractBukkitTest {
}
@Test
public void testDeserializationFull() {
public void testDeserializationFull() throws ItemDataDeserializeException {
ItemStack itemStack = createItemStackFull();
ItemData itemData = new ItemData(itemStack);
testDeserialization(itemData);
@ -253,7 +254,7 @@ public class ItemDataTest extends AbstractBukkitTest {
}
@Test
public void testDeserializationUncommon() {
public void testDeserializationUncommon() throws ItemDataDeserializeException {
ItemStack itemStack = createItemStackUncommon();
ItemData itemData = new ItemData(itemStack);
testDeserialization(itemData);
@ -286,7 +287,7 @@ public class ItemDataTest extends AbstractBukkitTest {
}
@Test
public void testDeserializationTileEntitySimple() {
public void testDeserializationTileEntitySimple() throws ItemDataDeserializeException {
ItemStack itemStack = createItemStackTileEntitySimple();
ItemData itemData = new ItemData(itemStack);
testDeserialization(itemData);
@ -324,7 +325,7 @@ public class ItemDataTest extends AbstractBukkitTest {
}
@Test
public void testDeserializationTileEntityMinimal() {
public void testDeserializationTileEntityMinimal() throws ItemDataDeserializeException {
ItemStack itemStack = createItemStackTileEntityMinimal();
ItemData itemData = new ItemData(itemStack);
testDeserialization(itemData);