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