Optimize single-property ClassTemplate hashCode()
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / BuilderImplTemplate.xtend
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
11 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME
12
13 import com.google.common.collect.ImmutableMap
14 import java.util.List
15 import java.util.Map
16 import java.util.Objects
17 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
18 import org.opendaylight.mdsal.binding.model.api.GeneratedType
19 import org.opendaylight.mdsal.binding.model.api.Type
20 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
21 import org.opendaylight.yangtools.yang.binding.DataObject
22
23 class BuilderImplTemplate extends AbstractBuilderTemplate {
24     val Type builderType;
25
26     new(BuilderTemplate builder, GeneratedType type) {
27         super(builder.javaType.getEnclosedType(type.identifier), type, builder.targetType, builder.properties,
28             builder.augmentType, builder.keyType)
29         this.builderType = builder.type
30     }
31
32     override body() '''
33         private static final class «type.name» implements «targetType.importedName» {
34
35             «generateFields(true)»
36
37             «IF augmentType !== null»
38                 private «generateAugmentField()»
39             «ENDIF»
40
41             «generateCopyConstructor(builderType, type)»
42
43             @«Override.importedName»
44             public «Class.importedName»<«targetType.importedName»> getImplementedInterface() {
45                 return «targetType.importedName».class;
46             }
47
48             «generateGetters(true)»
49
50             «generateHashCode()»
51
52             «generateEquals()»
53
54             «generateToString(properties)»
55         }
56     '''
57
58     /**
59      * Template method which generates the method <code>hashCode()</code>.
60      *
61      * @return string with the <code>hashCode()</code> method definition in JAVA format
62      */
63     def protected generateHashCode() '''
64         «IF !properties.empty || augmentType !== null»
65             private int hash = 0;
66             private volatile boolean hashValid = false;
67
68             @«Override.importedName»
69             public int hashCode() {
70                 if (hashValid) {
71                     return hash;
72                 }
73
74                 «hashCodeResult(properties)»
75                 «IF augmentType !== null»
76                     result = prime * result + «Objects.importedName».hashCode(«AUGMENTATION_FIELD»);
77                 «ENDIF»
78
79                 hash = result;
80                 hashValid = true;
81                 return result;
82             }
83         «ENDIF»
84     '''
85
86     /**
87      * Template method which generates the method <code>equals()</code>.
88      *
89      * @return string with the <code>equals()</code> method definition in JAVA format
90      */
91     def protected generateEquals() '''
92         «IF !properties.empty || augmentType !== null»
93             @«Override.importedName»
94             public boolean equals(«Object.importedName» obj) {
95                 if (this == obj) {
96                     return true;
97                 }
98                 if (!(obj instanceof «DataObject.importedName»)) {
99                     return false;
100                 }
101                 if (!«targetType.importedName».class.equals(((«DataObject.importedName»)obj).getImplementedInterface())) {
102                     return false;
103                 }
104                 «targetType.importedName» other = («targetType.importedName»)obj;
105                 «FOR property : properties»
106                     «val fieldName = property.fieldName»
107                     if (!«property.importedUtilClass».equals(«fieldName», other.«property.getterMethodName»())) {
108                         return false;
109                     }
110                 «ENDFOR»
111                 «IF augmentType !== null»
112                     if (getClass() == obj.getClass()) {
113                         // Simple case: we are comparing against self
114                         «type.name» otherImpl = («type.name») obj;
115                         if (!«Objects.importedName».equals(«AUGMENTATION_FIELD», otherImpl.«AUGMENTATION_FIELD»)) {
116                             return false;
117                         }
118                     } else {
119                         // Hard case: compare our augments with presence there...
120                         for («Map.importedName».Entry<«Class.importedName»<? extends «augmentType.importedName»>, «augmentType.importedName»> e : «AUGMENTATION_FIELD».entrySet()) {
121                             if (!e.getValue().equals(other.«AUGMENTABLE_AUGMENTATION_NAME»(e.getKey()))) {
122                                 return false;
123                             }
124                         }
125                         // .. and give the other one the chance to do the same
126                         if (!obj.equals(this)) {
127                             return false;
128                         }
129                     }
130                 «ENDIF»
131                 return true;
132             }
133         «ENDIF»
134     '''
135
136     override protected generateCopyKeys(List<GeneratedProperty> keyProps) '''
137         if (base.«BindingMapping.IDENTIFIABLE_KEY_NAME»() != null) {
138             this.key = base.«BindingMapping.IDENTIFIABLE_KEY_NAME»();
139         } else {
140             this.key = new «keyType.importedName»(«FOR keyProp : keyProps SEPARATOR ", "»base.«keyProp.getterMethodName»()«ENDFOR»);
141         }
142         «FOR field : keyProps»
143             this.«field.fieldName» = key.«field.getterMethodName»();
144         «ENDFOR»
145     '''
146
147     override protected generateCopyAugmentation(Type implType) '''
148         this.«AUGMENTATION_FIELD» = «ImmutableMap.importedName».copyOf(base.«AUGMENTATION_FIELD»);
149     '''
150 }