Index: tika-core/src/main/java/org/apache/tika/metadata/values/IntMetadataValue.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/main/java/org/apache/tika/metadata/values/IntMetadataValue.java	(revision )
+++ tika-core/src/main/java/org/apache/tika/metadata/values/IntMetadataValue.java	(revision )
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tika.metadata.values;
+
+import org.apache.tika.metadata.MetadataValue;
+import org.apache.tika.metadata.Property;
+import org.apache.tika.metadata.PropertyTypeException;
+
+/**
+ * Integer metadata value
+ */
+public class IntMetadataValue implements MetadataValue {
+
+    private final Integer i;
+    private final String intString;
+
+    public IntMetadataValue(String val) {
+        Integer tmp = null;
+        try {
+            tmp = Integer.valueOf(val);
+        } catch(NumberFormatException e) {
+        }
+        i = tmp;
+        intString = (i == null) ? val : Integer.toString(i);
+    }
+
+    public IntMetadataValue(Integer i) {
+        this.i = i;
+        this.intString = (i == null) ? null : Integer.toString(i);
+    }
+
+    @Override
+    public String getString() {
+        return intString;
+    }
+
+    @Override
+    public boolean isAllowed(Property property) {
+        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
+            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        }
+        if(property.getPrimaryProperty().getValueType() != Property.ValueType.INTEGER) {
+            throw new PropertyTypeException(Property.ValueType.INTEGER, property.getPrimaryProperty().getValueType());
+        }
+        return true;
+    }
+
+    public Integer getInt() {
+        return i;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        IntMetadataValue that = (IntMetadataValue) o;
+
+        if (i != null ? !i.equals(that.i) : that.i != null) return false;
+        return !(intString != null ? !intString.equals(that.intString) : that.intString != null);
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = i != null ? i.hashCode() : 0;
+        result = 31 * result + (intString != null ? intString.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "IntMetadataValue{" +
+                "i=" + i +
+                ", intString='" + intString + '\'' +
+                '}';
+    }
+}
Index: tika-core/src/main/java/org/apache/tika/metadata/values/StringMetadataValue.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/main/java/org/apache/tika/metadata/values/StringMetadataValue.java	(revision )
+++ tika-core/src/main/java/org/apache/tika/metadata/values/StringMetadataValue.java	(revision )
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.values;
+
+import org.apache.tika.metadata.MetadataValue;
+import org.apache.tika.metadata.Property;
+
+public class StringMetadataValue implements MetadataValue {
+    final String s;
+
+    public StringMetadataValue(final String s) {
+        this.s = s;
+    }
+
+    @Override
+    public String getString() {
+        return s;
+    }
+
+    @Override
+    public boolean isAllowed(Property property) {
+        //TODO: make this a tad more stringent?
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        StringMetadataValue that = (StringMetadataValue) o;
+
+        return !(s != null ? !s.equals(that.s) : that.s != null);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return s != null ? s.hashCode() : 0;
+    }
+}
Index: tika-core/src/main/java/org/apache/tika/metadata/values/DoubleMetadataValue.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/main/java/org/apache/tika/metadata/values/DoubleMetadataValue.java	(revision )
+++ tika-core/src/main/java/org/apache/tika/metadata/values/DoubleMetadataValue.java	(revision )
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tika.metadata.values;
+
+import org.apache.tika.metadata.MetadataValue;
+import org.apache.tika.metadata.Property;
+import org.apache.tika.metadata.PropertyTypeException;
+
+/**
+ * Double metadata value
+ */
+public class DoubleMetadataValue implements MetadataValue {
+
+    private final Double d;
+    private final String doubleString;
+
+    public DoubleMetadataValue(String val) {
+        Double tmp = null;
+        try {
+            tmp = Double.valueOf(val);
+        } catch(NumberFormatException e) {
+        }
+        d = tmp;
+        doubleString = (d == null) ? val : Double.toString(d);
+    }
+
+    public DoubleMetadataValue(Double d) {
+        this.d = d;
+        this.doubleString = (d == null) ? null : Double.toString(d);
+    }
+
+    @Override
+    public String getString() {
+        return doubleString;
+    }
+
+    @Override
+    public boolean isAllowed(Property property) {
+        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
+            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        }
+        if(property.getPrimaryProperty().getValueType() != Property.ValueType.REAL &&
+                property.getPrimaryProperty().getValueType() != Property.ValueType.RATIONAL) {
+            throw new PropertyTypeException(Property.ValueType.REAL, property.getPrimaryProperty().getValueType());
+        }
+        return true;
+    }
+
+    public Double getDouble() {
+        return d;
+    }
+
+
+}
Index: tika-core/src/main/java/org/apache/tika/metadata/values/DateMetadataValue.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/main/java/org/apache/tika/metadata/values/DateMetadataValue.java	(revision )
+++ tika-core/src/main/java/org/apache/tika/metadata/values/DateMetadataValue.java	(revision )
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata.values;
+
+import static org.apache.tika.utils.DateUtils.MIDDAY;
+import static org.apache.tika.utils.DateUtils.UTC;
+import static org.apache.tika.utils.DateUtils.formatDate;
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.tika.metadata.MetadataValue;
+import org.apache.tika.metadata.Property;
+import org.apache.tika.metadata.PropertyTypeException;
+
+public class DateMetadataValue implements MetadataValue {
+
+    private final String dateString;
+    private final Date date;
+
+    /**
+     * Some parsers will have the date as a ISO-8601 string
+     *  already, and will set that into the Metadata object.
+     * So we can return Date objects for these, this is the
+     *  list (in preference order) of the various ISO-8601
+     *  variants that we try when processing a date based
+     *  property.
+     */
+    private static final DateFormat[] iso8601InputFormats = new DateFormat[] {
+            // yyyy-mm-ddThh...
+            createDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", UTC),   // UTC/Zulu
+            createDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", null),    // With timezone
+            createDateFormat("yyyy-MM-dd'T'HH:mm:ss", null),     // Without timezone
+            // yyyy-mm-dd hh...
+            createDateFormat("yyyy-MM-dd' 'HH:mm:ss'Z'", UTC),   // UTC/Zulu
+            createDateFormat("yyyy-MM-dd' 'HH:mm:ssZ", null),    // With timezone
+            createDateFormat("yyyy-MM-dd' 'HH:mm:ss", null),     // Without timezone
+            // Date without time, set to Midday UTC
+            createDateFormat("yyyy-MM-dd", MIDDAY),              // Normal date format
+            createDateFormat("yyyy:MM:dd", MIDDAY),              // Image (IPTC/EXIF) format
+    };
+
+    private static DateFormat createDateFormat(String format, TimeZone timezone) {
+        SimpleDateFormat sdf =
+                new SimpleDateFormat(format, new DateFormatSymbols(Locale.US));
+        if (timezone != null) {
+            sdf.setTimeZone(timezone);
+        }
+        return sdf;
+    }
+
+    /**
+     * Parses the given date string. This method is synchronized to prevent
+     * concurrent access to the thread-unsafe date formats.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/TIKA-495">TIKA-495</a>
+     * @param date date string
+     * @return parsed date, or <code>null</code> if the date can't be parsed
+     */
+    private static synchronized Date parseDate(String date) {
+        // Java doesn't like timezones in the form ss+hh:mm
+        // It only likes the hhmm form, without the colon
+        int n = date.length();
+        if (date.charAt(n - 3) == ':'
+                && (date.charAt(n - 6) == '+' || date.charAt(n - 6) == '-')) {
+            date = date.substring(0, n - 3) + date.substring(n - 2);
+        }
+
+        // Try several different ISO-8601 variants
+        for (DateFormat format : iso8601InputFormats) {
+            try {
+                return format.parse(date);
+            } catch (ParseException ignore) {
+            }
+        }
+        return null;
+    }
+
+    public DateMetadataValue(String val) {
+        date = parseDate(val);
+        if (date == null) {
+            dateString = val;
+        } else {
+            dateString = formatDate(date);
+        }
+    }
+
+    public DateMetadataValue(Date date) {
+        //defensive copy
+        this.date = new Date(date.getTime());
+        dateString = formatDate(date);
+    }
+
+    @Override
+    public String getString() {
+        return dateString;
+    }
+
+    @Override
+    public boolean isAllowed(Property property) {
+        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
+            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        }
+        if(property.getPrimaryProperty().getValueType() != Property.ValueType.DATE) {
+            throw new PropertyTypeException(Property.ValueType.DATE, property.getPrimaryProperty().getValueType());
+        }
+        return true;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+}
Index: tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java	(revision ab1158a238571382da0a7ea72aca6eeca8552535)
+++ tika-core/src/test/java/org/apache/tika/metadata/TestMetadata.java	(revision )
@@ -17,20 +17,20 @@
 package org.apache.tika.metadata;
 
 //JDK imports
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.util.Date;
 import java.util.Properties;
 
 import org.apache.tika.utils.DateUtils;
 import org.junit.Test;
 
-
 //Junit imports
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 /**
  * JUnit based tests of class {@link org.apache.tika.metadata.Metadata}.
@@ -283,7 +283,7 @@
         
         // Can set it and retrieve it
         meta.set(TikaCoreProperties.CREATED, new Date(1000));
-        assertEquals("1970-01-01T00:00:01Z", meta.get(TikaCoreProperties.CREATED));
+        assertEquals("1970-01-01T00:00:01Z", meta.getMetadataValue(TikaCoreProperties.CREATED).getString());
         assertEquals(1000, meta.getDate(TikaCoreProperties.CREATED).getTime());
         
         // If you save a non date value, you get null
Index: tika-core/src/main/java/org/apache/tika/metadata/MetadataValue.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/main/java/org/apache/tika/metadata/MetadataValue.java	(revision )
+++ tika-core/src/main/java/org/apache/tika/metadata/MetadataValue.java	(revision )
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.metadata;
+
+public interface MetadataValue {
+
+    /**
+     *
+     * @return String value of this metadata value object, can be null
+     */
+    public String getString();
+
+    /**
+     *
+     * @param property
+     * @return whether or not this metadata value is compatible with this
+     * property
+     * @throws PropertyTypeException
+     */
+    public boolean isAllowed(Property property);
+}
Index: tika-core/src/main/java/org/apache/tika/metadata/Metadata.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- tika-core/src/main/java/org/apache/tika/metadata/Metadata.java	(revision ab1158a238571382da0a7ea72aca6eeca8552535)
+++ tika-core/src/main/java/org/apache/tika/metadata/Metadata.java	(revision )
@@ -16,25 +16,19 @@
  */
 package org.apache.tika.metadata;
 
-import static org.apache.tika.utils.DateUtils.MIDDAY;
-import static org.apache.tika.utils.DateUtils.UTC;
-import static org.apache.tika.utils.DateUtils.formatDate;
-
 import java.io.Serializable;
-import java.text.DateFormat;
-import java.text.DateFormatSymbols;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
-import java.util.TimeZone;
 
 import org.apache.tika.metadata.Property.PropertyType;
+import org.apache.tika.metadata.values.DateMetadataValue;
+import org.apache.tika.metadata.values.DoubleMetadataValue;
+import org.apache.tika.metadata.values.IntMetadataValue;
+import org.apache.tika.metadata.values.StringMetadataValue;
 
 /**
  * A multi-valued metadata container.
@@ -49,7 +43,7 @@
     /**
      * A map of all metadata attributes.
      */
-    private Map<String, String[]> metadata = null;
+    private Map<String, MetadataValue[]> metadata = null;
 
     /**
      * The common delimiter used between the namespace abbreviation and the property name
@@ -89,69 +83,13 @@
     /** @deprecated use TikaCoreProperties#TYPE */
     public static final String TYPE = "type";
 
-    /**
-     * Some parsers will have the date as a ISO-8601 string
-     *  already, and will set that into the Metadata object.
-     * So we can return Date objects for these, this is the
-     *  list (in preference order) of the various ISO-8601
-     *  variants that we try when processing a date based
-     *  property.
-     */
-    private static final DateFormat[] iso8601InputFormats = new DateFormat[] {
-        // yyyy-mm-ddThh...
-        createDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", UTC),   // UTC/Zulu
-        createDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", null),    // With timezone
-        createDateFormat("yyyy-MM-dd'T'HH:mm:ss", null),     // Without timezone
-        // yyyy-mm-dd hh...
-        createDateFormat("yyyy-MM-dd' 'HH:mm:ss'Z'", UTC),   // UTC/Zulu
-        createDateFormat("yyyy-MM-dd' 'HH:mm:ssZ", null),    // With timezone
-        createDateFormat("yyyy-MM-dd' 'HH:mm:ss", null),     // Without timezone
-        // Date without time, set to Midday UTC
-        createDateFormat("yyyy-MM-dd", MIDDAY),              // Normal date format
-        createDateFormat("yyyy:MM:dd", MIDDAY),              // Image (IPTC/EXIF) format
-    };
 
-    private static DateFormat createDateFormat(String format, TimeZone timezone) {
-        SimpleDateFormat sdf =
-            new SimpleDateFormat(format, new DateFormatSymbols(Locale.US));
-        if (timezone != null) {
-            sdf.setTimeZone(timezone);
-        }
-        return sdf;
-    }
 
     /**
-     * Parses the given date string. This method is synchronized to prevent
-     * concurrent access to the thread-unsafe date formats.
-     *
-     * @see <a href="https://issues.apache.org/jira/browse/TIKA-495">TIKA-495</a>
-     * @param date date string
-     * @return parsed date, or <code>null</code> if the date can't be parsed
-     */
-    private static synchronized Date parseDate(String date) {
-        // Java doesn't like timezones in the form ss+hh:mm
-        // It only likes the hhmm form, without the colon
-        int n = date.length();
-        if (date.charAt(n - 3) == ':'
-            && (date.charAt(n - 6) == '+' || date.charAt(n - 6) == '-')) {
-            date = date.substring(0, n - 3) + date.substring(n - 2);
-        }
-
-        // Try several different ISO-8601 variants
-        for (DateFormat format : iso8601InputFormats) {
-            try {
-                return format.parse(date);
-            } catch (ParseException ignore) {
-            }
-        }
-        return null;
-    }
-
-    /**
      * Constructs a new, empty metadata.
      */
     public Metadata() {
-        metadata = new HashMap<String, String[]>();
+        metadata = new HashMap<String, MetadataValue[]>();
     }
 
     /**
@@ -186,18 +124,49 @@
     }
 
     /**
-     * Get the value associated to a metadata name. If many values are assiociated
+     * Get the String value associated to a metadata name. If many values are assiociated
      * to the specified name, then the first one is returned.
-     * 
+     * @deprecated To be removed in Tika 2.0.  Use {@link #getMetadataValue(String)}.
      * @param name
      *          of the metadata.
      * @return the value associated to the specified metadata name.
      */
+    @Deprecated
     public String get(final String name) {
-        String[] values = metadata.get(name);
+        MetadataValue[] values = metadata.get(name);
         if (values == null) {
             return null;
         } else {
+            return values[0].getString();
+        }
+    }
+
+    /**
+     * Get the value associated to a metadata name. If many values are assiociated
+     * to the specified name, then the first one is returned.
+     *
+     * @param property
+     *          of the metadata.
+     * @return the value associated to the specified property or null if not found.
+     */
+    public MetadataValue getMetadataValue(final Property property) {
+        return getMetadataValue(property.getName());
+    }
+
+
+    /**
+     * Get the value associated to a metadata name. If many values are assiociated
+     * to the specified name, then the first one is returned.
+     *
+     * @param name
+     *          of the metadata.
+     * @return the value associated to the specified metadata name or null if not found.
+     */
+    public MetadataValue getMetadataValue(final String name) {
+        MetadataValue[] values = metadata.get(name);
+        if (values == null) {
+            return null;
+        } else {
             return values[0];
         }
     }
@@ -217,9 +186,11 @@
      * Returns the value of the identified Integer based metadata property.
      * 
      * @since Apache Tika 0.8
+     * @deprecated To be removed in Tika 2.0.  Use {@link #getMetadataValue(Property)}
      * @param property simple integer property definition
      * @return property value as a Integer, or <code>null</code> if the property is not set, or not a valid Integer
      */
+    @Deprecated
     public Integer getInt(Property property) {
         if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
             return null;
@@ -243,9 +214,11 @@
      * Returns the value of the identified Date based metadata property.
      * 
      * @since Apache Tika 0.8
+     * @deprecated To be removed in Tika 2.0.  Use {@link #getMetadataValue(String)}.
      * @param property simple date property definition
      * @return property value as a Date, or <code>null</code> if the property is not set, or not a valid Date
      */
+    @Deprecated
     public Date getDate(Property property) {
         if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
             return null;
@@ -255,45 +228,84 @@
         }
         
         String v = get(property);
-        if (v != null) {
-            return parseDate(v);
-        } else {
-            return null;
+        DateMetadataValue dmv = new DateMetadataValue(v);
+        return dmv.getDate();
-        }
+    }
-    }
     
     /**
      * Get the values associated to a metadata name.
-     * 
+     *
+     * @deprecated To be removed in Tika 2.0.  Use {@link #getMetadataValues(Property)}
+     *
      * @param property
      *          of the metadata.
      * @return the values associated to a metadata name.
      */
+    @Deprecated
     public String[] getValues(final Property property) {
         return _getValues(property.getName());
     }
 
     /**
-     * Get the values associated to a metadata name.
+     * Get the String values associated to a metadata name.
+     * @deprecated To be removed in Tika 2.0.  Use {@link #getMetadataValues(String)}.
-     * 
+     *
      * @param name
      *          of the metadata.
      * @return the values associated to a metadata name.
      */
+    @Deprecated
     public String[] getValues(final String name) {
         return _getValues(name);
     }
 
-    private String[] _getValues(final String name) {
-        String[] values = metadata.get(name);
+    /**
+     * Get the values associated to a metadata name.
+     *
+     *
+     * @param property
+     *          of the metadata.
+     * @return the values associated to a metadata name.
+     */
+    public MetadataValue[] getMetadataValues(final Property property) {
+        return _getMetadataValues(property.getName());
+    }
+
+    /**
+     * Get the {@link MetadataValue}s associated to a metadata name.
+     *
+     * @param name
+     *          of the metadata.
+     * @return the values associated to a metadata name.
+     */
+    public MetadataValue[] getMetadataValues(final String name) {
+        return _getMetadataValues(name);
+    }
+
+
+    private MetadataValue[] _getMetadataValues(final String name) {
+        MetadataValue[] values = metadata.get(name);
         if (values == null) {
-            values = new String[0];
+            return new MetadataValue[0];
         }
         return values;
     }
-    
+
-    private String[] appendedValues(String[] values, final String value) {
-        String[] newValues = new String[values.length + 1];
+    @Deprecated
+    private String[] _getValues(final String name) {
+        MetadataValue[] values = _getMetadataValues(name);
+        if (values.length == 0) {
+            return new String[0];
+        }
+        String[] stringValues = new String[values.length];
+        for (int i = 0; i < values.length; i++) {
+            stringValues[i] = values[i].getString();
+        }
+        return stringValues;
+    }
+    
+    private MetadataValue[] appendedValues(MetadataValue[] values, final MetadataValue value) {
+        MetadataValue[] newValues = new MetadataValue[values.length + 1];
         System.arraycopy(values, 0, newValues, 0, values.length);
         newValues[newValues.length - 1] = value;
         return newValues;
@@ -302,45 +314,102 @@
     /**
      * Add a metadata name/value mapping. Add the specified value to the list of
      * values associated to the specified metadata name.
-     * 
+     *
+     * @deprecated This will be removed in Tika 2.0.
+     *    Use {@link #add(String, MetadataValue)}, or consider using
+     *    {@link #add(Property, MetadataValue)} if possible.
+     *
      * @param name
      *          the metadata name.
      * @param value
      *          the metadata value.
      */
+    @Deprecated
     public void add(final String name, final String value) {
-        String[] values = metadata.get(name);
+        MetadataValue[] values = metadata.get(name);
         if (values == null) {
+            set(name, new StringMetadataValue(value));
+        } else {
+            metadata.put(name, appendedValues(values, new StringMetadataValue(value)));
+        }
+    }
+
+    /**
+     * Add a metadata name/value mapping. Add the specified value to the list of
+     * values associated to the specified metadata name.
+     *
+     * @deprecated This will be removed in Tika 2.0.
+     *    Use {@link #add(String, MetadataValue)}, or consider using
+     *    {@link #add(Property, MetadataValue)} if possible.
+     *
+     * @param name
+     *          the metadata name.
+     * @param value
+     *          the metadata value.
+     */
+    public void add(final String name, final MetadataValue value) {
+        MetadataValue[] values = metadata.get(name);
+        if (values == null) {
             set(name, value);
         } else {
             metadata.put(name, appendedValues(values, value));
         }
+
     }
+    /**
+     * Add a metadata property/value String mapping. Add the specified
+     * String value to the list of
+     * values associated to the specified metadata property.
+     *
+     * @deprecated This will be removed in Tika 2.0.
+     * Use {@link #add(Property, MetadataValue)} instead.
+     *
+     * @param property
+     *          the metadata property.
+     * @param value
+     *          the metadata value.
+     */
+    @Deprecated
+    public void add(final Property property, final String value) {
+        MetadataValue[] values = metadata.get(property.getName());
+        if (values == null) {
+            set(property, new StringMetadataValue(value));
+        } else {
+             if (property.isMultiValuePermitted()) {
+                 set(property, appendedValues(values, new StringMetadataValue(value)));
+             } else {
+                 throw new PropertyTypeException(property.getPropertyType());
+             }
+        }
+    }
-    
+
     /**
      * Add a metadata property/value mapping. Add the specified value to the list of
      * values associated to the specified metadata property.
-     * 
+     *
      * @param property
      *          the metadata property.
      * @param value
      *          the metadata value.
      */
-    public void add(final Property property, final String value) {
-        String[] values = metadata.get(property.getName());
+    public void add(final Property property, final MetadataValue value) {
+        if (! value.isAllowed(property)) {
+            throw new PropertyTypeException(value.getClass() + " is not compatible with "
+                    +property.toString());
+        }
+        MetadataValue[] values = metadata.get(property.getName());
         if (values == null) {
             set(property, value);
         } else {
-             if (property.isMultiValuePermitted()) {
-                 set(property, appendedValues(values, value));
-             } else {
-                 throw new PropertyTypeException(property.getPropertyType());
-             }
+            if (property.isMultiValuePermitted()) {
+                set(property, appendedValues(values, value));
+            } else {
+                throw new PropertyTypeException(property.getPropertyType());
+            }
         }
     }
-
     /**
-     * Copy All key-value pairs from properties.
+     * Copy All key-value String pairs from properties.
      * 
      * @param properties
      *          properties to copy from
@@ -351,38 +420,76 @@
             (Enumeration<String>) properties.propertyNames();
         while (names.hasMoreElements()) {
             String name = names.nextElement();
-            metadata.put(name, new String[] { properties.getProperty(name) });
+            metadata.put(name, new MetadataValue[]{ new StringMetadataValue(properties.getProperty(name)) });
         }
     }
 
     /**
-     * Set metadata name/value. Associate the specified value to the specified
+     * Set metadata name/value via Strings. Associate the specified value to the specified
      * metadata name. If some previous values were associated to this name,
      * they are removed. If the given value is <code>null</code>, then the
      * metadata entry is removed.
      *
+     * @deprecated This will be removed in Tika 2.0.
+     * Use {@link #set(Property, MetadataValue)}  or {@link #set(String, MetadataValue)} instead.
+     *
      * @param name the metadata name.
      * @param value  the metadata value, or <code>null</code>
      */
+    @Deprecated
     public void set(String name, String value) {
+        if (value == null) {
+            set(name, (MetadataValue) null);
+        } else {
+            set(name, new StringMetadataValue(value));
+        }
+    }
+
+    /**
+     * Set metadata name/value. Associate the specified value to the specified
+     * metadata name. If some previous values were associated to this name,
+     * they are removed. If the given value is <code>null</code>, then the
+     * metadata entry is removed.
+     *
+     * @param name the metadata name.
+     * @param value  the metadata value, or <code>null</code>
+     */
+    public void set(String name, MetadataValue value) {
         if (value != null) {
-            metadata.put(name, new String[] { value });
+            metadata.put(name, new MetadataValue[]{value});
         } else {
             metadata.remove(name);
         }
     }
 
     /**
-     * Sets the value of the identified metadata property.
+     * Sets the String value of the identified metadata property.
      *
      * @since Apache Tika 0.7
+     * @deprecated To be removed in Tika 2.0.  Use {@link #set(Property, MetadataValue[])} instead.
      * @param property property definition
      * @param value    property value
      */
+    @Deprecated
     public void set(Property property, String value) {
+        set(property, new StringMetadataValue(value));
+    }
+
+    /**
+     * Sets the value of the identified metadata property.
+     *
+     * @since Apache Tika 0.7
+     * @param property property definition
+     * @param value    property value
+     */
+    public void set(Property property, MetadataValue value) {
         if (property == null) {
             throw new NullPointerException("property must not be null");
         }
+        if (! value.isAllowed(property)) {
+            throw new PropertyTypeException(value.getClass().getName() +
+                " is not compatible with property: "+property.getName());
+        }
         if (property.getPropertyType() == PropertyType.COMPOSITE) {
             set(property.getPrimaryProperty(), value);
             if (property.getSecondaryExtractProperties() != null) {
@@ -399,13 +506,33 @@
      * Sets the values of the identified metadata property.
      *
      * @since Apache Tika 1.2
+     * @deprecated To be removed in Tika 2.0.  Use {@link #set(Property, MetadataValue[])} instead.
      * @param property property definition
      * @param values    property values
      */
+    @Deprecated
     public void set(Property property, String[] values) {
         if (property == null) {
             throw new NullPointerException("property must not be null");
         }
+        StringMetadataValue[] metadataValues = new StringMetadataValue[values.length];
+        for (int i = 0; i < values.length; i++) {
+            metadataValues[i] = new StringMetadataValue(values[i]);
+        }
+        set(property, metadataValues);
+    }
+
+    /**
+     * Sets the values of the identified metadata property.
+     *
+     * @since Apache Tika 1.2
+     * @param property property definition
+     * @param values    property values
+     */
+    public void set(Property property, MetadataValue[] values) {
+        if (property == null) {
+            throw new NullPointerException("property must not be null");
+        }
         if (property.getPropertyType() == PropertyType.COMPOSITE) {
             set(property.getPrimaryProperty(), values);
             if (property.getSecondaryExtractProperties() != null) {
@@ -414,6 +541,12 @@
                 }
             }
         } else {
+            for (MetadataValue v : values) {
+                if (! v.isAllowed(property)) {
+                    throw new PropertyTypeException(v.getClass().getName() +
+                            " is not compatible with property: "+property.getName());
+                }
+            }
             metadata.put(property.getName(), values);
         }
     }
@@ -422,78 +555,55 @@
      * Sets the integer value of the identified metadata property.
      *
      * @since Apache Tika 0.8
+     * @deprecated To be removed in Tika 2.0.  Use {@link #set(Property, MetadataValue)} instead.
      * @param property simple integer property definition
      * @param value    property value
      */
+    @Deprecated
     public void set(Property property, int value) {
-        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
-            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        set(property, new IntMetadataValue(value));
-        }
+    }
-        if(property.getPrimaryProperty().getValueType() != Property.ValueType.INTEGER) {
-            throw new PropertyTypeException(Property.ValueType.INTEGER, property.getPrimaryProperty().getValueType());
-        }
-        set(property, Integer.toString(value));
-    }
 
     /**
      * Sets the real or rational value of the identified metadata property.
      *
      * @since Apache Tika 0.8
+     * @deprecated To be removed in Tika 2.0.  Use {@link #set(Property, MetadataValue)} instead.
      * @param property simple real or simple rational property definition
      * @param value    property value
      */
+    @Deprecated
     public void set(Property property, double value) {
-        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
-            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        set(property, new DoubleMetadataValue(value));
-        }
+    }
-        if(property.getPrimaryProperty().getValueType() != Property.ValueType.REAL &&
-              property.getPrimaryProperty().getValueType() != Property.ValueType.RATIONAL) {
-            throw new PropertyTypeException(Property.ValueType.REAL, property.getPrimaryProperty().getValueType());
-        }
-        set(property, Double.toString(value));
-    }
 
     /**
      * Sets the date value of the identified metadata property.
      *
      * @since Apache Tika 0.8
+     * @deprecated To be removed in Tika 2.0.  Use {@link #set(Property, MetadataValue)} instead.
      * @param property simple integer property definition
      * @param date     property value
      */
+    @Deprecated
     public void set(Property property, Date date) {
-        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
-            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        set(property, new DateMetadataValue(date));
-        }
+    }
-        if(property.getPrimaryProperty().getValueType() != Property.ValueType.DATE) {
-            throw new PropertyTypeException(Property.ValueType.DATE, property.getPrimaryProperty().getValueType());
-        }
-        String dateString = null;
-        if (date != null) {
-            dateString = formatDate(date);
-        }
-        set(property, dateString);
-    }
 
     /**
      * Sets the date value of the identified metadata property.
      *
      * @since Apache Tika 0.8
+     * @deprecated To be removed in Tika 2.0.  Use {@link #set(Property, MetadataValue)} instead.
      * @param property simple integer property definition
      * @param date     property value
      */
+    @Deprecated
     public void set(Property property, Calendar date) {
-        if(property.getPrimaryProperty().getPropertyType() != Property.PropertyType.SIMPLE) {
-            throw new PropertyTypeException(Property.PropertyType.SIMPLE, property.getPrimaryProperty().getPropertyType());
+        //TODO: check to see if this is valid or if we need a CalendarMetadataValue
+        //that'd allow us not to lose Calendar info...probably better
+        set(property, new DateMetadataValue(date.getTime()));
-        }
+    }
-        if(property.getPrimaryProperty().getValueType() != Property.ValueType.DATE) {
-            throw new PropertyTypeException(Property.ValueType.DATE, property.getPrimaryProperty().getValueType());
-        }
-        String dateString = null;
-        if (date != null) {
-            dateString = formatDate(date);
-        }
-        set(property, dateString);
-    }
 
     /**
      * Remove a metadata and all its associated values.
@@ -533,8 +643,8 @@
 
         String[] names = names();
         for (int i = 0; i < names.length; i++) {
-            String[] otherValues = other._getValues(names[i]);
-            String[] thisValues = _getValues(names[i]);
+            MetadataValue[] otherValues = other._getMetadataValues(names[i]);
+            MetadataValue[] thisValues = _getMetadataValues(names[i]);
             if (otherValues.length != thisValues.length) {
                 return false;
             }
@@ -551,9 +661,9 @@
         StringBuffer buf = new StringBuffer();
         String[] names = names();
         for (int i = 0; i < names.length; i++) {
-            String[] values = _getValues(names[i]);
+            MetadataValue[] values = _getMetadataValues(names[i]);
             for (int j = 0; j < values.length; j++) {
-                buf.append(names[i]).append("=").append(values[j]).append(" ");
+                buf.append(names[i]).append("=").append(values[j].getString()).append(" ");
             }
         }
         return buf.toString();
