Refactor PathArgument to DataObjectStep 92/109692/21
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 9 Jan 2024 20:14:59 +0000 (21:14 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 12 Jan 2024 20:04:59 +0000 (21:04 +0100)
InstanceIdentifier.PathArgument is the basic modeling construct for
expressing a path composed of DataObject type references.

Extract it to a top-level construct, DataObjectStep, which has tree
specializations. AbstractPathArgument is kept around for serialization
complatibility.

This has the nice property of capturing the three possible addressing
states, so we can discern them when we see them.

Furthermore there is now only YangInstanceIdentifier.PathArgument, which
makes for cleaner method signatures and imports.

JIRA: MDSAL-815
Change-Id: I22706ccaecae4b70e8afe2644fc74057953c32b0
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
45 files changed:
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/DataObjectModification.java
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/AbstractDataObjectModification.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/DataTreeChangeListenerTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/Mdsal298Test.java
binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/BindingDataContainerCodecTreeNode.java
binding/mdsal-binding-dom-codec-api/src/main/java/org/opendaylight/mdsal/binding/dom/codec/api/CommonDataObjectCodecTreeNode.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataObjectCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AugmentationCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingToNormalizedStreamWriter.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CaseCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CodecItemFactory.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CommonDataObjectCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ContainerLikeCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ContainerLikeCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/IdentifiableItemCodec.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/InstanceIdentifierCodec.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ListCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/MapCodecPrototype.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/StructuralContainerCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/StructuralContainerCodecPrototype.java
binding/mdsal-binding-dom-codec/src/test/java/org/opendaylight/mdsal/binding/dom/codec/impl/InstanceIdentifierSerializeDeserializeTest.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataObjectStep.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/ExactDataObjectStep.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/IIv4.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifier.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifierV3.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KIIv4.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyStep.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedInstanceIdentifier.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyedInstanceIdentifierV2.java
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeylessStep.java [new file with mode: 0644]
binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/NodeStep.java [new file with mode: 0644]
binding/yang-binding/src/test/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifierTest.java
binding/yang-binding/src/test/java/org/opendaylight/yangtools/yang/binding/KeyedInstanceIdentifierTest.java
trace/mdsal-trace-impl/src/main/java/org/opendaylight/mdsal/trace/impl/TracingBroker.java

index b58fea7bd3a400acd866b1c2d21bb680f9d2df32..82c1859602cd0d997d090ce4de35aaf7fff9db00 100644 (file)
@@ -10,11 +10,13 @@ package org.opendaylight.mdsal.binding.api;
 import java.util.Collection;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
+import org.opendaylight.yangtools.yang.binding.ExactDataObjectStep;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
 
@@ -24,9 +26,7 @@ import org.opendaylight.yangtools.yang.binding.KeyAware;
  *
  * @param <T> Type of modified object
  */
-public interface DataObjectModification<T extends DataObject> extends
-        org.opendaylight.yangtools.concepts.Identifiable<PathArgument> {
-
+public interface DataObjectModification<T extends DataObject> extends Identifiable<DataObjectStep<?>> {
     /**
      * Represents type of modification which has occurred.
      */
@@ -46,7 +46,7 @@ public interface DataObjectModification<T extends DataObject> extends
     }
 
     @Override
-    PathArgument getIdentifier();
+    DataObjectStep<?> getIdentifier();
 
     /**
      * Returns type of modified object.
@@ -182,11 +182,10 @@ public interface DataObjectModification<T extends DataObject> extends
     /**
      * Returns a child modification if a node identified by {@code childArgument} was modified by this modification.
      *
-     * @param childArgument Path Argument of child node
-     * @return Modification of child identified by {@code childArgument} if {@code childArgument}
-     *         was modified, null otherwise.
-     * @throws IllegalArgumentException If supplied path argument is not valid child according to
-     *         generated model.
+     * @param childArgument {@link ExactDataObjectStep} of child node
+     * @return Modification of child identified by {@code childArgument} if {@code childArgument} was modified,
+     *         {@code null} otherwise
+     * @throws IllegalArgumentException If supplied step is not valid child according to generated model
      */
-    @Nullable DataObjectModification<? extends DataObject> getModifiedChild(PathArgument childArgument);
+    @Nullable DataObjectModification<? extends DataObject> getModifiedChild(ExactDataObjectStep<?> childArgument);
 }
index f879b96d902361b6a4c87e4d67981525c4c58f9c..a7e28bab404dba2b3beed3a0708396ea39a112c5 100644 (file)
@@ -71,7 +71,7 @@ class DataTreeIdentifierTest {
         }
 
         final var bytes = bos.toByteArray();
-        assertEquals(450, bytes.length);
+        assertEquals(342, bytes.length);
 
         try (var ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
             assertEquals(TEST_IDENTIFIER1, ois.readObject());
index 71d306df30e36b1eb528098ce8a8a40f40fb8a48..987639da7c709d68a702af8b0c81c18a2b1ce610 100644 (file)
@@ -36,11 +36,12 @@ import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
+import org.opendaylight.yangtools.yang.binding.ExactDataObjectStep;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
+import org.opendaylight.yangtools.yang.binding.KeyStep;
+import org.opendaylight.yangtools.yang.binding.NodeStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidateNode;
@@ -85,7 +86,7 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     }
 
     final @NonNull DataTreeCandidateNode domData;
-    final @NonNull PathArgument identifier;
+    final @NonNull DataObjectStep<?> identifier;
     final @NonNull N codec;
 
     @SuppressWarnings("unused")
@@ -101,9 +102,9 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
     private volatile Object dataAfter;
 
-    AbstractDataObjectModification(final DataTreeCandidateNode domData, final N codec, final PathArgument identifier) {
+    AbstractDataObjectModification(final DataTreeCandidateNode domData, final N codec, final DataObjectStep<?> step) {
         this.domData = requireNonNull(domData);
-        this.identifier = requireNonNull(identifier);
+        identifier = requireNonNull(step);
         this.codec = requireNonNull(codec);
     }
 
@@ -124,7 +125,7 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     }
 
     @Override
-    public final PathArgument getIdentifier() {
+    public final DataObjectStep<?> getIdentifier() {
         return identifier;
     }
 
@@ -189,7 +190,7 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     abstract @Nullable T deserialize(@NonNull NormalizedNode normalized);
 
     @Override
-    public final DataObjectModification<?> getModifiedChild(final PathArgument arg) {
+    public final DataObjectModification<?> getModifiedChild(final ExactDataObjectStep<?> arg) {
         final var domArgumentList = new ArrayList<YangInstanceIdentifier.PathArgument>();
         final var childCodec = codec.bindingPathArgumentChild(arg, domArgumentList);
         final var toEnter = domArgumentList.iterator();
@@ -225,7 +226,7 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     public final <H extends ChoiceIn<? super T> & DataObject, C extends ChildOf<? super H>>
             List<DataObjectModification<C>> getModifiedChildren(final Class<H> caseType, final Class<C> childType) {
         return streamModifiedChildren(childType)
-            .filter(child -> caseType.equals(child.identifier.getCaseType().orElse(null)))
+            .filter(child -> caseType.equals(child.identifier.caseType()))
             .collect(Collectors.toList());
     }
 
@@ -251,7 +252,7 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     @SuppressWarnings("unchecked")
     public final <C extends KeyAware<K> & ChildOf<? super T>, K extends Key<C>> DataObjectModification<C>
             getModifiedChildListItem(final Class<C> listItem, final K listKey) {
-        return (DataObjectModification<C>) getModifiedChild(IdentifiableItem.of(listItem, listKey));
+        return (DataObjectModification<C>) getModifiedChild(new KeyStep<>(listItem, listKey));
     }
 
     @Override
@@ -259,28 +260,28 @@ abstract sealed class AbstractDataObjectModification<T extends DataObject, N ext
     public final <H extends ChoiceIn<? super T> & DataObject, C extends KeyAware<K> & ChildOf<? super H>,
             K extends Key<C>> DataObjectModification<C> getModifiedChildListItem(final Class<H> caseType,
                     final Class<C> listItem, final K listKey) {
-        return (DataObjectModification<C>) getModifiedChild(IdentifiableItem.of(caseType, listItem, listKey));
+        return (DataObjectModification<C>) getModifiedChild(new KeyStep<>(listItem, caseType, listKey));
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public final <C extends ChildOf<? super T>> DataObjectModification<C> getModifiedChildContainer(
             final Class<C> child) {
-        return (DataObjectModification<C>) getModifiedChild(Item.of(child));
+        return (DataObjectModification<C>) getModifiedChild(new NodeStep<>(child));
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public final <H extends ChoiceIn<? super T> & DataObject, C extends ChildOf<? super H>> DataObjectModification<C>
             getModifiedChildContainer(final Class<H> caseType, final Class<C> child) {
-        return (DataObjectModification<C>) getModifiedChild(Item.of(caseType, child));
+        return (DataObjectModification<C>) getModifiedChild(new NodeStep<>(caseType, child));
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public final <C extends Augmentation<T> & DataObject> DataObjectModification<C> getModifiedAugmentation(
             final Class<C> augmentation) {
-        return (DataObjectModification<C>) getModifiedChild(Item.of(augmentation));
+        return (DataObjectModification<C>) getModifiedChild(new NodeStep<>(augmentation));
     }
 
     @Override
index 99867ca96d5999f22ab202fb894e725986470df6..58a61e2078dd8d376438ec3d5aaa9f985ba72a1d 100644 (file)
@@ -40,19 +40,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.te
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.TwoLevelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.binding.rev140701.two.level.list.TopLevelList;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 
 public class DataTreeChangeListenerTest extends AbstractDataBrokerTest {
 
     private static final InstanceIdentifier<Top> TOP_PATH = InstanceIdentifier.create(Top.class);
-    private static final PathArgument TOP_ARGUMENT = TOP_PATH.getPathArguments().iterator().next();
+    private static final DataObjectStep<?> TOP_ARGUMENT = TOP_PATH.getPathArguments().iterator().next();
     private static final InstanceIdentifier<TopLevelList> FOO_PATH = path(TOP_FOO_KEY);
-    private static final PathArgument FOO_ARGUMENT = Iterables.getLast(FOO_PATH.getPathArguments());
+    private static final DataObjectStep<?> FOO_ARGUMENT = Iterables.getLast(FOO_PATH.getPathArguments());
     private static final TopLevelList FOO_DATA = topLevelList(TOP_FOO_KEY, complexUsesAugment(USES_ONE_KEY));
     private static final InstanceIdentifier<TopLevelList> BAR_PATH = path(TOP_BAR_KEY);
-    private static final PathArgument BAR_ARGUMENT = Iterables.getLast(BAR_PATH.getPathArguments());
+    private static final DataObjectStep<?> BAR_ARGUMENT = Iterables.getLast(BAR_PATH.getPathArguments());
     private static final TopLevelList BAR_DATA = topLevelList(TOP_BAR_KEY);
     private static final DataTreeIdentifier<Top> TOP_IDENTIFIER
             = DataTreeIdentifier.of(LogicalDatastoreType.OPERATIONAL, TOP_PATH);
@@ -167,8 +167,8 @@ public class DataTreeChangeListenerTest extends AbstractDataBrokerTest {
     }
 
     private static void verifyModification(final DataObjectModification<? extends DataObject> barWrite,
-            final PathArgument pathArg, final ModificationType eventType) {
-        assertEquals(pathArg.getType(), barWrite.getDataType());
+            final DataObjectStep<?> pathArg, final ModificationType eventType) {
+        assertEquals(pathArg.type(), barWrite.getDataType());
         assertEquals(eventType,barWrite.getModificationType());
         assertEquals(pathArg, barWrite.getIdentifier());
     }
index d036163baf4e451e8c3a873cc3c3921f948ba0b6..956d09756e65f2c23d2aab60ac2f88d20035c4e1 100644 (file)
@@ -50,7 +50,7 @@ import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal298.rev180129.wit
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.DataRoot;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.NodeStep;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@@ -106,7 +106,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
             .build());
         domTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<Container>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -114,7 +114,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         final DataTreeModification<Container> change = capture.iterator().next();
         assertEquals(CONTAINER_TID, change.getRootPath());
         final DataObjectModification<Container> changedContainer = change.getRootNode();
-        assertEquals(Item.of(Container.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(Container.class), changedContainer.getIdentifier());
         assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.getModificationType());
 
         final Container containerAfter = changedContainer.getDataAfter();
@@ -161,7 +161,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
             .build());
         domTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<Container>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -169,7 +169,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         final DataTreeModification<Container> change = capture.iterator().next();
         assertEquals(CONTAINER_TID, change.getRootPath());
         final DataObjectModification<Container> changedContainer = change.getRootNode();
-        assertEquals(Item.of(Container.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(Container.class), changedContainer.getIdentifier());
         assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
 
         final Container containerAfter = changedContainer.getDataAfter();
@@ -193,7 +193,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         writeTx.put(CONFIGURATION, ADDRESSABLE_CASE, new AddressableBuilder().build());
         writeTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<WithChoice>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -202,7 +202,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         assertEquals(CHOICE_CONTAINER_TID, choiceChange.getRootPath());
         final DataObjectModification<WithChoice> changedContainer = choiceChange.getRootNode();
         assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.getModificationType());
-        assertEquals(Item.of(WithChoice.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(WithChoice.class), changedContainer.getIdentifier());
 
         final Collection<? extends DataObjectModification<?>> choiceChildren = changedContainer.getModifiedChildren();
         assertEquals(1, choiceChildren.size());
@@ -210,7 +210,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         final DataObjectModification<Addressable> changedCase = (DataObjectModification<Addressable>) choiceChildren
                 .iterator().next();
         assertEquals(ModificationType.WRITE, changedCase.getModificationType());
-        assertEquals(Item.of(Addressable.class), changedCase.getIdentifier());
+        assertEquals(new NodeStep<>(Addressable.class), changedCase.getIdentifier());
         assertEquals(new AddressableBuilder().build(), changedCase.getDataAfter());
     }
 
@@ -226,7 +226,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
             new AddressableChildBuilder().build());
         writeTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<AddressableCont>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -235,7 +235,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         assertEquals(ADDRESSABLE_CONTAINER_TID, contChange.getRootPath());
         final DataObjectModification<AddressableCont> changedContainer = contChange.getRootNode();
         assertEquals(ModificationType.SUBTREE_MODIFIED, changedContainer.getModificationType());
-        assertEquals(Item.of(AddressableCont.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(AddressableCont.class), changedContainer.getIdentifier());
 
         final Collection<? extends DataObjectModification<?>> contChildren = changedContainer.getModifiedChildren();
         assertEquals(1, contChildren.size());
@@ -243,7 +243,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         final DataObjectModification<Addressable> changedChild = (DataObjectModification<Addressable>) contChildren
                 .iterator().next();
         assertEquals(ModificationType.WRITE, changedChild.getModificationType());
-        assertEquals(Item.of(AddressableChild.class), changedChild.getIdentifier());
+        assertEquals(new NodeStep<>(AddressableChild.class), changedChild.getIdentifier());
         assertEquals(new AddressableChildBuilder().build(), changedChild.getDataAfter());
     }
 
@@ -260,7 +260,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
             ImmutableNodes.leafNode(BAZ_QNAME, "baz"));
         domTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<UnaddressableCont>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -269,7 +269,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         assertEquals(UNADDRESSABLE_CONTAINER_TID, contChange.getRootPath());
         final DataObjectModification<UnaddressableCont> changedContainer = contChange.getRootNode();
         assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
-        assertEquals(Item.of(UnaddressableCont.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(UnaddressableCont.class), changedContainer.getIdentifier());
 
         final Collection<? extends DataObjectModification<?>> contChildren = changedContainer.getModifiedChildren();
         assertEquals(0, contChildren.size());
@@ -292,7 +292,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
             .build());
         domTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<WithChoice>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -303,7 +303,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
 
         // Should be write
         assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
-        assertEquals(Item.of(WithChoice.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(WithChoice.class), changedContainer.getIdentifier());
 
         final Collection<? extends DataObjectModification<?>> choiceChildren = changedContainer.getModifiedChildren();
         assertEquals(0, choiceChildren.size());
@@ -332,7 +332,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         assertEquals(dti, change.getRootPath());
         final DataObjectModification<T> changedContainer = change.getRootNode();
         assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
-        assertEquals(Item.of(bindingClass), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(bindingClass), changedContainer.getIdentifier());
 
         final T containerAfter = changedContainer.getDataAfter();
         assertEquals(expected, containerAfter);
@@ -359,7 +359,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
             .build());
         domTx.commit().get();
 
-        final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class);
+        final var captor = ArgumentCaptor.forClass(Collection.class);
         verify(listener).onDataTreeChanged(captor.capture());
         Collection<DataTreeModification<WithChoice>> capture = captor.getValue();
         assertEquals(1, capture.size());
@@ -368,7 +368,7 @@ public class Mdsal298Test extends AbstractDataBrokerTest {
         assertEquals(CHOICE_CONTAINER_TID, change.getRootPath());
         final DataObjectModification<WithChoice> changedContainer = change.getRootNode();
         assertEquals(ModificationType.WRITE, changedContainer.getModificationType());
-        assertEquals(Item.of(WithChoice.class), changedContainer.getIdentifier());
+        assertEquals(new NodeStep<>(WithChoice.class), changedContainer.getIdentifier());
 
         final WithChoice containerAfter = changedContainer.getDataAfter();
         assertEquals(new WithChoiceBuilder().build(), containerAfter);
index c2ef310ca47b3f3162781a2a2cf7d3d501e4e19d..7ae64f48cfb728359b38651afc953133fa4fd078 100644 (file)
@@ -14,9 +14,9 @@ import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BindingContract;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.common.Empty;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
 /**
  * A {@link BindingObjectCodecTreeNode} which corresponds to a {@link DataContainer} construct.
@@ -76,31 +76,26 @@ public non-sealed interface BindingDataContainerCodecTreeNode<T extends DataCont
     }
 
     /**
-     * Returns nested node context using supplied YANG Instance Identifier.
+     * Returns nested node context using supplied {@link PathArgument}.
      *
-     * @param child
-     *            Yang Instance Identifier Argument
+     * @param child a {@link PathArgument}
      * @return Context of child
-     * @throws IllegalArgumentException
-     *             If supplied argument does not represent valid child.
+     * @throws IllegalArgumentException If supplied argument does not represent valid child.
      */
-    @NonNull BindingCodecTreeNode yangPathArgumentChild(YangInstanceIdentifier.@NonNull PathArgument child);
+    @NonNull BindingCodecTreeNode yangPathArgumentChild(@NonNull PathArgument child);
 
     /**
-     * Returns nested node context using supplied Binding Instance Identifier and adds YANG instance identifiers to
+     * Returns nested node context using supplied DataObjectStep and adds YANG instance identifiers to
      * the supplied list.
      *
-     * @param arg
-     *            Binding Instance Identifier Argument
-     * @param builder
-     *            Mutable instance of list, which is appended by YangInstanceIdentifiers
-     *            as tree is walked. Use null if such side-product is not needed.
-     * @return Context of child
-     * @throws IllegalArgumentException
-     *             If supplied argument does not represent valid child.
+     * @param step A {@link DataObjectStep}
+     * @param builder a mutable List to receive {@link PathArgument}s. Use {@code null} if such side-product is not
+     *                needed.
+     * @return A {@link CommonDataObjectCodecTreeNode}
+     * @throws IllegalArgumentException if supplied argument does not represent valid child.
      */
-    @NonNull CommonDataObjectCodecTreeNode<?> bindingPathArgumentChild(InstanceIdentifier.@NonNull PathArgument arg,
-            @Nullable List<YangInstanceIdentifier.PathArgument> builder);
+    @NonNull CommonDataObjectCodecTreeNode<?> bindingPathArgumentChild(@NonNull DataObjectStep<?> step,
+            @Nullable List<PathArgument> builder);
 
     /**
      * Return a summary of addressability of potential children. Binding specification does not allow all DOM tree
index e54b7d3a64fb7fb553c967934c1cd4164872ef0c..05f1734a14db57a139bebaa6dadb83eb984ac8f7 100644 (file)
@@ -10,8 +10,10 @@ package org.opendaylight.mdsal.binding.dom.codec.api;
 import com.google.common.annotations.Beta;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
 /**
  * Common interface shared between {@link BindingDataObjectCodecTreeNode} and {@link BindingAugmentationCodecTreeNode}.
@@ -21,27 +23,26 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
  */
 public interface CommonDataObjectCodecTreeNode<T extends DataObject> extends BindingDataContainerCodecTreeNode<T> {
     /**
-     * Serializes path argument for current node.
+     * Serializes the instance identifier step for current node.
      *
-     * @param arg Binding Path Argument, may be null if Binding Instance Identifier does not have a representation for
-     *            current node (e.g. choice or case).
-     * @return Yang Path Argument, may be null if Yang Instance Identifier does not have representation for current node
-     *         (e.g. case).
+     * @param step {@link DataObjectStep}, may be null if {@link InstanceIdentifier} does not have a representation for
+     *             current node (e.g. choice or case).
+     * @return {@link PathArgument}, may be null if {@link YangInstanceIdentifier} does not have representation for
+     *         current node (e.g. case).
      * @throws IllegalArgumentException If supplied {@code arg} is not valid.
      */
     @Beta
-    YangInstanceIdentifier.@Nullable PathArgument serializePathArgument(InstanceIdentifier.@Nullable PathArgument arg);
+    @Nullable PathArgument serializePathArgument(@Nullable DataObjectStep<?> step);
 
     /**
-     * Deserializes path argument for current node.
+     * Deserializes {@link PathArgument} for current node.
      *
-     * @param arg Yang Path Argument, may be null if Yang Instance Identifier does not have
-     *         representation for current node (e.g. case).
-     * @return Binding Path Argument, may be null if Binding Instance Identifier does not have
-     *        representation for current node (e.g. choice or case).
+     * @param arg a {@link PathArgument}, may be null if {@link YangInstanceIdentifier} does not have a representation
+     *            for current node (e.g. case).
+     * @return {@link DataObjectStep}, may be null if {@link InstanceIdentifier} does not have a representation for
+     *         current node (e.g. choice or case).
      * @throws IllegalArgumentException If supplied {@code arg} is not valid.
      */
     @Beta
-    InstanceIdentifier.@Nullable PathArgument deserializePathArgument(
-            YangInstanceIdentifier.@Nullable PathArgument arg);
+    @Nullable DataObjectStep<?> deserializePathArgument(@Nullable PathArgument arg);
 }
index 65394235dd76559feeb04737c84ac930ce0d81c9..83e9b0f721511dafc0b1aa28e148adba2ddac910 100644 (file)
@@ -17,7 +17,7 @@ import org.opendaylight.mdsal.binding.dom.codec.api.IncorrectNestingException;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
@@ -69,17 +69,17 @@ public abstract sealed class AbstractDataObjectCodecContext<D extends DataObject
     }
 
     @Override
-    public final CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(final InstanceIdentifier.PathArgument arg,
+    public final CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(final DataObjectStep<?> step,
             final List<PathArgument> builder) {
-        final var argType = arg.getType();
-        final var context = childNonNull(pathChildPrototype(argType), argType,
-            "Class %s is not valid child of %s", argType, getBindingClass())
+        final var type = step.type();
+        final var context = childNonNull(pathChildPrototype(type), type,
+            "Class %s is not valid child of %s", type, getBindingClass())
             .getCodecContext();
-        context.addYangPathArgument(arg, builder);
+        context.addYangPathArgument(step, builder);
         if (context instanceof CommonDataObjectCodecContext<?, ?> dataObject) {
             return dataObject;
         } else if (context instanceof ChoiceCodecContext<?> choice) {
-            return choice.bindingPathArgumentChild(arg, builder);
+            return choice.bindingPathArgumentChild(step, builder);
         } else {
             throw new IllegalStateException("Unhandled context " + context);
         }
index 3d0e09f59dd1e540e456d7067f15627e5a29bf27..d7842638aadb4a0c1020a81f8575cc05af36d647 100644 (file)
@@ -18,7 +18,7 @@ import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTree
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
@@ -55,15 +55,15 @@ final class AugmentationCodecContext<D extends DataObject & Augmentation<?>>
     }
 
     @Override
-    public PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
-        if (!bindingArg().equals(arg)) {
-            throw new IllegalArgumentException("Unexpected argument " + arg);
+    public PathArgument serializePathArgument(final DataObjectStep<?> step) {
+        if (!bindingArg().equals(step)) {
+            throw new IllegalArgumentException("Unexpected argument " + step);
         }
         return null;
     }
 
     @Override
-    public InstanceIdentifier.PathArgument deserializePathArgument(final PathArgument arg) {
+    public DataObjectStep<?> deserializePathArgument(final PathArgument arg) {
         if (arg != null) {
             throw new IllegalArgumentException("Unexpected argument " + arg);
         }
@@ -97,7 +97,7 @@ final class AugmentationCodecContext<D extends DataObject & Augmentation<?>>
     }
 
     @Override
-    void addYangPathArgument(final List<PathArgument> builder, final InstanceIdentifier.PathArgument arg) {
+    void addYangPathArgument(final List<PathArgument> builder, final DataObjectStep<?> step) {
         // No-op
     }
 
index dccf09ae3ca6f02174d0c9020c80e7639a2a35cd..5f10f1abc5d8e6321da7a9aa781f2eb58ff2523a 100644 (file)
@@ -13,16 +13,16 @@ import com.google.common.collect.ImmutableSet;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.NodeStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 final class AugmentationCodecPrototype extends CommonDataObjectCodecPrototype<AugmentRuntimeType> {
     private final @NonNull ImmutableSet<NodeIdentifier> childArgs;
 
     @SuppressWarnings("unchecked")
-    AugmentationCodecPrototype(final Class<?> cls, final AugmentRuntimeType type, final CodecContextFactory factory,
-            final ImmutableSet<NodeIdentifier> childArgs) {
-        super(Item.of((Class<? extends DataObject>) cls), type, factory);
+    AugmentationCodecPrototype(final @NonNull Class<?> cls, final AugmentRuntimeType type,
+            final CodecContextFactory factory, final ImmutableSet<NodeIdentifier> childArgs) {
+        super(new NodeStep<>((Class<? extends DataObject>) cls), type, factory);
         this.childArgs = requireNonNull(childArgs);
     }
 
index 2b351405b471bef7c1619eda01406cfe9c6e10ef..c6cf57a0419836e57494780377694a82f1c890b0 100644 (file)
@@ -76,6 +76,7 @@ import org.opendaylight.yangtools.yang.binding.BaseNotification;
 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
@@ -429,23 +430,23 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri
     @NonNull DataContainerCodecContext<?, ?, ?> getCodecContextNode(final InstanceIdentifier<?> binding,
             final List<PathArgument> builder) {
         final var it = binding.getPathArguments().iterator();
-        final var arg = it.next();
-
-        DataContainerCodecContext<?, ?, ?> current;
-        final var caseType = arg.getCaseType();
-        if (caseType.isPresent()) {
-            final @NonNull Class<? extends DataObject> type = caseType.orElseThrow();
-            final var choice = choicesByClass.getUnchecked(type);
-            choice.addYangPathArgument(arg, builder);
-            final var caze = choice.getStreamChild(type);
-            caze.addYangPathArgument(arg, builder);
-            current = caze.bindingPathArgumentChild(arg, builder);
+        final var step = it.next();
+
+        final DataContainerCodecContext<?, ?, ?> start;
+        final var caseType = step.caseType();
+        if (caseType != null) {
+            final var choice = choicesByClass.getUnchecked(caseType);
+            choice.addYangPathArgument(step, builder);
+            final var caze = choice.getStreamChild(caseType);
+            caze.addYangPathArgument(step, builder);
+            start = caze.bindingPathArgumentChild(step, builder);
         } else {
-            final var child = getStreamChild(arg.getType());
-            child.addYangPathArgument(arg, builder);
-            current = child;
+            final var child = getStreamChild(step.type());
+            child.addYangPathArgument(step, builder);
+            start = child;
         }
 
+        var current = start;
         while (it.hasNext()) {
             current = current.bindingPathArgumentChild(it.next(), builder);
         }
@@ -465,7 +466,7 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri
      * @throws IllegalArgumentException if {@code dom} is empty
      */
     @Nullable BindingDataObjectCodecTreeNode<?> getCodecContextNode(final @NonNull YangInstanceIdentifier dom,
-            final @Nullable Collection<InstanceIdentifier.PathArgument> bindingArguments) {
+            final @Nullable Collection<DataObjectStep<?>> bindingArguments) {
         final var it = dom.getPathArguments().iterator();
         if (!it.hasNext()) {
             throw new IllegalArgumentException("Path may not be empty");
@@ -885,7 +886,7 @@ public final class BindingCodecContext extends AbstractBindingNormalizedNodeSeri
             return null;
         }
 
-        final var builder = new ArrayList<InstanceIdentifier.PathArgument>();
+        final var builder = new ArrayList<DataObjectStep<?>>();
         final var codec = getCodecContextNode(path, builder);
         if (codec == null) {
             if (data != null) {
index 7ae433121825ed9b304cb44375bdcbd139a2c9d6..2bf031865aa797280b751faf408213c6175b1f9f 100644 (file)
@@ -24,10 +24,10 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
 import org.opendaylight.yangtools.yang.binding.OpaqueObject;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 
@@ -65,7 +65,7 @@ final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWrite
     }
 
     @SuppressWarnings({"unchecked", "rawtypes"})
-    private <T extends YangInstanceIdentifier.PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
+    private <T extends PathArgument> T enter(final Class<?> name, final Class<T> identifier) {
         final var current = current();
         final CodecContext next;
         if (current == null) {
@@ -80,7 +80,7 @@ final class BindingToNormalizedStreamWriter implements AnydataBindingStreamWrite
         return identifier.cast(next.getDomPathArgument());
     }
 
-    private <T extends YangInstanceIdentifier.PathArgument> T enter(final String localName, final Class<T> identifier) {
+    private <T extends PathArgument> T enter(final String localName, final Class<T> identifier) {
         final var current = current();
         final var next = ((AbstractDataObjectCodecContext<?, ?>) current).getLeafChild(localName);
         schema.push(next);
index 11d59e47a0947a6c535df690f574c92d9aac6f6d..4e3d7482d38477d9988e225af8a35a3aca64f7ad 100644 (file)
@@ -7,13 +7,11 @@
  */
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 import java.util.List;
 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
@@ -23,7 +21,7 @@ final class CaseCodecContext<D extends DataObject> extends DataObjectCodecContex
     }
 
     @Override
-    void addYangPathArgument(final List<YangInstanceIdentifier.PathArgument> builder, final PathArgument arg) {
+    void addYangPathArgument(final List<PathArgument> builder, final DataObjectStep<?> step) {
         // NOOP
     }
 
@@ -38,14 +36,18 @@ final class CaseCodecContext<D extends DataObject> extends DataObjectCodecContex
     }
 
     @Override
-    public YangInstanceIdentifier.PathArgument serializePathArgument(final PathArgument arg) {
-        checkArgument(arg == null, "Unexpected argument %s", arg);
+    public PathArgument serializePathArgument(final DataObjectStep<?> step) {
+        if (step != null) {
+            throw new IllegalArgumentException("Unexpected argument " + step);
+        }
         return null;
     }
 
     @Override
-    public PathArgument deserializePathArgument(final YangInstanceIdentifier.PathArgument arg) {
-        checkArgument(arg == null, "Unexpected argument %s", arg);
+    public DataObjectStep<?> deserializePathArgument(final PathArgument arg) {
+        if (arg != null) {
+            throw new IllegalArgumentException("Unexpected argument " + arg);
+        }
         return null;
     }
 }
index 8454de4f25a283c49e07ded78f501b23ad5e5429..918b34c5b65393ed070e818f033ac1de7555c4aa 100644 (file)
@@ -33,10 +33,10 @@ import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.contract.Naming;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
@@ -216,7 +216,7 @@ final class ChoiceCodecContext<T extends ChoiceIn<?>>
     }
 
     @Override
-    public CodecContext yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg) {
+    public CodecContext yangPathArgumentChild(final PathArgument arg) {
         return ((CaseCodecContext<?>) super.yangPathArgumentChild(arg)).yangPathArgumentChild(arg);
     }
 
@@ -241,20 +241,14 @@ final class ChoiceCodecContext<T extends ChoiceIn<?>>
     }
 
     @Override
-    public CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(final PathArgument arg,
-            final List<YangInstanceIdentifier.PathArgument> builder) {
-        final var caseType = arg.getCaseType();
-        final var type = arg.getType();
-        final DataContainerCodecContext<?, ?, ?> caze;
-        if (caseType.isPresent()) {
-            // Non-ambiguous addressing this should not pose any problems
-            caze = getStreamChild(caseType.orElseThrow());
-        } else {
-            caze = getCaseByChildClass(type);
-        }
-
-        caze.addYangPathArgument(arg, builder);
-        return caze.bindingPathArgumentChild(arg, builder);
+    public CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(final DataObjectStep<?> step,
+            final List<PathArgument> builder) {
+        final var caseType = step.caseType();
+        // Prefer non-ambiguous addressing, which should not pose any problems. Otherwise fall back to checking for
+        // ambiguities
+        final var caze = caseType != null ? getStreamChild(caseType) : getCaseByChildClass(step.type());
+        caze.addYangPathArgument(step, builder);
+        return caze.bindingPathArgumentChild(step, builder);
     }
 
     private DataContainerCodecContext<?, ?, ?> getCaseByChildClass(final @NonNull Class<? extends DataObject> type) {
index 10a3248a1c29f2e2d6426bbfdb98fe6c15e34ef8..bc0eb020c9dc68ea6c89dcdfefa46fbeecaff8f2 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 import static java.util.Objects.requireNonNull;
 
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 
@@ -25,10 +25,11 @@ sealed class CodecItemFactory {
 
         @Override
         @SuppressWarnings({ "rawtypes", "unchecked" })
-        Item<?> createItem(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
+        DataObjectStep<?> createItem(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
             // FIXME: MDSAL-697: see overridden method for further guidance
             return childSchema instanceof AddedByUsesAware aware && aware.isAddedByUses()
-                ? Item.of((Class) bindingClass, (Class) childClass) : super.createItem(childClass, childSchema);
+                ? InstanceIdentifier.createStep((Class) bindingClass, (Class) childClass)
+                    : super.createItem(childClass, childSchema);
         }
     }
 
@@ -44,9 +45,8 @@ sealed class CodecItemFactory {
     //        receiving childSchema from it via findChildSchemaDefinition, we should be able to receive the equivalent
     //        of Map.Entry<Item, DataSchemaNode>, along with the override we create here. One more input we may need to
     //        provide is our bindingClass().
-    @SuppressWarnings("unchecked")
-    Item<?> createItem(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
-        return Item.of((Class<? extends DataObject>) childClass);
+    DataObjectStep<?> createItem(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
+        return InstanceIdentifier.createStep((Class) childClass);
     }
 
     static @NonNull CodecItemFactory of() {
index 219ef7ca84654ec37ea48455658b159c2158c3f7..1e38caae1a06eb677e1298c3581a19f215588baf 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 import org.opendaylight.mdsal.binding.dom.codec.api.CommonDataObjectCodecTreeNode;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
 /**
  * Base implementation of {@link CommonDataObjectCodecTreeNode}.
@@ -27,11 +27,11 @@ abstract sealed class CommonDataObjectCodecContext<D extends DataObject, T exten
     /**
      * Returns deserialized Binding Path Argument from YANG instance identifier.
      */
-    protected PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
+    protected DataObjectStep<?> getBindingPathArgument(final PathArgument domArg) {
         return bindingArg();
     }
 
-    protected final PathArgument bindingArg() {
+    protected final DataObjectStep<?> bindingArg() {
         return prototype().getBindingArg();
     }
 }
index 0962fea4adc133c33f9fa920b9e141c80a3a82cc..18e84c33c64e5f2202a02a14af85519c5147b9d0 100644 (file)
@@ -12,7 +12,7 @@ import static java.util.Objects.requireNonNull;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 
 /**
  * Common superclass for {@link DataObjectCodecPrototype} and {@link AugmentationCodecPrototype}.
@@ -22,19 +22,20 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
 abstract sealed class CommonDataObjectCodecPrototype<R extends CompositeRuntimeType>
         extends DataContainerPrototype<CommonDataObjectCodecContext<?, R>, R>
         permits AugmentationCodecPrototype, DataObjectCodecPrototype {
-    private final @NonNull Item<?> bindingArg;
+    private final @NonNull DataObjectStep<?> step;
 
-    CommonDataObjectCodecPrototype(final Item<?> bindingArg, final R runtimeType, final CodecContextFactory factory) {
+    CommonDataObjectCodecPrototype(final DataObjectStep<?> step, final R runtimeType,
+            final CodecContextFactory factory) {
         super(factory, runtimeType);
-        this.bindingArg = requireNonNull(bindingArg);
+        this.step = requireNonNull(step);
     }
 
     @Override
     final Class<? extends DataObject> javaClass() {
-        return bindingArg.getType();
+        return step.type();
     }
 
-    final @NonNull Item<?> getBindingArg() {
-        return bindingArg;
+    final @NonNull DataObjectStep<?> getBindingArg() {
+        return step;
     }
 }
index b906ff3f2569dd35575f42b41d94127dc6451ac1..c3fc7ea7e232e5b0f678c88e4fee8c9111306b20 100644 (file)
@@ -9,7 +9,7 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.NodeStep;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
@@ -18,7 +18,7 @@ sealed class ContainerLikeCodecContext<D extends DataObject>
         permits StructuralContainerCodecContext {
     ContainerLikeCodecContext(final Class<D> cls, final ContainerLikeRuntimeType<?, ?> type,
             final CodecContextFactory factory) {
-        this(new ContainerLikeCodecPrototype(Item.of(cls), type, factory));
+        this(new ContainerLikeCodecPrototype(new NodeStep<>(cls), type, factory));
     }
 
     ContainerLikeCodecContext(final ContainerLikeCodecPrototype prototype) {
index bfc9f009afc450465b5aca7ffe666221a6f0fdcc..3d7a253be5e989bc1d77b21c4adb7a5d8cab050e 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 /**
@@ -16,9 +16,9 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
  */
 sealed class ContainerLikeCodecPrototype extends DataObjectCodecPrototype<ContainerLikeRuntimeType<?, ?>>
         permits StructuralContainerCodecPrototype {
-    ContainerLikeCodecPrototype(final Item<?> item, final ContainerLikeRuntimeType<?, ?> type,
+    ContainerLikeCodecPrototype(final DataObjectStep<?> step, final ContainerLikeRuntimeType<?, ?> type,
             final CodecContextFactory factory) {
-        super(item, NodeIdentifier.create(type.statement().argument()), type, factory);
+        super(step, NodeIdentifier.create(type.statement().argument()), type, factory);
     }
 
     @Override
index ebd628c0ff1c5c4fcdb41cf482a2c4d1df95a573..2848884b277148ce1a9343210324234ea3e7b4f6 100644 (file)
@@ -41,11 +41,11 @@ import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BindingObject;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
@@ -114,7 +114,7 @@ abstract sealed class DataContainerCodecContext<D extends DataContainer, R exten
 
     // Non-final for ChoiceCodecContext
     @Override
-    public CodecContext yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg) {
+    public CodecContext yangPathArgumentChild(final PathArgument arg) {
         CodecContextSupplier supplier;
         if (arg instanceof NodeIdentifier nodeId) {
             supplier = yangChildSupplier(nodeId);
@@ -129,22 +129,22 @@ abstract sealed class DataContainerCodecContext<D extends DataContainer, R exten
     abstract @Nullable CodecContextSupplier yangChildSupplier(@NonNull NodeIdentifier arg);
 
     @Override
-    public abstract CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(PathArgument arg,
-        List<YangInstanceIdentifier.PathArgument> builder);
+    public abstract CommonDataObjectCodecContext<?, ?> bindingPathArgumentChild(DataObjectStep<?> step,
+        List<PathArgument> builder);
 
     /**
      * Serializes supplied Binding Path Argument and adds all necessary YANG instance identifiers to supplied list.
      *
-     * @param arg Binding Path Argument
+     * @param step Binding Path Argument
      * @param builder DOM Path argument.
      */
-    final void addYangPathArgument(final PathArgument arg, final List<YangInstanceIdentifier.PathArgument> builder) {
+    final void addYangPathArgument(final DataObjectStep<?> step, final List<PathArgument> builder) {
         if (builder != null) {
-            addYangPathArgument(builder, arg);
+            addYangPathArgument(builder, step);
         }
     }
 
-    void addYangPathArgument(final @NonNull List<YangInstanceIdentifier.PathArgument> builder, final PathArgument arg) {
+    void addYangPathArgument(final @NonNull List<PathArgument> builder, final DataObjectStep<?> step) {
         final var yangArg = getDomPathArgument();
         if (yangArg != null) {
             builder.add(yangArg);
@@ -178,8 +178,8 @@ abstract sealed class DataContainerCodecContext<D extends DataContainer, R exten
             : new CachingNormalizedNodeCodec<>(context, ImmutableSet.copyOf(cacheSpecifier));
     }
 
-    protected final <V> @NonNull V childNonNull(final @Nullable V nullable,
-            final YangInstanceIdentifier.PathArgument child, final String message, final Object... args) {
+    protected final <V> @NonNull V childNonNull(final @Nullable V nullable, final PathArgument child,
+            final String message, final Object... args) {
         if (nullable == null) {
             throw childNullException(child.getNodeType(), message, args);
         }
index 8a45102c3b03cb5f08f6bafe6bc6d9cea82c0702..6ab6c0157b46b20e8de3390c698ce810ab336dee 100644 (file)
@@ -37,7 +37,7 @@ import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.BindingObject;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
@@ -307,14 +307,14 @@ public abstract sealed class DataObjectCodecContext<D extends DataObject, T exte
     }
 
     @Override
-    public InstanceIdentifier.PathArgument deserializePathArgument(final PathArgument arg) {
+    public DataObjectStep<?> deserializePathArgument(final PathArgument arg) {
         checkArgument(getDomPathArgument().equals(arg));
         return bindingArg();
     }
 
     @Override
-    public PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
-        checkArgument(bindingArg().equals(arg));
+    public PathArgument serializePathArgument(final DataObjectStep<?> step) {
+        checkArgument(bindingArg().equals(step));
         return getDomPathArgument();
     }
 
index e53354f09d2618902efa030cd997742c3ea8c9b3..2137b0f2ac31af831bbe6b4ca42b9d78fd9d958a 100644 (file)
@@ -12,7 +12,8 @@ import static java.util.Objects.requireNonNull;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 abstract sealed class DataObjectCodecPrototype<T extends CompositeRuntimeType> extends CommonDataObjectCodecPrototype<T>
@@ -24,10 +25,10 @@ abstract sealed class DataObjectCodecPrototype<T extends CompositeRuntimeType> e
     @SuppressWarnings("unchecked")
     DataObjectCodecPrototype(final Class<?> cls, final NodeIdentifier yangArg, final T type,
             final CodecContextFactory factory) {
-        this(Item.of((Class<? extends DataObject>) cls), yangArg, type, factory);
+        this(InstanceIdentifier.createStep((Class<? extends DataObject>) cls), yangArg, type, factory);
     }
 
-    DataObjectCodecPrototype(final Item<?> bindingArg, final NodeIdentifier yangArg, final T type,
+    DataObjectCodecPrototype(final DataObjectStep<?> bindingArg, final NodeIdentifier yangArg, final T type,
             final CodecContextFactory factory) {
         super(bindingArg, type, factory);
         this.yangArg = requireNonNull(yangArg);
index 34c8fed782f2c097e5bc3ff8c653660545af6581..a8a00d52fcc44d10dae44a7f9c0b3f1a825909f0 100644 (file)
@@ -22,9 +22,9 @@ import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.util.ImmutableOffsetMap;
 import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
+import org.opendaylight.yangtools.yang.binding.KeyStep;
 import org.opendaylight.yangtools.yang.binding.contract.Naming;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -122,8 +122,8 @@ abstract sealed class IdentifiableItemCodec {
 
     private static final Logger LOG = LoggerFactory.getLogger(IdentifiableItemCodec.class);
 
-    private final Class<?> identifiable;
-    private final QName qname;
+    private final @NonNull Class<?> identifiable;
+    private final @NonNull QName qname;
 
     private IdentifiableItemCodec(final ListEffectiveStatement schema, final Class<? extends Key<?>> keyClass,
             final Class<?> identifiable) {
@@ -145,12 +145,12 @@ abstract sealed class IdentifiableItemCodec {
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    final @NonNull IdentifiableItem<?, ?> domToBinding(final NodeIdentifierWithPredicates input) {
-        return IdentifiableItem.of((Class) identifiable, (Key) deserializeIdentifier(requireNonNull(input)));
+    final @NonNull KeyStep<?, ?> domToBinding(final NodeIdentifierWithPredicates input) {
+        return new KeyStep(identifiable, deserializeIdentifier(requireNonNull(input)));
     }
 
-    final @NonNull NodeIdentifierWithPredicates bindingToDom(final IdentifiableItem<?, ?> input) {
-        return serializeIdentifier(qname, input.getKey());
+    final @NonNull NodeIdentifierWithPredicates bindingToDom(final KeyStep<?, ?> input) {
+        return serializeIdentifier(qname, input.key());
     }
 
     @SuppressWarnings("checkstyle:illegalCatch")
index b7f60447f3aa50f4bf007c4e96d823a01e7d0301..587af64a584dfd2487a6e059b45559a860b9d0db 100644 (file)
@@ -11,12 +11,12 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
-import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingInstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeylessStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 
@@ -31,12 +31,12 @@ final class InstanceIdentifierCodec implements BindingInstanceIdentifierCodec,
 
     @Override
     public <T extends DataObject> InstanceIdentifier<T> toBinding(final YangInstanceIdentifier domPath) {
-        final List<InstanceIdentifier.PathArgument> builder = new ArrayList<>();
-        final BindingDataObjectCodecTreeNode<?> codec = context.getCodecContextNode(domPath, builder);
+        final var builder = new ArrayList<DataObjectStep<?>>();
+        final var codec = context.getCodecContextNode(domPath, builder);
         if (codec == null) {
             return null;
         }
-        if (codec instanceof ListCodecContext && Iterables.getLast(builder) instanceof InstanceIdentifier.Item) {
+        if (codec instanceof ListCodecContext && Iterables.getLast(builder) instanceof KeylessStep) {
             // We ended up in list, but without key, which means it represent list as a whole,
             // which is not binding representable.
             return null;
@@ -47,7 +47,7 @@ final class InstanceIdentifierCodec implements BindingInstanceIdentifierCodec,
 
     @Override
     public @NonNull YangInstanceIdentifier fromBinding(@NonNull final InstanceIdentifier<?> bindingPath) {
-        final List<PathArgument> domArgs = new ArrayList<>();
+        final var domArgs = new ArrayList<PathArgument>();
         context.getCodecContextNode(bindingPath, domArgs);
         return YangInstanceIdentifier.of(domArgs);
     }
index 7e3019c4be16e5ad98f801aeaa390a7280af6cf9..4023e0d4ae81949dd017c7d0f0e66e1151fee29f 100644 (file)
@@ -14,7 +14,7 @@ import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.NodeStep;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -24,7 +24,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
 sealed class ListCodecContext<D extends DataObject> extends DataObjectCodecContext<D, ListRuntimeType>
         permits MapCodecContext {
     ListCodecContext(final Class<D> cls, final ListRuntimeType list, final CodecContextFactory factory) {
-        this(new ListCodecPrototype(Item.of(cls), list, factory));
+        this(new ListCodecPrototype(new NodeStep<>(cls), list, factory));
     }
 
     ListCodecContext(final ListCodecPrototype prototype) {
index f63eaa27e9c54d2a8ba749f68f9aa9bdf6df4288..2c6bbdcafd35eeb941908c36b784acbfb6f9a8df 100644 (file)
@@ -8,15 +8,15 @@
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 /**
  * A prototype for {@link ListCodecContext}.
  */
 sealed class ListCodecPrototype extends DataObjectCodecPrototype<ListRuntimeType> permits MapCodecPrototype {
-    ListCodecPrototype(final Item<?> item, final ListRuntimeType type, final CodecContextFactory factory) {
-        super(item, NodeIdentifier.create(type.statement().argument()), type, factory);
+    ListCodecPrototype(final DataObjectStep<?> step, final ListRuntimeType type, final CodecContextFactory factory) {
+        super(step, NodeIdentifier.create(type.statement().argument()), type, factory);
     }
 
     @Override
index 9b497fce4b34e00e4bceb72453e56e4e7c1b7504..39e8e419bf5497778c2235bd52c09fd1c19906fb 100644 (file)
@@ -15,15 +15,15 @@ import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.Key;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
+import org.opendaylight.yangtools.yang.binding.KeyStep;
+import org.opendaylight.yangtools.yang.binding.KeylessStep;
 import org.opendaylight.yangtools.yang.binding.contract.Naming;
 import org.opendaylight.yangtools.yang.common.Ordering;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 
 abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & KeyAware<I>>
@@ -56,9 +56,9 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
         this.codec = requireNonNull(codec);
     }
 
-    static @NonNull MapCodecContext<?, ?>  of(final Class<? extends DataObject> cls, final ListRuntimeType type,
+    static @NonNull MapCodecContext<?, ?> of(final Class<? extends DataObject> cls, final ListRuntimeType type,
             final CodecContextFactory factory) {
-        return of(new MapCodecPrototype(Item.of(cls), type, factory));
+        return of(new MapCodecPrototype(new KeylessStep(cls), type, factory));
     }
 
     static @NonNull MapCodecContext<?, ?> of(final MapCodecPrototype prototype) {
@@ -78,8 +78,7 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
     }
 
     @Override
-    void addYangPathArgument(final List<YangInstanceIdentifier.PathArgument> builder,
-            final InstanceIdentifier.PathArgument arg) {
+    void addYangPathArgument(final List<PathArgument> builder, final DataObjectStep<?> step) {
         /*
          * DOM Instance Identifier for list is always represent by two entries one for map and one for children. This
          * is also true for wildcarded instance identifiers
@@ -87,8 +86,8 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
         final var yangArg = getDomPathArgument();
         builder.add(yangArg);
 
-        if (arg instanceof IdentifiableItem<?, ?> identifiable) {
-            builder.add(codec.bindingToDom(identifiable));
+        if (step instanceof KeyStep<?, ?> keyStep) {
+            builder.add(codec.bindingToDom(keyStep));
         } else {
             // Adding wildcarded
             builder.add(yangArg);
@@ -96,15 +95,14 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
     }
 
     @Override
-    protected final InstanceIdentifier.PathArgument getBindingPathArgument(
-            final YangInstanceIdentifier.PathArgument domArg) {
+    protected final DataObjectStep<?> getBindingPathArgument(final PathArgument domArg) {
         return domArg instanceof NodeIdentifierWithPredicates nip ? codec.domToBinding(nip)
             : super.getBindingPathArgument(domArg);
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     final NodeIdentifierWithPredicates serialize(final Key<?> key) {
-        return codec.bindingToDom(IdentifiableItem.of((Class)getBindingClass(), (Key)key));
+        return codec.bindingToDom(new KeyStep(getBindingClass(), key));
     }
 
     final @NonNull Key<?> deserialize(final @NonNull NodeIdentifierWithPredicates arg) {
@@ -112,14 +110,12 @@ abstract sealed class MapCodecContext<I extends Key<D>, D extends DataObject & K
     }
 
     @Override
-    public final YangInstanceIdentifier.PathArgument serializePathArgument(final InstanceIdentifier.PathArgument arg) {
-        return arg instanceof IdentifiableItem<?, ?> identifiable ? codec.bindingToDom(identifiable)
-            : super.serializePathArgument(arg);
+    public final PathArgument serializePathArgument(final DataObjectStep<?> step) {
+        return step instanceof KeyStep<?, ?> keyStep ? codec.bindingToDom(keyStep) : super.serializePathArgument(step);
     }
 
     @Override
-    public final InstanceIdentifier.PathArgument deserializePathArgument(
-        final YangInstanceIdentifier.PathArgument arg) {
+    public final DataObjectStep<?> deserializePathArgument(final PathArgument arg) {
         return arg instanceof NodeIdentifierWithPredicates nip ? codec.domToBinding(nip)
             : super.deserializePathArgument(arg);
     }
index 58080631b9ae11949814a0ab4b54799333afc08b..c72d4f09664d125093a075c7da457ee0c90ca93b 100644 (file)
@@ -10,15 +10,15 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 import static com.google.common.base.Preconditions.checkArgument;
 
 import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 import org.opendaylight.yangtools.yang.binding.KeyAware;
 
 /**
  * A prototype for a {@link MapCodecContext}.
  */
 final class MapCodecPrototype extends ListCodecPrototype {
-    MapCodecPrototype(final Item<?> item, final ListRuntimeType type, final CodecContextFactory factory) {
-        super(item, type, factory);
+    MapCodecPrototype(final DataObjectStep<?> step, final ListRuntimeType type, final CodecContextFactory factory) {
+        super(step, type, factory);
         final var clazz = javaClass();
         checkArgument(KeyAware.class.isAssignableFrom(clazz), "%s is not KeyAware", clazz);
     }
index dfa7e874cf81130eb3cb194a9c717a5fd12bdb4e..ceddb77cda71d5d85525a9dff20525093085c560 100644 (file)
@@ -13,7 +13,7 @@ import java.lang.invoke.VarHandle;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.NodeStep;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 
 /**
@@ -37,7 +37,7 @@ final class StructuralContainerCodecContext<D extends DataObject> extends Contai
 
     StructuralContainerCodecContext(final Class<D> cls, final ContainerRuntimeType type,
             final CodecContextFactory factory) {
-        this(new StructuralContainerCodecPrototype(Item.of(cls), type, factory));
+        this(new StructuralContainerCodecPrototype(new NodeStep<>(cls), type, factory));
     }
 
     StructuralContainerCodecContext(final StructuralContainerCodecPrototype prototype) {
index 4fb130c5bf9d3120d3cc54f9400e25478a5cd924..b41337ff22fd13e22faae61dbb474697ac7bd892 100644 (file)
@@ -8,15 +8,15 @@
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
 import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.binding.DataObjectStep;
 
 /**
  * A prototype for a {@link StructuralContainerCodecContext}.
  */
 final class StructuralContainerCodecPrototype extends ContainerLikeCodecPrototype {
-    StructuralContainerCodecPrototype(final Item<?> item, final ContainerRuntimeType container,
+    StructuralContainerCodecPrototype(final DataObjectStep<?> step, final ContainerRuntimeType container,
             final CodecContextFactory factory) {
-        super(item, container, factory);
+        super(step, container, factory);
     }
 
     @Override
index 8050fadf344a33dab03d1b8060def0a50fc4243a..ae62ab8acc86d8973279e42c706e7ea57b37c68d 100644 (file)
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 
 import com.google.common.collect.Iterables;
 import org.junit.Test;
@@ -34,7 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.con
 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.grp.GrpCont;
 import org.opendaylight.yang.gen.v1.urn.test.opendaylight.mdsal45.base.norev.root.RootBase;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.Key;
+import org.opendaylight.yangtools.yang.binding.KeyStep;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@@ -75,8 +76,7 @@ public class InstanceIdentifierSerializeDeserializeTest extends AbstractBindingC
         final var last = Iterables.getLast(instanceIdentifier.getPathArguments());
         assertEquals(TopLevelList.class, instanceIdentifier.getTargetType());
         assertFalse(instanceIdentifier.isWildcarded());
-        assertTrue(last instanceof InstanceIdentifier.IdentifiableItem);
-        final Key<?> key = ((InstanceIdentifier.IdentifiableItem<?, ?>) last).getKey();
+        final var key = assertInstanceOf(KeyStep.class, last).key();
         assertEquals(TopLevelListKey.class, key.getClass());
         assertEquals(TOP_LEVEL_LIST_KEY_VALUE, ((TopLevelListKey)key).getName());
     }
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataObjectStep.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/DataObjectStep.java
new file mode 100644 (file)
index 0000000..2926ba3
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2024 PANTHEON.tech, 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.yangtools.yang.binding;
+
+import java.io.Serializable;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * A reference to a {@link DataObject} type forming a single step in a path similar to {@code instance-identifier}.
+ *
+ * @param <T> DataObject type
+ */
+/*
+ * FIXME: this interface forms a partial model of the following RFC7950 construct:
+ *
+ *          ;; Instance Identifiers
+ *
+ *          instance-identifier = 1*("/" (node-identifier [1*key-predicate / leaf-list-predicate / pos]))
+ *
+ * We handle the 'node-identifier for DataObjects' and 'key-predicate' cases. What is missing are interfaces for:
+ * - 'leaf-list-predicate' (exact value match)
+ * - 'pos' interfaces (index into a list or a leaf-list}
+ * - 'node-identifier for non-DataObjects' (i.e. leaf, anydata, anyxml)
+ */
+public sealed interface DataObjectStep<T extends DataObject> extends Comparable<DataObjectStep<?>>, Serializable
+        permits ExactDataObjectStep, KeylessStep {
+    /**
+     * Return the data object type backing this PathArgument.
+     *
+     * @return Data object type
+     */
+    @NonNull Class<T> type();
+
+    /**
+     * Return an optional enclosing case type. This is used only when {@link #type()} references a node defined
+     * in a {@code grouping} which is reference inside a {@code case} statement in order to safely reference the node.
+     *
+     * @return case class, or {@code null}
+     */
+    @Nullable Class<? extends DataObject> caseType();
+
+    @Override
+    default int compareTo(final DataObjectStep<?> other) {
+        final var typeCmp = compareClasses(type(), other.type());
+        if (typeCmp != 0) {
+            return typeCmp;
+        }
+        final var caseType = caseType();
+        final var otherCaseType = other.caseType();
+        if (caseType == null) {
+            return otherCaseType == null ? 0 : -1;
+        }
+        final var caseCmp = otherCaseType == null ? 1 : compareClasses(caseType, otherCaseType);
+        return caseCmp != 0 ? caseCmp : compareHierarchy(this, other);
+    }
+
+    private static int compareHierarchy(final DataObjectStep<?> recv, final DataObjectStep<?> other) {
+        if (recv instanceof NodeStep) {
+            if (other instanceof NodeStep) {
+                return 0;
+            } else if (other instanceof KeylessStep || other instanceof KeyStep) {
+                return -1;
+            }
+        } else if (recv instanceof KeyStep thisAware) {
+            if (other instanceof KeyStep otherAware) {
+                @SuppressWarnings("unchecked")
+                final var thisKey = (Comparable<Object>) thisAware.key();
+                return  thisKey.compareTo(otherAware.key());
+            } else if (other instanceof NodeStep || other instanceof KeylessStep) {
+                return 1;
+            }
+        } else if (recv instanceof KeylessStep) {
+            if (other instanceof KeylessStep) {
+                return 0;
+            } else if (other instanceof NodeStep || other instanceof KeyStep) {
+                return 1;
+            }
+        }
+        throw new IllegalStateException("Unhandled " + recv + ".compareTo(" + other + ")");
+    }
+
+    private static int compareClasses(final Class<?> first, final Class<?> second) {
+        return first.getCanonicalName().compareTo(second.getCanonicalName());
+    }
+}
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/ExactDataObjectStep.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/ExactDataObjectStep.java
new file mode 100644 (file)
index 0000000..34541f2
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024 PANTHEON.tech, 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.yangtools.yang.binding;
+
+/**
+ * A {@link DataObjectStep} which is exactly specified. Due to how {@link DataObject} and {@link KeyAware} are tied
+ * together, a class generated for a {@code list} is strictly a {@link DataObject}, but its semantics differ.
+ *
+ * <p>
+ * This interface captures two possible outcomes:
+ * <ol>
+ *   <li>this is a plain {@link NodeStep}</li>
+ *   <li>this is a fully-specified {@link KeyStep}</li>
+ * </ol>
+ *
+ * @param <T> DataObject type
+ */
+public sealed interface ExactDataObjectStep<T extends DataObject> extends DataObjectStep<T>
+    permits KeyStep, NodeStep {
+    // for class hierarchy only
+}
\ No newline at end of file
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/IIv4.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/IIv4.java
new file mode 100644 (file)
index 0000000..59cd94b
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.yangtools.yang.binding;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import org.eclipse.jdt.annotation.Nullable;
+
+sealed class IIv4<T extends DataObject> implements Externalizable permits KIIv4 {
+    @java.io.Serial
+    private static final long serialVersionUID = 1L;
+
+    private @Nullable Iterable<DataObjectStep<?>> pathArguments;
+    private @Nullable Class<T> targetType;
+    private boolean wildcarded;
+    private int hash;
+
+    @SuppressWarnings("redundantModifier")
+    public IIv4() {
+        // For Externalizable
+    }
+
+    IIv4(final InstanceIdentifier<T> source) {
+        pathArguments = source.pathArguments;
+        targetType = source.getTargetType();
+        wildcarded = source.isWildcarded();
+        hash = source.hashCode();
+    }
+
+    final int getHash() {
+        return hash;
+    }
+
+    final Iterable<DataObjectStep<?>> getPathArguments() {
+        return pathArguments;
+    }
+
+    final Class<T> getTargetType() {
+        return targetType;
+    }
+
+    final boolean isWildcarded() {
+        return wildcarded;
+    }
+
+    @Override
+    public void writeExternal(final ObjectOutput out) throws IOException {
+        out.writeObject(targetType);
+        out.writeBoolean(wildcarded);
+        out.writeInt(hash);
+        out.writeInt(Iterables.size(pathArguments));
+        for (var o : pathArguments) {
+            out.writeObject(o);
+        }
+    }
+
+    @Override
+    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+        targetType = (Class<T>) in.readObject();
+        wildcarded = in.readBoolean();
+        hash = in.readInt();
+
+        final int size = in.readInt();
+        final var builder = ImmutableList.<DataObjectStep<?>>builderWithExpectedSize(size);
+        for (int i = 0; i < size; ++i) {
+            builder.add((DataObjectStep<?>) in.readObject());
+        }
+        pathArguments = builder.build();
+    }
+
+    @java.io.Serial
+    Object readResolve() throws ObjectStreamException {
+        return new InstanceIdentifier<>(targetType, pathArguments, wildcarded, hash);
+    }
+}
index da23b8fc0c97addc043756e9ca0857e8a16a2151..22681a4d0f13e789f541c444d117e22d76b08df2 100644 (file)
@@ -12,6 +12,7 @@ import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.VerifyException;
@@ -24,10 +25,8 @@ import java.io.ObjectOutputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
-import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.HierarchicalIdentifier;
@@ -38,23 +37,20 @@ import org.opendaylight.yangtools.util.HashCodeBuilder;
  *
  * <p>
  * For Example let's say you were trying to refer to a node in inventory which was modeled in YANG as follows,
+ * <pre>code{
+ *   module opendaylight-inventory {
+ *     ....
  *
- * <p>
- * <pre>
- * module opendaylight-inventory {
- *      ....
- *
- *      container nodes {
- *        list node {
- *            key "id";
- *            ext:context-instance "node-context";
- *
- *            uses node;
- *        }
- *    }
+ *     container nodes {
+ *       list node {
+ *         key "id";
+ *         ext:context-instance "node-context";
  *
- * }
- * </pre>
+ *         uses node;
+ *       }
+ *     }
+ *   }
+ * }</pre>
  *
  * <p>
  * You can create an instance identifier as follows to get to a node with id "openflow:1": {@code
@@ -64,8 +60,9 @@ import org.opendaylight.yangtools.util.HashCodeBuilder;
  * <p>
  * This would be the same as using a path like so, "/nodes/node/openflow:1" to refer to the openflow:1 node
  */
-public class InstanceIdentifier<T extends DataObject>
-        implements HierarchicalIdentifier<InstanceIdentifier<? extends DataObject>> {
+public sealed class InstanceIdentifier<T extends DataObject>
+        implements HierarchicalIdentifier<InstanceIdentifier<? extends DataObject>>
+        permits KeyedInstanceIdentifier {
     @java.io.Serial
     private static final long serialVersionUID = 3L;
 
@@ -73,13 +70,13 @@ public class InstanceIdentifier<T extends DataObject>
      * Protected to differentiate internal and external access. Internal access is required never to modify
      * the contents. References passed to outside entities have to be wrapped in an unmodifiable view.
      */
-    final Iterable<PathArgument> pathArguments;
+    final Iterable<DataObjectStep<?>> pathArguments;
 
     private final @NonNull Class<T> targetType;
     private final boolean wildcarded;
     private final int hash;
 
-    InstanceIdentifier(final Class<T> type, final Iterable<PathArgument> pathArguments, final boolean wildcarded,
+    InstanceIdentifier(final Class<T> type, final Iterable<DataObjectStep<?>> pathArguments, final boolean wildcarded,
             final int hash) {
         this.pathArguments = requireNonNull(pathArguments);
         targetType = requireNonNull(type);
@@ -115,7 +112,7 @@ public class InstanceIdentifier<T extends DataObject>
      *
      * @return Path argument chain. Immutable and does not contain nulls.
      */
-    public final @NonNull Iterable<PathArgument> getPathArguments() {
+    public final @NonNull Iterable<DataObjectStep<?>> getPathArguments() {
         return Iterables.unmodifiableIterable(pathArguments);
     }
 
@@ -145,43 +142,24 @@ public class InstanceIdentifier<T extends DataObject>
             return false;
         }
 
-        final InstanceIdentifier<?> other = (InstanceIdentifier<?>) obj;
+        final var other = (InstanceIdentifier<?>) obj;
         if (pathArguments == other.pathArguments) {
             return true;
         }
 
         /*
-         * We could now just go and compare the pathArguments, but that
-         * can be potentially expensive. Let's try to avoid that by
-         * checking various things that we have cached from pathArguments
-         * and trying to prove the identifiers are *not* equal.
+         * We could now just go and compare the pathArguments, but that can be potentially expensive. Let's try to avoid
+         * that by checking various things that we have cached from pathArguments and trying to prove the identifiers
+         * are *not* equal.
          */
-        if (hash != other.hash) {
-            return false;
-        }
-        if (wildcarded != other.wildcarded) {
-            return false;
-        }
-        if (targetType != other.targetType) {
-            return false;
-        }
-        if (fastNonEqual(other)) {
-            return false;
-        }
-
-        // Everything checks out so far, so we have to do a full equals
-        return Iterables.elementsEqual(pathArguments, other.pathArguments);
+        return hash == other.hash && wildcarded == other.wildcarded && targetType == other.targetType
+            && keyEquals(other)
+            // Everything checks out so far, so we have to do a full equals
+            && Iterables.elementsEqual(pathArguments, other.pathArguments);
     }
 
-    /**
-     * Perform class-specific fast checks for non-equality. This allows subclasses to avoid iterating over the
-     * pathArguments by performing quick checks on their specific fields.
-     *
-     * @param other The other identifier, guaranteed to be the same class
-     * @return true if the other identifier cannot be equal to this one.
-     */
-    protected boolean fastNonEqual(final InstanceIdentifier<?> other) {
-        return false;
+    boolean keyEquals(final InstanceIdentifier<?> other) {
+        return true;
     }
 
     @Override
@@ -224,11 +202,10 @@ public class InstanceIdentifier<T extends DataObject>
     public final <I extends DataObject> @Nullable InstanceIdentifier<I> firstIdentifierOf(
             final Class<@NonNull I> type) {
         int count = 1;
-        for (final PathArgument a : pathArguments) {
-            if (type.equals(a.getType())) {
+        for (var step : pathArguments) {
+            if (type.equals(step.type())) {
                 @SuppressWarnings("unchecked")
-                final InstanceIdentifier<I> ret = (InstanceIdentifier<I>) internalCreate(
-                        Iterables.limit(pathArguments, count));
+                final var ret = (InstanceIdentifier<I>) internalCreate(Iterables.limit(pathArguments, count));
                 return ret;
             }
 
@@ -248,14 +225,13 @@ public class InstanceIdentifier<T extends DataObject>
      */
     public final <N extends KeyAware<K> & DataObject, K extends Key<N>> @Nullable K firstKeyOf(
             final Class<@NonNull N> listItem) {
-        for (final PathArgument i : pathArguments) {
-            if (listItem.equals(i.getType())) {
+        for (var step : pathArguments) {
+            if (step instanceof KeyStep<?, ?> keyPredicate && listItem.equals(step.type())) {
                 @SuppressWarnings("unchecked")
-                final K ret = ((IdentifiableItem<N, K>)i).getKey();
+                final var ret = (K) keyPredicate.key();
                 return ret;
             }
         }
-
         return null;
     }
 
@@ -283,18 +259,15 @@ public class InstanceIdentifier<T extends DataObject>
     public final boolean contains(final InstanceIdentifier<? extends DataObject> other) {
         requireNonNull(other, "other should not be null");
 
-        final Iterator<?> oit = other.pathArguments.iterator();
-
-        for (PathArgument pathArgument : pathArguments) {
+        final var oit = other.pathArguments.iterator();
+        for (var step : pathArguments) {
             if (!oit.hasNext()) {
                 return false;
             }
-
-            if (!pathArgument.equals(oit.next())) {
+            if (!step.equals(oit.next())) {
                 return false;
             }
         }
-
         return true;
     }
 
@@ -309,27 +282,30 @@ public class InstanceIdentifier<T extends DataObject>
     public final boolean containsWildcarded(final InstanceIdentifier<?> other) {
         requireNonNull(other, "other should not be null");
 
-        final Iterator<PathArgument> oit = other.pathArguments.iterator();
-
-        for (PathArgument la : pathArguments) {
-            if (!oit.hasNext()) {
+        final var otherSteps = other.pathArguments.iterator();
+        for (var step : pathArguments) {
+            if (!otherSteps.hasNext()) {
                 return false;
             }
 
-            final PathArgument oa = oit.next();
-
-            if (!la.getType().equals(oa.getType())) {
-                return false;
-            }
-            if (la instanceof IdentifiableItem<?, ?> && oa instanceof IdentifiableItem<?, ?> && !la.equals(oa)) {
-                return false;
+            final var otherStep = otherSteps.next();
+            if (step instanceof ExactDataObjectStep) {
+                if (!step.equals(otherStep)) {
+                    return false;
+                }
+            } else if (step instanceof KeylessStep<?> keyless) {
+                if (!keyless.matches(otherStep)) {
+                    return false;
+                }
+            } else {
+                throw new IllegalStateException("Unhandled step " + step);
             }
         }
 
         return true;
     }
 
-    private <N extends DataObject> @NonNull InstanceIdentifier<N> childIdentifier(final AbstractPathArgument<N> arg) {
+    private <N extends DataObject> @NonNull InstanceIdentifier<N> childIdentifier(final DataObjectStep<N> arg) {
         return trustedCreate(arg, Iterables.concat(pathArguments, Collections.singleton(arg)),
             HashCodeBuilder.nextHashCode(hash, arg), wildcarded);
     }
@@ -345,7 +321,7 @@ public class InstanceIdentifier<T extends DataObject>
      */
     public final <N extends ChildOf<? super T>> @NonNull InstanceIdentifier<N> child(
             final Class<@NonNull N> container) {
-        return childIdentifier(Item.of(container));
+        return childIdentifier(createStep(container));
     }
 
     /**
@@ -362,7 +338,7 @@ public class InstanceIdentifier<T extends DataObject>
     @SuppressWarnings("unchecked")
     public final <N extends KeyAware<K> & ChildOf<? super T>, K extends Key<N>>
             @NonNull KeyedInstanceIdentifier<N, K> child(final Class<@NonNull N> listItem, final K listKey) {
-        return (KeyedInstanceIdentifier<N, K>) childIdentifier(IdentifiableItem.of(listItem, listKey));
+        return (KeyedInstanceIdentifier<N, K>) childIdentifier(new KeyStep<>(listItem, listKey));
     }
 
     /**
@@ -379,7 +355,7 @@ public class InstanceIdentifier<T extends DataObject>
     // FIXME: add a proper caller
     public final <C extends ChoiceIn<? super T> & DataObject, N extends ChildOf<? super C>>
             @NonNull InstanceIdentifier<N> child(final Class<@NonNull C> caze, final Class<@NonNull N> container) {
-        return childIdentifier(Item.of(caze, container));
+        return childIdentifier(createStep(caze, container));
     }
 
     /**
@@ -400,7 +376,7 @@ public class InstanceIdentifier<T extends DataObject>
     public final <C extends ChoiceIn<? super T> & DataObject, K extends Key<N>,
         N extends KeyAware<K> & ChildOf<? super C>> @NonNull KeyedInstanceIdentifier<N, K> child(
                 final Class<@NonNull C> caze, final Class<@NonNull N> listItem, final K listKey) {
-        return (KeyedInstanceIdentifier<N, K>) childIdentifier(IdentifiableItem.of(caze, listItem, listKey));
+        return (KeyedInstanceIdentifier<N, K>) childIdentifier(new KeyStep<>(listItem, requireNonNull(caze), listKey));
     }
 
     /**
@@ -414,12 +390,12 @@ public class InstanceIdentifier<T extends DataObject>
      */
     public final <N extends DataObject & Augmentation<? super T>> @NonNull InstanceIdentifier<N> augmentation(
             final Class<@NonNull N> container) {
-        return childIdentifier(Item.of(container));
+        return childIdentifier(new NodeStep<>(container));
     }
 
     @java.io.Serial
-    private Object writeReplace() throws ObjectStreamException {
-        return new InstanceIdentifierV3<>(this);
+    Object writeReplace() throws ObjectStreamException {
+        return new IIv4<>(this);
     }
 
     @java.io.Serial
@@ -461,7 +437,7 @@ public class InstanceIdentifier<T extends DataObject>
      */
     public static <T extends ChildOf<? extends DataRoot>> @NonNull Builder<T> builder(
             final Class<T> container) {
-        return new RegularBuilder<>(Item.of(container));
+        return new RegularBuilder<>(createStep(container));
     }
 
     /**
@@ -477,7 +453,7 @@ public class InstanceIdentifier<T extends DataObject>
      */
     public static <C extends ChoiceIn<? extends DataRoot> & DataObject, T extends ChildOf<? super C>>
             @NonNull Builder<T> builder(final Class<C> caze, final Class<T> container) {
-        return new RegularBuilder<>(Item.of(caze, container));
+        return new RegularBuilder<>(createStep(caze, container));
     }
 
     /**
@@ -493,7 +469,7 @@ public class InstanceIdentifier<T extends DataObject>
     public static <N extends KeyAware<K> & ChildOf<? extends DataRoot>,
             K extends Key<N>> @NonNull KeyedBuilder<N, K> builder(final Class<N> listItem,
                     final K listKey) {
-        return new KeyedBuilder<>(IdentifiableItem.of(listItem, listKey));
+        return new KeyedBuilder<>(new KeyStep<>(listItem, listKey));
     }
 
     /**
@@ -513,13 +489,13 @@ public class InstanceIdentifier<T extends DataObject>
             N extends KeyAware<K> & ChildOf<? super C>, K extends Key<N>>
             @NonNull KeyedBuilder<N, K> builder(final Class<C> caze, final Class<N> listItem,
                     final K listKey) {
-        return new KeyedBuilder<>(IdentifiableItem.of(caze, listItem, listKey));
+        return new KeyedBuilder<>(new KeyStep<>(listItem, requireNonNull(caze), listKey));
     }
 
     public static <R extends DataRoot & DataObject, T extends ChildOf<? super R>>
             @NonNull Builder<T> builderOfInherited(final Class<R> root, final Class<T> container) {
         // FIXME: we are losing root identity, hence namespaces may not work correctly
-        return new RegularBuilder<>(Item.of(container));
+        return new RegularBuilder<>(createStep(container));
     }
 
     public static <R extends DataRoot & DataObject, C extends ChoiceIn<? super R> & DataObject,
@@ -527,7 +503,7 @@ public class InstanceIdentifier<T extends DataObject>
             @NonNull Builder<T> builderOfInherited(final Class<R> root,
                 final Class<C> caze, final Class<T> container) {
         // FIXME: we are losing root identity, hence namespaces may not work correctly
-        return new RegularBuilder<>(Item.of(caze, container));
+        return new RegularBuilder<>(createStep(caze, container));
     }
 
     public static <R extends DataRoot & DataObject, N extends KeyAware<K> & ChildOf<? super R>,
@@ -535,7 +511,7 @@ public class InstanceIdentifier<T extends DataObject>
             @NonNull KeyedBuilder<N, K> builderOfInherited(final Class<R> root,
                 final Class<N> listItem, final K listKey) {
         // FIXME: we are losing root identity, hence namespaces may not work correctly
-        return new KeyedBuilder<>(IdentifiableItem.of(listItem, listKey));
+        return new KeyedBuilder<>(new KeyStep<>(listItem, listKey));
     }
 
     public static <R extends DataRoot & DataObject, C extends ChoiceIn<? super R> & DataObject,
@@ -543,7 +519,19 @@ public class InstanceIdentifier<T extends DataObject>
             @NonNull KeyedBuilder<N, K> builderOfInherited(final Class<R> root,
                 final Class<C> caze, final Class<N> listItem, final K listKey) {
         // FIXME: we are losing root identity, hence namespaces may not work correctly
-        return new KeyedBuilder<>(IdentifiableItem.of(caze, listItem, listKey));
+        return new KeyedBuilder<>(new KeyStep<>(listItem, requireNonNull(caze), listKey));
+    }
+
+    @Beta
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static <T extends DataObject, C extends ChoiceIn<?> & DataObject> @NonNull DataObjectStep<T> createStep(
+            final Class<C> caze, final Class<T> type) {
+        return KeyAware.class.isAssignableFrom(type) ? new KeylessStep(type, caze) : new NodeStep<>(type, caze);
+    }
+
+    @Beta
+    public static <T extends DataObject> @NonNull DataObjectStep<T> createStep(final Class<T> type) {
+        return createStep(null, type);
     }
 
     /**
@@ -555,24 +543,24 @@ public class InstanceIdentifier<T extends DataObject>
      * @throws IllegalArgumentException if pathArguments is empty or contains a null element.
      * @throws NullPointerException if {@code pathArguments} is null
      */
-    private static @NonNull InstanceIdentifier<?> internalCreate(final Iterable<PathArgument> pathArguments) {
+    private static @NonNull InstanceIdentifier<?> internalCreate(final Iterable<DataObjectStep<?>> pathArguments) {
         final var it = requireNonNull(pathArguments, "pathArguments may not be null").iterator();
         checkArgument(it.hasNext(), "pathArguments may not be empty");
 
-        final HashCodeBuilder<PathArgument> hashBuilder = new HashCodeBuilder<>();
+        final var hashBuilder = new HashCodeBuilder<DataObjectStep<?>>();
         boolean wildcard = false;
-        PathArgument arg;
+        DataObjectStep<?> arg;
 
         do {
             arg = it.next();
             // Non-null is implied by our callers
-            final var type = verifyNotNull(arg).getType();
+            final var type = verifyNotNull(arg).type();
             checkArgument(ChildOf.class.isAssignableFrom(type) || Augmentation.class.isAssignableFrom(type),
                 "%s is not a valid path argument", type);
 
             hashBuilder.addArgument(arg);
 
-            if (KeyAware.class.isAssignableFrom(type) && !(arg instanceof IdentifiableItem)) {
+            if (!(arg instanceof ExactDataObjectStep)) {
                 wildcard = true;
             }
         } while (it.hasNext());
@@ -581,7 +569,7 @@ public class InstanceIdentifier<T extends DataObject>
     }
 
     /**
-     * Create an instance identifier for a sequence of {@link PathArgument} steps. The steps are required to be formed
+     * Create an instance identifier for a sequence of {@link DataObjectStep} steps. The steps are required to be formed
      * of classes extending either {@link ChildOf} or {@link Augmentation} contracts. This method does not check whether
      * or not the sequence is structurally sound, for example that an {@link Augmentation} follows an
      * {@link Augmentable} step. Furthermore the compile-time indicated generic type of the returned object does not
@@ -599,7 +587,7 @@ public class InstanceIdentifier<T extends DataObject>
      */
     @SuppressWarnings("unchecked")
     public static <T extends DataObject> @NonNull InstanceIdentifier<T> unsafeOf(
-            final List<? extends PathArgument> pathArguments) {
+            final List<? extends DataObjectStep<?>> pathArguments) {
         return (InstanceIdentifier<T>) internalCreate(ImmutableList.copyOf(pathArguments));
     }
 
@@ -620,7 +608,7 @@ public class InstanceIdentifier<T extends DataObject>
     @SuppressWarnings("unchecked")
     public static <T extends ChildOf<? extends DataRoot>> @NonNull InstanceIdentifier<T> create(
             final Class<@NonNull T> type) {
-        return (InstanceIdentifier<T>) internalCreate(ImmutableList.of(Item.of(type)));
+        return (InstanceIdentifier<T>) internalCreate(ImmutableList.of(createStep(type)));
     }
 
     /**
@@ -643,88 +631,90 @@ public class InstanceIdentifier<T extends DataObject>
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    static <N extends DataObject> @NonNull InstanceIdentifier<N> trustedCreate(final PathArgument arg,
-            final Iterable<PathArgument> pathArguments, final int hash, final boolean wildcarded) {
-        if (arg instanceof IdentifiableItem<?, ?> identifiable) {
-            return new KeyedInstanceIdentifier(arg.getType(), pathArguments, wildcarded, hash, identifiable.getKey());
+    static <N extends DataObject> @NonNull InstanceIdentifier<N> trustedCreate(final DataObjectStep<?> lastStep,
+            final Iterable<DataObjectStep<?>> pathArguments, final int hash, final boolean wildcarded) {
+        if (lastStep instanceof NodeStep) {
+            return new InstanceIdentifier(lastStep.type(), pathArguments, wildcarded, hash);
+        } else if (lastStep instanceof KeyStep<?, ?> predicate) {
+            return new KeyedInstanceIdentifier(predicate, pathArguments, wildcarded, hash);
+        } else if (lastStep instanceof KeylessStep) {
+            return new InstanceIdentifier(lastStep.type(), pathArguments, true, hash);
+        } else {
+            throw new IllegalStateException("Unhandled step " + lastStep);
         }
-
-        final var type = arg.getType();
-        return new InstanceIdentifier(type, pathArguments, wildcarded || KeyAware.class.isAssignableFrom(type),
-            hash);
     }
 
-    /**
-     * Path argument of {@link InstanceIdentifier}. Interface which implementations are used as path components of the
-     * path in overall data tree.
-     */
-    public interface PathArgument extends Comparable<PathArgument> {
+    @Deprecated(since = "13.0.0", forRemoval = true)
+    private abstract static sealed class AbstractPathArgument<T extends DataObject>
+            implements Comparable<AbstractPathArgument<?>>, Serializable {
+        @java.io.Serial
+        private static final long serialVersionUID = 1L;
+
+        private final @NonNull Class<T> type;
+
+        AbstractPathArgument(final Class<T> type) {
+            this.type = requireNonNull(type, "Type may not be null.");
+        }
+
         /**
          * Return the data object type backing this PathArgument.
          *
          * @return Data object type.
          */
-        @NonNull Class<? extends DataObject> getType();
+        final @NonNull Class<T> type() {
+            return type;
+        }
 
         /**
-         * Return an optional enclosing case type. This is used only when {@link #getType()} references a node defined
+         * Return an optional enclosing case type. This is used only when {@link #type()} references a node defined
          * in a {@code grouping} which is reference inside a {@code case} statement in order to safely reference the
          * node.
          *
-         * @return Optional case class.
+         * @return case class or {@code null}
          */
-        default Optional<? extends Class<? extends DataObject>> getCaseType() {
-            return Optional.empty();
-        }
-    }
-
-    private abstract static class AbstractPathArgument<T extends DataObject> implements PathArgument, Serializable {
-        @java.io.Serial
-        private static final long serialVersionUID = 1L;
-
-        private final @NonNull Class<T> type;
-
-        AbstractPathArgument(final Class<T> type) {
-            this.type = requireNonNull(type, "Type may not be null.");
-        }
-
-        @Override
-        public final Class<T> getType() {
-            return type;
+        Class<? extends DataObject> caseType() {
+            return null;
         }
 
-        Object getKey() {
+        @Nullable Object key() {
             return null;
         }
 
         @Override
         public final int hashCode() {
-            return Objects.hash(type, getCaseType(), getKey());
+            return Objects.hash(type, caseType(), key());
         }
 
         @Override
         public final boolean equals(final Object obj) {
             return this == obj || obj instanceof AbstractPathArgument<?> other && type.equals(other.type)
-                && Objects.equals(getKey(), other.getKey()) && getCaseType().equals(other.getCaseType());
+                && Objects.equals(key(), other.key()) && Objects.equals(caseType(), other.caseType());
         }
 
         @Override
-        public final int compareTo(final PathArgument arg) {
-            final int cmp = compareClasses(type, arg.getType());
+        public final int compareTo(final AbstractPathArgument<?> arg) {
+            final int cmp = compareClasses(type, arg.type());
             if (cmp != 0) {
                 return cmp;
             }
-            final Optional<? extends Class<?>> caseType = getCaseType();
-            if (!caseType.isPresent()) {
-                return arg.getCaseType().isPresent() ? -1 : 1;
+            final var caseType = caseType();
+            final var argCaseType = arg.caseType();
+            if (caseType == null) {
+                return argCaseType == null ? 1 : -1;
             }
-            final Optional<? extends Class<?>> argCaseType = getCaseType();
-            return argCaseType.isPresent() ? compareClasses(caseType.orElseThrow(), argCaseType.orElseThrow()) : 1;
+            return argCaseType == null ? 1 : compareClasses(caseType, argCaseType);
         }
 
         private static int compareClasses(final Class<?> first, final Class<?> second) {
             return first.getCanonicalName().compareTo(second.getCanonicalName());
         }
+
+        @java.io.Serial
+        final Object readResolve() throws ObjectStreamException {
+            return toStep();
+        }
+
+        abstract DataObjectStep<?> toStep();
     }
 
     /**
@@ -733,7 +723,8 @@ public class InstanceIdentifier<T extends DataObject>
      *
      * @param <T> Item type
      */
-    public static class Item<T extends DataObject> extends AbstractPathArgument<T> {
+    @Deprecated(since = "13.0.0", forRemoval = true)
+    private static sealed class Item<T extends DataObject> extends AbstractPathArgument<T> {
         @java.io.Serial
         private static final long serialVersionUID = 1L;
 
@@ -741,37 +732,15 @@ public class InstanceIdentifier<T extends DataObject>
             super(type);
         }
 
-        /**
-         * Return a PathArgument instance backed by the specified class.
-         *
-         * @param type Backing class
-         * @param <T> Item type
-         * @return A new PathArgument
-         * @throws NullPointerException if {@code} is null.
-         */
-        public static <T extends DataObject> @NonNull Item<T> of(final Class<T> type) {
-            return new Item<>(type);
-        }
-
-        /**
-         * Return a PathArgument instance backed by the specified class, which in turn is defined in a {@code grouping}
-         * used in a corresponding {@code case} statement.
-         *
-         * @param caseType defining case class
-         * @param type Backing class
-         * @param <C> Case type
-         * @param <T> Item type
-         * @return A new PathArgument
-         * @throws NullPointerException if any argument is null.
-         */
-        public static <C extends ChoiceIn<?> & DataObject, T extends ChildOf<? super C>> @NonNull Item<T> of(
-                final Class<C> caseType, final Class<T> type) {
-            return new CaseItem<>(caseType, type);
+        @Override
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        final DataObjectStep<?> toStep() {
+            return createStep((Class) caseType(), type());
         }
 
         @Override
         public String toString() {
-            return getType().getName();
+            return type().getName();
         }
     }
 
@@ -782,7 +751,8 @@ public class InstanceIdentifier<T extends DataObject>
      * @param <I> An object that is identifiable by an identifier
      * @param <T> The identifier of the object
      */
-    public static class IdentifiableItem<I extends KeyAware<T> & DataObject, T extends Key<I>>
+    @Deprecated(since = "13.0.0", forRemoval = true)
+    private static sealed class IdentifiableItem<I extends KeyAware<T> & DataObject, T extends Key<I>>
             extends AbstractPathArgument<I> {
         @java.io.Serial
         private static final long serialVersionUID = 1L;
@@ -794,55 +764,28 @@ public class InstanceIdentifier<T extends DataObject>
             this.key = requireNonNull(key, "Key may not be null.");
         }
 
-        /**
-         * Return an IdentifiableItem instance backed by the specified class with specified key.
-         *
-         * @param type Backing class
-         * @param key Key
-         * @param <T> List type
-         * @param <I> Key type
-         * @return An IdentifiableItem
-         * @throws NullPointerException if any argument is null.
-         */
-        public static <T extends KeyAware<I> & DataObject, I extends Key<T>>
-                @NonNull IdentifiableItem<T, I> of(final Class<T> type, final I key) {
-            return new IdentifiableItem<>(type, key);
-        }
-
-        /**
-         * Return an IdentifiableItem instance backed by the specified class with specified key. The class is in turn
-         * defined in a {@code grouping} used in a corresponding {@code case} statement.
-         *
-         * @param caseType defining case class
-         * @param type Backing class
-         * @param <C> Case type
-         * @param <T> List type
-         * @param <I> Key type
-         * @return A new PathArgument
-         * @throws NullPointerException if any argument is null.
-         */
-        public static <C extends ChoiceIn<?> & DataObject, T extends ChildOf<? super C> & KeyAware<I>,
-                I extends Key<T>> @NonNull IdentifiableItem<T, I> of(final Class<C> caseType,
-                        final Class<T> type, final I key) {
-            return new CaseIdentifiableItem<>(caseType, type, key);
-        }
-
         /**
          * Return the data object type backing this PathArgument.
          *
          * @return Data object type.
          */
         @Override
-        public final @NonNull T getKey() {
+        final @NonNull T key() {
             return key;
         }
 
+        @Override
+        final KeyStep<?, ?> toStep() {
+            return new KeyStep<>(type(), caseType(), key);
+        }
+
         @Override
         public String toString() {
-            return getType().getName() + "[key=" + key + "]";
+            return type().getName() + "[key=" + key + "]";
         }
     }
 
+    @Deprecated(since = "13.0.0", forRemoval = true)
     private static final class CaseItem<C extends ChoiceIn<?> & DataObject, T extends ChildOf<? super C>>
             extends Item<T> {
         @java.io.Serial
@@ -856,11 +799,12 @@ public class InstanceIdentifier<T extends DataObject>
         }
 
         @Override
-        public Optional<Class<C>> getCaseType() {
-            return Optional.of(caseType);
+        Class<C> caseType() {
+            return caseType;
         }
     }
 
+    @Deprecated(since = "13.0.0", forRemoval = true)
     private static final class CaseIdentifiableItem<C extends ChoiceIn<?> & DataObject,
             T extends ChildOf<? super C> & KeyAware<K>, K extends Key<T>> extends IdentifiableItem<T, K> {
         @java.io.Serial
@@ -874,8 +818,8 @@ public class InstanceIdentifier<T extends DataObject>
         }
 
         @Override
-        public Optional<Class<C>> getCaseType() {
-            return Optional.of(caseType);
+        Class<C> caseType() {
+            return caseType;
         }
     }
 
@@ -885,18 +829,18 @@ public class InstanceIdentifier<T extends DataObject>
      * @param <T> Instance identifier target type
      */
     public abstract static sealed class Builder<T extends DataObject> {
-        private final ImmutableList.Builder<PathArgument> pathBuilder;
-        private final HashCodeBuilder<PathArgument> hashBuilder;
-        private final Iterable<? extends PathArgument> basePath;
+        private final ImmutableList.Builder<DataObjectStep<?>> pathBuilder;
+        private final HashCodeBuilder<DataObjectStep<?>> hashBuilder;
+        private final Iterable<? extends DataObjectStep<?>> basePath;
 
         private boolean wildcard;
 
-        Builder(final Builder<?> prev, final PathArgument item, final boolean isWildcard) {
+        Builder(final Builder<?> prev, final DataObjectStep<?> item) {
             pathBuilder = prev.pathBuilder;
             hashBuilder = prev.hashBuilder;
             basePath = prev.basePath;
             wildcard = prev.wildcard;
-            appendItem(item, isWildcard);
+            appendItem(item);
         }
 
         Builder(final InstanceIdentifier<T> identifier) {
@@ -906,7 +850,7 @@ public class InstanceIdentifier<T extends DataObject>
             basePath = identifier.pathArguments;
         }
 
-        Builder(final PathArgument item, final boolean wildcard) {
+        Builder(final DataObjectStep<?> item, final boolean wildcard) {
             pathBuilder = ImmutableList.builder();
             hashBuilder = new HashCodeBuilder<>();
             basePath = null;
@@ -930,7 +874,7 @@ public class InstanceIdentifier<T extends DataObject>
          */
         public final <N extends DataObject & Augmentation<? super T>> Builder<N> augmentation(
                 final Class<N> container) {
-            return append(Item.of(container), false);
+            return append(new NodeStep<>(container));
         }
 
         /**
@@ -951,7 +895,7 @@ public class InstanceIdentifier<T extends DataObject>
          * @throws NullPointerException if {@code container} is null
          */
         public final <N extends ChildOf<? super T>> Builder<N> child(final Class<N> container) {
-            return append(Item.of(container), KeyAware.class.isAssignableFrom(container));
+            return append(createStep(container));
         }
 
         /**
@@ -968,7 +912,7 @@ public class InstanceIdentifier<T extends DataObject>
          */
         public final <C extends ChoiceIn<? super T> & DataObject, N extends ChildOf<? super C>> Builder<N> child(
                 final Class<C> caze, final Class<N> container) {
-            return append(Item.of(caze, container), KeyAware.class.isAssignableFrom(container));
+            return append(createStep(caze, container));
         }
 
         /**
@@ -985,7 +929,7 @@ public class InstanceIdentifier<T extends DataObject>
          */
         public final <N extends KeyAware<K> & ChildOf<? super T>, K extends Key<N>> KeyedBuilder<N, K> child(
                 final Class<@NonNull N> listItem, final K listKey) {
-            return append(IdentifiableItem.of(listItem, listKey));
+            return append(new KeyStep<>(listItem, listKey));
         }
 
         /**
@@ -1005,7 +949,7 @@ public class InstanceIdentifier<T extends DataObject>
         public final <C extends ChoiceIn<? super T> & DataObject, K extends Key<N>,
                 N extends KeyAware<K> & ChildOf<? super C>> KeyedBuilder<N, K> child(final Class<C> caze,
                     final Class<N> listItem, final K listKey) {
-            return append(IdentifiableItem.of(caze, listItem, listKey));
+            return append(new KeyStep<>(listItem, requireNonNull(caze), listKey));
         }
 
         /**
@@ -1027,40 +971,42 @@ public class InstanceIdentifier<T extends DataObject>
                 && Iterables.elementsEqual(pathArguments(), other.pathArguments());
         }
 
-        final Iterable<PathArgument> pathArguments() {
+        final Iterable<DataObjectStep<?>> pathArguments() {
             final var args = pathBuilder.build();
             return basePath == null ? args : Iterables.concat(basePath, args);
         }
 
-        final void appendItem(final PathArgument item, final boolean isWildcard) {
+        final void appendItem(final DataObjectStep<?> item) {
             hashBuilder.addArgument(item);
             pathBuilder.add(item);
-            wildcard |= isWildcard;
+            if (!(item instanceof ExactDataObjectStep)) {
+                wildcard = true;
+            }
         }
 
-        abstract <X extends DataObject> @NonNull RegularBuilder<X> append(Item<X> item, boolean isWildcard);
+        abstract <X extends DataObject> @NonNull RegularBuilder<X> append(DataObjectStep<X> step);
 
-        abstract <X extends DataObject & KeyAware<Y>, Y extends Key<X>>
-            @NonNull KeyedBuilder<X, Y> append(IdentifiableItem<X, Y> item);
+        abstract <X extends DataObject & KeyAware<Y>, Y extends Key<X>> @NonNull KeyedBuilder<X, Y> append(
+            KeyStep<Y, X> step);
     }
 
     public static final class KeyedBuilder<T extends DataObject & KeyAware<K>, K extends Key<T>>
             extends Builder<T> {
-        private @NonNull IdentifiableItem<T, K> lastItem;
+        private @NonNull KeyStep<K, T> lastStep;
 
-        KeyedBuilder(final IdentifiableItem<T, K> item) {
-            super(item, false);
-            lastItem = requireNonNull(item);
+        KeyedBuilder(final KeyStep<K, T> firstStep) {
+            super(firstStep, false);
+            lastStep = requireNonNull(firstStep);
         }
 
         KeyedBuilder(final KeyedInstanceIdentifier<T, K> identifier) {
             super(identifier);
-            lastItem = IdentifiableItem.of(identifier.getTargetType(), identifier.getKey());
+            lastStep = identifier.lastStep();
         }
 
-        private KeyedBuilder(final RegularBuilder<?> prev, final IdentifiableItem<T, K> item) {
-            super(prev, item, false);
-            lastItem = requireNonNull(item);
+        private KeyedBuilder(final RegularBuilder<?> prev, final KeyStep<K, T> lastStep) {
+            super(prev, lastStep);
+            this.lastStep = requireNonNull(lastStep);
         }
 
         /**
@@ -1070,21 +1016,19 @@ public class InstanceIdentifier<T extends DataObject>
          */
         @Override
         public @NonNull KeyedInstanceIdentifier<T, K> build() {
-            return new KeyedInstanceIdentifier<>(lastItem.getType(), pathArguments(), wildcard(), hashCode(),
-                lastItem.getKey());
+            return new KeyedInstanceIdentifier<>(lastStep, pathArguments(), wildcard(), hashCode());
         }
 
         @Override
-        <X extends DataObject> @NonNull RegularBuilder<X> append(final Item<X> item, final boolean isWildcard) {
-            return new RegularBuilder<>(this, item, isWildcard);
+        <X extends DataObject> @NonNull RegularBuilder<X> append(final DataObjectStep<X> step) {
+            return new RegularBuilder<>(this, step);
         }
 
         @Override
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
-                final IdentifiableItem<X, Y> item) {
-            appendItem(item, false);
-            lastItem = (IdentifiableItem) item;
+        @SuppressWarnings("unchecked")
+        <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(final KeyStep<Y, X> step) {
+            appendItem(step);
+            lastStep = (KeyStep<K, T>) requireNonNull(step);
             return (KeyedBuilder<X, Y>) this;
         }
     }
@@ -1092,9 +1036,9 @@ public class InstanceIdentifier<T extends DataObject>
     private static final class RegularBuilder<T extends DataObject> extends Builder<T> {
         private @NonNull Class<T> type;
 
-        RegularBuilder(final Item<T> item) {
-            super(item, KeyAware.class.isAssignableFrom(item.getType()));
-            type = item.getType();
+        RegularBuilder(final DataObjectStep<T> item) {
+            super(item, !(item instanceof ExactDataObjectStep));
+            type = item.type();
         }
 
         RegularBuilder(final InstanceIdentifier<T> identifier) {
@@ -1102,9 +1046,9 @@ public class InstanceIdentifier<T extends DataObject>
             type = identifier.getTargetType();
         }
 
-        private RegularBuilder(final KeyedBuilder<?, ?> prev, final Item<T> item, final boolean wildcard) {
-            super(prev, item, wildcard);
-            type = item.getType();
+        private RegularBuilder(final KeyedBuilder<?, ?> prev, final DataObjectStep<T> item) {
+            super(prev, item);
+            type = item.type();
         }
 
         @Override
@@ -1114,15 +1058,15 @@ public class InstanceIdentifier<T extends DataObject>
 
         @Override
         @SuppressWarnings({ "rawtypes", "unchecked" })
-        <X extends DataObject> RegularBuilder<X> append(final Item<X> item, final boolean isWildcard) {
-            appendItem(item, isWildcard);
-            type = (Class) item.getType();
+        <X extends DataObject> RegularBuilder<X> append(final DataObjectStep<X> step) {
+            appendItem(step);
+            type = (Class) step.type();
             return (RegularBuilder<X>) this;
         }
 
         @Override
         <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
-                final IdentifiableItem<X, Y> item) {
+                final KeyStep<Y, X> item) {
             return new KeyedBuilder<>(this, item);
         }
     }
index 80fcf144417f3978987822482ff1b5b6e7cdfac5..4158b1f3c205612080553550c01b3b6a060bc7d8 100644 (file)
@@ -8,23 +8,20 @@
 package org.opendaylight.yangtools.yang.binding;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import java.io.Externalizable;
 import java.io.IOException;
+import java.io.NotSerializableException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.io.ObjectStreamException;
 import java.io.Serial;
-import java.util.ArrayList;
-import java.util.List;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
 
 class InstanceIdentifierV3<T extends DataObject> implements Externalizable {
     @Serial
     private static final long serialVersionUID = 3L;
 
-    private @Nullable Iterable<PathArgument> pathArguments;
+    private @Nullable Iterable<DataObjectStep<?>> pathArguments;
     private @Nullable Class<T> targetType;
     private boolean wildcarded;
     private int hash;
@@ -34,18 +31,11 @@ class InstanceIdentifierV3<T extends DataObject> implements Externalizable {
         // For Externalizable
     }
 
-    InstanceIdentifierV3(final InstanceIdentifier<T> source) {
-        pathArguments = source.pathArguments;
-        targetType = source.getTargetType();
-        wildcarded = source.isWildcarded();
-        hash = source.hashCode();
-    }
-
     final int getHash() {
         return hash;
     }
 
-    final Iterable<PathArgument> getPathArguments() {
+    final Iterable<DataObjectStep<?>> getPathArguments() {
         return pathArguments;
     }
 
@@ -59,13 +49,7 @@ class InstanceIdentifierV3<T extends DataObject> implements Externalizable {
 
     @Override
     public void writeExternal(final ObjectOutput out) throws IOException {
-        out.writeObject(targetType);
-        out.writeBoolean(wildcarded);
-        out.writeInt(hash);
-        out.writeInt(Iterables.size(pathArguments));
-        for (Object o : pathArguments) {
-            out.writeObject(o);
-        }
+        throw new NotSerializableException(InstanceIdentifierV3.class.getName());
     }
 
     @Override
@@ -75,14 +59,14 @@ class InstanceIdentifierV3<T extends DataObject> implements Externalizable {
         hash = in.readInt();
 
         final int size = in.readInt();
-        final List<PathArgument> args = new ArrayList<>();
+        final var builder = ImmutableList.<DataObjectStep<?>>builderWithExpectedSize(size);
         for (int i = 0; i < size; ++i) {
-            args.add((PathArgument) in.readObject());
+            builder.add((DataObjectStep<?>) in.readObject());
         }
-        pathArguments = ImmutableList.copyOf(args);
+        pathArguments = builder.build();
     }
 
-    @Serial
+    @java.io.Serial
     Object readResolve() throws ObjectStreamException {
         return new InstanceIdentifier<>(targetType, pathArguments, wildcarded, hash);
     }
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KIIv4.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KIIv4.java
new file mode 100644 (file)
index 0000000..3cb9087
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.yangtools.yang.binding;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+
+final class KIIv4<T extends KeyAware<K> & DataObject, K extends Key<T>> extends IIv4<T> {
+    @java.io.Serial
+    private static final long serialVersionUID = 2L;
+
+    private K key;
+
+    @SuppressWarnings("redundantModifier")
+    public KIIv4() {
+        // For Externalizable
+    }
+
+    KIIv4(final KeyedInstanceIdentifier<T, K> source) {
+        super(source);
+        key = source.getKey();
+    }
+
+    @Override
+    public void writeExternal(final ObjectOutput out) throws IOException {
+        super.writeExternal(out);
+        out.writeObject(key);
+    }
+
+    @Override
+    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+        super.readExternal(in);
+        key = (K) in.readObject();
+    }
+
+    @java.io.Serial
+    @Override
+    Object readResolve() throws ObjectStreamException {
+        return new KeyedInstanceIdentifier<>(new KeyStep<>(getTargetType(), key), getPathArguments(),
+            isWildcarded(), getHash());
+    }
+}
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyStep.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeyStep.java
new file mode 100644 (file)
index 0000000..ed002cc
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2024 PANTHEON.tech, 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.yangtools.yang.binding;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * A {@link KeyAware}-based step with a {@link #key()}. It equates to a {@code node-identifier} with a
+ * {@code key-predicate}.
+ *
+ * @param <K> Key type
+ * @param <T> KeyAware type
+ */
+public record KeyStep<K extends Key<T>, T extends KeyAware<K> & DataObject>(
+        @NonNull Class<T> type,
+        @Nullable Class<? extends DataObject> caseType,
+        @NonNull K key) implements ExactDataObjectStep<T>, KeyAware<K> {
+    @java.io.Serial
+    private static final long serialVersionUID = 0;
+
+    public KeyStep {
+        NodeStep.checkType(type, true);
+        NodeStep.checkCaseType(caseType);
+        requireNonNull(key);
+    }
+
+    public KeyStep(final @NonNull Class<T> type, final @NonNull K key) {
+        this(type, null, key);
+    }
+}
index ecbc48aeb63f8c20a9a15bfc2a3894dfb6cd28f4..ebd5cd258b0ed20ddcbd806995ac9e5e232aa092 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.yang.binding;
 
 import java.io.ObjectStreamException;
-import java.io.Serial;
 import org.eclipse.jdt.annotation.NonNull;
 
 /**
@@ -17,17 +16,21 @@ import org.eclipse.jdt.annotation.NonNull;
  * @param <T> Target data type
  * @param <K> Target key type
  */
-public class KeyedInstanceIdentifier<T extends KeyAware<K> & DataObject, K extends Key<T>>
+public final class KeyedInstanceIdentifier<T extends KeyAware<K> & DataObject, K extends Key<T>>
         extends InstanceIdentifier<T> {
-    @Serial
+    @java.io.Serial
     private static final long serialVersionUID = 2L;
 
-    private final K key;
+    private final @NonNull KeyStep<K, T> lastStep;
 
-    KeyedInstanceIdentifier(final Class<@NonNull T> type, final Iterable<PathArgument> pathArguments,
-            final boolean wildcarded, final int hash, final K key) {
-        super(type, pathArguments, wildcarded, hash);
-        this.key = key;
+    KeyedInstanceIdentifier(final KeyStep<K, T> lastStep, final Iterable<DataObjectStep<?>> pathArguments,
+            final boolean wildcarded, final int hash) {
+        super(lastStep.type(), pathArguments, wildcarded, hash);
+        this.lastStep = lastStep;
+    }
+
+    @NonNull KeyStep<K, T> lastStep() {
+        return lastStep;
     }
 
     /**
@@ -36,29 +39,22 @@ public class KeyedInstanceIdentifier<T extends KeyAware<K> & DataObject, K exten
      *
      * @return Key associated with this instance identifier.
      */
-    public final K getKey() {
-        return key;
+    public @NonNull K getKey() {
+        return lastStep.key();
     }
 
     @Override
-    public final KeyedBuilder<T, K> builder() {
+    public KeyedBuilder<T, K> builder() {
         return new KeyedBuilder<>(this);
     }
 
     @Override
-    protected boolean fastNonEqual(final InstanceIdentifier<?> other) {
-        final KeyedInstanceIdentifier<?, ?> kii = (KeyedInstanceIdentifier<?, ?>) other;
-
-        /*
-         * We could do an equals() here, but that may actually be expensive.
-         * equals() in superclass falls back to a full compare, which will
-         * end up running that equals anyway, so do not bother here.
-         */
-        return key == null != (kii.key == null);
+    boolean keyEquals(final InstanceIdentifier<?> other) {
+        return getKey().equals(((KeyedInstanceIdentifier<?, ?>) other).getKey());
     }
 
-    @Serial
-    private Object writeReplace() throws ObjectStreamException {
-        return new KeyedInstanceIdentifierV2<>(this);
+    @Override
+    Object writeReplace() throws ObjectStreamException {
+        return new KIIv4<>(this);
     }
 }
index df19d31ff6ba6c053c28da5a1164525f0d93c094..a9f718298d5440d564a5759fd231f53ec3c722eb 100644 (file)
@@ -12,25 +12,19 @@ import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.io.ObjectStreamException;
 import java.io.Serial;
-import org.eclipse.jdt.annotation.Nullable;
 
 final class KeyedInstanceIdentifierV2<T extends KeyAware<K> & DataObject, K extends Key<T>>
         extends InstanceIdentifierV3<T> {
-    @Serial
+    @java.io.Serial
     private static final long serialVersionUID = 2L;
 
-    private @Nullable K key;
+    private K key;
 
     @SuppressWarnings("redundantModifier")
     public KeyedInstanceIdentifierV2() {
         // For Externalizable
     }
 
-    KeyedInstanceIdentifierV2(final KeyedInstanceIdentifier<T, K> source) {
-        super(source);
-        key = source.getKey();
-    }
-
     @Override
     public void writeExternal(final ObjectOutput out) throws IOException {
         super.writeExternal(out);
@@ -46,6 +40,7 @@ final class KeyedInstanceIdentifierV2<T extends KeyAware<K> & DataObject, K exte
     @Serial
     @Override
     Object readResolve() throws ObjectStreamException {
-        return new KeyedInstanceIdentifier<>(getTargetType(), getPathArguments(), isWildcarded(), getHash(), key);
+        return new KeyedInstanceIdentifier<>(new KeyStep<>(getTargetType(), key), getPathArguments(),
+            isWildcarded(), getHash());
     }
 }
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeylessStep.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/KeylessStep.java
new file mode 100644 (file)
index 0000000..8d1fce0
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2024 PANTHEON.tech, 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.yangtools.yang.binding;
+
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * A {@link KeyAware}-based step without the corresponding key. This corresponds to a {@code node-identifier} step,
+ * where we know there is a {@code key-predicate} possible, but we do not have it.
+ *
+ * @param <T> KeyAware type
+ */
+public record KeylessStep<T extends KeyAware<?> & DataObject>(
+        @NonNull Class<T> type,
+        @Nullable Class<? extends DataObject> caseType) implements DataObjectStep<T> {
+    @java.io.Serial
+    private static final long serialVersionUID = 0;
+
+    public KeylessStep {
+        NodeStep.checkType(type, true);
+        NodeStep.checkCaseType(caseType);
+    }
+
+    public KeylessStep(final @NonNull Class<T> type) {
+        this(type, null);
+    }
+
+    boolean matches(final @NonNull DataObjectStep<?> other) {
+        // FIXME: this should be an instanceof check for KeyStep, then a match -- i.e. reject match on plain NodeStep,
+        //        because that is an addressing mismatch
+        return type.equals(other.type()) && Objects.equals(caseType, other.caseType());
+    }
+}
diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/NodeStep.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/NodeStep.java
new file mode 100644 (file)
index 0000000..d14fbf2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2024 PANTHEON.tech, 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.yangtools.yang.binding;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * A {@link DataObject}-based step along an {@code instance-identifier}. It equates to a {@code node-identifier} and
+ * carries additional assertion that there are no valid predicates for this type.
+ *
+ * @param <T> DataObject type
+ */
+public record NodeStep<T extends DataObject>(
+        @NonNull Class<T> type,
+        @Nullable Class<? extends DataObject> caseType) implements ExactDataObjectStep<T> {
+    @java.io.Serial
+    private static final long serialVersionUID = 0;
+
+    public NodeStep {
+        checkType(type, false);
+        checkCaseType(caseType);
+    }
+
+    public NodeStep(final @NonNull Class<T> type) {
+        this(type, null);
+    }
+
+    static void checkType(final Class<?> type, final boolean keyAware) {
+        if (!DataObject.class.isAssignableFrom(type) || KeyAware.class.isAssignableFrom(type) != keyAware) {
+            throw new IllegalArgumentException("Invalid type " + type);
+        }
+    }
+
+    static void checkCaseType(final @Nullable Class<?> caseType) {
+        if (caseType != null && !DataObject.class.isAssignableFrom(caseType)) {
+            throw new IllegalArgumentException("Invalid case type " + caseType);
+        }
+    }
+}
index b560e84da63872de618b10e4f25b2cdaa8f269eb..bf173a65abbd72f6f4b055f8b1bac8b9e6709f4f 100644 (file)
@@ -14,7 +14,6 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
 
 import com.google.common.base.VerifyException;
 import com.google.common.collect.ImmutableList;
@@ -183,9 +182,9 @@ public class InstanceIdentifierTest {
 
     @Test
     public void keyOfTest() {
-        final Key<?> identifier = mock(Key.class);
-        assertEquals(identifier, InstanceIdentifier.keyOf(
-                new KeyedInstanceIdentifier(KeyAware.class, ImmutableList.of(), false, 0, identifier)));
+        final var key = new NodeKey(42);
+        assertEquals(key, InstanceIdentifier.keyOf(
+            new KeyedInstanceIdentifier<>(new KeyStep<>(Node.class, key), ImmutableList.of(), false, 0)));
     }
 
     @Test
index 466b168a00c8c84dc8f9ba5480c1ca90db4483ad..f9531a8f0bd342df0551a40b45ceedd5952fa706 100644 (file)
@@ -8,25 +8,24 @@
 package org.opendaylight.yangtools.yang.binding;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
 
 import com.google.common.collect.ImmutableList;
 import org.junit.Test;
+import org.opendaylight.yangtools.yang.binding.test.mock.Node;
+import org.opendaylight.yangtools.yang.binding.test.mock.NodeKey;
 
 public class KeyedInstanceIdentifierTest {
-
     @Test
     public void basicTest() {
-        final Key<?> key = mock(Key.class);
-        final KeyedInstanceIdentifier<?, ?> keyedInstanceIdentifier =
-                new KeyedInstanceIdentifier(KeyAware.class, ImmutableList.of(), false, 0, key);
+        final var key = new NodeKey(0);
+        final var keyed = new KeyedInstanceIdentifier<>(new KeyStep<>(Node.class, key), ImmutableList.of(),
+            false, 0);
 
-        assertEquals(key, keyedInstanceIdentifier.getKey());
+        assertEquals(key, keyed.getKey());
+        assertTrue(keyed.keyEquals(keyed.builder().build()));
 
-        assertFalse(keyedInstanceIdentifier.fastNonEqual(keyedInstanceIdentifier.builder().build()));
-        assertTrue(new KeyedInstanceIdentifier(KeyAware.class, ImmutableList.of(), false, 0, null)
-                .fastNonEqual(keyedInstanceIdentifier.builder().build()));
+        final var keyless = new InstanceIdentifier<>(Node.class, ImmutableList.of(), true, 0);
+        assertTrue(keyless.keyEquals(keyed.builder().build()));
     }
 }
\ No newline at end of file
index 641e185d1b3db68fd2c0d21984b1fe3f198b26b0..49df6240bd8117fa726f4fc11475f86db1b4a6fb 100644 (file)
@@ -233,8 +233,8 @@ public class TracingBroker implements TracingDOMDataBroker {
     }
 
     static void toPathString(final InstanceIdentifier<? extends DataObject> iid, final StringBuilder builder) {
-        for (InstanceIdentifier.PathArgument pathArg : iid.getPathArguments()) {
-            builder.append('/').append(pathArg.getType().getSimpleName());
+        for (var pathArg : iid.getPathArguments()) {
+            builder.append('/').append(pathArg.type().getSimpleName());
         }
     }