Merge "BUG-1382: eliminate QName.getPrefix()"
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / codec / TypeDefinitionAwareCodec.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.impl.codec;
9
10 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT16_QNAME;
11 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT32_QNAME;
12 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT64_QNAME;
13 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.INT8_QNAME;
14 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT16_QNAME;
15 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT32_QNAME;
16 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT64_QNAME;
17 import static org.opendaylight.yangtools.yang.model.util.BaseTypes.UINT8_QNAME;
18
19 import com.google.common.base.CharMatcher;
20 import com.google.common.base.Joiner;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import com.google.common.base.Splitter;
24 import com.google.common.base.Strings;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.Sets;
27 import com.google.common.io.BaseEncoding;
28 import java.math.BigDecimal;
29 import java.math.BigInteger;
30 import java.util.Set;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33 import javax.xml.bind.DatatypeConverter;
34 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
35 import org.opendaylight.yangtools.yang.data.api.codec.BitsCodec;
36 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
37 import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
38 import org.opendaylight.yangtools.yang.data.api.codec.EmptyCodec;
39 import org.opendaylight.yangtools.yang.data.api.codec.EnumCodec;
40 import org.opendaylight.yangtools.yang.data.api.codec.Int16Codec;
41 import org.opendaylight.yangtools.yang.data.api.codec.Int32Codec;
42 import org.opendaylight.yangtools.yang.data.api.codec.Int64Codec;
43 import org.opendaylight.yangtools.yang.data.api.codec.Int8Codec;
44 import org.opendaylight.yangtools.yang.data.api.codec.StringCodec;
45 import org.opendaylight.yangtools.yang.data.api.codec.Uint16Codec;
46 import org.opendaylight.yangtools.yang.data.api.codec.Uint32Codec;
47 import org.opendaylight.yangtools.yang.data.api.codec.Uint64Codec;
48 import org.opendaylight.yangtools.yang.data.api.codec.Uint8Codec;
49 import org.opendaylight.yangtools.yang.data.api.codec.UnionCodec;
50 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
51 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
52 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
53 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
54 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
55 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
56 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
57 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
58 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
59 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
60 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
61 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
62
63 public abstract class TypeDefinitionAwareCodec<J, T extends TypeDefinition<T>> implements DataStringCodec<J> {
64
65     private static final Pattern intPattern = Pattern.compile("[+-]?[1-9][0-9]*$");
66     private static final Pattern hexPattern = Pattern.compile("[+-]?0[xX][0-9a-fA-F]+");
67     private static final Pattern octalPattern = Pattern.compile("[+-]?0[1-7][0-7]*$");
68
69     // For up to two characters, this is very fast
70     private static final CharMatcher X_MATCHER = CharMatcher.anyOf("xX");
71
72     private final Optional<T> typeDefinition;
73     private final Class<J> inputClass;
74
75     private static final int provideBase(final String integer) {
76         if (integer == null) {
77             throw new IllegalArgumentException("String representing integer number cannot be NULL");
78         }
79
80         if ((integer.length() == 1) && (integer.charAt(0) == '0')) {
81             return 10;
82         }
83
84         final Matcher intMatcher = intPattern.matcher(integer);
85         if (intMatcher.matches()) {
86             return 10;
87         } else {
88             final Matcher hexMatcher = hexPattern.matcher(integer);
89             if (hexMatcher.matches()) {
90                 return 16;
91             } else {
92                 final Matcher octMatcher = octalPattern.matcher(integer);
93                 if (octMatcher.matches()) {
94                     return 8;
95                 } else {
96                     String formatedMessage = String.format("Incorrect lexical representation of integer value: %s."
97                             + "%nAn integer value can be defined as: "
98                             + "%n  - a decimal number,"
99                             + "%n  - a hexadecimal number (prefix 0x),"
100                             + "%n  - an octal number (prefix 0)."
101                             + "%nSigned values are allowed. Spaces between digits are NOT allowed.", integer);
102                     throw new NumberFormatException(formatedMessage);
103                 }
104             }
105         }
106     }
107
108     private static String normalizeHexadecimal(final String hexInt) {
109         if (hexInt == null) {
110             throw new IllegalArgumentException(
111                     "String representing integer number in Hexadecimal format cannot be NULL!");
112         }
113
114         return X_MATCHER.removeFrom(hexInt);
115     }
116
117     private static final BinaryCodecStringImpl BINARY_DEFAULT_CODEC = new BinaryCodecStringImpl(
118             Optional.<BinaryTypeDefinition> absent());
119
120     private static final BooleanCodecStringImpl BOOLEAN_DEFAULT_CODEC = new BooleanCodecStringImpl(
121             Optional.<BooleanTypeDefinition> absent());
122
123     private static final DecimalCodecStringImpl DECIMAL64_DEFAULT_CODEC = new DecimalCodecStringImpl(
124             Optional.<DecimalTypeDefinition> absent());
125
126     private static final EmptyCodecStringImpl EMPTY_DEFAULT_CODEC = new EmptyCodecStringImpl(
127             Optional.<EmptyTypeDefinition> absent());
128
129     private static final Int8CodecStringImpl INT8_DEFAULT_CODEC = new Int8CodecStringImpl(
130             Optional.<IntegerTypeDefinition> absent());
131
132     private static final Int16CodecStringImpl INT16_DEFAULT_CODEC = new Int16CodecStringImpl(
133             Optional.<IntegerTypeDefinition> absent());
134
135     private static final Int32CodecStringImpl INT32_DEFAULT_CODEC = new Int32CodecStringImpl(
136             Optional.<IntegerTypeDefinition> absent());
137
138     private static final Int64CodecStringImpl INT64_DEFAULT_CODEC = new Int64CodecStringImpl(
139             Optional.<IntegerTypeDefinition> absent());
140
141     private static final StringCodecStringImpl STRING_DEFAULT_CODEC = new StringCodecStringImpl(
142             Optional.<StringTypeDefinition> absent());
143
144     private static final Uint8CodecStringImpl UINT8_DEFAULT_CODEC = new Uint8CodecStringImpl(
145             Optional.<UnsignedIntegerTypeDefinition> absent());
146
147     private static final Uint16CodecStringImpl UINT16_DEFAULT_CODEC = new Uint16CodecStringImpl(
148             Optional.<UnsignedIntegerTypeDefinition> absent());
149
150     private static final Uint32CodecStringImpl UINT32_DEFAULT_CODEC = new Uint32CodecStringImpl(
151             Optional.<UnsignedIntegerTypeDefinition> absent());
152
153     private static final Uint64CodecStringImpl UINT64_DEFAULT_CODEC = new Uint64CodecStringImpl(
154             Optional.<UnsignedIntegerTypeDefinition> absent());
155
156     @Override
157     public Class<J> getInputClass() {
158         return inputClass;
159     }
160
161     protected TypeDefinitionAwareCodec(final Optional<T> typeDefinition, final Class<J> outputClass) {
162         Preconditions.checkArgument(outputClass != null, "Output class must be specified.");
163         this.typeDefinition = typeDefinition;
164         this.inputClass = outputClass;
165     }
166
167     public Optional<T> getTypeDefinition() {
168         return typeDefinition;
169     }
170
171     @SuppressWarnings({ "rawtypes", "unchecked" })
172     public static final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> from(final TypeDefinition typeDefinition) {
173         return fromType(typeDefinition);
174     }
175
176     @SuppressWarnings("unchecked")
177     public static final <T extends TypeDefinition<T>> TypeDefinitionAwareCodec<?, T> fromType(final T typeDefinition) {
178         T superType = typeDefinition;
179         while (superType.getBaseType() != null) {
180             superType = superType.getBaseType();
181         }
182
183         @SuppressWarnings("rawtypes")
184         TypeDefinitionAwareCodec codec = null;
185
186         if (superType instanceof BinaryTypeDefinition) {
187             codec = BINARY_DEFAULT_CODEC;
188         } else if (superType instanceof BitsTypeDefinition) {
189             codec = new BitsCodecStringImpl( Optional.of( (BitsTypeDefinition)superType ) );
190         } else if (superType instanceof BooleanTypeDefinition) {
191             codec = BOOLEAN_DEFAULT_CODEC;
192         } else if (superType instanceof DecimalTypeDefinition) {
193             codec = DECIMAL64_DEFAULT_CODEC;
194         } else if (superType instanceof EmptyTypeDefinition) {
195             codec = EMPTY_DEFAULT_CODEC;
196         } else if (superType instanceof EnumTypeDefinition) {
197             codec = new EnumCodecStringImpl( Optional.of( (EnumTypeDefinition)superType ) );
198         } else if (superType instanceof IntegerTypeDefinition) {
199             if (INT8_QNAME.equals(superType.getQName())) {
200                 codec = INT8_DEFAULT_CODEC;
201             } else if (INT16_QNAME.equals(superType.getQName())) {
202                 codec = INT16_DEFAULT_CODEC;
203             } else if (INT32_QNAME.equals(superType.getQName())) {
204                 codec = INT32_DEFAULT_CODEC;
205             } else if (INT64_QNAME.equals(superType.getQName())) {
206                 codec = INT64_DEFAULT_CODEC;
207             }
208         } else if (superType instanceof StringTypeDefinition) {
209             codec = STRING_DEFAULT_CODEC;
210         } else if (superType instanceof UnionTypeDefinition) {
211             codec = new UnionCodecStringImpl( Optional.of( (UnionTypeDefinition)superType ) );
212         } else if (superType instanceof UnsignedIntegerTypeDefinition) {
213             if (UINT8_QNAME.equals(superType.getQName())) {
214                 codec = UINT8_DEFAULT_CODEC;
215             }
216             if (UINT16_QNAME.equals(superType.getQName())) {
217                 codec = UINT16_DEFAULT_CODEC;
218             }
219             if (UINT32_QNAME.equals(superType.getQName())) {
220                 codec = UINT32_DEFAULT_CODEC;
221             }
222             if (UINT64_QNAME.equals(superType.getQName())) {
223                 codec = UINT64_DEFAULT_CODEC;
224             }
225         }
226
227         return codec;
228     }
229
230     public static class BooleanCodecStringImpl extends TypeDefinitionAwareCodec<Boolean, BooleanTypeDefinition>
231             implements BooleanCodec<String> {
232
233         protected BooleanCodecStringImpl(final Optional<BooleanTypeDefinition> typeDef) {
234             super(typeDef, Boolean.class);
235         }
236
237         @Override
238         public String serialize(final Boolean data) {
239             return data == null ? "" : data.toString();
240         }
241
242         @Override
243         public Boolean deserialize(final String stringRepresentation) {
244             return Boolean.valueOf(stringRepresentation);
245         }
246     };
247
248     public static class Uint8CodecStringImpl extends TypeDefinitionAwareCodec<Short, UnsignedIntegerTypeDefinition>
249             implements Uint8Codec<String> {
250
251         protected Uint8CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
252             super(typeDef, Short.class);
253         }
254
255         @Override
256         public String serialize(final Short data) {
257             return data == null ? "" : data.toString();
258         }
259
260         @Override
261         public Short deserialize(final String stringRepresentation) {
262             int base = provideBase(stringRepresentation);
263             if (base == 16) {
264                 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
265             }
266             return Short.valueOf(stringRepresentation, base);
267         }
268     };
269
270     public static class Uint16CodecStringImpl extends TypeDefinitionAwareCodec<Integer, UnsignedIntegerTypeDefinition>
271             implements Uint16Codec<String> {
272         protected Uint16CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
273             super(typeDef, Integer.class);
274         }
275
276         @Override
277         public Integer deserialize(final String stringRepresentation) {
278             int base = provideBase(stringRepresentation);
279             if (base == 16) {
280                 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
281             }
282             return Integer.valueOf(stringRepresentation, base);
283         }
284
285         @Override
286         public String serialize(final Integer data) {
287             return data == null ? "" : data.toString();
288         }
289     };
290
291     public static class Uint32CodecStringImpl extends TypeDefinitionAwareCodec<Long, UnsignedIntegerTypeDefinition>
292             implements Uint32Codec<String> {
293
294         protected Uint32CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
295             super(typeDef, Long.class);
296         }
297
298         @Override
299         public Long deserialize(final String stringRepresentation) {
300             int base = provideBase(stringRepresentation);
301             if (base == 16) {
302                 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
303             }
304             return Long.valueOf(stringRepresentation, base);
305         }
306
307         @Override
308         public String serialize(final Long data) {
309             return data == null ? "" : data.toString();
310         }
311     };
312
313     public static class Uint64CodecStringImpl extends
314             TypeDefinitionAwareCodec<BigInteger, UnsignedIntegerTypeDefinition> implements Uint64Codec<String> {
315
316         protected Uint64CodecStringImpl(final Optional<UnsignedIntegerTypeDefinition> typeDef) {
317             super(typeDef, BigInteger.class);
318         }
319
320         @Override
321         public BigInteger deserialize(final String stringRepresentation) {
322             int base = provideBase(stringRepresentation);
323             if (base == 16) {
324                 return new BigInteger(normalizeHexadecimal(stringRepresentation), base);
325             }
326             return new BigInteger(stringRepresentation, base);
327         }
328
329         @Override
330         public String serialize(final BigInteger data) {
331             return data == null ? "" : data.toString();
332         }
333     };
334
335     public static class StringCodecStringImpl extends TypeDefinitionAwareCodec<String, StringTypeDefinition> implements
336             StringCodec<String> {
337
338         protected StringCodecStringImpl(final Optional<StringTypeDefinition> typeDef) {
339             super(typeDef, String.class);
340         }
341
342         @Override
343         public String deserialize(final String stringRepresentation) {
344             return stringRepresentation == null ? "" : stringRepresentation;
345         }
346
347         @Override
348         public String serialize(final String data) {
349             return data == null ? "" : data;
350         }
351     };
352
353     public static class Int16CodecStringImpl extends TypeDefinitionAwareCodec<Short, IntegerTypeDefinition> implements
354             Int16Codec<String> {
355
356         protected Int16CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
357             super(typeDef, Short.class);
358         }
359
360         @Override
361         public Short deserialize(final String stringRepresentation) {
362             int base = provideBase(stringRepresentation);
363             if (base == 16) {
364                 return Short.valueOf(normalizeHexadecimal(stringRepresentation), base);
365             }
366             return Short.valueOf(stringRepresentation, base);
367         }
368
369         @Override
370         public String serialize(final Short data) {
371             return data == null ? "" : data.toString();
372         }
373     };
374
375     public static class Int32CodecStringImpl extends TypeDefinitionAwareCodec<Integer, IntegerTypeDefinition> implements
376             Int32Codec<String> {
377
378         protected Int32CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
379             super(typeDef, Integer.class);
380         }
381
382         @Override
383         public Integer deserialize(final String stringRepresentation) {
384             int base = provideBase(stringRepresentation);
385             if (base == 16) {
386                 return Integer.valueOf(normalizeHexadecimal(stringRepresentation), base);
387             }
388             return Integer.valueOf(stringRepresentation, base);
389         }
390
391         @Override
392         public String serialize(final Integer data) {
393             return data == null ? "" : data.toString();
394         }
395     };
396
397     public static class Int64CodecStringImpl extends TypeDefinitionAwareCodec<Long, IntegerTypeDefinition> implements
398             Int64Codec<String> {
399
400         protected Int64CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
401             super(typeDef, Long.class);
402         }
403
404         @Override
405         public Long deserialize(final String stringRepresentation) {
406             int base = provideBase(stringRepresentation);
407             if (base == 16) {
408                 return Long.valueOf(normalizeHexadecimal(stringRepresentation), base);
409             }
410             return Long.valueOf(stringRepresentation, base);
411         }
412
413         @Override
414         public String serialize(final Long data) {
415             return data == null ? "" : data.toString();
416         }
417     };
418
419     public static class Int8CodecStringImpl extends TypeDefinitionAwareCodec<Byte, IntegerTypeDefinition> implements
420             Int8Codec<String> {
421
422         protected Int8CodecStringImpl(final Optional<IntegerTypeDefinition> typeDef) {
423             super(typeDef, Byte.class);
424         }
425
426         @Override
427         public Byte deserialize(final String stringRepresentation) {
428             int base = provideBase(stringRepresentation);
429             if (base == 16) {
430                 return Byte.valueOf(normalizeHexadecimal(stringRepresentation), base);
431             }
432             return Byte.valueOf(stringRepresentation, base);
433         }
434
435         @Override
436         public String serialize(final Byte data) {
437             return data == null ? "" : data.toString();
438         }
439     };
440
441     public static class EmptyCodecStringImpl extends TypeDefinitionAwareCodec<Void, EmptyTypeDefinition> implements
442             EmptyCodec<String> {
443
444         protected EmptyCodecStringImpl(final Optional<EmptyTypeDefinition> typeDef) {
445             super(typeDef, Void.class);
446         }
447
448         @Override
449         public String serialize(final Void data) {
450             return "";
451         }
452
453         @Override
454         public Void deserialize(final String stringRepresentation) {
455             Preconditions.checkArgument( Strings.isNullOrEmpty( stringRepresentation ),
456                                          "The value must be empty" );
457             return null;
458         }
459     };
460
461     public static final class BinaryCodecStringImpl extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
462             implements BinaryCodec<String> {
463
464         protected BinaryCodecStringImpl(final Optional<BinaryTypeDefinition> typeDef) {
465             super(typeDef, byte[].class);
466         }
467
468         @Override
469         public String serialize(final byte[] data) {
470             return data == null ? "" : BaseEncoding.base64().encode(data);
471         }
472
473         @Override
474         public byte[] deserialize(final String stringRepresentation) {
475             return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
476         }
477     };
478
479     public static final class BitsCodecStringImpl extends TypeDefinitionAwareCodec<Set<String>, BitsTypeDefinition>
480             implements BitsCodec<String> {
481
482         public static final Joiner JOINER = Joiner.on(" ").skipNulls();
483         public static final Splitter SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
484
485         @SuppressWarnings("unchecked")
486         protected BitsCodecStringImpl(final Optional<BitsTypeDefinition> typeDef) {
487             super(typeDef, (Class<Set<String>>) ((Class<?>) Set.class));
488         }
489
490         @Override
491         public String serialize(final Set<String> data) {
492             return data == null ? "" : JOINER.join(data);
493         }
494
495         @Override
496         public Set<String> deserialize(final String stringRepresentation) {
497             if (stringRepresentation == null) {
498                 return ImmutableSet.of();
499             }
500
501             Iterable<String> strings = SPLITTER.split(stringRepresentation);
502
503             if( getTypeDefinition().isPresent() ) {
504                 Set<String> allowedNames = Sets.newHashSet();
505                 for( BitsTypeDefinition.Bit bit: getTypeDefinition().get().getBits() ) {
506                     allowedNames.add( bit.getName() );
507                 }
508
509                 for( String bit: strings ) {
510                     if( !allowedNames.contains( bit ) ) {
511                         throw new IllegalArgumentException(
512                             "Invalid value \"" + bit + "\" for bits type. Allowed values are: " +
513                             allowedNames );
514                     }
515                 }
516             }
517
518             return ImmutableSet.copyOf(strings);
519         }
520     };
521
522     public static class EnumCodecStringImpl extends TypeDefinitionAwareCodec<String, EnumTypeDefinition> implements
523             EnumCodec<String> {
524
525         protected EnumCodecStringImpl(final Optional<EnumTypeDefinition> typeDef) {
526             super(typeDef, String.class);
527         }
528
529         @Override
530         public String deserialize(final String stringRepresentation) {
531             if( getTypeDefinition().isPresent() ) {
532                 Set<String> allowedNames = Sets.newHashSet();
533                 for( EnumPair pair: getTypeDefinition().get().getValues() ) {
534                     allowedNames.add( pair.getName() );
535                 }
536
537                 if( !allowedNames.contains( stringRepresentation ) ) {
538                     throw new IllegalArgumentException(
539                         "Invalid value \"" + stringRepresentation + "\" for enum type. Allowed values are: " +
540                         allowedNames );
541                 }
542             }
543
544             return stringRepresentation;
545         }
546
547         @Override
548         public String serialize(final String data) {
549             return data == null ? "" : data;
550         }
551     };
552
553     public static class DecimalCodecStringImpl extends TypeDefinitionAwareCodec<BigDecimal, DecimalTypeDefinition>
554             implements DecimalCodec<String> {
555
556         protected DecimalCodecStringImpl(final Optional<DecimalTypeDefinition> typeDef) {
557             super(typeDef, BigDecimal.class);
558         }
559
560         @Override
561         public String serialize(final BigDecimal data) {
562             return data == null ? "" : data.toString();
563         }
564
565         @Override
566         public BigDecimal deserialize(final String stringRepresentation) {
567             Preconditions.checkArgument( stringRepresentation != null , "Input cannot be null" );
568             return new BigDecimal(stringRepresentation);
569         }
570     };
571
572     public static class UnionCodecStringImpl extends TypeDefinitionAwareCodec<Object, UnionTypeDefinition> implements
573             UnionCodec<String> {
574
575         protected UnionCodecStringImpl(final Optional<UnionTypeDefinition> typeDef) {
576             super(typeDef, Object.class);
577         }
578
579         @Override
580         public String serialize(final Object data) {
581             return data == null ? "" : data.toString();
582         }
583
584         @Override
585         public Object deserialize(final String stringRepresentation) {
586             if( getTypeDefinition().isPresent() ) {
587                 boolean valid = false;
588                 for( TypeDefinition<?> type: getTypeDefinition().get().getTypes() ) {
589                     TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwareCodec = from( type );
590                     if( typeAwareCodec == null ) {
591                         // This is a type for which we have no codec (eg identity ref) so we'll say it's valid
592                         // but we'll continue in case there's another type for which we do have a codec.
593                         valid = true;
594                         continue;
595                     }
596
597                     try {
598                         typeAwareCodec.deserialize( stringRepresentation );
599                         valid = true;
600                         break;
601                     }
602                     catch( Exception e ) {
603                         // invalid - try the next union type.
604                     }
605                 }
606
607                 if( !valid ) {
608                     throw new IllegalArgumentException(
609                                         "Invalid value \"" + stringRepresentation + "\" for union type." );
610                 }
611             }
612
613             return stringRepresentation;
614         }
615     };
616 }