Generate @param for RPC invocation methods
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / ClassTemplate.xtend
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.java.api.generator
9
10 import static java.util.Objects.requireNonNull
11 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.BINARY_TYPE
12 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.BOOLEAN_TYPE
13 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.EMPTY_TYPE
14 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.INSTANCE_IDENTIFIER
15 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.INT16_TYPE
16 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.INT32_TYPE
17 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.INT64_TYPE
18 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.INT8_TYPE
19 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.STRING_TYPE
20 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.UINT16_TYPE
21 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.UINT32_TYPE
22 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.UINT64_TYPE
23 import static org.opendaylight.mdsal.binding.model.util.BaseYangTypes.UINT8_TYPE
24 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.SCALAR_TYPE_OBJECT
25 import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN
26 import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
27 import static extension org.apache.commons.text.StringEscapeUtils.escapeJava
28
29 import com.google.common.base.MoreObjects
30 import com.google.common.base.Preconditions
31 import com.google.common.collect.ImmutableList
32 import com.google.common.collect.Lists
33 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
34 import java.beans.ConstructorProperties
35 import java.util.ArrayList
36 import java.util.Base64;
37 import java.util.Collection
38 import java.util.Comparator
39 import java.util.List
40 import java.util.Map
41 import java.util.Set
42 import javax.management.ConstructorParameters
43 import org.gaul.modernizer_maven_annotations.SuppressModernizer
44 import org.opendaylight.mdsal.binding.model.api.ConcreteType
45 import org.opendaylight.mdsal.binding.model.api.Constant
46 import org.opendaylight.mdsal.binding.model.api.Enumeration
47 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
48 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
49 import org.opendaylight.mdsal.binding.model.api.Restrictions
50 import org.opendaylight.mdsal.binding.model.api.Type
51 import org.opendaylight.mdsal.binding.model.util.TypeConstants
52 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
53 import org.opendaylight.yangtools.yang.common.Empty
54 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
55
56 /**
57  * Template for generating JAVA class.
58  */
59 @SuppressModernizer
60 class ClassTemplate extends BaseTemplate {
61     static val Comparator<GeneratedProperty> PROP_COMPARATOR = Comparator.comparing([prop | prop.name])
62     static val VALUEOF_TYPES = Set.of(
63         BOOLEAN_TYPE,
64         INT8_TYPE,
65         INT16_TYPE,
66         INT32_TYPE,
67         INT64_TYPE,
68         UINT8_TYPE,
69         UINT16_TYPE,
70         UINT32_TYPE,
71         UINT64_TYPE)
72
73     protected val List<GeneratedProperty> properties
74     protected val List<GeneratedProperty> finalProperties
75     protected val List<GeneratedProperty> parentProperties
76     protected val List<GeneratedProperty> allProperties
77     protected val Restrictions restrictions
78
79     /**
80      * List of enumeration which are generated as JAVA enum type.
81      */
82     protected val List<Enumeration> enums
83
84     /**
85      * List of constant instances which are generated as JAVA public static final attributes.
86      */
87     protected val List<Constant> consts
88
89     protected val GeneratedTransferObject genTO
90
91     val AbstractRangeGenerator<?> rangeGenerator
92
93     /**
94      * Creates instance of this class with concrete <code>genType</code>.
95      *
96      * @param genType generated transfer object which will be transformed to JAVA class source code
97      */
98     new(GeneratedTransferObject genType) {
99         this(new TopLevelJavaGeneratedType(genType), genType)
100     }
101
102     /**
103      * Creates instance of this class with concrete <code>genType</code>.
104      *
105      * @param genType generated transfer object which will be transformed to JAVA class source code
106      */
107     new(AbstractJavaGeneratedType javaType, GeneratedTransferObject genType) {
108         super(javaType, genType)
109         this.genTO = genType
110         this.properties = genType.properties
111         this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)
112         this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)
113         this.restrictions = genType.restrictions
114
115         val sorted = new ArrayList();
116         sorted.addAll(properties);
117         sorted.addAll(parentProperties);
118         sorted.sort(PROP_COMPARATOR);
119
120         this.allProperties = sorted
121         this.enums = genType.enumerations
122         this.consts = genType.constantDefinitions
123
124         if (restrictions !== null && restrictions.rangeConstraint.present) {
125             rangeGenerator = requireNonNull(AbstractRangeGenerator.forType(TypeUtils.encapsulatedValueType(genType)))
126         } else {
127             rangeGenerator = null
128         }
129     }
130
131     /**
132      * Generates JAVA class source code (class body only).
133      *
134      * @return string with JAVA class body source code
135      */
136     def CharSequence generateAsInnerClass() {
137         return generateBody(true)
138     }
139
140     override protected body() {
141         generateBody(false);
142     }
143
144     /**
145      * Template method which generates class body.
146      *
147      * @param isInnerClass boolean value which specify if generated class is|isn't inner
148      * @return string with class source code in JAVA format
149      */
150     def protected generateBody(boolean isInnerClass) '''
151         «type.formatDataForJavaDoc.wrapToDocumentation»
152         «annotationDeclaration»
153         «generateClassDeclaration(isInnerClass)» {
154             «suidDeclaration»
155             «innerClassesDeclarations»
156             «enumDeclarations»
157             «constantsDeclarations»
158             «generateFields»
159
160             «IF restrictions !== null»
161                 «IF restrictions.lengthConstraint.present»
162                     «LengthGenerator.generateLengthChecker("_value", TypeUtils.encapsulatedValueType(genTO),
163                         restrictions.lengthConstraint.get, this)»
164                 «ENDIF»
165                 «IF restrictions.rangeConstraint.present»
166                     «rangeGenerator.generateRangeChecker("_value", restrictions.rangeConstraint.get, this)»
167                 «ENDIF»
168             «ENDIF»
169
170             «constructors»
171
172             «defaultInstance»
173
174             «propertyMethods»
175
176             «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
177                 «generateGetValueForBitsTypeDef»
178             «ENDIF»
179
180             «generateHashCode»
181
182             «generateEquals»
183
184             «generateToString(genTO.toStringIdentifiers)»
185         }
186
187     '''
188
189     def private propertyMethods() {
190         if (properties.empty) {
191             return ""
192         }
193         isScalarTypeObject ? scalarTypeObjectValue(properties.get(0)) : defaultProperties
194     }
195
196     def private isScalarTypeObject() {
197         for (impl : genTO.implements) {
198             if (SCALAR_TYPE_OBJECT.identifier.equals(impl.identifier)) {
199                 return true
200             }
201         }
202         return false
203     }
204
205     def private defaultProperties() '''
206         «FOR field : properties SEPARATOR "\n"»
207             «field.getterMethod»
208             «IF !field.readOnly»
209                 «field.setterMethod»
210             «ENDIF»
211         «ENDFOR»
212     '''
213
214     def private scalarTypeObjectValue(GeneratedProperty field) '''
215         @«OVERRIDE.importedName»
216         public «field.returnType.importedName» «BindingMapping.SCALAR_TYPE_OBJECT_GET_VALUE_NAME»() {
217             return «field.fieldName»«IF field.returnType.name.endsWith("[]")».clone()«ENDIF»;
218         }
219     '''
220
221     /**
222      * Template method which generates the method <code>getValue()</code> for typedef,
223      * which base type is BitsDefinition.
224      *
225      * @return string with the <code>getValue()</code> method definition in JAVA format
226      */
227     def protected generateGetValueForBitsTypeDef() '''
228
229         public boolean[] getValue() {
230             return new boolean[]{
231             «FOR property: genTO.properties SEPARATOR ','»
232                  «property.fieldName»
233             «ENDFOR»
234             };
235         }
236     '''
237
238     /**
239      * Template method which generates inner classes inside this interface.
240      *
241      * @return string with the source code for inner classes in JAVA format
242      */
243     def protected innerClassesDeclarations() '''
244         «IF !type.enclosedTypes.empty»
245             «FOR innerClass : type.enclosedTypes SEPARATOR "\n"»
246                 «generateInnerClass(innerClass)»
247             «ENDFOR»
248         «ENDIF»
249     '''
250
251     def protected constructors() '''
252         «IF genTO.unionType»
253             «genUnionConstructor»
254         «ELSEIF genTO.typedef && allProperties.size == 1 && allProperties.get(0).name.equals(TypeConstants.VALUE_PROP)»
255             «typedefConstructor»
256             «legacyConstructor»
257         «ELSE»
258             «allValuesConstructor»
259             «legacyConstructor»
260         «ENDIF»
261
262         «IF !allProperties.empty»
263             «copyConstructor»
264         «ENDIF»
265         «IF properties.empty && !parentProperties.empty »
266             «parentConstructor»
267         «ENDIF»
268     '''
269
270     def allValuesConstructor() '''
271     public «type.name»(«allProperties.asArgumentsDeclaration») {
272         «IF !parentProperties.empty»
273             super(«parentProperties.asArguments»);
274         «ENDIF»
275         «FOR p : allProperties»
276             «generateRestrictions(type, p.fieldName, p.returnType)»
277         «ENDFOR»
278
279         «FOR p : properties»
280             «val fieldName = p.fieldName»
281             «IF p.returnType.name.endsWith("[]")»
282                 this.«fieldName» = «fieldName» == null ? null : «fieldName».clone();
283             «ELSE»
284                 this.«fieldName» = «fieldName»;
285             «ENDIF»
286         «ENDFOR»
287     }
288     '''
289
290     def private typedefConstructor() '''
291     @«ConstructorParameters.importedName»("«TypeConstants.VALUE_PROP»")
292     @«ConstructorProperties.importedName»("«TypeConstants.VALUE_PROP»")
293     public «type.name»(«allProperties.asArgumentsDeclaration») {
294         «IF !parentProperties.empty»
295             super(«parentProperties.asArguments»);
296         «ENDIF»
297         «FOR p : allProperties»
298             «generateRestrictions(type, p.fieldName, p.returnType)»
299         «ENDFOR»
300         «/*
301          * If we have patterns, we need to apply them to the value field. This is a sad consequence of how this code is
302          * structured.
303          */»
304         «CODEHELPERS.importedName».requireValue(_value);
305         «genPatternEnforcer("_value")»
306
307         «FOR p : properties»
308             «val fieldName = p.fieldName»
309             «IF p.returnType.name.endsWith("[]")»
310                 this.«fieldName» = «fieldName».clone();
311             «ELSE»
312                 this.«fieldName» = «fieldName»;
313             «ENDIF»
314         «ENDFOR»
315     }
316     '''
317
318     def private legacyConstructor() {
319         if (!hasUintProperties) {
320             return ""
321         }
322
323         val compatUint = CODEHELPERS.importedName + ".compatUint("
324         return '''
325
326             /**
327              * Utility migration constructor.
328              *
329              «FOR prop : allProperties»
330              * @param «prop.fieldName» «prop.name»«IF prop.isUintType» in legacy Java type«ENDIF»
331              «ENDFOR»
332              * @deprecated Use {#link «type.name»(«FOR prop : allProperties SEPARATOR ", "»«prop.returnType.importedJavadocName»«ENDFOR»)} instead.
333              */
334             @Deprecated(forRemoval = true)
335             public «type.getName»(«FOR prop : allProperties SEPARATOR ", "»«prop.legacyType.importedName» «prop.fieldName»«ENDFOR») {
336                 this(«FOR prop : allProperties SEPARATOR ", "»«IF prop.isUintType»«compatUint»«prop.fieldName»)«ELSE»«prop.fieldName»«ENDIF»«ENDFOR»);
337             }
338         '''
339     }
340
341     def protected genUnionConstructor() '''
342     «FOR p : allProperties»
343         «val List<GeneratedProperty> other = new ArrayList(properties)»
344         «IF other.remove(p)»
345             «genConstructor(p, other)»
346         «ENDIF»
347     «ENDFOR»
348     '''
349
350     def protected genConstructor(GeneratedProperty property, Iterable<GeneratedProperty> other) '''
351     public «type.name»(«property.returnType.importedName + " " + property.name») {
352         «IF !parentProperties.empty»
353             super(«parentProperties.asArguments»);
354         «ENDIF»
355
356         «val fieldName = property.fieldName»
357         «generateRestrictions(type, fieldName, property.returnType)»
358
359         this.«fieldName» = «property.name»;
360         «FOR p : other»
361             this.«p.fieldName» = null;
362         «ENDFOR»
363     }
364     '''
365
366     def private genPatternEnforcer(String ref) '''
367         «FOR c : consts»
368             «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
369             «CODEHELPERS.importedName».checkPattern(«ref», «Constants.MEMBER_PATTERN_LIST», «Constants.MEMBER_REGEX_LIST»);
370             «ENDIF»
371         «ENDFOR»
372     '''
373
374     def private static paramValue(Type returnType, String paramName) {
375         if (returnType instanceof ConcreteType) {
376             return paramName
377         } else {
378             return paramName + ".getValue()"
379         }
380     }
381
382     def generateRestrictions(Type type, String paramName, Type returnType) '''
383         «val restrictions = type.restrictions»
384         «IF restrictions !== null»
385             «IF restrictions.lengthConstraint.present || restrictions.rangeConstraint.present»
386             if («paramName» != null) {
387                 «IF restrictions.lengthConstraint.present»
388                     «LengthGenerator.generateLengthCheckerCall(paramName, paramValue(returnType, paramName))»
389                 «ENDIF»
390                 «IF restrictions.rangeConstraint.present»
391                     «rangeGenerator.generateRangeCheckerCall(paramName, paramValue(returnType, paramName))»
392                 «ENDIF»
393             }
394             «ENDIF»
395         «ENDIF»
396     '''
397
398     def protected copyConstructor() '''
399     /**
400      * Creates a copy from Source Object.
401      *
402      * @param source Source object
403      */
404     public «type.name»(«type.name» source) {
405         «IF !parentProperties.empty»
406             super(source);
407         «ENDIF»
408         «FOR p : properties»
409             «val fieldName = p.fieldName»
410             this.«fieldName» = source.«fieldName»;
411         «ENDFOR»
412     }
413     '''
414
415     def protected parentConstructor() '''
416     /**
417      * Creates a new instance from «genTO.superType.importedName»
418      *
419      * @param source Source object
420      */
421     public «type.name»(«genTO.superType.importedName» source) {
422         super(source);
423         «genPatternEnforcer("getValue()")»
424     }
425     '''
426
427     def protected defaultInstance() '''
428         «IF genTO.typedef && !allProperties.empty && !genTO.unionType»
429             «val prop = allProperties.get(0)»
430             «val propType = prop.returnType»
431             «IF !(INSTANCE_IDENTIFIER.identifier.equals(propType.identifier))»
432             public static «genTO.name» getDefaultInstance(final String defaultValue) {
433                 «IF allProperties.size > 1»
434                     «bitsArgs»
435                 «ELSEIF VALUEOF_TYPES.contains(propType)»
436                     return new «genTO.name»(«propType.importedName».valueOf(defaultValue));
437                 «ELSEIF STRING_TYPE.equals(propType)»
438                     return new «genTO.name»(defaultValue);
439                 «ELSEIF BINARY_TYPE.equals(propType)»
440                     return new «genTO.name»(«Base64.importedName».getDecoder().decode(defaultValue));
441                 «ELSEIF EMPTY_TYPE.equals(propType)»
442                     «Preconditions.importedName».checkArgument(defaultValue.isEmpty(), "Invalid value %s", defaultValue);
443                     return new «genTO.name»(«Empty.importedName».getInstance());
444                 «ELSE»
445                     return new «genTO.name»(new «propType.importedName»(defaultValue));
446                 «ENDIF»
447             }
448             «ENDIF»
449         «ENDIF»
450     '''
451
452     @SuppressFBWarnings(value = "DLS_DEAD_LOCAL_STORE", justification = "FOR with SEPARATOR, not needing for value")
453     def protected bitsArgs() '''
454         «JU_LIST.importedName»<«STRING.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»);
455         if (!properties.contains(defaultValue)) {
456             throw new «IllegalArgumentException.importedName»("invalid default parameter");
457         }
458         int i = 0;
459         return new «genTO.name»(
460         «FOR prop : allProperties SEPARATOR ","»
461             properties.get(i++).equals(defaultValue) ? «BOOLEAN.importedName».TRUE : null
462         «ENDFOR»
463         );
464     '''
465
466     def protected propsAsArgs(Iterable<GeneratedProperty> properties) '''
467         «FOR prop : properties SEPARATOR ","»
468             "«prop.name»"
469         «ENDFOR»
470     '''
471
472     /**
473      * Template method which generates JAVA class declaration.
474      *
475      * @param isInnerClass boolean value which specify if generated class is|isn't inner
476      * @return string with class declaration in JAVA format
477      */
478     def protected generateClassDeclaration(boolean isInnerClass) '''
479         public«
480         IF (isInnerClass)»«
481             " static final "»«
482         ELSEIF (type.abstract)»«
483             " abstract "»«
484         ELSE»«
485             " "»«
486         ENDIF»class «type.name»«
487         IF (genTO.superType !== null)»«
488             " extends "»«genTO.superType.importedName»«
489         ENDIF»
490         «IF (!type.implements.empty)»«
491             " implements "»«
492             FOR type : type.implements SEPARATOR ", "»«
493                 type.importedName»«
494             ENDFOR»«
495         ENDIF
496     »'''
497
498     /**
499      * Template method which generates JAVA enum type.
500      *
501      * @return string with inner enum source code in JAVA format
502      */
503     def protected enumDeclarations() '''
504         «IF !enums.empty»
505             «FOR e : enums SEPARATOR "\n"»
506                 «new EnumTemplate(javaType.getEnclosedType(e.identifier), e).generateAsInnerClass»
507             «ENDFOR»
508         «ENDIF»
509     '''
510
511     def protected suidDeclaration() '''
512         «IF genTO.SUID !== null»
513             private static final long serialVersionUID = «genTO.SUID.value»L;
514         «ENDIF»
515     '''
516
517     def protected annotationDeclaration() '''
518         «IF genTO.getAnnotations !== null»
519             «FOR e : genTO.getAnnotations»
520                 @«e.getName»
521             «ENDFOR»
522         «ENDIF»
523     '''
524
525     /**
526      * Template method which generates JAVA constants.
527      *
528      * @return string with constants in JAVA format
529      */
530     def protected constantsDeclarations() '''
531         «IF !consts.empty»
532             «FOR c : consts»
533                 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
534                     «val cValue = c.value as Map<String, String>»
535                     «val jurPatternRef = JUR_PATTERN.importedName»
536                     public static final «JU_LIST.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
537                     FOR v : cValue.keySet SEPARATOR ", "»"«v.escapeJava»"«ENDFOR»);
538                     «IF cValue.size == 1»
539                         private static final «jurPatternRef» «Constants.MEMBER_PATTERN_LIST» = «jurPatternRef».compile(«TypeConstants.PATTERN_CONSTANT_NAME».get(0));
540                         private static final String «Constants.MEMBER_REGEX_LIST» = "«cValue.values.iterator.next.escapeJava»";
541                     «ELSE»
542                         private static final «jurPatternRef»[] «Constants.MEMBER_PATTERN_LIST» = «CODEHELPERS.importedName».compilePatterns(«TypeConstants.PATTERN_CONSTANT_NAME»);
543                         private static final String[] «Constants.MEMBER_REGEX_LIST» = { «
544                         FOR v : cValue.values SEPARATOR ", "»"«v.escapeJava»"«ENDFOR» };
545                     «ENDIF»
546                 «ELSE»
547                     «emitConstant(c)»
548                 «ENDIF»
549             «ENDFOR»
550         «ENDIF»
551     '''
552
553     /**
554      * Template method which generates JAVA class attributes.
555      *
556      * @return string with the class attributes in JAVA format
557      */
558     def protected generateFields() '''
559         «IF !properties.empty»
560             «FOR f : properties»
561                 private«IF isReadOnly(f)» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
562             «ENDFOR»
563         «ENDIF»
564     '''
565
566     protected def isReadOnly(GeneratedProperty field) {
567         return field.readOnly
568     }
569
570     /**
571      * Template method which generates the method <code>hashCode()</code>.
572      *
573      * @return string with the <code>hashCode()</code> method definition in JAVA format
574      */
575     def protected generateHashCode() {
576         val size = genTO.hashCodeIdentifiers.size
577         if (size == 0) {
578             return ""
579         }
580         return '''
581             @«OVERRIDE.importedName»
582             public int hashCode() {
583                 «IF size != 1»
584                     final int prime = 31;
585                     int result = 1;
586                     «FOR property : genTO.hashCodeIdentifiers»
587                         result = prime * result + «property.importedUtilClass».hashCode(«property.fieldName»);
588                     «ENDFOR»
589                     return result;
590                 «ELSE»
591                     return «CODEHELPERS.importedName».wrapperHashCode(«genTO.hashCodeIdentifiers.get(0).fieldName»);
592                 «ENDIF»
593             }
594         '''
595     }
596
597     /**
598      * Template method which generates the method <code>equals()</code>.
599      *
600      * @return string with the <code>equals()</code> method definition in JAVA format
601      */
602     def private generateEquals() '''
603         «IF !genTO.equalsIdentifiers.empty»
604             @«OVERRIDE.importedName»
605             public final boolean equals(java.lang.Object obj) {
606                 if (this == obj) {
607                     return true;
608                 }
609                 if (!(obj instanceof «type.name»)) {
610                     return false;
611                 }
612                 final «type.name» other = («type.name») obj;
613                 «FOR property : genTO.equalsIdentifiers»
614                     «val fieldName = property.fieldName»
615                     if (!«property.importedUtilClass».equals(«fieldName», other.«fieldName»)) {
616                         return false;
617                     }
618                 «ENDFOR»
619                 return true;
620             }
621         «ENDIF»
622     '''
623
624     def private generateToString(Collection<? extends GeneratedProperty> properties) '''
625         «IF !properties.empty»
626             @«OVERRIDE.importedName»
627             public «STRING.importedName» toString() {
628                 final «MoreObjects.importedName».ToStringHelper helper = «MoreObjects.importedName».toStringHelper(«type.importedName».class);
629                 «FOR property : properties»
630                     «CODEHELPERS.importedName».appendValue(helper, "«property.fieldName»", «property.fieldName»);
631                 «ENDFOR»
632                 return helper.toString();
633             }
634         «ENDIF»
635     '''
636
637     def GeneratedProperty getPropByName(String name) {
638         for (GeneratedProperty prop : allProperties) {
639             if (prop.name.equals(name)) {
640                 return prop;
641             }
642         }
643         return null
644     }
645
646     def private hasUintProperties() {
647         for (GeneratedProperty prop : allProperties) {
648             if (prop.isUintType) {
649                 return true
650             }
651         }
652         return false
653     }
654
655     def private static isUintType(GeneratedProperty prop) {
656         UINT_TYPES.containsKey(prop.returnType)
657     }
658
659     def private static legacyType(GeneratedProperty prop) {
660         val type = prop.returnType
661         val uint = UINT_TYPES.get(type)
662         if (uint !== null) {
663             return uint
664         }
665         return type
666     }
667 }