Specialize relative leafref types during instantiation
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / BuilderTemplate.xtend
index 14b91bcf2fc995ea873e92b1d03cf96fbb562ba5..8bfa8817a3b1dd2a43cea6c61fa33aeddeb4d0d9 100644 (file)
@@ -14,6 +14,7 @@ import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTA
 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
 
 import com.google.common.collect.ImmutableList
+import com.google.common.collect.Sets
 import java.util.ArrayList
 import java.util.Collection
 import java.util.HashSet
@@ -25,13 +26,14 @@ import org.opendaylight.mdsal.binding.model.api.GeneratedProperty
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
 import org.opendaylight.mdsal.binding.model.api.GeneratedType
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName
+import org.opendaylight.mdsal.binding.model.api.MethodSignature;
 import org.opendaylight.mdsal.binding.model.api.ParameterizedType
 import org.opendaylight.mdsal.binding.model.api.Type
 import org.opendaylight.mdsal.binding.model.util.TypeConstants
 import org.opendaylight.mdsal.binding.model.util.Types
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping
 import org.opendaylight.yangtools.concepts.Builder
-import org.opendaylight.yangtools.yang.binding.AugmentationHolder
+import com.google.common.collect.ImmutableSet
 
 /**
  * Template for generating JAVA builder classes.
@@ -44,13 +46,15 @@ class BuilderTemplate extends AbstractBuilderTemplate {
 
     static val BUILDER = JavaTypeName.create(Builder)
 
+    val BuilderImplTemplate implTemplate
+
     /**
      * Constructs new instance of this class.
      * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
      */
-    new(GeneratedType genType, GeneratedType targetType, Set<BuilderGeneratedProperty> properties, Type augmentType,
-            Type keyType) {
-        super(genType, targetType, properties, augmentType, keyType)
+    new(GeneratedType genType, GeneratedType targetType, Type keyType) {
+        super(genType, targetType, keyType)
+        implTemplate = new BuilderImplTemplate(this, type.enclosedTypes.get(0))
     }
 
     override isLocalInnerClass(JavaTypeName name) {
@@ -95,7 +99,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
                 return new «type.enclosedTypes.get(0).importedName»(this);
             }
 
-            «new BuilderImplTemplate(this, type.enclosedTypes.get(0)).body»
+            «implTemplate.body»
         }
     '''
 
@@ -113,8 +117,9 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     def private generateConstructorsFromIfcs() '''
         public «type.name»() {
         }
+
         «IF (!(targetType instanceof GeneratedTransferObject))»
-            «FOR impl : targetType.implements»
+            «FOR impl : targetType.implements SEPARATOR "\n"»
                 «generateConstructorFromIfc(impl)»
             «ENDFOR»
         «ENDIF»
@@ -141,15 +146,41 @@ class BuilderTemplate extends AbstractBuilderTemplate {
             «val ifc = implementedIfc as GeneratedType»
             «FOR getter : ifc.nonDefaultMethods»
                 «IF BindingMapping.isGetterMethodName(getter.name)»
-                    this._«getter.propertyNameFromGetter» = arg.«getter.name»();
+                    «val propertyName = getter.propertyNameFromGetter»
+                    «printPropertySetter(getter, '''arg.«getter.name»()''', propertyName)»;
                 «ENDIF»
             «ENDFOR»
             «FOR impl : ifc.implements»
-                «printConstructorPropertySetter(impl)»
+                «printConstructorPropertySetter(impl, getSpecifiedGetters(ifc))»
+            «ENDFOR»
+        «ENDIF»
+    '''
+
+    def private Object printConstructorPropertySetter(Type implementedIfc, Set<MethodSignature> alreadySetProperties) '''
+        «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
+            «val ifc = implementedIfc as GeneratedType»
+            «FOR getter : ifc.nonDefaultMethods»
+                «IF BindingMapping.isGetterMethodName(getter.name) && getterByName(alreadySetProperties, getter.name).isEmpty»
+                    «val propertyName = getter.propertyNameFromGetter»
+                    «printPropertySetter(getter, '''arg.«getter.name»()''', propertyName)»;
+                «ENDIF»
+            «ENDFOR»
+            «FOR descendant : ifc.implements»
+                «printConstructorPropertySetter(descendant, Sets.union(alreadySetProperties, getSpecifiedGetters(ifc)))»
             «ENDFOR»
         «ENDIF»
     '''
 
+    def static Set<MethodSignature> getSpecifiedGetters(GeneratedType type) {
+        val ImmutableSet.Builder<MethodSignature> setBuilder = new ImmutableSet.Builder
+        for (MethodSignature method : type.getMethodDefinitions()) {
+            if (method.hasOverrideAnnotation) {
+                setBuilder.add(method)
+            }
+        }
+        return setBuilder.build()
+    }
+
     /**
      * Generate 'fieldsFrom' method to set builder properties based on type of given argument.
      */
@@ -179,7 +210,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
          * </ul>
          *
          * @param arg grouping object
-         * @throws IllegalArgumentException if given argument is none of valid types
+         * @throws IllegalArgumentException if given argument is none of valid types or has property with incompatible value
         */
     '''
 
@@ -210,13 +241,28 @@ class BuilderTemplate extends AbstractBuilderTemplate {
         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
         «val ifc = implementedIfc as GeneratedType»
         «FOR getter : ifc.nonDefaultMethods»
-            «IF BindingMapping.isGetterMethodName(getter.name)»
-                this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();
+            «IF BindingMapping.isGetterMethodName(getter.name) && !hasOverrideAnnotation(getter)»
+                «printPropertySetter(getter, '''((«ifc.fullyQualifiedName»)arg).«getter.name»()''', getter.propertyNameFromGetter)»;
             «ENDIF»
         «ENDFOR»
         «ENDIF»
     '''
 
+    def private printPropertySetter(MethodSignature getter, String retrieveProperty, String propertyName) {
+        val ownGetter = implTemplate.findGetter(getter.name)
+        val ownGetterType = ownGetter.returnType
+        if (Types.strictTypeEquals(getter.returnType, ownGetterType)) {
+            return "this._" + propertyName + " = " + retrieveProperty
+        }
+        if (Types.isListType(ownGetterType)) {
+            val itemType = (ownGetterType as ParameterizedType).actualTypeArguments.get(0)
+            return '''
+                this._«propertyName» = «CODEHELPERS.importedName».checkListFieldCast(«itemType.fullyQualifiedName».class, "«propertyName»", «retrieveProperty»)'''
+        }
+        return '''
+            this._«propertyName» = «CODEHELPERS.importedName».checkFieldCast(«ownGetter.returnType.fullyQualifiedName».class, "«propertyName»", «retrieveProperty»)'''
+    }
+
     private def List<Type> getBaseIfcs(GeneratedType type) {
         val List<Type> baseIfcs = new ArrayList();
         for (ifc : type.implements) {
@@ -358,6 +404,21 @@ class BuilderTemplate extends AbstractBuilderTemplate {
             this.«field.fieldName» = value;
             return this;
         }
+        «val uintType = UINT_TYPES.get(field.returnType)»
+        «IF uintType !== null»
+
+            /**
+             * Utility migration setter.
+             *
+             * @param value field value in legacy type
+             * @return this builder
+             * @deprecated Use {#link «setterName»(«field.returnType.importedJavadocName»)} instead.
+             */
+            @Deprecated(forRemoval = true)
+            public «type.getName» «setterName»(final «uintType.importedName» value) {
+                return «setterName»(«CODEHELPERS.importedName».compatUint(value));
+            }
+        «ENDIF»
     '''
 
     /**
@@ -388,20 +449,13 @@ class BuilderTemplate extends AbstractBuilderTemplate {
               * @throws NullPointerException if {@code augmentation} is null
               */
             public «type.name» addAugmentation(«augmentTypeRef» augmentation) {
-                return doAddAugmentation(augmentation.«DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»(), augmentation);
-            }
+                «jlClassRef»<? extends «augmentTypeRef»> augmentationType = augmentation.«DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»();
+                if (!(this.«AUGMENTATION_FIELD» instanceof «hashMapRef»)) {
+                    this.«AUGMENTATION_FIELD» = new «hashMapRef»<>();
+                }
 
-            /**
-              * Add or remove an augmentation to this builder's product.
-              *
-              * @param augmentationType augmentation type to be added or removed
-              * @param augmentationValue augmentation value, null if the augmentation type should be removed
-              * @return this builder
-              * @deprecated Use either {@link #addAugmentation(«augmentType.importedJavadocName»)} or {@link #removeAugmentation(«CLASS.importedName»)} instead.
-              */
-            @«DEPRECATED.importedName»(forRemoval = true)
-            public «type.name» addAugmentation(«jlClassRef»<? extends «augmentTypeRef»> augmentationType, «augmentTypeRef» augmentationValue) {
-                return augmentationValue == null ? removeAugmentation(augmentationType) : doAddAugmentation(augmentationType, augmentationValue);
+                this.«AUGMENTATION_FIELD».put(augmentationType, augmentation);
+                return this;
             }
 
             /**
@@ -417,15 +471,6 @@ class BuilderTemplate extends AbstractBuilderTemplate {
                 }
                 return this;
             }
-
-            private «type.name» doAddAugmentation(«jlClassRef»<? extends «augmentTypeRef»> augmentationType, «augmentTypeRef» augmentationValue) {
-                if (!(this.«AUGMENTATION_FIELD» instanceof «hashMapRef»)) {
-                    this.«AUGMENTATION_FIELD» = new «hashMapRef»<>();
-                }
-
-                this.«AUGMENTATION_FIELD».put(augmentationType, augmentationValue);
-                return this;
-            }
         «ENDIF»
     '''
 
@@ -502,26 +547,13 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     '''
 
     override protected generateCopyAugmentation(Type implType) {
-        val augmentationHolderRef = AugmentationHolder.importedName
-        val typeRef = targetType.importedName
         val hashMapRef = JU_HASHMAP.importedName
         val augmentTypeRef = augmentType.importedName
         return '''
-            if (base instanceof «augmentationHolderRef») {
-                @SuppressWarnings("unchecked")
-                «JU_MAP.importedName»<«CLASS.importedName»<? extends «augmentTypeRef»>, «augmentTypeRef»> aug =((«augmentationHolderRef»<«typeRef»>) base).augmentations();
-                if (!aug.isEmpty()) {
-                    this.«AUGMENTATION_FIELD» = new «hashMapRef»<>(aug);
-                }
+            «JU_MAP.importedName»<«CLASS.importedName»<? extends «augmentTypeRef»>, «augmentTypeRef»> aug = base.augmentations();
+            if (!aug.isEmpty()) {
+                this.«AUGMENTATION_FIELD» = new «hashMapRef»<>(aug);
             }
         '''
     }
-
-    private static def hasNonDefaultMethods(GeneratedType type) {
-        !type.methodDefinitions.isEmpty && type.methodDefinitions.exists([def | !def.isDefault])
-    }
-
-    private static def nonDefaultMethods(GeneratedType type) {
-        type.methodDefinitions.filter([def | !def.isDefault])
-    }
 }