From 0d2be83dcf857b4b29c304bfb4b5d67dde23a13c Mon Sep 17 00:00:00 2001
From: crast <contact@jamescrasta.com>
Date: Sat, 16 Feb 2013 14:33:24 -0700
Subject: [PATCH] Refactor conversions from LazyMetadataValue into abstract
 base class

Implementing MetadataValue interface is significant work due to having
to provide a large amount of conversion stub method. This adds a new
optional abstract base class to aid in implementation.

Includes comprehensive unit tests including a sample adapter class, and
all existing metadata tests pass.
---
 .../org/bukkit/metadata/LazyMetadataValue.java     | 60 +----------------
 .../org/bukkit/metadata/MetadataValueAdapter.java  | 77 ++++++++++++++++++++++
 .../bukkit/metadata/MetadataValueAdapterTest.java  | 44 +++++++++++++
 3 files changed, 123 insertions(+), 58 deletions(-)
 create mode 100644 src/main/java/org/bukkit/metadata/MetadataValueAdapter.java
 create mode 100644 src/test/java/org/bukkit/metadata/MetadataValueAdapterTest.java

diff --git a/src/main/java/org/bukkit/metadata/LazyMetadataValue.java b/src/main/java/org/bukkit/metadata/LazyMetadataValue.java
index cc0ba50..9b66da9 100644
--- a/src/main/java/org/bukkit/metadata/LazyMetadataValue.java
+++ b/src/main/java/org/bukkit/metadata/LazyMetadataValue.java
@@ -5,7 +5,6 @@ import java.util.concurrent.Callable;
 
 import org.apache.commons.lang.Validate;
 import org.bukkit.plugin.Plugin;
-import org.bukkit.util.NumberConversions;
 
 /**
  * The LazyMetadataValue class implements a type of metadata that is not computed until another plugin asks for it.
@@ -14,11 +13,10 @@ import org.bukkit.util.NumberConversions;
  * or invalidated at the individual or plugin level. Once invalidated, the LazyMetadataValue will recompute its value
  * when asked.
  */
-public class LazyMetadataValue implements MetadataValue {
+public class LazyMetadataValue extends MetadataValueAdapter implements MetadataValue {
     private Callable<Object> lazyValue;
     private CacheStrategy cacheStrategy;
     private SoftReference<Object> internalValue = new SoftReference<Object>(null);
-    private Plugin owningPlugin;
     private static final Object ACTUALLY_NULL = new Object();
 
     /**
@@ -39,19 +37,14 @@ public class LazyMetadataValue implements MetadataValue {
      * @param lazyValue the lazy value assigned to this metadata value.
      */
     public LazyMetadataValue(Plugin owningPlugin, CacheStrategy cacheStrategy, Callable<Object> lazyValue) {
-        Validate.notNull(owningPlugin, "owningPlugin cannot be null");
+        super(owningPlugin);
         Validate.notNull(cacheStrategy, "cacheStrategy cannot be null");
         Validate.notNull(lazyValue, "lazyValue cannot be null");
 
         this.lazyValue = lazyValue;
-        this.owningPlugin = owningPlugin;
         this.cacheStrategy = cacheStrategy;
     }
 
-    public Plugin getOwningPlugin() {
-        return owningPlugin;
-    }
-
     public Object value() {
         eval();
         Object value = internalValue.get();
@@ -61,55 +54,6 @@ public class LazyMetadataValue implements MetadataValue {
         return value;
     }
 
-    public int asInt() {
-        return NumberConversions.toInt(value());
-    }
-
-    public float asFloat() {
-        return NumberConversions.toFloat(value());
-    }
-
-    public double asDouble() {
-        return NumberConversions.toDouble(value());
-    }
-
-    public long asLong() {
-        return NumberConversions.toLong(value());
-    }
-
-    public short asShort() {
-        return NumberConversions.toShort(value());
-    }
-
-    public byte asByte() {
-        return NumberConversions.toByte(value());
-    }
-
-    public boolean asBoolean() {
-        Object value = value();
-        if (value instanceof Boolean) {
-            return (Boolean) value;
-        }
-
-        if (value instanceof Number) {
-            return ((Number) value).intValue() != 0;
-        }
-
-        if (value instanceof String) {
-            return Boolean.parseBoolean((String) value);
-        }
-
-        return value != null;
-    }
-
-    public String asString() {
-        Object value = value();
-
-        if (value == null) {
-            return "";
-        }
-        return value.toString();
-    }
 
     /**
      * Lazily evaluates the value of this metadata item.
diff --git a/src/main/java/org/bukkit/metadata/MetadataValueAdapter.java b/src/main/java/org/bukkit/metadata/MetadataValueAdapter.java
new file mode 100644
index 0000000..9ec7e61
--- /dev/null
+++ b/src/main/java/org/bukkit/metadata/MetadataValueAdapter.java
@@ -0,0 +1,77 @@
+package org.bukkit.metadata;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.NumberConversions;
+
+/**
+ * Optional base class for facilitating MetadataValue implementations.
+ * 
+ * This provides all the conversion functions for MetadataValue 
+ * so that writing an implementation of MetadataValue is as simple 
+ * as implementing value() and invalidate()
+ *
+ */
+public abstract class MetadataValueAdapter implements MetadataValue {
+    protected final Plugin owningPlugin;
+
+    protected MetadataValueAdapter(Plugin owningPlugin) {
+        Validate.notNull(owningPlugin, "owningPlugin cannot be null");
+        this.owningPlugin = owningPlugin;
+    }
+
+    public Plugin getOwningPlugin() {
+        return owningPlugin;
+    }
+
+    public int asInt() {
+        return NumberConversions.toInt(value());
+    }
+
+    public float asFloat() {
+        return NumberConversions.toFloat(value());
+    }
+
+    public double asDouble() {
+        return NumberConversions.toDouble(value());
+    }
+
+    public long asLong() {
+        return NumberConversions.toLong(value());
+    }
+
+    public short asShort() {
+        return NumberConversions.toShort(value());
+    }
+
+    public byte asByte() {
+        return NumberConversions.toByte(value());
+    }
+
+    public boolean asBoolean() {
+        Object value = value();
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        }
+
+        if (value instanceof Number) {
+            return ((Number) value).intValue() != 0;
+        }
+
+        if (value instanceof String) {
+            return Boolean.parseBoolean((String) value);
+        }
+
+        return value != null;
+    }
+
+    public String asString() {
+        Object value = value();
+
+        if (value == null) {
+            return "";
+        }
+        return value.toString();
+    }
+
+}
diff --git a/src/test/java/org/bukkit/metadata/MetadataValueAdapterTest.java b/src/test/java/org/bukkit/metadata/MetadataValueAdapterTest.java
new file mode 100644
index 0000000..5ae7df4
--- /dev/null
+++ b/src/test/java/org/bukkit/metadata/MetadataValueAdapterTest.java
@@ -0,0 +1,44 @@
+package org.bukkit.metadata;
+
+import static org.junit.Assert.assertEquals;
+
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.TestPlugin;
+import org.junit.Test;
+
+public class MetadataValueAdapterTest {
+    private TestPlugin plugin = new TestPlugin("x");
+
+    @Test
+    public void testIncrementingAdapter() {
+        IncrementingMetaValue mv = new IncrementingMetaValue(plugin);
+        // check getOwningPlugin
+        assertEquals(mv.getOwningPlugin(), this.plugin);
+
+        // check the various value-making methods
+        assertEquals(mv.asInt(), 1);
+        assertEquals(mv.asLong(), 2L);
+        assertEquals(mv.asFloat(), 3.0, 0.001);
+        assertEquals(mv.asByte(), 4);
+        assertEquals(mv.asDouble(), 5.0, 0.001);
+        assertEquals(mv.asShort(), 6);
+        assertEquals(mv.asString(), "7");
+    }
+
+    /** Silly Metadata implementation that increments every time value() is called */
+    class IncrementingMetaValue extends MetadataValueAdapter {
+        private int internalValue = 0;
+
+        protected IncrementingMetaValue(Plugin owningPlugin) {
+            super(owningPlugin);
+        }
+
+        public Object value() {
+            return ++internalValue;
+        }
+
+        public void invalidate() {
+            internalValue = 0;
+        }
+    }
+}
-- 
1.8.1-rc2