Merge "Add better exception handling to config-persister-directory-adapter"
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / dom / serializer / impl / TransformerGenerator.xtend
1 package org.opendaylight.controller.sal.binding.dom.serializer.impl
2
3 import javassist.ClassPool
4 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
5 import org.opendaylight.yangtools.yang.model.api.SchemaNode
6 import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils
7 import javassist.CtClass
8 import java.util.Map
9 import org.opendaylight.yangtools.yang.common.QName
10 import javassist.CtField
11 import static javassist.Modifier.*
12 import static org.opendaylight.controller.sal.binding.dom.serializer.impl.CodecMapping.*
13 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
14 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
15 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
16 import org.opendaylight.yangtools.sal.binding.model.api.Type
17 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
18 import org.opendaylight.yangtools.binding.generator.util.Types
19 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
20 import java.util.HashMap
21 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
22 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
23 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
24 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
25 import java.util.List
26 import java.util.TreeSet
27 import com.google.common.base.Joiner
28 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
29 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
30 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
31 import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*;
32 import org.opendaylight.yangtools.yang.binding.BindingDeserializer
33 import org.opendaylight.yangtools.yang.binding.BindingCodec
34 import org.slf4j.LoggerFactory
35 import org.opendaylight.controller.sal.binding.codegen.CodeGenerationException
36 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
37 import java.security.ProtectionDomain
38 import java.io.File
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
40 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
41 import java.util.Map.Entry
42 import java.util.AbstractMap.SimpleEntry
43 import org.opendaylight.yangtools.yang.binding.DataObject
44 import org.opendaylight.yangtools.yang.binding.Augmentation
45 import java.util.Iterator
46 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
47 import java.util.concurrent.ConcurrentHashMap
48 import static extension org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils.*;
49 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
50 import org.opendaylight.yangtools.yang.model.util.ExtendedType
51 import org.opendaylight.yangtools.yang.model.util.EnumerationType
52
53 class TransformerGenerator {
54
55     private static val log = LoggerFactory.getLogger(TransformerGenerator)
56
57     public static val STRING = Types.typeForClass(String);
58     public static val BOOLEAN = Types.typeForClass(Boolean);
59     public static val INTEGER = Types.typeForClass(Integer);
60     public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier)
61
62     //public static val DECIMAL = Types.typeForClass(Decimal);
63     public static val LONG = Types.typeForClass(Long);
64
65     val ClassPool classPool
66     val extension JavassistUtils utils;
67
68     CtClass BINDING_CODEC
69
70     CtClass ctQName
71
72     @Property
73     var File classFileCapturePath;
74
75     @Property
76     var Map<Type, Type> typeDefinitions = new ConcurrentHashMap();
77
78     @Property
79     var Map<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
80
81     @Property
82     var Map<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
83
84     @Property
85     var Map<Type, AugmentationSchema> typeToAugmentation = new ConcurrentHashMap();
86
87     @Property
88     var GeneratorListener listener;
89
90     public new(ClassPool pool) {
91         classPool = pool;
92         utils = new JavassistUtils(pool)
93
94         BINDING_CODEC = BindingCodec.asCtClass;
95         ctQName = QName.asCtClass
96     }
97
98     def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType) {
99         return withClassLoaderAndLock(inputType.classLoader, lock) [ |
100             val ret = getGeneratedClass(inputType)
101             if (ret !== null) {
102                 listener.onClassProcessed(inputType);
103                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
104             }
105             val ref = Types.typeForClass(inputType)
106             val node = typeToSchemaNode.get(ref)
107             val typeSpecBuilder = typeToDefinition.get(ref)
108             val typeSpec = typeSpecBuilder.toInstance();
109             val newret = generateTransformerFor(inputType, typeSpec, node);
110             listener.onClassProcessed(inputType);
111             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
112         ]
113     }
114
115     def Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentationTransformerFor(Class<?> inputType) {
116         return withClassLoaderAndLock(inputType.classLoader, lock) [ |
117             val ret = getGeneratedClass(inputType)
118             if (ret !== null) {
119                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
120             }
121             val ref = Types.typeForClass(inputType)
122             val node = typeToAugmentation.get(ref)
123             val typeSpecBuilder = typeToDefinition.get(ref)
124             val typeSpec = typeSpecBuilder.toInstance();
125             val newret = generateAugmentationTransformerFor(inputType, typeSpec, node);
126             listener.onClassProcessed(inputType);
127             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
128         ]
129     }
130
131     def Class<? extends BindingCodec<Object, Object>> caseCodecFor(Class<?> inputType, ChoiceCaseNode node) {
132         return withClassLoaderAndLock(inputType.classLoader, lock) [ |
133             val ret = getGeneratedClass(inputType)
134             if (ret !== null) {
135                 return ret as Class<? extends BindingCodec<Object, Object>>;
136             }
137             val ref = Types.typeForClass(inputType)
138             val typeSpecBuilder = typeToDefinition.get(ref)
139             val typeSpec = typeSpecBuilder.toInstance();
140             val newret = generateCaseCodec(inputType, typeSpec, node);
141             return newret as Class<? extends BindingCodec<Object, Object>>;
142         ]
143     }
144
145     def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifiable(Class<?> parentType) {
146         return withClassLoaderAndLock(parentType.classLoader, lock) [ |
147             val inputName = parentType.name + "Key";
148             val inputType = loadClassWithTCCL(inputName);
149             val ret = getGeneratedClass(inputType)
150             if (ret !== null) {
151                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
152             }
153             val ref = Types.typeForClass(parentType)
154             val node = typeToSchemaNode.get(ref) as ListSchemaNode
155             val typeSpecBuilder = typeToDefinition.get(ref)
156             val typeSpec = typeSpecBuilder.identifierDefinition;
157             val newret = generateKeyTransformerFor(inputType, typeSpec, node);
158             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
159         ]
160     }
161
162     def getIdentifierDefinition(GeneratedTypeBuilder builder) {
163         val inst = builder.toInstance
164         val keyMethod = inst.methodDefinitions.findFirst[name == "getKey"]
165         return keyMethod.returnType as GeneratedTransferObject
166     }
167
168     def Class<? extends BindingCodec<Map<QName, Object>, Object>> keyTransformerForIdentifier(Class<?> inputType) {
169         return withClassLoaderAndLock(inputType.classLoader, lock) [ |
170             val ret = getGeneratedClass(inputType)
171             if (ret !== null) {
172                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
173             }
174             val ref = Types.typeForClass(inputType)
175             val node = typeToSchemaNode.get(ref) as ListSchemaNode
176             val typeSpecBuilder = typeToDefinition.get(ref)
177             val typeSpec = typeSpecBuilder.toInstance();
178             val newret = generateKeyTransformerFor(inputType, typeSpec, node);
179             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
180         ]
181     }
182
183     private def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
184         return withClassLoaderAndLock(inputType.classLoader, lock) [ |
185             val transformer = getGeneratedClass(inputType)
186             if (transformer != null) {
187                 return transformer;
188             }
189             val newret = generateKeyTransformerFor(inputType, type, schema);
190             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
191         ]
192     }
193
194     private def Class<?> getGeneratedClass(Class<? extends Object> cls) {
195
196         try {
197             return loadClassWithTCCL(cls.codecClassName)
198         } catch (ClassNotFoundException e) {
199             return null;
200         }
201     }
202
203     private def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
204         val cls = loadClassWithTCCL(type.resolvedName + "Key");
205         keyTransformerFor(cls, type, node);
206     }
207
208     private def serializer(Type type) {
209         val cls = loadClassWithTCCL(type.resolvedName);
210
211         transformerFor(cls);
212
213     }
214
215     private def Class<?> getValueSerializer(GeneratedTransferObject type) {
216         val cls = loadClassWithTCCL(type.resolvedName);
217         val transformer = cls.generatedClass;
218         if (transformer !== null) {
219             return transformer;
220         }
221         return withClassLoaderAndLock(cls.classLoader, lock) [ |
222             val valueTransformer = generateValueTransformer(cls, type);
223             return valueTransformer;
224         ]
225     }
226
227     private def Class<?> getValueSerializer(Enumeration type) {
228         val cls = loadClassWithTCCL(type.resolvedName);
229         val transformer = cls.generatedClass;
230         if (transformer !== null) {
231             return transformer;
232         }
233
234         return withClassLoaderAndLock(cls.classLoader, lock) [ |
235             val valueTransformer = generateValueTransformer(cls, type);
236             return valueTransformer;
237         ]
238     }
239
240     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
241         try {
242
243             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
244             val properties = typeSpec.allProperties;
245             val ctCls = createClass(inputType.codecClassName) [
246                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
247                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
248                 staticQNameField(node.QName);
249                 implementsType(BINDING_CODEC)
250                 method(Object, "toDomStatic", QName, Object) [
251                     modifiers = PUBLIC + FINAL + STATIC
252                     body = '''
253                         {
254                             «QName.name» _resultName;
255                             if($1 != null) {
256                                 _resultName = «QName.name».create($1,QNAME.getLocalName());
257                             } else {
258                                 _resultName = QNAME;
259                             }
260                             java.util.List _childNodes = new java.util.ArrayList();
261                             «inputType.resolvedName» value = («inputType.name») $2;
262                             «FOR key : node.keyDefinition»
263                                 «val propertyName = key.getterName»
264                                 «val keyDef = node.getDataChildByName(key)»
265                                 «val property = properties.get(propertyName)»
266                                 «serializeProperty(keyDef, property, propertyName)»;
267                             «ENDFOR»
268                             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
269                         }
270                     '''
271                 ]
272                 method(Object, "fromDomStatic", QName, Object) [
273                     modifiers = PUBLIC + FINAL + STATIC
274                     body = '''
275                         {
276                             if($2 == null){
277                                 return  null;
278                             }
279                             «QName.name» _localQName = $1;
280                             java.util.Map _compositeNode = (java.util.Map) $2;
281                             boolean _is_empty = true;
282                             «FOR key : node.keyDefinition»
283                                 «val propertyName = key.getterName»
284                                 «val keyDef = node.getDataChildByName(key)»
285                                 «val property = properties.get(propertyName)»
286                                 «deserializeProperty(keyDef, property, propertyName)»;
287                             «ENDFOR»
288                             «inputType.resolvedName» _value = new «inputType.name»(«node.keyDefinition.
289                             keyConstructorList»);
290                             return _value;
291                         }
292                     '''
293                 ]
294                 method(Object, "serialize", Object) [
295                     body = '''
296                         {
297                             java.util.Map.Entry _input =  (java.util.Map.Entry) $1;
298                             «QName.name» _localQName = («QName.name») _input.getKey();
299                             «inputType.name» _keyValue = («inputType.name») _input.getValue();
300                             return toDomStatic(_localQName,_keyValue);
301                         }
302                     '''
303                 ]
304                 method(Object, "deserialize", Object) [
305                     body = '''
306                         return fromDomStatic(QNAME,$1);
307                     '''
308                 ]
309             ]
310             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
311             log.info("DOM Codec for {} was generated {}", inputType, ret)
312             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
313         } catch (Exception e) {
314             processException(inputType, e);
315             return null;
316         }
317     }
318
319     private def Class<? extends BindingCodec<Object, Object>> generateCaseCodec(Class<?> inputType, GeneratedType type,
320         ChoiceCaseNode node) {
321         try {
322
323             //log.info("Generating DOM Codec for {} with {}, TCCL is: {}", inputType, inputType.classLoader,Thread.currentThread.contextClassLoader)
324             val ctCls = createClass(type.codecClassName) [
325                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
326                 implementsType(BINDING_CODEC)
327                 staticQNameField(node.QName);
328                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
329                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
330                 method(Object, "toDomStatic", QName, Object) [
331                     modifiers = PUBLIC + FINAL + STATIC
332                     body = '''
333                         {
334                             «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
335                             java.util.List _childNodes = new java.util.ArrayList();
336                             «type.resolvedName» value = («type.resolvedName») $2;
337                             «transformDataContainerBody(type, type.allProperties, node)»
338                             return ($r) _childNodes;
339                         }
340                     '''
341                 ]
342                 method(Object, "serialize", Object) [
343                     body = '''
344                         {
345                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
346                             «QName.name» _localName = QNAME;
347                             if(_input.getKey() != null) {
348                                 _localName = («QName.name») _input.getKey();
349                             }
350                             return toDomStatic(_localName,_input.getValue());
351                         }
352                     '''
353                 ]
354                 method(Object, "fromDomStatic", QName, Object) [
355                     modifiers = PUBLIC + FINAL + STATIC
356                     body = deserializeBody(type, node)
357                 ]
358                 method(Object, "deserialize", Object) [
359                     body = '''
360                         {
361                             //System.out.println("«type.name»#deserialize: " +$1);
362                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
363                             return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue());
364                         }
365                     '''
366                 ]
367             ]
368
369             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)  as Class<? extends BindingCodec<Object, Object>>
370             listener?.onDataContainerCodecCreated(inputType,ret);
371             log.info("DOM Codec for {} was generated {}", inputType, ret)
372             return ret;
373         } catch (Exception e) {
374             processException(inputType, e);
375             return null;
376         }
377     }
378
379     private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
380         Class<?> inputType, GeneratedType typeSpec, SchemaNode node) {
381         try {
382
383             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
384             val ctCls = createClass(typeSpec.codecClassName) [
385                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
386                 staticQNameField(node.QName);
387                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
388                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
389                 implementsType(BINDING_CODEC)
390                 method(Object, "toDomStatic", QName, Object) [
391                     modifiers = PUBLIC + FINAL + STATIC
392                     body = serializeBodyFacade(typeSpec, node)
393                 ]
394                 method(Object, "serialize", Object) [
395                     body = '''
396                         {
397                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
398                             «QName.name» _localName = QNAME;
399                             if(_input.getKey() != null) {
400                                 _localName = («QName.name») _input.getKey();
401                             }
402                             return toDomStatic(_localName,_input.getValue());
403                         }
404                     '''
405                 ]
406                 method(Object, "fromDomStatic", QName, Object) [
407                     modifiers = PUBLIC + FINAL + STATIC
408                     body = deserializeBody(typeSpec, node)
409                 ]
410                 method(Object, "deserialize", Object) [
411                     body = '''
412                         return fromDomStatic(QNAME,$1);
413                     '''
414                 ]
415             ]
416
417             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
418             listener?.onDataContainerCodecCreated(inputType, ret);
419             log.info("DOM Codec for {} was generated {}", inputType, ret)
420             return ret;
421         } catch (Exception e) {
422             processException(inputType, e);
423             return null;
424         }
425     }
426
427     private def Class<? extends BindingCodec<Map<QName, Object>, Object>> generateAugmentationTransformerFor(
428         Class<?> inputType, GeneratedType type, AugmentationSchema node) {
429         try {
430
431             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
432             val properties = type.allProperties
433             val ctCls = createClass(type.codecClassName) [
434                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
435                 staticQNameField(node.augmentationQName);
436                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
437                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
438                 implementsType(BINDING_CODEC)
439                 method(Object, "toDomStatic", QName, Object) [
440                     modifiers = PUBLIC + FINAL + STATIC
441                     body = '''
442                         {
443                             //System.out.println("Qname " + $1);
444                             //System.out.println("Value " + $2);
445                             «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
446                             java.util.List _childNodes = new java.util.ArrayList();
447                             «type.resolvedName» value = («type.resolvedName») $2;
448                             «FOR child : node.childNodes»
449                                 «var signature = properties.getFor(child)»
450                                 //System.out.println("«signature.key»" + value.«signature.key»());
451                                 «serializeProperty(child, signature.value, signature.key)»
452                             «ENDFOR»
453                             return ($r) _childNodes;
454                         }
455                     '''
456                 ]
457                 method(Object, "serialize", Object) [
458                     body = '''
459                         {
460                         java.util.Map.Entry _input = (java.util.Map.Entry) $1;
461                         «QName.name» _localName = QNAME;
462                         if(_input.getKey() != null) {
463                             _localName = («QName.name») _input.getKey();
464                         }
465                         return toDomStatic(_localName,_input.getValue());
466                         }
467                     '''
468                 ]
469                 method(Object, "fromDomStatic", QName, Object) [
470                     modifiers = PUBLIC + FINAL + STATIC
471                     body = '''
472                         {
473                             «QName.name» _localQName = QNAME;
474                             
475                             if($2 == null) {
476                             return null;
477                             }
478                             java.util.Map _compositeNode = (java.util.Map) $2;
479                             //System.out.println(_localQName + " " + _compositeNode);
480                             «type.builderName» _builder = new «type.builderName»();
481                             boolean _is_empty = true;
482                             «FOR child : node.childNodes»
483                                 «val signature = properties.getFor(child)»
484                                 «deserializeProperty(child, signature.value, signature.key)»
485                                 _builder.«signature.key.toSetter»(«signature.key»);
486                             «ENDFOR»
487                             if(_is_empty) {
488                                 return null;
489                             }
490                             return _builder.build();
491                         }
492                     '''
493                 ]
494                 method(Object, "deserialize", Object) [
495                     body = '''
496                         return fromDomStatic(QNAME,$1);
497                     '''
498                 ]
499             ]
500
501             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
502             listener?.onDataContainerCodecCreated(inputType, ret);
503             return ret;
504         } catch (Exception e) {
505             processException(inputType, e);
506             return null;
507         }
508     }
509
510     private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
511         Class<?> inputType, GeneratedType typeSpec, ChoiceNode node) {
512         try {
513
514             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
515             val ctCls = createClass(typeSpec.codecClassName) [
516                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
517                 //staticQNameField(inputType);
518                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
519                 staticField(it, CLASS_TO_CASE_MAP, Map)
520                 staticField(it, COMPOSITE_TO_CASE, Map)
521                 //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
522                 implementsType(BINDING_CODEC)
523                 method(List, "toDomStatic", QName, Object) [
524                     modifiers = PUBLIC + FINAL + STATIC
525                     body = '''
526                         {
527                             if($2 == null) {
528                                 return null;
529                             }
530                             «DataObject.name» _baValue = («DataObject.name») $2;
531                             Class _baClass = _baValue.getImplementedInterface();
532                             «BINDING_CODEC.name» _codec =  «CLASS_TO_CASE_MAP».get(_baClass);
533                             if(_codec == null) {
534                                 return null;
535                             }
536                             java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue);
537                             Object _ret =  _codec.serialize(_input);
538                             //System.out.println("«typeSpec.name»#toDomStatic: " + _ret);
539                             return («List.name») _ret;
540                         }
541                     '''
542                 ]
543                 method(Object, "serialize", Object) [
544                     body = '''
545                         throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
546                     '''
547                 ]
548                 method(Object, "fromDomStatic", QName, Map) [
549                     modifiers = PUBLIC + FINAL + STATIC
550                     body = '''
551                         {
552                             «BINDING_CODEC.name» _codec = («BINDING_CODEC.name») «COMPOSITE_TO_CASE».get($2);
553                             if(_codec != null) {
554                                 return _codec.deserialize(new «SimpleEntry.name»($1,$2));
555                             }
556                             return null;
557                         }
558                     '''
559                 ]
560                 method(Object, "deserialize", Object) [
561                     body = '''
562                         throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
563                     '''
564                 ]
565             ]
566
567             val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
568             val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
569             listener?.onChoiceCodecCreated(inputType, ret, node);
570             log.info("DOM Codec for {} was generated {}", inputType, ret)
571             return ret;
572         } catch (Exception e) {
573             processException(inputType, e);
574             return null;
575         }
576     }
577
578     private def keyConstructorList(List<QName> qnames) {
579         val names = new TreeSet<String>()
580         for (name : qnames) {
581             val fieldName = name.getterName;
582             names.add(fieldName);
583         }
584         return Joiner.on(",").join(names);
585     }
586
587     private def serializeBodyFacade(GeneratedType type, SchemaNode node) {
588         val ret = serializeBody(type, node);
589         return ret;
590     }
591
592     private def String deserializeBody(GeneratedType type, SchemaNode node) {
593         val ret = deserializeBodyImpl(type, node);
594         return ret;
595     }
596
597     private def deserializeKey(GeneratedType type, ListSchemaNode node) {
598         if (node.keyDefinition != null && !node.keyDefinition.empty) {
599             return '''
600                 «type.resolvedName»Key getKey = («type.resolvedName»Key) «keyTransformer(type, node).canonicalName».fromDomStatic(_localQName,_compositeNode);
601                 _builder.setKey(getKey);
602             ''';
603         }
604     }
605
606     private def dispatch String deserializeBodyImpl(GeneratedType type, SchemaNode node) '''
607         {
608             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
609             
610             if($2 == null) {
611                 return null;
612             }
613             java.util.Map _compositeNode = (java.util.Map) $2;
614             «type.builderName» _builder = new «type.builderName»();
615             return _builder.build();
616         }
617     '''
618
619     private def dispatch String deserializeBodyImpl(GeneratedType type, ListSchemaNode node) '''
620         {
621             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
622             if($2 == null) {
623                 return null;
624             }
625             java.util.Map _compositeNode = (java.util.Map) $2;
626             «type.builderName» _builder = new «type.builderName»();
627             «deserializeKey(type, node)»
628             «deserializeDataNodeContainerBody(type, node)»
629             «deserializeAugmentations»
630             return _builder.build();
631         }
632     '''
633
634     private def dispatch String deserializeBodyImpl(GeneratedType type, ContainerSchemaNode node) '''
635         {
636             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
637             if($2 == null) {
638                 return null;
639             }
640             java.util.Map _compositeNode = (java.util.Map) $2;
641             «type.builderName» _builder = new «type.builderName»();
642             «deserializeDataNodeContainerBody(type, node)»
643             «deserializeAugmentations»
644             return _builder.build();
645         }
646     '''
647
648     private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node) '''
649         {
650             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
651             
652             if($2 == null) {
653                 return null;
654             }
655             java.util.Map _compositeNode = (java.util.Map) $2;
656             //System.out.println(_localQName + " " + _compositeNode);
657             «type.builderName» _builder = new «type.builderName»();
658             «deserializeDataNodeContainerBody(type, node)»
659             «deserializeAugmentations»
660             return _builder.build();
661         }
662     '''
663
664     private def deserializeDataNodeContainerBody(GeneratedType type, DataNodeContainer node) {
665         deserializeNodeContainerBodyImpl(type, type.allProperties, node);
666     }
667
668     private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, Type> properties,
669         DataNodeContainer node) {
670         val ret = '''
671             boolean _is_empty = true;
672             «FOR child : node.childNodes»
673                 «val signature = properties.getFor(child)»
674                 «IF signature !== null»
675                     «deserializeProperty(child, signature.value, signature.key)»
676                     _builder.«signature.key.toSetter»(«signature.key»);
677                 «ENDIF»
678             «ENDFOR»
679         '''
680         return ret;
681     }
682
683     def deserializeAugmentations() '''
684         java.util.Map _augmentation = (java.util.Map) «AUGMENTATION_CODEC».deserialize(_compositeNode);
685         if(_augmentation != null) {
686             «Iterator.name» _entries = _augmentation.entrySet().iterator();
687             while(_entries.hasNext()) {
688                 java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next();
689                 //System.out.println("Aug. key:" + _entry.getKey());
690                 Class _type = (Class) _entry.getKey();
691                 «Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue();
692                 if(_value != null) {
693                     _builder.addAugmentation(_type,_value);
694                 }
695             }
696         }
697     '''
698
699     private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type,
700         String propertyName) '''
701         java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
702             localName»"));
703         //System.out.println("«propertyName»#deCode"+_dom_«propertyName»);
704         java.util.List «propertyName» = new java.util.ArrayList();
705         if(_dom_«propertyName» != null) {
706             java.util.List _serialized = new java.util.ArrayList();
707             java.util.Iterator _iterator = _dom_«propertyName».iterator();
708             boolean _hasNext = _iterator.hasNext();
709             while(_hasNext) {
710                 Object _listItem = _iterator.next();
711                 _is_empty = false;
712                 //System.out.println("  item" + _listItem);
713                 Object _value = «type.actualTypeArguments.get(0).serializer.resolvedName».fromDomStatic(_localQName,_listItem);
714                 //System.out.println("  value" + _value);
715                 «propertyName».add(_value);
716                 _hasNext = _iterator.hasNext();
717             }
718         }
719         
720         //System.out.println(" list" + «propertyName»);
721     '''
722
723     private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
724         String propertyName) '''
725         java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
726             localName»"));
727         java.util.List «propertyName» = new java.util.ArrayList();
728         if(_dom_«propertyName» != null) {
729             java.util.List _serialized = new java.util.ArrayList();
730             java.util.Iterator _iterator = _dom_«propertyName».iterator();
731             boolean _hasNext = _iterator.hasNext();
732             while(_hasNext) {
733                 _is_empty = false;
734                 Object _listItem = _iterator.next();
735                 if(_listItem instanceof java.util.Map.Entry) {
736                     Object _innerValue = ((java.util.Map.Entry) _listItem).getValue();
737                     Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»;
738                     «propertyName».add(_value);
739                 }
740                 _hasNext = _iterator.hasNext();
741             }
742         }
743     '''
744
745     private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
746         java.util.List _dom_«propertyName»_list = 
747             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
748         «type.resolvedName» «propertyName» = null;
749         if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
750             _is_empty = false;
751             java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0);
752             Object _inner_value = _dom_«propertyName».getValue();
753             «propertyName» = «deserializeValue(type, "_inner_value")»;
754         }
755     '''
756
757     private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type,
758         String propertyName) '''
759         java.util.List _dom_«propertyName»_list = 
760             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
761         «type.resolvedName» «propertyName» = null;
762         if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
763             _is_empty = false;
764             java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0);
765             «propertyName» =  «type.serializer.resolvedName».fromDomStatic(_localQName,_dom_«propertyName»);
766         }
767     '''
768
769     private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) '''
770         «type.resolvedName» «propertyName» = «type.serializer.resolvedName».fromDomStatic(_localQName,_compositeNode);
771         if(«propertyName» != null) {
772             _is_empty = false;
773         }
774     '''
775
776     private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) '''
777         («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»)
778     '''
779
780     private def dispatch String deserializeValue(Enumeration type, String domParameter) '''
781         («type.resolvedName») «type.valueSerializer.resolvedName».fromDomValue(«domParameter»)
782     '''
783
784     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
785         Class<?> inputType, GeneratedTransferObject typeSpec) {
786         try {
787
788             val returnType = typeSpec.valueReturnType;
789             if (returnType == null) {
790                 val ctCls = createDummyImplementation(inputType, typeSpec);
791                 val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
792                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
793             }
794             var hasBinding = false;
795             try {
796                 val bindingCodecClass = loadClassWithTCCL(BINDING_CODEC.name);
797                 hasBinding = bindingCodecClass !== null;
798             } catch (ClassNotFoundException e) {
799                 hasBinding = false;
800             }
801             val hasYangBinding = hasBinding
802             val ctCls = createClass(typeSpec.codecClassName) [
803                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
804                 if (hasYangBinding) {
805                     implementsType(BINDING_CODEC)
806                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
807                     implementsType(BindingDeserializer.asCtClass)
808                 }
809                 method(Object, "toDomValue", Object) [
810                     modifiers = PUBLIC + FINAL + STATIC
811                     body = '''
812                         {
813                             //System.out.println("«inputType.simpleName»#toDomValue: "+$1);
814                             
815                             if($1 == null) {
816                                 return null;
817                             }
818                             «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
819                             //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
820                             «returnType.resolvedName» _value =  _encapsulatedValue.getValue();
821                             //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
822                             Object _domValue = «serializeValue(returnType, "_value")»;
823                             return _domValue;
824                         }
825                     '''
826                 ]
827                 method(Object, "serialize", Object) [
828                     body = '''
829                         {
830                             return toDomValue($1);
831                         }
832                     '''
833                 ]
834                 method(Object, "fromDomValue", Object) [
835                     modifiers = PUBLIC + FINAL + STATIC
836                     body = '''
837                         {
838                             //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
839                             
840                             if($1 == null) {
841                                 return null;
842                             }
843                             «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1")»;
844                             «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue);
845                             return _value;
846                         }
847                     '''
848                 ]
849                 method(Object, "deserialize", Object) [
850                     body = '''{
851                             return fromDomValue($1);
852                     }
853                     '''
854                 ]
855             ]
856
857             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
858             log.info("DOM Codec for {} was generated {}", inputType, ret)
859             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
860         } catch (Exception e) {
861             log.error("Cannot compile DOM Codec for {}", inputType, e);
862             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
863             exception.addSuppressed(e);
864             throw exception;
865         }
866
867     }
868
869     private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
870         log.info("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
871         return createClass(typeSpec.codecClassName) [
872             //staticField(Map,"AUGMENTATION_SERIALIZERS");
873             implementsType(BINDING_CODEC)
874             implementsType(BindingDeserializer.asCtClass)
875             method(Object, "toDomValue", Object) [
876                 modifiers = PUBLIC + FINAL + STATIC
877                 body = '''return null;'''
878             ]
879             method(Object, "serialize", Object) [
880                 body = '''
881                     {
882                         return toDomValue($1);
883                     }
884                 '''
885             ]
886             method(Object, "fromDomValue", Object) [
887                 modifiers = PUBLIC + FINAL + STATIC
888                 body = '''return null;'''
889             ]
890             method(Object, "deserialize", Object) [
891                 body = '''{
892                         return fromDomValue($1);
893                     }
894                     '''
895             ]
896         ]
897     }
898
899     private def Type getValueReturnType(GeneratedTransferObject object) {
900         for (prop : object.properties) {
901             if (prop.name == "value") {
902                 return prop.returnType;
903             }
904         }
905         if (object.superType != null) {
906             return getValueReturnType(object.superType);
907         }
908         return null;
909     }
910
911     private def dispatch Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec) {
912         try {
913             val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name);
914             val schema = typeToSchemaNode.get(typeRef) as ExtendedType;
915             val enumSchema = schema.baseType as EnumerationType;
916
917             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
918             val ctCls = createClass(typeSpec.codecClassName) [
919                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
920                 //implementsType(BINDING_CODEC)
921                 method(Object, "toDomValue", Object) [
922                     modifiers = PUBLIC + FINAL + STATIC
923                     body = '''{
924                             if($1 == null) {
925                                 return null;
926                             }
927                             «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
928                             «FOR en : enumSchema.values»
929                             if(«typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)».equals(_value)) {
930                                 return "«en.name»";
931                             }
932                             «ENDFOR»
933                             return null;
934                         }
935                     '''
936                 ]
937                 method(Object, "serialize", Object) [
938                     body = '''
939                         return toDomValue($1);
940                     '''
941                 ]
942                 method(Object, "fromDomValue", Object) [
943                     modifiers = PUBLIC + FINAL + STATIC
944                     body = '''
945                         {
946                             if($1 == null) {
947                                 return null;
948                             }
949                             String _value = (String) $1;
950                             «FOR en : enumSchema.values»
951                                 if("«en.name»".equals(_value)) {
952                                     return «typeSpec.resolvedName».«BindingGeneratorUtil.parseToClassName(en.name)»;
953                                 }
954                             «ENDFOR»
955                             return null;
956                         }
957                     '''
958                 ]
959                 method(Object, "deserialize", Object) [
960                     body = '''
961                         return fromDomValue($1);
962                     '''
963                 ]
964             ]
965
966             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
967             log.info("DOM Codec for {} was generated {}", inputType, ret)
968             return ret;
969         } catch (CodeGenerationException e) {
970             throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
971         } catch (Exception e) {
972             log.error("Cannot compile DOM Codec for {}", inputType, e);
973             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
974             exception.addSuppressed(e);
975             throw exception;
976         }
977
978     }
979
980     def Class<?> toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) {
981         val cls = newClass.toClass(loader, domain);
982         if (classFileCapturePath !== null) {
983             newClass.writeFile(classFileCapturePath.absolutePath);
984         }
985         listener?.onCodecCreated(cls);
986         return cls;
987     }
988
989     def debugWriteClass(CtClass class1) {
990         val path = class1.name.replace(".", "/") + ".class"
991
992         val captureFile = new File(classFileCapturePath, path);
993         captureFile.createNewFile
994
995     }
996
997     private def dispatch String deserializeValue(Type type, String domParameter) {
998         if (INSTANCE_IDENTIFIER.equals(type)) {
999
1000             return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
1001         }
1002
1003         return '''(«type.resolvedName») «domParameter»'''
1004
1005     }
1006
1007     /** 
1008      * Default catch all
1009      * 
1010      **/
1011     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, String propertyName) '''
1012         «type.resolvedName» «propertyName» = null;
1013     '''
1014
1015     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
1016         String propertyName) {
1017         _deserializeProperty(container, type.toInstance, propertyName)
1018     }
1019
1020     public static def toSetter(String it) {
1021
1022         if (startsWith("is")) {
1023             return "set" + substring(2);
1024         } else if (startsWith("get")) {
1025             return "set" + substring(3);
1026         }
1027         return "set" + it;
1028     }
1029
1030     /* 
1031     private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, String propertyName) '''
1032         «type.resolvedName» «propertyName» = value.«propertyName»();
1033         if(«propertyName» != null) {
1034             Object domValue = «type.serializer».toDomStatic(QNAME,«propertyName»);
1035             _childNodes.add(domValue);
1036         }
1037     '''
1038     */
1039     private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder'''
1040
1041     private def staticQNameField(CtClass it, QName node) {
1042         val field = new CtField(ctQName, "QNAME", it);
1043         field.modifiers = PUBLIC + FINAL + STATIC;
1044         addField(field,
1045             '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
1046     }
1047
1048     private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) '''
1049         {
1050             «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
1051             java.util.List _childNodes = new java.util.ArrayList();
1052             «type.resolvedName» value = («type.resolvedName») $2;
1053             «transformDataContainerBody(type, type.allProperties, node)»
1054             «serializeAugmentations»
1055             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
1056         }
1057     '''
1058
1059     private def dispatch String serializeBody(GeneratedType type, ContainerSchemaNode node) '''
1060         {
1061             «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
1062             java.util.List _childNodes = new java.util.ArrayList();
1063             «type.resolvedName» value = («type.resolvedName») $2;
1064             «transformDataContainerBody(type, type.allProperties, node)»
1065             «serializeAugmentations»
1066             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
1067         }
1068     '''
1069
1070     private def dispatch String serializeBody(GeneratedType type, ChoiceCaseNode node) '''
1071         {
1072         «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
1073             java.util.List _childNodes = new java.util.ArrayList();
1074             «type.resolvedName» value = («type.resolvedName») $2;
1075             «transformDataContainerBody(type, type.allProperties, node)»
1076             «serializeAugmentations»
1077             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
1078         }
1079     '''
1080
1081     private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
1082         {
1083         «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
1084             java.util.List _childNodes = new java.util.ArrayList();
1085             «type.resolvedName» value = («type.resolvedName») $2;
1086             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
1087         }
1088     '''
1089
1090     private def transformDataContainerBody(Type type, Map<String, Type> properties, DataNodeContainer node) {
1091         val ret = '''
1092             «FOR child : node.childNodes»
1093                 «val signature = properties.getFor(child)»
1094                 «IF signature !== null»
1095                     //System.out.println("«type.name»#«signature.key»" + value.«signature.key»());
1096                     «serializeProperty(child, signature.value, signature.key)»
1097                 «ENDIF»
1098             «ENDFOR»
1099         '''
1100         return ret;
1101     }
1102
1103     private def serializeAugmentations() '''
1104         java.util.List _augmentations = (java.util.List) «AUGMENTATION_CODEC».serialize(value);
1105         if(_augmentations != null) {
1106             _childNodes.addAll(_augmentations);
1107         }
1108     '''
1109
1110     def Entry<String, Type> getFor(Map<String, Type> map, DataSchemaNode node) {
1111         var sig = map.get(node.getterName);
1112         if (sig != null) {
1113             return new SimpleEntry(node.getterName, sig);
1114         }
1115         sig = map.get(node.booleanGetterName);
1116         if (sig != null) {
1117             return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName));
1118         }
1119         return null;
1120     }
1121
1122     private static def String getBooleanGetterName(DataSchemaNode node) {
1123         return "is" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
1124     }
1125
1126     private static def String getGetterName(DataSchemaNode node) {
1127         return "get" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
1128     }
1129
1130     private static def String getGetterName(QName node) {
1131         return "get" + BindingGeneratorUtil.parseToClassName(node.localName);
1132     }
1133
1134     private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
1135         String propertyName) '''
1136         «type.resolvedName» «propertyName» = value.«propertyName»();
1137         //System.out.println("«propertyName»:" + «propertyName»);
1138         if(«propertyName» != null) {
1139             java.util.Iterator _iterator = «propertyName».iterator();
1140             boolean _hasNext = _iterator.hasNext();
1141             while(_hasNext) {
1142                 Object _listItem = _iterator.next();
1143                 Object _domValue = «type.actualTypeArguments.get(0).serializer.resolvedName».toDomStatic(_resultName,_listItem);
1144                 _childNodes.add(_domValue);
1145                 _hasNext = _iterator.hasNext();
1146             }
1147         }
1148     '''
1149
1150     private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
1151         «type.resolvedName» «propertyName» = value.«propertyName»();
1152         
1153         if(«propertyName» != null) {
1154             «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
1155             Object _propValue = «serializeValue(type, propertyName)»;
1156             if(_propValue != null) {
1157                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
1158                 _childNodes.add(_domValue);
1159             }
1160         }
1161     '''
1162
1163     private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.
1164         resolvedName».toDomValue(«parameter»)'''
1165
1166     private def dispatch serializeValue(Enumeration type, String parameter) '''«type.valueSerializer.resolvedName».toDomValue(«parameter»)'''
1167
1168     private def dispatch serializeValue(Type signature, String property) {
1169         if (INSTANCE_IDENTIFIER == signature) {
1170             return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
1171         }
1172         return '''«property»''';
1173     }
1174
1175     private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, ParameterizedType type,
1176         String propertyName) '''
1177         «type.resolvedName» «propertyName» = value.«propertyName»();
1178         if(«propertyName» != null) {
1179             «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
1180             java.util.Iterator _iterator = «propertyName».iterator();
1181             boolean _hasNext = _iterator.hasNext();
1182             while(_hasNext) {
1183                 Object _listItem = _iterator.next();
1184                 Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem")»;
1185                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
1186                 _childNodes.add(_domValue);
1187                 _hasNext = _iterator.hasNext();
1188             }
1189         }
1190     '''
1191
1192     private def dispatch CharSequence serializeProperty(ChoiceNode container, GeneratedType type,
1193         String propertyName) '''
1194         «type.resolvedName» «propertyName» = value.«propertyName»();
1195         if(«propertyName» != null) {
1196             java.util.List domValue = «type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
1197             _childNodes.addAll(domValue);
1198         }
1199     '''
1200
1201     /** 
1202      * Default catch all
1203      * 
1204      **/
1205     private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, String propertyName) '''
1206         «type.resolvedName» «propertyName» = value.«propertyName»();
1207         if(«propertyName» != null) {
1208             Object domValue = «propertyName»;
1209             _childNodes.add(domValue);
1210         }
1211     '''
1212
1213     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
1214         String propertyName) {
1215         serializeProperty(container, type.toInstance, propertyName)
1216     }
1217
1218     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type,
1219         String propertyName) '''
1220         «type.resolvedName» «propertyName» = value.«propertyName»();
1221         if(«propertyName» != null) {
1222             Object domValue = «type.serializer.resolvedName».toDomStatic(_resultName,«propertyName»);
1223             _childNodes.add(domValue);
1224         }
1225     '''
1226
1227     private def codecClassName(GeneratedType typeSpec) {
1228         return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
1229     }
1230
1231     private def codecClassName(Class<?> typeSpec) {
1232         return '''«typeSpec.name»$Broker$Codec$DOM'''
1233     }
1234
1235     private def HashMap<String, Type> getAllProperties(GeneratedType type) {
1236         val ret = new HashMap<String, Type>();
1237         type.collectAllProperties(ret);
1238         return ret;
1239     }
1240
1241     private def dispatch void collectAllProperties(GeneratedType type, Map<String, Type> set) {
1242         for (definition : type.methodDefinitions) {
1243             set.put(definition.name, definition.returnType);
1244         }
1245         for (property : type.properties) {
1246             set.put(property.getterName, property.returnType);
1247         }
1248         for (parent : type.implements) {
1249             parent.collectAllProperties(set);
1250         }
1251     }
1252
1253     def String getGetterName(GeneratedProperty property) {
1254         return "get" + property.name.toFirstUpper
1255     }
1256
1257     private def dispatch void collectAllProperties(Type type, Map<String, Type> set) {
1258         // NOOP for generic type.
1259     }
1260
1261     def String getResolvedName(Type type) {
1262         return type.asCtClass.name;
1263     }
1264
1265     def String getResolvedName(Class<?> type) {
1266         return type.asCtClass.name;
1267     }
1268
1269     def CtClass asCtClass(Type type) {
1270         val cls = loadClassWithTCCL(type.fullyQualifiedName)
1271         return cls.asCtClass;
1272     }
1273
1274     private def dispatch processException(Class<?> inputType, CodeGenerationException e) {
1275         log.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.", inputType);
1276         throw e;
1277     }
1278
1279     private def dispatch processException(Class<?> inputType, Exception e) {
1280         log.error("Cannot compile DOM Codec for {}", inputType, e);
1281         val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
1282         throw exception;
1283     }
1284
1285 }
1286
1287 @Data
1288 class PropertyPair {
1289
1290     String getterName;
1291
1292     Type type;
1293
1294     @Property
1295     Type returnType;
1296     @Property
1297     SchemaNode schemaNode;
1298 }