Teach MethodSignature about default methods 02/78102/9
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 23 Nov 2018 18:30:11 +0000 (19:30 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 27 Nov 2018 09:07:12 +0000 (10:07 +0100)
MethodSignature dates back to Java 7 days and has no notion of
interface-default methods. Retrofit the support, as it may come
handy when dealing with various aspects of codegen.

Also propagate the knowledge of them into java-api-generator, so
that we have a cleaner nonnull method generation and new default
methods do not break Builder{Generator,Template} assumptions.

JIRA: MDSAL-18
JIRA: MDSAL-396
Change-Id: I12ea42d096ee50ae61f908e9f9347c45883f66b3
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/MethodSignature.java
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/type/builder/MethodSignatureBuilder.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureBuilderImpl.java
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureImpl.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderGenerator.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend
binding/mdsal-binding-test-model/src/test/java/org/opendaylight/mdsal/binding/test/model/TestCopyBuilders.java [new file with mode: 0644]

index c47452cdb78f1cd8c0ea12b3b45ca570158921ea..9e4047e1d1e76de6f0791b0af1a515246a67d002 100644 (file)
@@ -22,22 +22,29 @@ import java.util.List;
  * Method Signature.
  */
 public interface MethodSignature extends TypeMember {
-
     /**
      * Returns <code>true</code> if the method signature is defined as abstract. <br>
-     * By default in java all method declarations in interface are defined as
-     * abstract, but the user don't need necessary to declare abstract keyword
-     * in front of each method. <br>
-     * The abstract methods are allowed in Class definitions but only when the
-     * class is declared as abstract.
+     * By default in java all method declarations in interface are defined as abstract, but the user does not need
+     * necessarily to declare abstract keyword in front of each method. <br>
+     * The abstract methods are allowed in Class definitions but only when the class is declared as abstract.
      *
      * @return <code>true</code> if the method signature is defined as abstract.
      */
     boolean isAbstract();
 
     /**
-     * Returns the List of parameters that method declare. If the method does
-     * not contain any parameters, the method will return empty List.
+     * Returns {@code true} if this method is a {@code interface default} method.
+     *
+     * @return <code>true</code> if the method signature is defined as default.
+     */
+    // FIXME: 4.0.0: make this method non-default
+    default boolean isDefault() {
+        return false;
+    }
+
+    /**
+     * Returns the List of parameters that method declare. If the method does not contain any parameters, the method
+     * will return empty List.
      *
      * @return the List of parameters that method declare.
      */
index 316de89c184a240234de78dc2cc8423f2ba65056..6a82004ab0d239a68ebfe8097fecd5f07f03a580 100644 (file)
@@ -26,18 +26,27 @@ import org.opendaylight.mdsal.binding.model.api.Type;
  */
 public interface MethodSignatureBuilder extends TypeMemberBuilder<MethodSignatureBuilder> {
     /**
-     * Sets the flag for declaration of method as abstract or non abstract. If
-     * the flag <code>isAbstract == true</code> The instantiated Method
-     * Signature MUST have return value for {@link MethodSignature#isAbstract()}
-     * also equals to <code>true</code>.
+     * Sets the flag for declaration of method as abstract or non abstract. If the flag {@code isAbstract == true}
+     * the instantiated Method Signature MUST have return value for {@link MethodSignature#isAbstract()} also equals to
+     * <code>true</code>.
      *
      * @param isAbstract is abstract flag
      */
     MethodSignatureBuilder setAbstract(boolean isAbstract);
 
     /**
-     * Adds Parameter into the List of method parameters. Neither the Name or
-     * Type of parameter can be <code>null</code>.
+     * Sets the flag indicating whether this is a {@code default interface} method.
+     *
+     * @param isDefault true if this signature is to represent a default method.
+     * @return this builder
+     */
+    // FIXME: 4.0.0: make this method non-default
+    default MethodSignatureBuilder setDefault(final boolean isDefault) {
+        throw new UnsupportedOperationException(getClass() + " does not override setDefault");
+    }
+
+    /**
+     * Adds Parameter into the List of method parameters. Neither the Name or Type of parameter can be {@code null}.
      *
      * <br>
      * In case that any of parameters are defined as <code>null</code> the
@@ -50,11 +59,9 @@ public interface MethodSignatureBuilder extends TypeMemberBuilder<MethodSignatur
 
     /**
      * Returns <code>new</code> <i>immutable</i> instance of Method Signature. <br>
-     * The <code>definingType</code> param cannot be <code>null</code>. The
-     * every method in Java MUST be declared and defined inside the scope of
-     * <code>class</code> or <code>interface</code> definition. In case that
-     * defining Type will be passed as <code>null</code> reference the method
-     * SHOULD thrown {@link IllegalArgumentException}.
+     * The <code>definingType</code> param cannot be <code>null</code>. Every method in Java MUST be declared and
+     * defined inside the scope of <code>class</code> or <code>interface</code> definition. In case that defining Type
+     * will be passed as <code>null</code> reference the method SHOULD thrown {@link IllegalArgumentException}.
      *
      * @param definingType Defining Type of Method Signature
      * @return <code>new</code> <i>immutable</i> instance of Method Signature.
index b06f3714af1ce9a3a98713e9d123b8481fe6fcd7..8cdce60969e008574330d59cc50496c9ed5db973 100644 (file)
@@ -1684,7 +1684,7 @@ abstract class AbstractTypeGenerator {
             final ListSchemaNode node) {
         final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod(
             BindingMapping.getNonnullMethodName(node.getQName().getLocalName()));
-        getMethod.setReturnType(returnType);
+        getMethod.setReturnType(returnType).setDefault(true);
         annotateDeprecatedIfNecessary(node.getStatus(), getMethod);
     }
 
index 17ae8e3c390eed6faa4d7ec35a4ef4d2fe324097..a8e6247215f07650816f8a431755dfa796e8814b 100644 (file)
@@ -22,6 +22,7 @@ final class MethodSignatureBuilderImpl extends AbstractTypeMemberBuilder<MethodS
     private List<MethodSignature.Parameter> parameters = Collections.emptyList();
     private List<MethodSignature.Parameter> unmodifiableParams = Collections.emptyList();
     private boolean isAbstract;
+    private boolean isDefault;
 
     MethodSignatureBuilderImpl(final String name) {
         super(name);
@@ -33,6 +34,12 @@ final class MethodSignatureBuilderImpl extends AbstractTypeMemberBuilder<MethodS
         return this;
     }
 
+    @Override
+    public MethodSignatureBuilder setDefault(final boolean newIsDefault) {
+        this.isDefault = newIsDefault;
+        return this;
+    }
+
     @Override
     public MethodSignatureBuilder addParameter(final Type type, final String name) {
         this.parameters = LazyCollections.lazyAdd(this.parameters, new MethodParameterImpl(name, type));
@@ -49,7 +56,7 @@ final class MethodSignatureBuilderImpl extends AbstractTypeMemberBuilder<MethodS
     public MethodSignature toInstance(final Type definingType) {
         final List<AnnotationType> annotations = toAnnotationTypes();
         return new MethodSignatureImpl(definingType, getName(), annotations, getComment(), getAccessModifier(),
-                getReturnType(), this.unmodifiableParams, isFinal(), this.isAbstract, isStatic());
+                getReturnType(), this.unmodifiableParams, isFinal(), this.isAbstract, isStatic(), isDefault);
     }
 
     @Override
index eae052323aebe4413c88c02b2cde2b95d0f5af73..7d3b7a62f35be3fe22df1375c09ac7a1c29790b6 100644 (file)
@@ -18,13 +18,23 @@ class MethodSignatureImpl extends AbstractTypeMember implements MethodSignature
 
     private final List<Parameter> params;
     private final boolean isAbstract;
+    private final boolean isDefault;
+
+    MethodSignatureImpl(final Type definingType, final String name, final List<AnnotationType> annotations,
+        final String comment, final AccessModifier accessModifier, final Type returnType,
+        final List<Parameter> params, final boolean isFinal, final boolean isAbstract, final boolean isStatic) {
+        this(definingType, name, annotations, comment, accessModifier, returnType, params, isFinal, isAbstract,
+            isStatic, false);
+    }
 
     MethodSignatureImpl(final Type definingType, final String name, final List<AnnotationType> annotations,
             final String comment, final AccessModifier accessModifier, final Type returnType,
-            final List<Parameter> params, final boolean isFinal, final boolean isAbstract, final boolean isStatic) {
+            final List<Parameter> params, final boolean isFinal, final boolean isAbstract, final boolean isStatic,
+            final boolean isDefault) {
         super(definingType, name, annotations, comment, accessModifier, returnType, isFinal, isStatic);
         this.params = params;
         this.isAbstract = isAbstract;
+        this.isDefault = isDefault;
     }
 
     @Override
@@ -32,6 +42,11 @@ class MethodSignatureImpl extends AbstractTypeMember implements MethodSignature
         return this.isAbstract;
     }
 
+    @Override
+    public boolean isDefault() {
+        return isDefault;
+    }
+
     @Override
     public List<Parameter> getParameters() {
         return this.params;
index 12df6a80355bb70b79879a421a5ec870d947911f..98d111e894950cc67073a092d960a6a92b5f8a4b 100644 (file)
@@ -206,6 +206,9 @@ public final class BuilderGenerator implements CodeGenerator {
         checkArgument(method.getReturnType() != null);
         checkArgument(method.getName() != null);
         checkArgument(!method.getName().isEmpty());
+        if (method.isDefault()) {
+            return null;
+        }
         final String prefix = BindingMapping.getGetterPrefix(Types.BOOLEAN.equals(method.getReturnType()));
         if (!method.getName().startsWith(prefix)) {
             return null;
index 0e6729b54074c928e6ae71e3707babd8d1b8c8c4..ceac5eae09808f7d64e9c9c54b23aea6767e01e1 100644 (file)
@@ -110,7 +110,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
      */
     def private Object generateConstructorFromIfc(Type impl) '''
         «IF (impl instanceof GeneratedType)»
-            «IF !(impl.methodDefinitions.empty)»
+            «IF impl.hasNonDefaultMethods»
                 public «type.name»(«impl.fullyQualifiedName» arg) {
                     «printConstructorPropertySetter(impl)»
                 }
@@ -124,8 +124,10 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     def private Object printConstructorPropertySetter(Type implementedIfc) '''
         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
             «val ifc = implementedIfc as GeneratedType»
-            «FOR getter : ifc.methodDefinitions»
-                this._«getter.propertyNameFromGetter» = arg.«getter.name»();
+            «FOR getter : ifc.nonDefaultMethods»
+                «IF BindingMapping.isGetterMethodName(getter.name)»
+                    this._«getter.propertyNameFromGetter» = arg.«getter.name»();
+                «ENDIF»
             «ENDFOR»
             «FOR impl : ifc.implements»
                 «printConstructorPropertySetter(impl)»
@@ -172,7 +174,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     def boolean hasImplementsFromUses(GeneratedType type) {
         var i = 0
         for (impl : type.getAllIfcs) {
-            if ((impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)) {
+            if (impl instanceof GeneratedType && (impl as GeneratedType).hasNonDefaultMethods) {
                 i = i + 1
             }
         }
@@ -180,7 +182,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     }
 
     def private generateIfCheck(Type impl, List<Type> done) '''
-        «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty
+        «IF (impl instanceof GeneratedType && (impl as GeneratedType).hasNonDefaultMethods
             «val implType = impl as GeneratedType»
             if (arg instanceof «implType.fullyQualifiedName») {
                 «printPropertySetter(implType)»
@@ -192,8 +194,10 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     def private printPropertySetter(Type implementedIfc) '''
         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
         «val ifc = implementedIfc as GeneratedType»
-        «FOR getter : ifc.methodDefinitions»
-            this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();
+        «FOR getter : ifc.nonDefaultMethods»
+            «IF BindingMapping.isGetterMethodName(getter.name)»
+                this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();
+            «ENDIF»
         «ENDFOR»
         «ENDIF»
     '''
@@ -201,7 +205,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
     private def List<Type> getBaseIfcs(GeneratedType type) {
         val List<Type> baseIfcs = new ArrayList();
         for (ifc : type.implements) {
-            if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) {
+            if (ifc instanceof GeneratedType && (ifc as GeneratedType).hasNonDefaultMethods) {
                 baseIfcs.add(ifc)
             }
         }
@@ -213,7 +217,7 @@ class BuilderTemplate extends AbstractBuilderTemplate {
         if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
             val ifc = type as GeneratedType
             for (impl : ifc.implements) {
-                if (impl instanceof GeneratedType && !(impl as GeneratedType).methodDefinitions.empty) {
+                if (impl instanceof GeneratedType && (impl as GeneratedType).hasNonDefaultMethods) {
                     baseIfcs.add(impl)
                 }
                 baseIfcs.addAll(impl.getAllIfcs)
@@ -379,5 +383,13 @@ class BuilderTemplate extends AbstractBuilderTemplate {
             }
         '''
     }
+
+    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])
+    }
 }
 
index 4b1e18860688d83899a9d372d8e73dd80fce1838..8efa940ae895b811bbde165223ef12b418480ecc 100644 (file)
@@ -172,11 +172,10 @@ class InterfaceTemplate extends BaseTemplate {
     def private generateMethods() '''
         «IF !methods.empty»
             «FOR m : methods SEPARATOR "\n"»
-                «val noParams = m.parameters.empty»
-                «IF noParams && m.name.isGetterMethodName»
+                «IF m.isDefault»
+                    «generateDefaultMethod(m)»
+                «ELSEIF m.parameters.empty && m.name.isGetterMethodName»
                     «generateAccessorMethod(m)»
-                «ELSEIF noParams && m.name.isNonnullMethodName»
-                    «generateNonnullMethod(m)»
                 «ELSE»
                     «generateMethod(m)»
                 «ENDIF»
@@ -184,6 +183,12 @@ class InterfaceTemplate extends BaseTemplate {
         «ENDIF»
     '''
 
+    def private generateDefaultMethod(MethodSignature method) {
+        if (method.name.isNonnullMethodName) {
+            return generateNonnullMethod(method)
+        }
+    }
+
     def private generateMethod(MethodSignature method) '''
         «method.comment.asJavadoc»
         «method.annotations.generateAnnotations»
diff --git a/binding/mdsal-binding-test-model/src/test/java/org/opendaylight/mdsal/binding/test/model/TestCopyBuilders.java b/binding/mdsal-binding-test-model/src/test/java/org/opendaylight/mdsal/binding/test/model/TestCopyBuilders.java
new file mode 100644 (file)
index 0000000..67fe764
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.test.model;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugment;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.TreeComplexUsesAugmentBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.put.top.input.choice.list.choice.in.choice.list.ComplexViaUses;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.augment.rev140709.put.top.input.choice.list.choice.in.choice.list.ComplexViaUsesBuilder;
+
+public class TestCopyBuilders {
+
+    @Test
+    public void testBuilderListCopy() {
+        final TreeComplexUsesAugment source = new TreeComplexUsesAugmentBuilder().build();
+        final ComplexViaUses viaUses = new ComplexViaUsesBuilder().build();
+        final TreeComplexUsesAugment copied = new TreeComplexUsesAugmentBuilder(viaUses).build();
+        assertEquals(source, copied);
+    }
+}