Generate legacy List adaptation 09/89309/3
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 23 Apr 2020 10:50:53 +0000 (12:50 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 23 Apr 2020 11:39:36 +0000 (13:39 +0200)
In order to lower the pain of migration, generate legacy setFoo()
methods with List argument. These internally perform translation
to an ImmutableMap with unique index.

JIRA: MDSAL-434
Change-Id: If364c50a1f48d94b72520c674cbd033fe53646a8
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/CodeHelpers.java

index 5e6de37fb1b8dd3ea0a3faee8f68ea65a8bff0f1..14b91bcf2fc995ea873e92b1d03cf96fbb562ba5 100644 (file)
@@ -275,15 +275,15 @@ class BuilderTemplate extends AbstractBuilderTemplate {
         val returnType = field.returnType
         if (returnType instanceof ParameterizedType) {
             if (Types.isListType(returnType)) {
-                return generateListSetter(field, returnType.actualTypeArguments.get(0), "")
+                return generateListSetter(field, returnType.actualTypeArguments.get(0))
             } else if (Types.isMapType(returnType)) {
-                return generateListSetter(field, returnType.actualTypeArguments.get(1), ".values()")
+                return generateMapSetter(field, returnType.actualTypeArguments.get(1))
             }
         }
         return generateSimpleSetter(field, returnType)
     }
 
-    def private generateListSetter(GeneratedProperty field, Type actualType, String extractor) '''
+    def private generateListSetter(GeneratedProperty field, Type actualType) '''
         «val restrictions = restrictionsForSetter(actualType)»
         «IF restrictions !== null»
             «generateCheckers(field, restrictions, actualType)»
@@ -291,7 +291,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
         public «type.getName» set«field.getName.toFirstUpper»(final «field.returnType.importedName» values) {
         «IF restrictions !== null»
             if (values != null) {
-               for («actualType.importedName» value : values«extractor») {
+               for («actualType.importedName» value : values) {
                    «checkArgument(field, restrictions, actualType, "value")»
                }
             }
@@ -302,6 +302,45 @@ class BuilderTemplate extends AbstractBuilderTemplate {
 
     '''
 
+    // FIXME: MDSAL-540: remove the migration setter
+    def private generateMapSetter(GeneratedProperty field, Type actualType) '''
+        «val restrictions = restrictionsForSetter(actualType)»
+        «val actualTypeRef = actualType.importedName»
+        «val setterName = "set" + field.name.toFirstUpper»
+        «IF restrictions !== null»
+            «generateCheckers(field, restrictions, actualType)»
+        «ENDIF»
+        public «type.getName» «setterName»(final «field.returnType.importedName» values) {
+        «IF restrictions !== null»
+            if (values != null) {
+               for («actualTypeRef» value : values.values()) {
+                   «checkArgument(field, restrictions, actualType, "value")»
+               }
+            }
+        «ENDIF»
+            this.«field.fieldName» = values;
+            return this;
+        }
+
+        /**
+          * Utility migration setter.
+          *
+          * <b>IMPORTANT NOTE</b>: This method does not completely match previous mechanics, as the list is processed as
+          *                        during this method's execution. Any future modifications of the list are <b>NOT</b>
+          *                        reflected in this builder nor its products.
+          *
+          * @param values Legacy List of values
+          * @return this builder
+          * @throws IllegalArgumentException if the list contains entries with the same key
+          * @throws NullPointerException if the list contains a null entry
+          * @deprecated Use {#link #«setterName»(«JU_MAP.importedName»)} instead.
+          */
+        @«DEPRECATED.importedName»(forRemoval = true)
+        public «type.getName» «setterName»(final «JU_LIST.importedName»<«actualTypeRef»> values) {
+            return «setterName»(«CODEHELPERS.importedName».compatMap(values));
+        }
+    '''
+
     def private generateSimpleSetter(GeneratedProperty field, Type actualType) '''
         «val restrictions = restrictionsForSetter(actualType)»
         «IF restrictions !== null»
index 5a49f51e05663f4453977d847f8de248d432396c..2dd7ac1674c302dbd93cf2997dca7a6e257437a2 100644 (file)
@@ -15,6 +15,7 @@ import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.VerifyException;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -272,6 +273,24 @@ public final class CodeHelpers {
         return input != null && input.isEmpty() ? null : input;
     }
 
+    /**
+     * Compatibility utility for turning a List of identifiable objects to an indexed map.
+     *
+     * @param <K> key type
+     * @param <V> identifiable type
+     * @param list legacy list
+     * @return Indexed map
+     * @throws IllegalArgumentException if the list contains entries with the same key
+     * @throws NullPointerException if the list contains a null entry
+     * @deprecated This method is a transitional helper used only in methods deprecated themselves.
+     */
+    // FIXME: MDSAL-540: remove this method
+    @Deprecated
+    public static <K extends Identifier<V>, V extends Identifiable<K>> @Nullable Map<K, V> compatMap(
+            final @Nullable List<V> list) {
+        return list == null || list.isEmpty() ? null : Maps.uniqueIndex(list, Identifiable::key);
+    }
+
     /**
      * Return hash code of a single-property wrapper class. Since the wrapper is not null, we really want to discern
      * this object being present, hence {@link Objects#hashCode()} is not really useful we would end up with {@code 0}