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