Generate implementedInterface 94/77894/40
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 23 Nov 2018 18:48:03 +0000 (19:48 +0100)
committerJie Han <han.jie@zte.com.cn>
Wed, 20 Mar 2019 00:41:59 +0000 (00:41 +0000)
getImplementedInterface() is trampling on getter namespace, making
it possible to clash with a user-supplied model. It also is not properly
overridden in generated code.

Fix both these issues by introducing DataContainer.implementedInterface()
and overriding it as needed wither with a narrower specification
(groupings) or a default implementation (other interfaces).

JIRA: MDSAL-396
Change-Id: I902350f0979067a9e035770e683ab18e966deb7f
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
28 files changed:
binding/mdsal-binding-api/src/test/java/org/opendaylight/mdsal/binding/api/DataTreeIdentifierTest.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/LazySerializedDOMNotification.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingToNormalizedNodeCodecTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/ContextExtractorTest.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingNormalizedNodeCodecRegistry.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CachingNormalizedNodeSerializer.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/LazyDataObject.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/util/ChoiceDispatchSerializer.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/GenEnumResolvingTest.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/GeneratedTypesTest.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal320Test.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/UsesTest.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BuilderImplTemplate.xtend
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-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/test/CompilationTest.java
binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/naming/BindingMapping.java
binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java
binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/util/DataObjectReadingUtil.java
binding/mdsal-binding-spec-util/src/test/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflectionsTest.java
binding/mdsal-binding-spec-util/src/test/java/org/opendaylight/mdsal/binding/spec/util/DataObjectReadingUtilTest.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataContainer.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataObject.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/Notification.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/RpcInput.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/RpcOutput.java
entityownership/mdsal-eos-binding-api/src/test/java/org/opendaylight/mdsal/eos/binding/api/EntityTest.java

index 6e22e98029c999241b6bd925a3e59a45b2b7963a..dcff60346b9d5a05fa18dfb4225f3f70d59fc5f7 100644 (file)
@@ -59,15 +59,27 @@ public class DataTreeIdentifierTest {
 
     private static class TestDataObject1 implements DataObject {
         @Override
+        @Deprecated
         public Class<? extends DataContainer> getImplementedInterface() {
-            return null;
+            return DataObject.class;
+        }
+
+        @Override
+        public Class<? extends DataObject> implementedInterface() {
+            return DataObject.class;
         }
     }
 
     private static class TestDataObject2 implements DataObject {
         @Override
+        @Deprecated
         public Class<? extends DataContainer> getImplementedInterface() {
-            return null;
+            return DataObject.class;
+        }
+
+        @Override
+        public Class<? extends DataObject> implementedInterface() {
+            return DataObject.class;
         }
     }
-}
\ No newline at end of file
+}
index 4246537b9a3ffc85b561fb933596fe4ec13920ac..6fd7f13edebb3733edf42f0b0d955a8ff24bed2c 100644 (file)
@@ -38,7 +38,7 @@ public final class LazySerializedDOMNotification implements DOMNotification {
     }
 
     static DOMNotification create(final BindingNormalizedNodeSerializer codec, final Notification data) {
-        final SchemaPath type = SchemaPath.create(true, BindingReflections.findQName(data.getImplementedInterface()));
+        final SchemaPath type = SchemaPath.create(true, BindingReflections.findQName(data.implementedInterface()));
         return new LazySerializedDOMNotification(codec, data, type);
     }
 
index 84952c94cc62f7406c2f7f4e234259c425efb787..7a329690471e86d5244c801b59bd02e0bf8b1736 100644 (file)
@@ -59,9 +59,10 @@ public class BindingToNormalizedNodeCodecTest {
 
         final DataObject value = fromNormalizedNode.getValue();
         assertNotNull(value);
-        assertEquals("Cont", value.getImplementedInterface().getSimpleName());
+        final Class<? extends DataObject> iface = value.implementedInterface();
+        assertEquals("Cont", iface.getSimpleName());
         final Object[] objs = {};
-        final Object invoked = value.getImplementedInterface().getDeclaredMethods()[0].invoke(value, objs);
+        final Object invoked = iface.getDeclaredMethod("getVlanId").invoke(value, objs);
         final Field declaredField = invoked.getClass().getDeclaredField("_id");
         declaredField.setAccessible(true);
         final Object id = declaredField.get(invoked);
@@ -89,10 +90,11 @@ public class BindingToNormalizedNodeCodecTest {
         final Entry<InstanceIdentifier<?>, DataObject> fromNormalizedNode = fromNormalizedNode(data, schemaCtx);
         final DataObject value = fromNormalizedNode.getValue();
         assertNotNull(value);
-        assertEquals("Cont", value.getImplementedInterface().getSimpleName());
+        final Class<? extends DataObject> iface = value.implementedInterface();
+        assertEquals("Cont", iface.getSimpleName());
         final Object[] objs = {};
         try {
-            value.getImplementedInterface().getDeclaredMethods()[0].invoke(value, objs);
+            iface.getDeclaredMethod("getVlanId").invoke(value, objs);
             fail();
         } catch (final InvocationTargetException e) {
             final Throwable cause = e.getCause();
index 401acfcd7e510d06cc3d950947a03cfb2bf4cd9d..5dc08a792ce40ea774c5ff2c9414eb4ecb2a64ac 100644 (file)
@@ -31,10 +31,16 @@ public final class ContextExtractorTest {
     private static final Transitive TEST_GROUPING = new Transitive() {
 
         @Override
+        @Deprecated
         public Class<? extends DataContainer> getImplementedInterface() {
             return Transitive.class;
         }
 
+        @Override
+        public Class<? extends Transitive> implementedInterface() {
+            return Transitive.class;
+        }
+
         @Override
         public EncapsulatedRoute getRoute() {
             return new EncapsulatedRoute(TEST_ROUTE);
index 37c16b45b880c170e8181026228c0b4246c05086..775a7b7045f269870b21d4848869d3279b93756f 100644 (file)
@@ -166,8 +166,8 @@ public class BindingNormalizedNodeCodecRegistry implements DataObjectSerializerR
         final NormalizedNodeResult result = new NormalizedNodeResult();
         // We create DOM stream writer which produces normalized nodes
         final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final Class<? extends DataObject> type = data.implementedInterface();
         @SuppressWarnings("unchecked")
-        final Class<? extends DataObject> type = (Class<? extends DataObject>) data.getImplementedInterface();
         final BindingStreamEventWriter writer = newWriter.apply((Class<T>)type, domWriter);
         try {
             getSerializer(type).serialize(data, writer);
index d8f08d96b71bea022a01e756e0c286fcc307e823..ab1f3a87cce27ce045ae0781df96e1f8402f4f55 100644 (file)
@@ -66,7 +66,7 @@ final class CachingNormalizedNodeSerializer extends ForwardingBindingStreamEvent
      */
     @Override
     public NormalizedNode<?, ?> serialize(final DataObject input) {
-        final BindingNormalizedNodeCache cachingSerializer = getCacheSerializer(input.getImplementedInterface());
+        final BindingNormalizedNodeCache cachingSerializer = getCacheSerializer(input.implementedInterface());
         if (cachingSerializer != null) {
             final NormalizedNode<?, ?> domData = cachingSerializer.get(input);
             domWriter.addChild(domData);
index 9467c868e01bdce97591f40a123fa321e3738db0..231d0415809950728a30ed2be5bbac9dffac56da 100644 (file)
@@ -11,6 +11,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME;
 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_GET_IMPLEMENTED_INTERFACE_NAME;
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
@@ -72,6 +73,7 @@ class LazyDataObject<D extends DataObject> implements InvocationHandler, Augment
                 final String methodName = method.getName();
                 switch (methodName) {
                     case DATA_CONTAINER_GET_IMPLEMENTED_INTERFACE_NAME:
+                    case DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME:
                         return context.getBindingClass();
                     case TO_STRING:
                         return bindingToString();
index 609bec050df25543207534dc1062218b7fabfecc..20ee58fdcb54886a808555197a83ac9cfe43a099 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.dom.codec.util;
 import static java.util.Objects.requireNonNull;
 
 import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -20,27 +21,22 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class ChoiceDispatchSerializer implements DataObjectSerializerImplementation {
-
     private static final Logger LOG = LoggerFactory.getLogger(ChoiceDispatchSerializer.class);
 
-    @SuppressWarnings("rawtypes")
-    private final Class choiceClass;
+    private final @NonNull Class<? extends DataContainer> choiceClass;
 
-    @SuppressWarnings("rawtypes")
-    private ChoiceDispatchSerializer(final Class choiceClass) {
+    private ChoiceDispatchSerializer(final Class<? extends DataContainer> choiceClass) {
         this.choiceClass = requireNonNull(choiceClass);
     }
 
-    public static ChoiceDispatchSerializer from(final Class<? extends DataContainer> choiceClass) {
+    public static @NonNull ChoiceDispatchSerializer from(final Class<? extends DataContainer> choiceClass) {
         return new ChoiceDispatchSerializer(choiceClass);
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public void serialize(final DataObjectSerializerRegistry reg, final DataObject obj,
             final BindingStreamEventWriter stream) throws IOException {
-        @SuppressWarnings("rawtypes")
-        Class cazeClass = obj.getImplementedInterface();
+        Class<? extends DataObject> cazeClass = obj.implementedInterface();
         stream.startChoiceNode(choiceClass, BindingStreamEventWriter.UNKNOWN_SIZE);
         DataObjectSerializer caseSerializer = reg.getSerializer(cazeClass);
         if (caseSerializer != null) {
index 460b566906f545a831ce88e5617479fc99a0f3ea..620f5532e17cd1c5c70b7ff09629ca25e4a7cc3e 100644 (file)
@@ -32,9 +32,14 @@ import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifier;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.keyedListAction;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.rpcResult;
 import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN;
+import static org.opendaylight.mdsal.binding.model.util.Types.STRING;
+import static org.opendaylight.mdsal.binding.model.util.Types.augmentationTypeFor;
+import static org.opendaylight.mdsal.binding.model.util.Types.classType;
 import static org.opendaylight.mdsal.binding.model.util.Types.listTypeFor;
 import static org.opendaylight.mdsal.binding.model.util.Types.listenableFutureTypeFor;
+import static org.opendaylight.mdsal.binding.model.util.Types.primitiveVoidType;
 import static org.opendaylight.mdsal.binding.model.util.Types.typeForClass;
+import static org.opendaylight.mdsal.binding.model.util.Types.wildcardTypeFor;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
@@ -74,7 +79,6 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder;
 import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil;
 import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl;
 import org.opendaylight.mdsal.binding.model.util.TypeConstants;
-import org.opendaylight.mdsal.binding.model.util.Types;
 import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedPropertyBuilderImpl;
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.mdsal.binding.yang.types.AbstractTypeProvider;
@@ -272,6 +276,7 @@ abstract class AbstractTypeGenerator {
             return null;
         }
         final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, node, baseInterface);
+        defaultImplementedInterace(genType);
         annotateDeprecatedIfNecessary(node.getStatus(), genType);
 
         final Module module = context.module();
@@ -528,6 +533,7 @@ abstract class AbstractTypeGenerator {
         addImplementedInterfaceFromUses(schema, outType);
         outType.addImplementsType(type);
         outType.addImplementsType(augmentable(outType));
+        defaultImplementedInterace(outType);
         annotateDeprecatedIfNecessary(rpc.getStatus(), outType);
         resolveDataSchemaNodes(context, outType, outType, schema.getChildNodes());
         context.addChildNodeType(schema, outType);
@@ -567,6 +573,7 @@ abstract class AbstractTypeGenerator {
 
                 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(
                     context.modulePackageName(), notification, DATA_OBJECT, context);
+                defaultImplementedInterace(notificationInterface);
                 annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
                 notificationInterface.addImplementsType(NOTIFICATION);
                 context.addChildNodeType(notification, notificationInterface);
@@ -577,7 +584,7 @@ abstract class AbstractTypeGenerator {
 
                 addComment(listenerInterface.addMethod("on" + notificationInterface.getName())
                     .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
-                    .setReturnType(Types.primitiveVoidType()), notification);
+                    .setReturnType(primitiveVoidType()), notification);
             }
         }
 
@@ -686,6 +693,7 @@ abstract class AbstractTypeGenerator {
             // Converts individual grouping to GeneratedType. Firstly generated type builder is created and every child
             // node of grouping is resolved to the method.
             final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, grouping);
+            narrowImplementedInterface(genType);
             annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
             context.addGroupingType(grouping, genType);
             resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes());
@@ -914,7 +922,9 @@ abstract class AbstractTypeGenerator {
             JavaTypeName.create(augmentPackageName, augTypeName));
 
         augTypeBuilder.addImplementsType(DATA_OBJECT);
-        augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
+        defaultImplementedInterace(augTypeBuilder);
+
+        augTypeBuilder.addImplementsType(augmentationTypeFor(targetTypeRef));
         annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
         addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
 
@@ -1106,6 +1116,7 @@ abstract class AbstractTypeGenerator {
             if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode);
                 caseTypeBuilder.addImplementsType(refChoiceType);
+                defaultImplementedInterace(caseTypeBuilder);
                 annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder);
                 context.addCaseType(caseNode.getPath(), caseTypeBuilder);
                 context.addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
@@ -1181,6 +1192,7 @@ abstract class AbstractTypeGenerator {
             if (caseNode != null) {
                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode);
                 caseTypeBuilder.addImplementsType(targetType);
+                defaultImplementedInterace(caseTypeBuilder);
 
                 CaseSchemaNode node = null;
                 final String caseLocalName = caseNode.getQName().getLocalName();
@@ -1538,7 +1550,7 @@ abstract class AbstractTypeGenerator {
 
         final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
         method.setReturnType(returnType);
-        method.addParameter(Types.STRING, "defaultValue");
+        method.addParameter(STRING, "defaultValue");
         method.setAccessModifier(AccessModifier.PUBLIC);
         method.setStatic(true);
 
@@ -1579,7 +1591,6 @@ abstract class AbstractTypeGenerator {
         }
 
         final GeneratedTypeBuilder it = addRawInterfaceDefinition(name, schemaNode);
-
         it.addImplementsType(baseInterface);
         if (!(schemaNode instanceof GroupingDefinition)) {
             it.addImplementsType(augmentable(it));
@@ -1895,4 +1906,23 @@ abstract class AbstractTypeGenerator {
             builder.addAnnotation(DEPRECATED_ANNOTATION);
         }
     }
+
+    private static void narrowImplementedInterface(final GeneratedTypeBuilder typeBuilder) {
+        defineImplementedInterfaceMethod(typeBuilder, wildcardTypeFor(typeBuilder.getIdentifier()));
+    }
+
+    private static void defaultImplementedInterace(final GeneratedTypeBuilder typeBuilder) {
+        defineImplementedInterfaceMethod(typeBuilder, new ReferencedTypeImpl(typeBuilder.getIdentifier()))
+            .setDefault(true);
+    }
+
+    private static MethodSignatureBuilder defineImplementedInterfaceMethod(final GeneratedTypeBuilder typeBuilder,
+            final Type classType) {
+        final MethodSignatureBuilder ret = typeBuilder
+                .addMethod(BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME)
+                .setAccessModifier(AccessModifier.PUBLIC)
+                .setReturnType(classType(classType));
+        ret.addAnnotation(OVERRIDE_ANNOTATION);
+        return ret;
+    }
 }
index 639eba1e19b71eb8304134b191d87fe55fb0dcdc..407a4cdb395071f02a540195772bbd9f982936e6 100644 (file)
@@ -71,7 +71,7 @@ public class GenEnumResolvingTest {
 
         assertNotNull("Generated Interface cannot contain NULL reference for Method Signature Definitions!", methods);
 
-        assertEquals("Expected count of method signature definitions is 15", 15, methods.size());
+        assertEquals("Expected count of method signature definitions is 16", 16, methods.size());
         Enumeration ianaIfType = null;
         for (final MethodSignature method : methods) {
             if (method.getName().equals("getType")) {
@@ -128,7 +128,7 @@ public class GenEnumResolvingTest {
         Type operStatus = null;
         final List<MethodSignature> methods = genInterface.getMethodDefinitions();
         assertNotNull("Generated Type Interface cannot contain NULL reference to Enumeration types!", methods);
-        assertEquals("Generated Type Interface MUST contain 5 Methods ", 5, methods.size());
+        assertEquals("Generated Type Interface MUST contain 6 Methods ", 6, methods.size());
         for (final MethodSignature method : methods) {
             if (method.getName().equals("getLinkUpDownTrapEnable")) {
                 linkUpDownTrapEnable = method.getReturnType();
index 7b60b50ee57fe3db8674aa335a9a7f5c6d991e43..0824dd41750043c9ae7ef310c58ea9727bccd761 100644 (file)
@@ -60,8 +60,8 @@ public class GeneratedTypesTest {
         }
         assertNotNull(simpleContainer);
         assertNotNull(nestedContainer);
-        assertEquals(3, simpleContainer.getMethodDefinitions().size());
-        assertEquals(2, nestedContainer.getMethodDefinitions().size());
+        assertEquals(4, simpleContainer.getMethodDefinitions().size());
+        assertEquals(3, nestedContainer.getMethodDefinitions().size());
 
         int getFooMethodCounter = 0;
         int getBarMethodCounter = 0;
@@ -144,8 +144,8 @@ public class GeneratedTypesTest {
         }
         assertNotNull(simpleContainer);
         assertNotNull(nestedContainer);
-        assertEquals(3, simpleContainer.getMethodDefinitions().size());
-        assertEquals(2, nestedContainer.getMethodDefinitions().size());
+        assertEquals(4, simpleContainer.getMethodDefinitions().size());
+        assertEquals(3, nestedContainer.getMethodDefinitions().size());
 
         int getFooMethodCounter = 0;
         int getBarMethodCounter = 0;
@@ -155,6 +155,9 @@ public class GeneratedTypesTest {
         String getBarMethodReturnTypeName = "";
         String getNestedContainerReturnTypeName = "";
         for (final MethodSignature method : simpleContainer.getMethodDefinitions()) {
+            if (method.isDefault()) {
+                continue;
+            }
             if (method.getName().equals("getFoo")) {
                 getFooMethodCounter++;
                 getFooMethodReturnTypeName = method.getReturnType().getName();
@@ -307,8 +310,8 @@ public class GeneratedTypesTest {
             }
         }
 
-        assertEquals(2, listParentContainerMethodsCount);
-        assertEquals(1, listChildContainerMethodsCount);
+        assertEquals(3, listParentContainerMethodsCount);
+        assertEquals(2, listChildContainerMethodsCount);
         assertEquals(1, getSimpleListKeyMethodCount);
         assertEquals(1, listKeyClassCount);
 
@@ -333,7 +336,7 @@ public class GeneratedTypesTest {
         assertEquals(0, setSimpleLeafListMethodCount);
         assertEquals(1, getBarMethodCount);
 
-        assertEquals(6, simpleListMethodsCount);
+        assertEquals(7, simpleListMethodsCount);
     }
 
     @Test
index 1bc39313d726b5b7c6988530d3c8b003ec6c0663..25ecff9393204f9cccdcb7dbc374528725381296 100644 (file)
@@ -8,10 +8,11 @@
 package org.opendaylight.mdsal.binding.generator.impl;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import com.google.common.collect.Iterables;
+import java.util.Iterator;
 import java.util.List;
 import org.junit.Test;
 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
@@ -58,7 +59,15 @@ public class Mdsal320Test {
         assertNotNull(bar1);
         assertTrue(bar1.isUnionType());
 
-        final MethodSignature getBar = Iterables.getOnlyElement(foo.getMethodDefinitions());
+        final Iterator<MethodSignature> it = foo.getMethodDefinitions().iterator();
+        assertTrue(it.hasNext());
+        final MethodSignature getImplIface = it.next();
+        assertEquals("implementedInterface", getImplIface.getName());
+        assertTrue(getImplIface.isDefault());
+        assertTrue(it.hasNext());
+
+        final MethodSignature getBar = it.next();
+        assertFalse(it.hasNext());
         final Type getBarType = getBar.getReturnType();
         assertTrue(getBarType instanceof GeneratedTransferObject);
         final GeneratedTransferObject getBarTO = (GeneratedTransferObject) getBarType;
index 1531f3bf271c15e3090792ab2247f6956adfb425..60a57c08b20755b8a01660977a2593206c0234eb 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.mdsal.binding.generator.impl;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 import static org.opendaylight.mdsal.binding.generator.impl.SupportTestUtil.containsInterface;
 import static org.opendaylight.mdsal.binding.generator.impl.SupportTestUtil.containsMethods;
 
@@ -117,9 +116,9 @@ public class UsesTest {
                 "org.opendaylight.yang.gen.v1.urn.grouping.uses._case.rev130718", groupingCaseTest.getPackageName());
 
         containsInterface("GroupingCaseTest", caseC);
-        assertTrue("Case C shouldn't contain any method.", caseC.getMethodDefinitions().isEmpty());
+        assertEquals("Case C shouldn't contain any method.", 1, caseC.getMethodDefinitions().size());
 
-        assertEquals("Number of method in GroupingCaseTest is incorrect", 1, groupingCaseTest.getMethodDefinitions()
+        assertEquals("Number of method in GroupingCaseTest is incorrect", 2, groupingCaseTest.getMethodDefinitions()
                 .size());
         containsMethods(groupingCaseTest.getMethodDefinitions(), new NameTypePattern("getLeafGroupingCaseTest1",
                 "String"));
@@ -166,9 +165,9 @@ public class UsesTest {
 
         containsInterface("GroupingContainerTest", containerTest);
 
-        assertEquals("Number of method in GroupingContainerTestis incorrect", 2, groupingContainerTest
+        assertEquals("Number of method in GroupingContainerTestis incorrect", 3, groupingContainerTest
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in ContainerTest is incorrect", 1, containerTest.getMethodDefinitions().size());
+        assertEquals("Number of method in ContainerTest is incorrect", 2, containerTest.getMethodDefinitions().size());
 
         containsMethods(groupingContainerTest.getMethodDefinitions(), new NameTypePattern(
                 "getLeafGroupingContainerTest1", "String"), new NameTypePattern("getLeafGroupingContainerTest2",
@@ -217,9 +216,9 @@ public class UsesTest {
 
         containsInterface("GroupingGroupingTest", groupingTest);
 
-        assertEquals("Number of method in GroupingGroupingTest is incorrect", 1, groupingGroupingTest
+        assertEquals("Number of method in GroupingGroupingTest is incorrect", 2, groupingGroupingTest
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in GroupingTest is incorrect", 1, groupingTest.getMethodDefinitions().size());
+        assertEquals("Number of method in GroupingTest is incorrect", 2, groupingTest.getMethodDefinitions().size());
 
         containsMethods(groupingGroupingTest.getMethodDefinitions(), new NameTypePattern("getLeafGroupingGrouping",
                 "String"));
@@ -289,12 +288,12 @@ public class UsesTest {
 
         containsInterface("GroupingListTest", listTest);
 
-        assertEquals("Number of method in GroupingListTest is incorrect", 5, groupingListTest.getMethodDefinitions()
+        assertEquals("Number of method in GroupingListTest is incorrect", 6, groupingListTest.getMethodDefinitions()
                 .size());
-        assertEquals("Number of method in ListTest is incorrect", 1, listTest.getMethodDefinitions().size());
-        assertEquals("Number of method in ContainerGroupingListTest is incorrect", 1, containerGroupingListTest
+        assertEquals("Number of method in ListTest is incorrect", 2, listTest.getMethodDefinitions().size());
+        assertEquals("Number of method in ContainerGroupingListTest is incorrect", 2, containerGroupingListTest
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in ListGroupingListTest is incorrect", 1, listGroupingListTest
+        assertEquals("Number of method in ListGroupingListTest is incorrect", 2, listGroupingListTest
                 .getMethodDefinitions().size());
 
         containsMethods(groupingListTest.getMethodDefinitions(), new NameTypePattern("getContainerGroupingListTest",
@@ -351,7 +350,7 @@ public class UsesTest {
 
         assertEquals("Number of method in GroupingUsesModulData is incorrect", 0, groupingUsesModulData
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in GroupingModulTest is incorrect", 2, groupingModulTest.getMethodDefinitions()
+        assertEquals("Number of method in GroupingModulTest is incorrect", 3, groupingModulTest.getMethodDefinitions()
                 .size());
 
         containsMethods(groupingModulTest.getMethodDefinitions(), new NameTypePattern("getLeafGroupingModulTest",
@@ -432,13 +431,13 @@ public class UsesTest {
         containsInterface("GroupingRpcInputTest", rpcTestInput);
         containsInterface("GroupingRpcOutputTest", rpcTestOutput);
 
-        assertEquals("Number of method in RpcTestInput is incorrect", 0, rpcTestInput.getMethodDefinitions().size());
-        assertEquals("Number of method in RpcTestOutput is incorrect", 0, rpcTestOutput.getMethodDefinitions().size());
-        assertEquals("Number of method in GroupingRpcInputTest is incorrect", 2, groupingRpcInputTest
+        assertEquals("Number of method in RpcTestInput is incorrect", 1, rpcTestInput.getMethodDefinitions().size());
+        assertEquals("Number of method in RpcTestOutput is incorrect", 1, rpcTestOutput.getMethodDefinitions().size());
+        assertEquals("Number of method in GroupingRpcInputTest is incorrect", 3, groupingRpcInputTest
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in GroupingRpcOutputTest is incorrect", 1, groupingRpcOutputTest
+        assertEquals("Number of method in GroupingRpcOutputTest is incorrect", 2, groupingRpcOutputTest
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in ContainerGroupingRpcInputTest is incorrect", 1, containerGroupingRpcInputTest
+        assertEquals("Number of method in ContainerGroupingRpcInputTest is incorrect", 2, containerGroupingRpcInputTest
                 .getMethodDefinitions().size());
 
         containsMethods(groupingRpcInputTest.getMethodDefinitions(), new NameTypePattern(
@@ -490,12 +489,12 @@ public class UsesTest {
 
         containsInterface("GroupingAugmentTest", containerAugment1);
 
-        assertEquals("Number of method in GroupingCaseTest is incorrect", 0, containerAugment1.getMethodDefinitions()
+        assertEquals("Number of method in GroupingCaseTest is incorrect", 1, containerAugment1.getMethodDefinitions()
                 .size());
 
-        assertEquals("Number of method in ContainerAugment1 is incorrect", 0, containerAugment1.getMethodDefinitions()
+        assertEquals("Number of method in ContainerAugment1 is incorrect", 1, containerAugment1.getMethodDefinitions()
                 .size());
-        assertEquals("Number of method in GroupingCaseTest is incorrect", 1, groupingAugmentTest.getMethodDefinitions()
+        assertEquals("Number of method in GroupingCaseTest is incorrect", 2, groupingAugmentTest.getMethodDefinitions()
                 .size());
 
         containsMethods(groupingAugmentTest.getMethodDefinitions(), new NameTypePattern("getLeafGroupingAugmentTest",
@@ -557,11 +556,11 @@ public class UsesTest {
 
         containsInterface("GroupingNotificationTest", notificationTest);
 
-        assertEquals("Number of method in NotificationTest is incorrect", 1, notificationTest.getMethodDefinitions()
+        assertEquals("Number of method in NotificationTest is incorrect", 2, notificationTest.getMethodDefinitions()
                 .size());
-        assertEquals("Number of method in GroupingNotificationTest is incorrect", 2, groupingNotificationTest
+        assertEquals("Number of method in GroupingNotificationTest is incorrect", 3, groupingNotificationTest
                 .getMethodDefinitions().size());
-        assertEquals("Number of method in ContainerGroupingNotificationTest is incorrect", 1,
+        assertEquals("Number of method in ContainerGroupingNotificationTest is incorrect", 2,
                 containerGroupingNotificationTest.getMethodDefinitions().size());
 
         containsMethods(notificationTest.getMethodDefinitions(), new NameTypePattern("getLeafNotificationTest",
index 1f7a83ea2bdf4a3bc15614127465106c5b8d6cfc..b6e38045ce14d79ebbec5f1dd27df69be42c043f 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.mdsal.binding.java.api.generator
 
 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTATION_FIELD
 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.AUGMENTABLE_AUGMENTATION_NAME
+import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
 
 import com.google.common.collect.ImmutableMap
 import java.util.List
@@ -40,6 +41,7 @@ class BuilderImplTemplate extends AbstractBuilderTemplate {
 
             «generateCopyConstructor(builderType, type)»
 
+            @«Deprecated.importedName»
             @«Override.importedName»
             public «Class.importedName»<«targetType.importedName»> getImplementedInterface() {
                 return «targetType.importedName».class;
@@ -98,7 +100,7 @@ class BuilderImplTemplate extends AbstractBuilderTemplate {
                 if (!(obj instanceof «DataObject.importedName»)) {
                     return false;
                 }
-                if (!«targetType.importedName».class.equals(((«DataObject.importedName»)obj).getImplementedInterface())) {
+                if (!«targetType.importedName».class.equals(((«DataObject.importedName»)obj).«DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»())) {
                     return false;
                 }
                 «targetType.importedName» other = («targetType.importedName»)obj;
index 8efa940ae895b811bbde165223ef12b418480ecc..c2479c3a9d9fe9b2da7d4013fdeb01ffeeb0a195 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.java.api.generator
 
+import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME
 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getGetterMethodForNonnull
 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.isGetterMethodName
 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.isNonnullMethodName
@@ -185,7 +186,11 @@ class InterfaceTemplate extends BaseTemplate {
 
     def private generateDefaultMethod(MethodSignature method) {
         if (method.name.isNonnullMethodName) {
-            return generateNonnullMethod(method)
+            generateNonnullMethod(method)
+        } else {
+            switch method.name {
+                case DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME : generateDefaultImplementedInterface
+            }
         }
     }
 
@@ -202,6 +207,13 @@ class InterfaceTemplate extends BaseTemplate {
         «nullableType(ret)» «method.name»();
     '''
 
+    def private generateDefaultImplementedInterface() '''
+        @«Override.importedName»
+        default «Class.importedName»<«type.fullyQualifiedName»> «DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME»() {
+            return «type.fullyQualifiedName».class;
+        }
+    '''
+
     def private generateNonnullMethod(MethodSignature method) '''
         «val ret = method.returnType»
         «val name = method.name»
index 29fd0ab01225240b49f670d500cfa317a2ce4967..2b5e5fdb4f0d1bf661f804c76dce1726ba34bf9e 100644 (file)
@@ -106,7 +106,7 @@ public class CompilationTest extends BaseCompilationTest {
         assertTrue(keyArgsClass.isInterface());
         CompilationTestUtils.assertContainsMethod(keyArgsClass, String.class, "getName");
         CompilationTestUtils.assertContainsMethod(keyArgsClass, Integer.class, "getSize");
-        assertEquals(2, abstractMethods(keyArgsClass).size());
+        assertEquals(3, abstractMethods(keyArgsClass).size());
 
         // Test generated 'list links'
         assertTrue(linksClass.isInterface());
index d02f05f4fffc5a27a57915e68bc2c05f479105bf..de0037a3a8ca1b972f19676fb491ecd2f3a27cc8 100644 (file)
@@ -77,8 +77,14 @@ public final class BindingMapping {
     /**
      * Name of {@link DataContainer#getImplementedInterface()}.
      */
+    // FIXME: 4.0.0: remove this constant
     public static final String DATA_CONTAINER_GET_IMPLEMENTED_INTERFACE_NAME = "getImplementedInterface";
 
+    /**
+     * Name of {@link DataContainer#implementedInterface()}.
+     */
+    public static final String DATA_CONTAINER_IMPLEMENTED_INTERFACE_NAME = "implementedInterface";
+
     /**
      * Prefix for getter methods working on top of boolean.
      */
index a960aaf325a27549b9c8eb5454161c8ada86cbca..a8374d00023963204d0eae939b995578832fc4b7 100644 (file)
@@ -99,7 +99,7 @@ public final class BindingReflections {
 
     /**
      * Find data hierarchy parent from concrete Data class. This method is shorthand which gets DataObject class by
-     * invoking {@link DataObject#getImplementedInterface()} and uses {@link #findHierarchicalParent(Class)}.
+     * invoking {@link DataObject#implementedInterface()} and uses {@link #findHierarchicalParent(Class)}.
      *
      * @param child
      *            Child object for which the parent needs to be located.
@@ -107,7 +107,7 @@ public final class BindingReflections {
      */
     public static Class<?> findHierarchicalParent(final DataObject child) {
         if (child instanceof ChildOf) {
-            return ClassLoaderUtils.findFirstGenericArgument(child.getImplementedInterface(), ChildOf.class);
+            return ClassLoaderUtils.findFirstGenericArgument(child.implementedInterface(), ChildOf.class);
         }
         return null;
     }
index ad239a3f8425afd8773f7c4d790003724d71cff8..914248409432e8566c50a91e67fb9fb49779c510 100644 (file)
@@ -90,7 +90,7 @@ public final class DataObjectReadingUtil {
     public static <T extends DataObject> Optional<T> readData(final DataObject source, final Class<T> child) {
         checkArgument(source != null, "Object should not be null.");
         checkArgument(child != null, "Child type should not be null");
-        Class<? extends DataContainer> parentClass = source.getImplementedInterface();
+        Class<? extends DataContainer> parentClass = source.implementedInterface();
 
         @SuppressWarnings("unchecked")
         T potential = (T) resolveReadStrategy(parentClass, child).read(source, child);
@@ -102,7 +102,7 @@ public final class DataObjectReadingUtil {
             final InstanceIdentifier parentPath, final PathArgument child) {
         checkArgument(parent != null, "Object should not be null.");
         checkArgument(child != null, "Child argument should not be null");
-        Class<? extends DataContainer> parentClass = parent.getImplementedInterface();
+        Class<? extends DataContainer> parentClass = parent.implementedInterface();
         return resolveReadStrategy(parentClass, child.getType()).readUsingPathArgument(parent, child, parentPath);
     }
 
index 208cd683539d5e1ca8884f0932fb72f6b8e32a4a..e629129389b3ec12f9556735f0699782e72027e7 100644 (file)
@@ -48,7 +48,7 @@ public class BindingReflectionsTest {
         assertNull(findHierarchicalParent(mock(DataObject.class)));
         assertEquals(GroupingFoo.class, BindingReflections.findHierarchicalParent(FooChild.class));
         final ChildOf<?> childOf = mock(FooChild.class);
-        doReturn(FooChild.class).when(childOf).getImplementedInterface();
+        doReturn(FooChild.class).when(childOf).implementedInterface();
         assertEquals(GroupingFoo.class, BindingReflections.findHierarchicalParent(childOf));
         assertTrue(BindingReflections.isRpcMethod(TestImplementation.class.getDeclaredMethod("rpcMethodTest")));
         assertEquals(TestImplementation.class, BindingReflections.findAugmentationTarget(TestImplementation.class));
index 390ad8f63843c9d45ef973a3503e1437a1f023dd..5289a077f9329cf532e761e98ee77b36d6de1e8c 100644 (file)
@@ -56,7 +56,7 @@ public class DataObjectReadingUtilTest {
     @Test
     public void testReadData() throws Exception {
         final Nodes nodes = mock(Nodes.class);
-        doReturn(Nodes.class).when(nodes).getImplementedInterface();
+        doReturn(Nodes.class).when(nodes).implementedInterface();
         doReturn(null).when(nodes).getNode();
         entry = ImmutableMap.<InstanceIdentifier<? extends DataObject>, DataObject>builder()
                 .put(path, nodes).build().entrySet().iterator().next();
index 9aaaabac937194fde78dc03aa1c6a2c62786bec6..b2745a572d489035455e097fb8a97e06d931dc09 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.binding;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Data Container - object contains structured data. Marker interface which must be implemented by all interfaces
  * generated for YANG:
@@ -20,6 +22,16 @@ package org.opendaylight.yangtools.yang.binding;
  * </ul>
  */
 public interface DataContainer {
-
+    /**
+     * Return the interface implemented by this object. This method differs from {@link Object#getClass()} in that it
+     * returns the interface contract, not a concrete implementation class.
+     *
+     * @return Implemented contract
+     * @deprecated Use {@link #implementedInterface()} instead.
+     */
+    // FIXME: 4.0.0: MDSAL-395: remove this method
+    @Deprecated
     Class<? extends DataContainer> getImplementedInterface();
+
+    @NonNull Class<? extends DataContainer> implementedInterface();
 }
index 0051833af7481b460a83413f8718fd9d0dfe9186..cf25e2da88b1dd2cbb8746e8aa1310496fcfd34d 100644 (file)
@@ -13,6 +13,6 @@ package org.opendaylight.yangtools.yang.binding;
  * @author Tony Tkacik
  */
 public interface DataObject extends DataContainer, BindingObject {
-
-
+    @Override
+    Class<? extends DataObject> implementedInterface();
 }
index f073fa705eca794083a7f2991971c4c3f75d03a1..bba5049d2249b0a4c4634ec530084230f8a9d9f4 100644 (file)
@@ -13,4 +13,3 @@ package org.opendaylight.yangtools.yang.binding;
 public interface Notification extends DataContainer {
 
 }
-
index b1664e0dea4aba97d854bcb455d301d70a628c20..4f04b27fb8cd5dbcc5459443a17945aa11067091 100644 (file)
@@ -12,5 +12,6 @@ package org.opendaylight.yangtools.yang.binding;
  * statement.
  */
 public interface RpcInput extends DataObject {
-
+    @Override
+    Class<? extends RpcInput> implementedInterface();
 }
index 3f0d07327341a0b29b077b09aad1cb44173be196..2f35be1ac07bf62291abc59ace4967020abd71c7 100644 (file)
@@ -17,5 +17,6 @@ import com.google.common.annotations.Beta;
  */
 @Beta
 public interface RpcOutput extends DataObject {
-
+    @Override
+    Class<? extends RpcOutput> implementedInterface();
 }
index 6be0adda8e0c25fcaec93e573bdf6065a169d848..cf22c64fdd37608c6f9259f5dd8fc85d56fcffbb 100644 (file)
@@ -13,7 +13,6 @@ import static org.junit.Assert.assertNotNull;
 
 import org.apache.commons.lang3.SerializationUtils;
 import org.junit.Test;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Identifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -73,15 +72,27 @@ public class EntityTest {
 
     static class TestDataObject1 implements DataObject {
         @Override
-        public Class<? extends DataContainer> getImplementedInterface() {
-            return null;
+        @Deprecated
+        public Class<? extends DataObject> getImplementedInterface() {
+            return DataObject.class;
+        }
+
+        @Override
+        public Class<? extends DataObject> implementedInterface() {
+            return DataObject.class;
         }
     }
 
     static class TestDataObject2 implements DataObject {
         @Override
-        public Class<? extends DataContainer> getImplementedInterface() {
-            return null;
+        @Deprecated
+        public Class<? extends DataObject> getImplementedInterface() {
+            return DataObject.class;
+        }
+
+        @Override
+        public Class<? extends DataObject> implementedInterface() {
+            return DataObject.class;
         }
     }
 }