From e6f7bf84fe00c345a988e592de5aa6c43b5b916b Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 23 Nov 2018 19:30:11 +0100 Subject: [PATCH] Teach MethodSignature about default methods 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 --- .../binding/model/api/MethodSignature.java | 23 +++++++++----- .../type/builder/MethodSignatureBuilder.java | 29 +++++++++++------- .../generator/impl/AbstractTypeGenerator.java | 2 +- .../builder/MethodSignatureBuilderImpl.java | 9 +++++- .../type/builder/MethodSignatureImpl.java | 17 ++++++++++- .../java/api/generator/BuilderGenerator.java | 3 ++ .../java/api/generator/BuilderTemplate.xtend | 30 +++++++++++++------ .../api/generator/InterfaceTemplate.xtend | 13 +++++--- .../binding/test/model/TestCopyBuilders.java | 27 +++++++++++++++++ 9 files changed, 118 insertions(+), 35 deletions(-) create mode 100644 binding/mdsal-binding-test-model/src/test/java/org/opendaylight/mdsal/binding/test/model/TestCopyBuilders.java diff --git a/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/MethodSignature.java b/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/MethodSignature.java index c47452cdb7..9e4047e1d1 100644 --- a/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/MethodSignature.java +++ b/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/MethodSignature.java @@ -22,22 +22,29 @@ import java.util.List; * Method Signature. */ public interface MethodSignature extends TypeMember { - /** * Returns true if the method signature is defined as abstract.
- * 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.
- * 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.
+ * The abstract methods are allowed in Class definitions but only when the class is declared as abstract. * * @return true 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 true 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. */ diff --git a/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/type/builder/MethodSignatureBuilder.java b/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/type/builder/MethodSignatureBuilder.java index 316de89c18..6a82004ab0 100644 --- a/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/type/builder/MethodSignatureBuilder.java +++ b/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/type/builder/MethodSignatureBuilder.java @@ -26,18 +26,27 @@ import org.opendaylight.mdsal.binding.model.api.Type; */ public interface MethodSignatureBuilder extends TypeMemberBuilder { /** - * Sets the flag for declaration of method as abstract or non abstract. If - * the flag isAbstract == true The instantiated Method - * Signature MUST have return value for {@link MethodSignature#isAbstract()} - * also equals to true. + * 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 + * true. * * @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 null. + * 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}. * *
* In case that any of parameters are defined as null the @@ -50,11 +59,9 @@ public interface MethodSignatureBuilder extends TypeMemberBuildernew immutable instance of Method Signature.
- * The definingType param cannot be null. The - * every method in Java MUST be declared and defined inside the scope of - * class or interface definition. In case that - * defining Type will be passed as null reference the method - * SHOULD thrown {@link IllegalArgumentException}. + * The definingType param cannot be null. Every method in Java MUST be declared and + * defined inside the scope of class or interface definition. In case that defining Type + * will be passed as null reference the method SHOULD thrown {@link IllegalArgumentException}. * * @param definingType Defining Type of Method Signature * @return new immutable instance of Method Signature. diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java index b06f3714af..8cdce60969 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java @@ -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); } diff --git a/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureBuilderImpl.java b/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureBuilderImpl.java index 17ae8e3c39..a8e6247215 100644 --- a/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureBuilderImpl.java +++ b/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureBuilderImpl.java @@ -22,6 +22,7 @@ final class MethodSignatureBuilderImpl extends AbstractTypeMemberBuilder parameters = Collections.emptyList(); private List unmodifiableParams = Collections.emptyList(); private boolean isAbstract; + private boolean isDefault; MethodSignatureBuilderImpl(final String name) { super(name); @@ -33,6 +34,12 @@ final class MethodSignatureBuilderImpl extends AbstractTypeMemberBuilder 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 diff --git a/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureImpl.java b/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureImpl.java index eae052323a..7d3b7a62f3 100644 --- a/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureImpl.java +++ b/binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/MethodSignatureImpl.java @@ -18,13 +18,23 @@ class MethodSignatureImpl extends AbstractTypeMember implements MethodSignature private final List params; private final boolean isAbstract; + private final boolean isDefault; + + MethodSignatureImpl(final Type definingType, final String name, final List annotations, + final String comment, final AccessModifier accessModifier, final Type returnType, + final List 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 annotations, final String comment, final AccessModifier accessModifier, final Type returnType, - final List params, final boolean isFinal, final boolean isAbstract, final boolean isStatic) { + final List 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 getParameters() { return this.params; diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderGenerator.java b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderGenerator.java index 12df6a8035..98d111e894 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderGenerator.java +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderGenerator.java @@ -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; diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend index 0e6729b540..ceac5eae09 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderTemplate.xtend @@ -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 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 getBaseIfcs(GeneratedType type) { val List 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]) + } } diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend index 4b1e188606..8efa940ae8 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend @@ -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 index 0000000000..67fe764980 --- /dev/null +++ b/binding/mdsal-binding-test-model/src/test/java/org/opendaylight/mdsal/binding/test/model/TestCopyBuilders.java @@ -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); + } +} -- 2.36.6