Merge "Added tests for yang.model.util"
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / codec / TypeDefinitionAwareCodec.java
index 8cb399584d0343b27b5a745c08d9d42ead4cd35b..e735b28d61ec1192ad8383430dc21b3d0a06d337 100644 (file)
@@ -16,12 +16,21 @@ import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT32_QNAME;
 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT64_QNAME;
 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT8_QNAME;
 
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.common.io.BaseEncoding;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-
+import javax.xml.bind.DatatypeConverter;
 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
 import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
@@ -45,30 +54,27 @@ import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.io.BaseEncoding;
-
 public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
 
     private static final Pattern intPattern = Pattern.compile("[+-]?[1-9][0-9]*$");
     private static final Pattern hexPattern = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
     private static final Pattern octalPattern = Pattern.compile("[+-]?0[1-7][0-7]*$");
 
+    // For up to two characters, this is very fast
+    private static final CharMatcher X_MATCHER = CharMatcher.anyOf("xX");
+
     private final Optional<T> typeDefinition;
     private final Class<J> inputClass;
 
     private static final int provideBase(final String integer) {
         if (integer == null) {
-            throw new IllegalArgumentException("String representing integer number cannot be NULL!");
+            throw new IllegalArgumentException("String representing integer number cannot be NULL");
         }
 
         if ((integer.length() == 1) && (integer.charAt(0) == '0')) {
@@ -87,10 +93,13 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
                 if (octMatcher.matches()) {
                     return 8;
                 } else {
-                    throw new NumberFormatException("Incorrect lexical representation of Integer value: " + integer
-                            + "The Integer value can be defined as Integer Number, Hexadecimal Number or"
-                            + "Octal Number. The sign vlues are allowed. "
-                            + "Spaces between digits are NOT allowed!");
+                    String formatedMessage = String.format("Incorrect lexical representation of integer value: %s."
+                            + "%nAn integer value can be defined as: "
+                            + "%n  - a decimal number,"
+                            + "%n  - a hexadecimal number (prefix 0x),"
+                            + "%n  - an octal number (prefix 0)."
+                            + "%nSigned values are allowed. Spaces between digits are NOT allowed.", integer);
+                    throw new NumberFormatException(formatedMessage);
                 }
             }
         }
@@ -101,70 +110,55 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
             throw new IllegalArgumentException(
                     "String representing integer number in Hexadecimal format cannot be NULL!");
         }
-        final String normalizedString;
-        if (hexInt.contains("x")) {
-            normalizedString = hexInt.replace("x", "");
-        } else if (hexInt.contains("X")) {
-            normalizedString = hexInt.replace("X", "");
-        } else {
-            normalizedString = hexInt;
-        }
-        return normalizedString;
+
+        return X_MATCHER.removeFrom(hexInt);
     }
 
-    public static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
+    private static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
             Optional.<BinaryTypeDefinition> absent());
 
-    public static final BitsCodecStringImpl BITS_DEFAULT_CODEC = new BitsCodecStringImpl(
-            Optional.<BitsTypeDefinition> absent());
-
-    public static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
+    private static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
             Optional.<BooleanTypeDefinition> absent());
 
-    public static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
+    private static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
             Optional.<DecimalTypeDefinition> absent());
 
-    public static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
+    private static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
             Optional.<EmptyTypeDefinition> absent());
 
-    public static final EnumCodecStringImpl ENUMERATION_DEFAULT_CODEC = new EnumCodecStringImpl(
-            Optional.<EnumTypeDefinition> absent());
-
-    public static final Int8CodecStringImpl INT8_DEFAULT_CODEC = new Int8CodecStringImpl(
+    private static final Int8CodecStringImpl INT8_DEFAULT_CODEC = new Int8CodecStringImpl(
             Optional.<IntegerTypeDefinition> absent());
 
-    public static final Int16CodecStringImpl INT16_DEFAULT_CODEC = new Int16CodecStringImpl(
+    private static final Int16CodecStringImpl INT16_DEFAULT_CODEC = new Int16CodecStringImpl(
             Optional.<IntegerTypeDefinition> absent());
 
-    public static final Int32CodecStringImpl INT32_DEFAULT_CODEC = new Int32CodecStringImpl(
+    private static final Int32CodecStringImpl INT32_DEFAULT_CODEC = new Int32CodecStringImpl(
             Optional.<IntegerTypeDefinition> absent());
 
-    public static final Int64CodecStringImpl INT64_DEFAULT_CODEC = new Int64CodecStringImpl(
+    private static final Int64CodecStringImpl INT64_DEFAULT_CODEC = new Int64CodecStringImpl(
             Optional.<IntegerTypeDefinition> absent());
 
-    public static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
+    private static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
             Optional.<StringTypeDefinition> absent());
 
-    public static final Uint8CodecStringImpl UINT8_DEFAULT_CODEC = new Uint8CodecStringImpl(
+    private static final Uint8CodecStringImpl UINT8_DEFAULT_CODEC = new Uint8CodecStringImpl(
             Optional.<UnsignedIntegerTypeDefinition> absent());
 
-    public static final Uint16CodecStringImpl UINT16_DEFAULT_CODEC = new Uint16CodecStringImpl(
+    private static final Uint16CodecStringImpl UINT16_DEFAULT_CODEC = new Uint16CodecStringImpl(
             Optional.<UnsignedIntegerTypeDefinition> absent());
 
-    public static final Uint32CodecStringImpl UINT32_DEFAULT_CODEC = new Uint32CodecStringImpl(
+    private static final Uint32CodecStringImpl UINT32_DEFAULT_CODEC = new Uint32CodecStringImpl(
             Optional.<UnsignedIntegerTypeDefinition> absent());
 
-    public static final Uint64CodecStringImpl UINT64_DEFAULT_CODEC = new Uint64CodecStringImpl(
+    private static final Uint64CodecStringImpl UINT64_DEFAULT_CODEC = new Uint64CodecStringImpl(
             Optional.<UnsignedIntegerTypeDefinition> absent());
 
-    public static final UnionCodecStringImpl UNION_DEFAULT_CODEC = new UnionCodecStringImpl(
-            Optional.<UnionTypeDefinition> absent());
-
+    @Override
     public Class<J> getInputClass() {
         return inputClass;
     }
 
-    protected TypeDefinitionAwareCodec(Optional<T> typeDefinition, Class<J> outputClass) {
+    protected TypeDefinitionAwareCodec(final Optional<T> typeDefinition, final Class<J> outputClass) {
         Preconditions.checkArgument(outputClass != null, "Output class must be specified.");
         this.typeDefinition = typeDefinition;
         this.inputClass = outputClass;
@@ -175,12 +169,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(TypeDefinition typeDefinition) {
-        final TypeDefinitionAwareCodec codec = fromType(typeDefinition);
-        return (TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>>) codec;
+    public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(final TypeDefinition typeDefinition) {
+        return fromType(typeDefinition);
     }
 
-    public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(T typeDefinition) {
+    @SuppressWarnings("unchecked")
+    public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(final T typeDefinition) {
         T superType = typeDefinition;
         while (superType.getBaseType() != null) {
             superType = superType.getBaseType();
@@ -192,7 +186,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         if (superType instanceof BinaryTypeDefinition) {
             codec = BINARY_DEFAULT_CODEC;
         } else if (superType instanceof BitsTypeDefinition) {
-            codec = BITS_DEFAULT_CODEC;
+            codec = new BitsCodecStringImpl( Optional.of( (BitsTypeDefinition)superType ) );
         } else if (superType instanceof BooleanTypeDefinition) {
             codec = BOOLEAN_DEFAULT_CODEC;
         } else if (superType instanceof DecimalTypeDefinition) {
@@ -200,7 +194,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         } else if (superType instanceof EmptyTypeDefinition) {
             codec = EMPTY_DEFAULT_CODEC;
         } else if (superType instanceof EnumTypeDefinition) {
-            codec = ENUMERATION_DEFAULT_CODEC;
+            codec = new EnumCodecStringImpl( Optional.of( (EnumTypeDefinition)superType ) );
         } else if (superType instanceof IntegerTypeDefinition) {
             if (INT8_QNAME.equals(superType.getQName())) {
                 codec = INT8_DEFAULT_CODEC;
@@ -214,7 +208,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         } else if (superType instanceof StringTypeDefinition) {
             codec = STRING_DEFAULT_CODEC;
         } else if (superType instanceof UnionTypeDefinition) {
-            codec = UNION_DEFAULT_CODEC;
+            codec = new UnionCodecStringImpl( Optional.of( (UnionTypeDefinition)superType ) );
         } else if (superType instanceof UnsignedIntegerTypeDefinition) {
             if (UINT8_QNAME.equals(superType.getQName())) {
                 codec = UINT8_DEFAULT_CODEC;
@@ -229,25 +223,24 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
                 codec = UINT64_DEFAULT_CODEC;
             }
         }
-        @SuppressWarnings("unchecked")
-        TypeDefinitionAwareCodec<?, T> ret = (TypeDefinitionAwareCodec<?, T>) codec;
-        return ret;
+
+        return codec;
     }
 
     public static class BooleanCodecStringImpl extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
             implements BooleanCodec<String> {
 
-        protected BooleanCodecStringImpl(Optional<BooleanTypeDefinition> typeDef) {
+        protected BooleanCodecStringImpl(final Optional<BooleanTypeDefinition> typeDef) {
             super(typeDef, Boolean.class);
         }
 
         @Override
-        public String serialize(Boolean data) {
+        public String serialize(final Boolean data) {
             return data == null ? "" : data.toString();
         }
 
         @Override
-        public Boolean deserialize(String stringRepresentation) {
+        public Boolean deserialize(final String stringRepresentation) {
             return Boolean.valueOf(stringRepresentation);
         }
     };
@@ -255,17 +248,17 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class Uint8CodecStringImpl extends TypeDefinitionAwareCodec<Short, UnsignedIntegerTypeDefinition>
             implements Uint8Codec<String> {
 
-        protected Uint8CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
+        protected Uint8CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
             super(typeDef, Short.class);
         }
 
         @Override
-        public String serialize(Short data) {
+        public String serialize(final Short data) {
             return data == null ? "" : data.toString();
         }
 
         @Override
-        public Short deserialize(String stringRepresentation) {
+        public Short deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -276,12 +269,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
 
     public static class Uint16CodecStringImpl extends TypeDefinitionAwareCodec<Integer, UnsignedIntegerTypeDefinition>
             implements Uint16Codec<String> {
-        protected Uint16CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
+        protected Uint16CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
             super(typeDef, Integer.class);
         }
 
         @Override
-        public Integer deserialize(String stringRepresentation) {
+        public Integer deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -290,7 +283,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(Integer data) {
+        public String serialize(final Integer data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -298,12 +291,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class Uint32CodecStringImpl extends TypeDefinitionAwareCodec<Long, UnsignedIntegerTypeDefinition>
             implements Uint32Codec<String> {
 
-        protected Uint32CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
+        protected Uint32CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
             super(typeDef, Long.class);
         }
 
         @Override
-        public Long deserialize(String stringRepresentation) {
+        public Long deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -312,7 +305,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(Long data) {
+        public String serialize(final Long data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -320,12 +313,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class Uint64CodecStringImpl extends
             TypeDefinitionAwareCodec<BigInteger, UnsignedIntegerTypeDefinition> implements Uint64Codec<String> {
 
-        protected Uint64CodecStringImpl(Optional<UnsignedIntegerTypeDefinition> typeDef) {
+        protected Uint64CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
             super(typeDef, BigInteger.class);
         }
 
         @Override
-        public BigInteger deserialize(String stringRepresentation) {
+        public BigInteger deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return new BigInteger(normalizeHexadecimal(stringRepresentation), base);
@@ -334,7 +327,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(BigInteger data) {
+        public String serialize(final BigInteger data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -342,30 +335,30 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class StringCodecStringImpl extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
             StringCodec<String> {
 
-        protected StringCodecStringImpl(Optional<StringTypeDefinition> typeDef) {
+        protected StringCodecStringImpl(final Optional<StringTypeDefinition> typeDef) {
             super(typeDef, String.class);
         }
 
         @Override
-        public String deserialize(String stringRepresentation) {
-            return stringRepresentation;
+        public String deserialize(final String stringRepresentation) {
+            return stringRepresentation == null ? "" : stringRepresentation;
         }
 
         @Override
-        public String serialize(String data) {
-            return data == null ? "" : data.toString();
+        public String serialize(final String data) {
+            return data == null ? "" : data;
         }
     };
 
     public static class Int16CodecStringImpl extends TypeDefinitionAwareCodec<Short, IntegerTypeDefinition> implements
             Int16Codec<String> {
 
-        protected Int16CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
+        protected Int16CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
             super(typeDef, Short.class);
         }
 
         @Override
-        public Short deserialize(String stringRepresentation) {
+        public Short deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -374,7 +367,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(Short data) {
+        public String serialize(final Short data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -382,12 +375,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class Int32CodecStringImpl extends TypeDefinitionAwareCodec<Integer, IntegerTypeDefinition> implements
             Int32Codec<String> {
 
-        protected Int32CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
+        protected Int32CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
             super(typeDef, Integer.class);
         }
 
         @Override
-        public Integer deserialize(String stringRepresentation) {
+        public Integer deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -396,7 +389,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(Integer data) {
+        public String serialize(final Integer data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -404,12 +397,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class Int64CodecStringImpl extends TypeDefinitionAwareCodec<Long, IntegerTypeDefinition> implements
             Int64Codec<String> {
 
-        protected Int64CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
+        protected Int64CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
             super(typeDef, Long.class);
         }
 
         @Override
-        public Long deserialize(String stringRepresentation) {
+        public Long deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -418,7 +411,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(Long data) {
+        public String serialize(final Long data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -426,12 +419,12 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class Int8CodecStringImpl extends TypeDefinitionAwareCodec<Byte, IntegerTypeDefinition> implements
             Int8Codec<String> {
 
-        protected Int8CodecStringImpl(Optional<IntegerTypeDefinition> typeDef) {
+        protected Int8CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
             super(typeDef, Byte.class);
         }
 
         @Override
-        public Byte deserialize(String stringRepresentation) {
+        public Byte deserialize(final String stringRepresentation) {
             int base = provideBase(stringRepresentation);
             if (base == 16) {
                 return Byte.valueOf(normalizeHexadecimal(stringRepresentation), base);
@@ -440,7 +433,7 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         }
 
         @Override
-        public String serialize(Byte data) {
+        public String serialize(final Byte data) {
             return data == null ? "" : data.toString();
         }
     };
@@ -448,17 +441,19 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class EmptyCodecStringImpl extends TypeDefinitionAwareCodec<Void, EmptyTypeDefinition> implements
             EmptyCodec<String> {
 
-        protected EmptyCodecStringImpl(Optional<EmptyTypeDefinition> typeDef) {
+        protected EmptyCodecStringImpl(final Optional<EmptyTypeDefinition> typeDef) {
             super(typeDef, Void.class);
         }
 
         @Override
-        public String serialize(Void data) {
+        public String serialize(final Void data) {
             return "";
         }
 
         @Override
-        public Void deserialize(String stringRepresentation) {
+        public Void deserialize(final String stringRepresentation) {
+            Preconditions.checkArgument( Strings.isNullOrEmpty( stringRepresentation ),
+                                         "The value must be empty" );
             return null;
         }
     };
@@ -466,18 +461,18 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static final class BinaryCodecStringImpl extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
             implements BinaryCodec<String> {
 
-        protected BinaryCodecStringImpl(Optional<BinaryTypeDefinition> typeDef) {
+        protected BinaryCodecStringImpl(final Optional<BinaryTypeDefinition> typeDef) {
             super(typeDef, byte[].class);
         }
 
         @Override
-        public String serialize(byte[] data) {
+        public String serialize(final byte[] data) {
             return data == null ? "" : BaseEncoding.base64().encode(data);
         }
 
         @Override
-        public byte[] deserialize(String stringRepresentation) {
-            return BaseEncoding.base64().decode(stringRepresentation);
+        public byte[] deserialize(final String stringRepresentation) {
+            return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
         }
     };
 
@@ -488,20 +483,38 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
         public static final Splitter SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
 
         @SuppressWarnings("unchecked")
-        protected BitsCodecStringImpl(Optional<BitsTypeDefinition> typeDef) {
+        protected BitsCodecStringImpl(final Optional<BitsTypeDefinition> typeDef) {
             super(typeDef, (Class<Set<String>>) ((Class<?>) Set.class));
         }
 
         @Override
-        public String serialize(Set<String> data) {
+        public String serialize(final Set<String> data) {
             return data == null ? "" : JOINER.join(data);
         }
 
         @Override
-        public Set<String> deserialize(String stringRepresentation) {
-            if (stringRepresentation == null)
+        public Set<String> deserialize(final String stringRepresentation) {
+            if (stringRepresentation == null) {
                 return ImmutableSet.of();
+            }
+
             Iterable<String> strings = SPLITTER.split(stringRepresentation);
+
+            if( getTypeDefinition().isPresent() ) {
+                Set<String> allowedNames = Sets.newHashSet();
+                for( BitsTypeDefinition.Bit bit: getTypeDefinition().get().getBits() ) {
+                    allowedNames.add( bit.getName() );
+                }
+
+                for( String bit: strings ) {
+                    if( !allowedNames.contains( bit ) ) {
+                        throw new IllegalArgumentException(
+                            "Invalid value \"" + bit + "\" for bits type. Allowed values are: " +
+                            allowedNames );
+                    }
+                }
+            }
+
             return ImmutableSet.copyOf(strings);
         }
     };
@@ -509,53 +522,94 @@ public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> i
     public static class EnumCodecStringImpl extends TypeDefinitionAwareCodec<String, EnumTypeDefinition> implements
             EnumCodec<String> {
 
-        protected EnumCodecStringImpl(Optional<EnumTypeDefinition> typeDef) {
+        protected EnumCodecStringImpl(final Optional<EnumTypeDefinition> typeDef) {
             super(typeDef, String.class);
         }
 
         @Override
-        public String deserialize(String stringRepresentation) {
+        public String deserialize(final String stringRepresentation) {
+            if( getTypeDefinition().isPresent() ) {
+                Set<String> allowedNames = Sets.newHashSet();
+                for( EnumPair pair: getTypeDefinition().get().getValues() ) {
+                    allowedNames.add( pair.getName() );
+                }
+
+                if( !allowedNames.contains( stringRepresentation ) ) {
+                    throw new IllegalArgumentException(
+                        "Invalid value \"" + stringRepresentation + "\" for enum type. Allowed values are: " +
+                        allowedNames );
+                }
+            }
+
             return stringRepresentation;
         }
 
         @Override
-        public String serialize(String data) {
-            return data == null ? "" : data.toString();
+        public String serialize(final String data) {
+            return data == null ? "" : data;
         }
     };
 
     public static class DecimalCodecStringImpl extends TypeDefinitionAwareCodec<BigDecimal, DecimalTypeDefinition>
             implements DecimalCodec<String> {
 
-        protected DecimalCodecStringImpl(Optional<DecimalTypeDefinition> typeDef) {
+        protected DecimalCodecStringImpl(final Optional<DecimalTypeDefinition> typeDef) {
             super(typeDef, BigDecimal.class);
         }
 
         @Override
-        public String serialize(BigDecimal data) {
+        public String serialize(final BigDecimal data) {
             return data == null ? "" : data.toString();
         }
 
         @Override
-        public BigDecimal deserialize(String stringRepresentation) {
+        public BigDecimal deserialize(final String stringRepresentation) {
+            Preconditions.checkArgument( stringRepresentation != null , "Input cannot be null" );
             return new BigDecimal(stringRepresentation);
         }
     };
 
-    public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<String, UnionTypeDefinition> implements
+    public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<Object, UnionTypeDefinition> implements
             UnionCodec<String> {
 
-        protected UnionCodecStringImpl(Optional<UnionTypeDefinition> typeDef) {
-            super(typeDef, String.class);
+        protected UnionCodecStringImpl(final Optional<UnionTypeDefinition> typeDef) {
+            super(typeDef, Object.class);
         }
 
         @Override
-        public String serialize(String data) {
-            return data == null ? "" : data;
+        public String serialize(final Object data) {
+            return data == null ? "" : data.toString();
         }
 
         @Override
-        public String deserialize(String stringRepresentation) {
+        public Object deserialize(final String stringRepresentation) {
+            if( getTypeDefinition().isPresent() ) {
+                boolean valid = false;
+                for( TypeDefinition<?> type: getTypeDefinition().get().getTypes() ) {
+                    TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwareCodec = from( type );
+                    if( typeAwareCodec == null ) {
+                        // This is a type for which we have no codec (eg identity ref) so we'll say it's valid
+                        // but we'll continue in case there's another type for which we do have a codec.
+                        valid = true;
+                        continue;
+                    }
+
+                    try {
+                        typeAwareCodec.deserialize( stringRepresentation );
+                        valid = true;
+                        break;
+                    }
+                    catch( Exception e ) {
+                        // invalid - try the next union type.
+                    }
+                }
+
+                if( !valid ) {
+                    throw new IllegalArgumentException(
+                                        "Invalid value \"" + stringRepresentation + "\" for union type." );
+                }
+            }
+
             return stringRepresentation;
         }
     };