Merge "Added @ConstructorProperties annotation to constructors of classes generated...
[mdsal.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / ClassTemplate.xtend
1 package org.opendaylight.yangtools.sal.java.api.generator\r
2 \r
3 import java.util.List\r
4 import org.opendaylight.yangtools.binding.generator.util.TypeConstants\r
5 import org.opendaylight.yangtools.sal.binding.model.api.Constant\r
6 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration\r
7 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty\r
8 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject\r
9 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType\r
10 import java.util.ArrayList\r
11 import java.util.Collections\rimport java.util.Arrays
12 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
13 import com.google.common.collect.Range
14 import java.util.regex.Pattern
15 import com.google.common.io.BaseEncoding
16 import java.beans.ConstructorProperties
17
18 /**\r
19  * Template for generating JAVA class. \r
20  */\r
21 class ClassTemplate extends BaseTemplate {\r
22 \r
23     protected val List<GeneratedProperty> properties\r
24     protected val List<GeneratedProperty> finalProperties\r
25     protected val List<GeneratedProperty> parentProperties\r
26     protected val Iterable<GeneratedProperty> allProperties;\r
27     protected val Restrictions restrictions\r
28     \r
29     /**\r
30      * List of enumeration which are generated as JAVA enum type.\r
31      */\r
32     protected val List<Enumeration> enums\r
33     \r
34     /**\r
35      * List of constant instances which are generated as JAVA public static final attributes.\r
36      */\r
37     protected val List<Constant> consts\r
38     \r
39     /**\r
40      * List of generated types which are enclosed inside <code>genType</code>\r
41      */\r
42     protected val List<GeneratedType> enclosedGeneratedTypes;\r
43     \r
44     \r
45     protected val GeneratedTransferObject genTO;\r
46 \r
47     /**\r
48      * Creates instance of this class with concrete <code>genType</code>.\r
49      * \r
50      * @param genType generated transfer object which will be transformed to JAVA class source code\r
51      */\r
52     new(GeneratedTransferObject genType) {\r
53         super(genType)\r
54         this.genTO = genType\r
55         this.properties = genType.properties\r
56         this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)\r
57         this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)\r
58         this.restrictions = genType.restrictions\r
59 \r
60         var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();\r
61         sorted.addAll(properties);\r
62         sorted.addAll(parentProperties);\r
63         Collections.sort(sorted, new PropertyComparator());\r
64 \r
65         this.allProperties = sorted\r
66         this.enums = genType.enumerations\r
67         this.consts = genType.constantDefinitions\r
68         this.enclosedGeneratedTypes = genType.enclosedTypes\r
69     }\r
70 \r
71 \r
72     /**\r
73      * Generates JAVA class source code (class body only).\r
74      * \r
75      * @return string with JAVA class body source code\r
76      */\r
77     def CharSequence generateAsInnerClass() {\r
78         return generateBody(true)\r
79     }\r
80 \r
81 \r
82     override protected body() {\r
83         generateBody(false);\r
84     }\r
85 \r
86     /**\r
87      * Template method which generates class body.\r
88      * \r
89      * @param isInnerClass boolean value which specify if generated class is|isn't inner\r
90      * @return string with class source code in JAVA format\r
91      */\r
92     def protected generateBody(boolean isInnerClass) '''\r
93         «type.comment.asJavadoc»\r
94         «generateClassDeclaration(isInnerClass)» {\r
95             «suidDeclaration»\r
96             «innerClassesDeclarations»\r
97             «enumDeclarations»\r
98             «constantsDeclarations»\r
99             «generateFields»\r
100 \r
101             «constructors»\r
102 \r
103             «FOR field : properties SEPARATOR "\n"»\r
104                 «field.getterMethod»\r
105                 «IF !field.readOnly»\r
106                     «field.setterMethod»\r
107                 «ENDIF»\r
108             «ENDFOR»\r
109 \r
110             «generateHashCode»\r
111 \r
112             «generateEquals»\r
113 \r
114             «generateToString(genTO.toStringIdentifiers)»\r
115 \r
116             «generateGetLength»\r
117 \r
118         }\r
119     '''\r
120 \r
121 \r
122     /**\r
123      * Template method which generates inner classes inside this interface.\r
124      * \r
125      * @return string with the source code for inner classes in JAVA format\r
126      */\r
127     def protected innerClassesDeclarations() '''\r
128         «IF !enclosedGeneratedTypes.empty»\r
129             «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»\r
130                 «IF (innerClass instanceof GeneratedTransferObject)»\r
131                     «val classTemplate = new ClassTemplate(innerClass as GeneratedTransferObject)»\r
132                     «classTemplate.generateAsInnerClass»\r
133                     \r
134                 «ENDIF»\r
135             «ENDFOR»\r
136         «ENDIF»\r
137     '''\r
138     \r
139     \r
140     def protected constructors() '''\r
141         «IF genTO.unionType»\r
142             «genUnionConstructor»\r
143         «ELSE»\r
144             «allValuesConstructor»\r
145         «ENDIF»\r
146         «IF !allProperties.empty»\r
147             «copyConstructor»\r
148         «ENDIF»\r
149         «IF properties.empty && !parentProperties.empty »\r
150             «parentConstructor»\r
151         «ENDIF»\r
152     '''\r
153     \r
154     def protected allValuesConstructor() '''\r
155     «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»\r
156         @«ConstructorProperties.importedName»("value")\r
157     «ENDIF»\r
158     public «type.name»(«allProperties.asArgumentsDeclaration») {\r
159         «IF false == parentProperties.empty»\r
160             super(«parentProperties.asArguments»);\r
161         «ENDIF»\r
162         «FOR p : allProperties» \r
163             «generateRestrictions(type, p.fieldName.toString, p.returnType)»\r
164         «ENDFOR»\r
165         «FOR p : properties» \r
166             this.«p.fieldName» = «p.fieldName»;\r
167         «ENDFOR»\r
168     }\r
169     '''\r
170 \r
171     def protected genUnionConstructor() '''\r
172     «FOR p : allProperties»\r
173         «val List<GeneratedProperty> other = new ArrayList(properties)»\r
174         «val added = other.remove(p)»\r
175         «genConstructor(p, other)»\r
176     «ENDFOR»\r
177 \r
178     '''\r
179 \r
180     def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''\r
181     public «type.name»(«property.returnType.importedName + " " + property.name») {\r
182         «IF false == parentProperties.empty»\r
183             super(«parentProperties.asArguments»);\r
184         «ENDIF»\r
185             «generateRestrictions(type, property.fieldName.toString, property.returnType)»\r
186             this.«property.fieldName» = «property.name»;\r
187             «FOR p : other»\r
188             this.«p.fieldName» = null;\r
189             «ENDFOR»\r
190     }\r
191     '''\r
192 \r
193     def protected copyConstructor() '''\r
194     /**\r
195      * Creates a copy from Source Object.\r
196      *\r
197      * @param source Source object\r
198      */\r
199     public «type.name»(«type.name» source) {\r
200         «IF false == parentProperties.empty»\r
201             super(source);\r
202         «ENDIF»\r
203         «FOR p : properties» \r
204             this.«p.fieldName» = source.«p.fieldName»;\r
205         «ENDFOR»\r
206     }\r
207     '''\r
208     \r
209     def protected parentConstructor() '''\r
210     /**\r
211      * Creates a new instance from «genTO.superType.importedName»\r
212      *\r
213      * @param source Source object\r
214      */\r
215     public «type.name»(«genTO.superType.importedName» source) {\r
216             super(source);\r
217     }\r
218     '''\r
219 \r
220     def protected defaultInstance() '''\r
221         «IF genTO.typedef && !allProperties.empty && !genTO.unionType»\r
222             «val prop = allProperties.get(0)»\r
223             public static «genTO.name» getDefaultInstance(String defaultValue) {\r
224                 «IF "byte[]".equals(prop.returnType.name)»\r
225                     «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64(); \r
226                     return new «genTO.name»(baseEncoding.decode(defaultValue));\r
227                 «ELSE»\r
228                     return new «genTO.name»(new «prop.returnType.importedName»(defaultValue));\r
229                 «ENDIF»\r
230             } \r
231         «ENDIF»\r
232     '''\r
233 \r
234     /**\r
235      * Template method which generates JAVA class declaration.\r
236      * \r
237      * @param isInnerClass boolean value which specify if generated class is|isn't inner\r
238      * @return string with class declaration in JAVA format\r
239      */\r
240     def protected generateClassDeclaration(boolean isInnerClass) '''\r
241         public«\r
242         IF (isInnerClass)»«\r
243             " static final "»«\r
244         ELSEIF (type.abstract)»«\r
245             " abstract "»«\r
246         ELSE»«\r
247             " "»«\r
248         ENDIF»class «type.name»«\r
249         IF (genTO.superType != null)»«\r
250             " extends "»«genTO.superType.importedName»«\r
251         ENDIF»\r
252         «IF (!type.implements.empty)»«\r
253             " implements "»«\r
254             FOR type : type.implements SEPARATOR ", "»«\r
255                 type.importedName»«\r
256             ENDFOR»«\r
257         ENDIF\r
258     »'''\r
259     \r
260     /**\r
261      * Template method which generates JAVA enum type.\r
262      * \r
263      * @return string with inner enum source code in JAVA format\r
264      */\r
265     def protected enumDeclarations() '''\r
266         «IF !enums.empty»\r
267             «FOR e : enums SEPARATOR "\n"»\r
268                 «val enumTemplate = new EnumTemplate(e)»\r
269                 «enumTemplate.generateAsInnerClass»\r
270             «ENDFOR»\r
271         «ENDIF»\r
272     '''\r
273 \r
274     def protected suidDeclaration() '''\r
275         «IF genTO.SUID != null»\r
276             private static final long serialVersionUID = «genTO.SUID.value»L; \r
277         «ENDIF»\r
278     '''\r
279 \r
280     /**\r
281      * Template method wich generates JAVA constants.\r
282      * \r
283      * @return string with constants in JAVA format \r
284      */\r
285     def protected constantsDeclarations() '''\r
286         «IF !consts.empty»\r
287             «FOR c : consts»\r
288                 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»\r
289                     «val cValue = c.value»\r
290                     «IF cValue instanceof List<?>»\r
291                         «val cValues = cValue as List<?>»\r
292                         private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST» = new «ArrayList.importedName»<«Pattern.importedName»>();\r
293                         public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «Arrays.importedName».asList(«\r
294                         FOR v : cValues SEPARATOR ", "»«\r
295                             IF v instanceof String»"«\r
296                                 v as String»"«\r
297                             ENDIF»«\r
298                         ENDFOR»);\r
299 \r
300                         «generateStaticInicializationBlock»\r
301                     «ENDIF»\r
302                 «ELSE»\r
303                     public static final «c.type.importedName» «c.name» = «c.value»;\r
304                 «ENDIF»\r
305             «ENDFOR»\r
306         «ENDIF»\r
307     '''\r
308 \r
309     /**\r
310      * Template method which generates JAVA static initialization block.\r
311      *\r
312      * @return string with static initialization block in JAVA format\r
313      */\r
314     def protected generateStaticInicializationBlock() '''\r
315         static {\r
316             for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {\r
317                 «Constants.MEMBER_PATTERN_LIST».add(Pattern.compile(regEx));\r
318             }\r
319         }\r
320     '''\r
321 \r
322     /**\r
323      * Template method which generates JAVA class attributes.\r
324      *\r
325      * @return string with the class attributes in JAVA format\r
326      */\r
327     def protected generateFields() '''\r
328         «IF !properties.empty»\r
329             «FOR f : properties»\r
330                 «IF f.readOnly»final«ENDIF» private «f.returnType.importedName» «f.fieldName»;\r
331             «ENDFOR»\r
332         «ENDIF»\r
333     '''\r
334 \r
335 \r
336     /**\r
337      * Template method which generates the method <code>hashCode()</code>.\r
338      *\r
339      * @return string with the <code>hashCode()</code> method definition in JAVA format\r
340      */\r
341     def protected generateHashCode() '''\r
342         «IF !genTO.hashCodeIdentifiers.empty»\r
343             @Override\r
344             public int hashCode() {\r
345                 final int prime = 31;\r
346                 int result = 1;\r
347                 «FOR property : genTO.hashCodeIdentifiers»\r
348                     «IF property.returnType.name.contains("[")»\r
349                     result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));\r
350                     «ELSE»\r
351                     result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());\r
352                     «ENDIF»\r
353                 «ENDFOR»\r
354                 return result;\r
355             }\r
356         «ENDIF»\r
357     '''\r
358 \r
359     /**\r
360      * Template method which generates the method <code>equals()</code>.\r
361      *\r
362      * @return string with the <code>equals()</code> method definition in JAVA format\r
363      */\r
364     def protected generateEquals() '''\r
365         «IF !genTO.equalsIdentifiers.empty»\r
366             @Override\r
367             public boolean equals(java.lang.Object obj) {\r
368                 if (this == obj) {\r
369                     return true;\r
370                 }\r
371                 if (obj == null) {\r
372                     return false;\r
373                 }\r
374                 if (getClass() != obj.getClass()) {\r
375                     return false;\r
376                 }\r
377                 «type.name» other = («type.name») obj;\r
378                 «FOR property : genTO.equalsIdentifiers»\r
379                     «val fieldName = property.fieldName»\r
380                     if («fieldName» == null) {\r
381                         if (other.«fieldName» != null) {\r
382                             return false;\r
383                         }\r
384                     «IF property.returnType.name.contains("[")»\r
385                     } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {\r
386                     «ELSE»\r
387                     } else if(!«fieldName».equals(other.«fieldName»)) {\r
388                     «ENDIF»\r
389                         return false;\r
390                     }\r
391                 «ENDFOR»\r
392                 return true;\r
393             }\r
394         «ENDIF»\r
395     '''\r
396 \r
397     def private generateGetLength() '''\r
398         «IF restrictions != null && !(restrictions.lengthConstraints.empty)»\r
399             public static «List.importedName»<«Range.importedName»<Integer>> getLength() {\r
400                 final «List.importedName»<«Range.importedName»<Integer>> result = new «ArrayList.importedName»<>();\r
401                 «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList.importedName»<>(); \r
402                 «FOR r : restrictions.lengthConstraints»\r
403                     result.add(«Range.importedName».closed(«r.min», «r.max»));\r
404                 «ENDFOR»\r
405                 return result;\r
406             }\r
407         «ENDIF»\r
408     '''\r
409 \r
410 }\r