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