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