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