Add DataObject{Identifier,Reference}.Builder(.WithKey) 62/112362/9
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 28 Jun 2024 09:30:44 +0000 (11:30 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 28 Jun 2024 16:58:27 +0000 (18:58 +0200)
This patch adds a proper Builder definition and specialized
implementations, which produce DataObject{Identifier,Reference} and not
InstanceIdentifier as such.

This also eliminates the notion that a Builder has a hashCode/equals
contract.

JIRA: YANGTOOLS-1577
Change-Id: Ie3fe06264f58a6985123034f439f413fce0d251b
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
16 files changed:
binding/binding-data-codec-dynamic/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataContainerAnalysis.java
binding/binding-data-codec-dynamic/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/DataObjectCodecPrototype.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/DataObjectIdentifier.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/DataObjectReference.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/DataObjectStep.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/AbstractDataObjectReference.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/AbstractDataObjectReferenceBuilder.java [new file with mode: 0644]
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectIdentifierImpl.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectIdentifierWithKey.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceBuilder.java [new file with mode: 0644]
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceBuilderWithKey.java [new file with mode: 0644]
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceImpl.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceWithKey.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/ORv1.java
binding/binding-spec/src/main/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifier.java
binding/binding-spec/src/test/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifierTest.java

index d3eb3c575e85ac1ce031a041c2b16136d710f4bb..bbf6920804b8699b9404df2f686cc93920ed1c2e 100644 (file)
@@ -34,7 +34,6 @@ import org.opendaylight.yangtools.binding.runtime.api.ContainerLikeRuntimeType;
 import org.opendaylight.yangtools.binding.runtime.api.ContainerRuntimeType;
 import org.opendaylight.yangtools.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.yangtools.util.ClassLoaderUtils;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
@@ -174,8 +173,7 @@ final class DataContainerAnalysis<R extends CompositeRuntimeType> {
     private static @NonNull DataObjectStep<?> createItem(final @Nullable Class<? extends DataObject> caseClass,
             final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
         return caseClass != null && childSchema instanceof AddedByUsesAware aware && aware.isAddedByUses()
-            ? InstanceIdentifier.createStep((Class) caseClass, (Class) childClass)
-                : InstanceIdentifier.createStep((Class) childClass);
+            ? DataObjectStep.of((Class) caseClass, (Class) childClass) : DataObjectStep.of((Class) childClass);
     }
 
     // FIXME: MDSAL-780: these methods perform analytics using java.lang.reflect to acquire the basic shape of the
index 8458b5c4017f9287c7b9e41abf98b06b706bca7b..717aec2dccb13556b244d76372551d4308183618 100644 (file)
@@ -13,7 +13,6 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.DataObject;
 import org.opendaylight.yangtools.binding.DataObjectStep;
 import org.opendaylight.yangtools.binding.runtime.api.CompositeRuntimeType;
-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>
@@ -23,7 +22,7 @@ abstract sealed class DataObjectCodecPrototype<T extends CompositeRuntimeType> e
 
     DataObjectCodecPrototype(final Class<?> cls, final NodeIdentifier yangArg, final T type,
             final CodecContextFactory factory) {
-        this(InstanceIdentifier.createStep(cls.asSubclass(DataObject.class)), yangArg, type, factory);
+        this(DataObjectStep.of(cls.asSubclass(DataObject.class)), yangArg, type, factory);
     }
 
     DataObjectCodecPrototype(final DataObjectStep<?> bindingArg, final NodeIdentifier yangArg, final T type,
index 373650b355d0355f9184176eca99c75c16d06653..8c5a237ad537f66b0b59a49d5396bf7e361f9637 100644 (file)
@@ -12,7 +12,6 @@ import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.impl.DataObjectIdentifierImpl;
 import org.opendaylight.yangtools.binding.impl.DataObjectIdentifierWithKey;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.KeyedBuilder;
 
 /**
  * A {@link DataObjectReference} matching at most one {@link DataObject}, consistent with YANG
@@ -36,7 +35,7 @@ public sealed interface DataObjectIdentifier<T extends DataObject>
         KeyStep<K, T> lastStep();
 
         @Override
-        KeyedBuilder<T, K> toBuilder();
+        Builder.WithKey<T, K> toBuilder();
     }
 
     static @NonNull DataObjectIdentifier<?> ofUnsafeSteps(
@@ -51,7 +50,6 @@ public sealed interface DataObjectIdentifier<T extends DataObject>
 
     static @NonNull DataObjectIdentifier<?> ofUnsafeSteps(
             final ImmutableList<? extends @NonNull ExactDataObjectStep<?>> steps) {
-        // FIXME: YANGTOOLS-1577: DataObjectReferenceImpl.ofUnsafeSteps() instead
         return DataObjectIdentifierImpl.ofUnsafeSteps(steps);
     }
 
index 2dc71c34ece1a7dbf8d4fb97bdaf760679907035..0d3b2279eda1a9c0d995f0a6d140e293a3aab009 100644 (file)
@@ -12,11 +12,13 @@ import java.io.Serializable;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReference;
+import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReferenceBuilder;
+import org.opendaylight.yangtools.binding.impl.DataObjectIdentifierImpl;
+import org.opendaylight.yangtools.binding.impl.DataObjectReferenceBuilderWithKey;
 import org.opendaylight.yangtools.binding.impl.DataObjectReferenceImpl;
 import org.opendaylight.yangtools.binding.impl.DataObjectReferenceWithKey;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Builder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.KeyedBuilder;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 
@@ -44,6 +46,101 @@ import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 //* </ul>
 public sealed interface DataObjectReference<T extends DataObject> extends Immutable, Serializable
         permits DataObjectIdentifier, DataObjectReference.WithKey, AbstractDataObjectReference {
+    /**
+     * A builder of {@link DataObjectReference} objects.
+     *
+     * @param <T> type of {@link DataObject} held in the last step.
+     */
+    sealed interface Builder<T extends DataObject> permits Builder.WithKey, AbstractDataObjectReferenceBuilder {
+        /**
+         * A builder of {@link DataObjectReference.WithKey} objects.
+         *
+         * @param <T> type of {@link KeyAware} {@link DataObject} held in the last step.
+         * @param <K> {@link Key} type
+         */
+        sealed interface WithKey<T extends KeyAware<K> & DataObject, K extends Key<T>> extends Builder<T>
+                permits DataObjectReferenceBuilderWithKey, KeyedBuilder {
+            @Override
+            DataObjectReference.WithKey<T, K> build();
+        }
+
+        /**
+         * Update this builder to build a reference to a specific augmentation of the data object this builder currently
+         * points to.
+         *
+         * @param <N> augmentation type
+         * @param augmentation augmentation class
+         * @return this builder
+         * @throws NullPointerException if {@code augmentation} is {@code null}
+         */
+        <N extends DataObject & Augmentation<? super T>> @NonNull Builder<N> augmentation(
+            @NonNull Class<N> augmentation);
+
+        /**
+         * Append the specified container as a child of the data object this build currently references. This method
+         * should be used when you want to build an instance identifier by appending top-level elements.
+         *
+         * @param <N> Container type
+         * @param container Container to append
+         * @return this builder
+         * @throws NullPointerException if {@code container} is null
+         */
+        <N extends ChildOf<? super T>> @NonNull Builder<N> child(@NonNull Class<N> container);
+
+        /**
+         * Append the specified container as a child of the data object this build currently references. This method
+         * should be used when you want to build an reference by appending a container node to the identifier and the
+         * {@code container} is defined in a {@code grouping} used in a {@code case} statement.
+         *
+         * @param <C> Case type
+         * @param <N> Container type
+         * @param caze Choice case class
+         * @param container Container to append
+         * @return this builder
+         * @throws NullPointerException if {@code container} is null
+         */
+        <C extends ChoiceIn<? super T> & DataObject, N extends ChildOf<? super C>> @NonNull Builder<N> child(
+                Class<C> caze, @NonNull Class<N> container);
+
+        /**
+         * Append the specified listItem as a child of the data object this build currently references. This method
+         * should be used when you want to build a reference by appending a specific list element to the identifier.
+         *
+         * @param <N> List type
+         * @param <K> Key type
+         * @param listItem List to append
+         * @param listKey List key
+         * @return this builder
+         * @throws NullPointerException if any argument is null
+         */
+        <N extends KeyAware<K> & ChildOf<? super T>, K extends Key<N>> @NonNull WithKey<N, K> child(
+                @NonNull Class<@NonNull N> listItem, @NonNull K listKey);
+
+        /**
+         * Append the specified listItem as a child of the data object this build currently references. This
+         * method should be used when you want to build a reference by appending a specific list element to the
+         * identifier and the {@code list} is defined in a {@code grouping} used in a {@code case} statement.
+         *
+         * @param <C> Case type
+         * @param <N> List type
+         * @param <K> Key type
+         * @param caze Choice case class
+         * @param listItem List to append
+         * @param listKey List key
+         * @return this builder
+         * @throws NullPointerException if any argument is null
+         */
+        <C extends ChoiceIn<? super T> & DataObject, K extends Key<N>, N extends KeyAware<K> & ChildOf<? super C>>
+            @NonNull WithKey<N, K> child(@NonNull Class<C> caze, @NonNull Class<N> listItem, @NonNull K listKey);
+
+        /**
+         * Build the data object reference.
+         *
+         * @return resulting {@link DataObjectReference}.
+         */
+        @NonNull DataObjectReference<T> build();
+    }
+
     /**
      * A {@link DataObjectReference} pointing to a {@link KeyAware} {@link DataObject}, typically a map entry.
      *
@@ -57,7 +154,7 @@ public sealed interface DataObjectReference<T extends DataObject> extends Immuta
         KeyStep<K, T> lastStep();
 
         @Override
-        KeyedBuilder<T, K> toBuilder();
+        Builder.WithKey<T, K> toBuilder();
 
         @Override
         default K key() {
@@ -85,8 +182,13 @@ public sealed interface DataObjectReference<T extends DataObject> extends Immuta
         return ofUnsafeSteps(ImmutableList.copyOf(steps));
     }
 
+    @SuppressWarnings("unchecked")
     static @NonNull DataObjectReference<?> ofUnsafeSteps(
             final ImmutableList<? extends @NonNull DataObjectStep<?>> steps) {
+        if (steps.stream().allMatch(ExactDataObjectStep.class::isInstance)) {
+            return DataObjectIdentifierImpl.ofUnsafeSteps(
+                (ImmutableList<? extends @NonNull ExactDataObjectStep<?>>) steps);
+        }
         return DataObjectReferenceImpl.ofUnsafeSteps(steps);
     }
 
index 237aee94331cda446b346d17805da8783f60b359..21a891be72a820058985ad1ed48542458553e84e 100644 (file)
@@ -30,6 +30,17 @@ import org.eclipse.jdt.annotation.Nullable;
  */
 public sealed interface DataObjectStep<T extends DataObject> extends Comparable<DataObjectStep<?>>, Serializable
         permits ExactDataObjectStep, InexactDataObjectStep {
+
+    static <T extends DataObject> @NonNull DataObjectStep<T> of(final @NonNull Class<T> type) {
+        return of(null, type);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    static <T extends DataObject, C extends ChoiceIn<?> & DataObject> @NonNull DataObjectStep<T> of(
+            final @Nullable Class<C> caze, final @NonNull Class<T> type) {
+        return KeyAware.class.isAssignableFrom(type) ? new KeylessStep(type, caze) : new NodeStep<>(type, caze);
+    }
+
     /**
      * Return the data object type backing this PathArgument.
      *
index 7ec2b446db2ecdd732c22017f72b5c879d35e88e..53428d3bdd95f5b4cc2dce477d32f95932506b07 100644 (file)
@@ -97,7 +97,7 @@ public abstract sealed class AbstractDataObjectReference<T extends DataObject, S
     }
 
     @NonNullByDefault
-    public static final <T> Iterable<? extends T> concat(final Iterable<? extends T> others, final T last) {
+    protected static final <T> Iterable<? extends T> concat(final Iterable<? extends T> others, final T last) {
         return new AppendIterable<>(others, last);
     }
 
diff --git a/binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/AbstractDataObjectReferenceBuilder.java b/binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/AbstractDataObjectReferenceBuilder.java
new file mode 100644 (file)
index 0000000..15aec3a
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.binding.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.binding.Augmentation;
+import org.opendaylight.yangtools.binding.ChildOf;
+import org.opendaylight.yangtools.binding.ChoiceIn;
+import org.opendaylight.yangtools.binding.DataObject;
+import org.opendaylight.yangtools.binding.DataObjectReference;
+import org.opendaylight.yangtools.binding.DataObjectReference.Builder;
+import org.opendaylight.yangtools.binding.DataObjectStep;
+import org.opendaylight.yangtools.binding.ExactDataObjectStep;
+import org.opendaylight.yangtools.binding.Key;
+import org.opendaylight.yangtools.binding.KeyAware;
+import org.opendaylight.yangtools.binding.KeyStep;
+import org.opendaylight.yangtools.binding.NodeStep;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Base implementation of {@link Builder}.
+ */
+public abstract sealed class AbstractDataObjectReferenceBuilder<T extends DataObject> implements Builder<T>
+        permits DataObjectReferenceBuilder, DataObjectReferenceBuilderWithKey, InstanceIdentifier.Builder {
+    private final ArrayList<@NonNull DataObjectStep<?>> pathBuilder;
+    private final Iterable<? extends @NonNull DataObjectStep<?>> basePath;
+
+    private boolean wildcard;
+
+    protected AbstractDataObjectReferenceBuilder(final AbstractDataObjectReferenceBuilder<?> prev,
+            final DataObjectStep<?> item) {
+        pathBuilder = prev.pathBuilder;
+        basePath = prev.basePath;
+        wildcard = prev.wildcard;
+        appendItem(item);
+    }
+
+    protected AbstractDataObjectReferenceBuilder(final DataObjectReference<T> base) {
+        pathBuilder = new ArrayList<>(4);
+        wildcard = base.isWildcarded();
+        basePath = base.steps();
+    }
+
+    protected AbstractDataObjectReferenceBuilder(final DataObjectStep<?> item, final boolean wildcard) {
+        pathBuilder = new ArrayList<>(4);
+        basePath = null;
+        this.wildcard = wildcard;
+        appendItem(item);
+    }
+
+    @Override
+    public <N extends DataObject & Augmentation<? super T>> Builder<N> augmentation(final Class<N> augmentation) {
+        return append(new NodeStep<>(augmentation));
+    }
+
+    @Override
+    public <N extends ChildOf<? super T>> Builder<N> child(final Class<N> container) {
+        return append(DataObjectStep.of(container));
+    }
+
+    @Override
+    public <C extends ChoiceIn<? super T> & DataObject, N extends ChildOf<? super C>> Builder<N> child(
+            final Class<C> caze, final Class<N> container) {
+        return append(DataObjectStep.of(caze, container));
+    }
+
+    @Override
+    public <N extends KeyAware<K> & ChildOf<? super T>, K extends Key<N>> WithKey<N, K> child(final Class<N> listItem,
+            final K listKey) {
+        return append(new KeyStep<>(listItem, listKey));
+    }
+
+    @Override
+    public <C extends ChoiceIn<? super T> & DataObject, K extends Key<N>, N extends KeyAware<K> & ChildOf<? super C>>
+            WithKey<N, K> child(final Class<C> caze, final Class<N> listItem, final K listKey) {
+        return append(new KeyStep<>(listItem, requireNonNull(caze), listKey));
+    }
+
+    @Override
+    public abstract DataObjectReference<T> build();
+
+    protected abstract <X extends DataObject> @NonNull Builder<X> append(@NonNull DataObjectStep<X> step);
+
+    protected abstract <X extends DataObject & KeyAware<Y>, Y extends Key<X>> @NonNull WithKey<X, Y> append(
+        @NonNull KeyStep<Y, X> step);
+
+    protected final boolean wildcard() {
+        return wildcard;
+    }
+
+    protected final void appendItem(final DataObjectStep<?> item) {
+        pathBuilder.add(requireNonNull(item));
+        if (!(item instanceof ExactDataObjectStep)) {
+            wildcard = true;
+        }
+    }
+
+    protected final @NonNull Iterable<? extends @NonNull DataObjectStep<?>> buildSteps() {
+        final var prefix = basePath;
+        if (prefix == null) {
+            return pathBuilder.isEmpty() ? ImmutableList.of() : ImmutableList.copyOf(pathBuilder);
+        }
+
+        return switch (pathBuilder.size()) {
+            case 0 -> prefix;
+            case 1 -> new AppendIterable<>(prefix, pathBuilder.getFirst());
+            default -> ImmutableList.<DataObjectStep<?>>builder().addAll(prefix).addAll(pathBuilder).build();
+        };
+    }
+}
index 251959806f744c1de9829f9efd761ac11225168c..0c7db6ddedd071b99306075efa15078c79f93ce9 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.binding.impl;
 
+import static com.google.common.base.Verify.verify;
+
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.io.ObjectInputStream;
@@ -15,10 +17,11 @@ import java.io.ObjectStreamException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.DataObject;
 import org.opendaylight.yangtools.binding.DataObjectIdentifier;
+import org.opendaylight.yangtools.binding.DataObjectStep;
 import org.opendaylight.yangtools.binding.ExactDataObjectStep;
+import org.opendaylight.yangtools.binding.KeyStep;
 
-// FIXME: YANGTOOLS-1577: non-abstract
-public abstract sealed class DataObjectIdentifierImpl<T extends DataObject>
+public sealed class DataObjectIdentifierImpl<T extends DataObject>
         extends AbstractDataObjectReference<T, ExactDataObjectStep<?>> implements DataObjectIdentifier<T>
         permits DataObjectIdentifierWithKey {
     @java.io.Serial
@@ -28,10 +31,27 @@ public abstract sealed class DataObjectIdentifierImpl<T extends DataObject>
         super(steps);
     }
 
+    DataObjectIdentifierImpl(final Void unused, final Iterable<? extends @NonNull DataObjectStep<?>> steps) {
+        this(verifySteps(steps));
+    }
+
+    @SuppressWarnings("unchecked")
+    private static @NonNull Iterable<? extends @NonNull ExactDataObjectStep<?>> verifySteps(
+            final Iterable<? extends @NonNull DataObjectStep<?>> steps) {
+        steps.forEach(step -> verify(step instanceof ExactDataObjectStep, "%s is not an exact step", step));
+        return (Iterable<? extends @NonNull ExactDataObjectStep<?>>) steps;
+    }
+
     public static final @NonNull DataObjectIdentifierImpl<?> ofUnsafeSteps(
             final ImmutableList<? extends @NonNull ExactDataObjectStep<?>> steps) {
-        // FIXME: YANGTOOLS-1577: implement this
-        throw new UnsupportedOperationException();
+        final var last = steps.getLast();
+        return last instanceof KeyStep ? new DataObjectIdentifierWithKey<>(steps)
+            : new DataObjectIdentifierImpl<>(steps);
+    }
+
+    @Override
+    public AbstractDataObjectReferenceBuilder<T> toBuilder() {
+        return new DataObjectReferenceBuilder<>(this);
     }
 
     @Override
index e5d9d19b22f40eaaf1a4978d9ebd811cae6b8c1f..f414d2d9fd680d7f2168dca704e86e29a906c29b 100644 (file)
@@ -14,13 +14,13 @@ import java.io.ObjectStreamException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.DataObject;
 import org.opendaylight.yangtools.binding.DataObjectIdentifier.WithKey;
+import org.opendaylight.yangtools.binding.DataObjectStep;
 import org.opendaylight.yangtools.binding.ExactDataObjectStep;
 import org.opendaylight.yangtools.binding.Key;
 import org.opendaylight.yangtools.binding.KeyAware;
 import org.opendaylight.yangtools.binding.KeyStep;
 
-// FIXME: YANGTOOLS-1577: final
-public abstract non-sealed class DataObjectIdentifierWithKey<T extends KeyAware<K> & DataObject, K extends Key<T>>
+public final class DataObjectIdentifierWithKey<T extends KeyAware<K> & DataObject, K extends Key<T>>
         extends DataObjectIdentifierImpl<T> implements WithKey<T, K> {
     @java.io.Serial
     private static final long serialVersionUID = 1L;
@@ -29,11 +29,20 @@ public abstract non-sealed class DataObjectIdentifierWithKey<T extends KeyAware<
         super(steps);
     }
 
+    DataObjectIdentifierWithKey(final Void unused, final Iterable<? extends @NonNull DataObjectStep<?>> steps) {
+        super(unused, steps);
+    }
+
     @Override
-    public final KeyStep<K, T> lastStep() {
+    public KeyStep<K, T> lastStep() {
         return getLast(steps());
     }
 
+    @Override
+    public DataObjectReferenceBuilderWithKey<T, K> toBuilder() {
+        return new DataObjectReferenceBuilderWithKey<>(this);
+    }
+
     @java.io.Serial
     private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
         throwNSE();
diff --git a/binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceBuilder.java b/binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceBuilder.java
new file mode 100644 (file)
index 0000000..251c12d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.binding.impl;
+
+import org.opendaylight.yangtools.binding.DataObject;
+import org.opendaylight.yangtools.binding.DataObjectReference;
+import org.opendaylight.yangtools.binding.DataObjectStep;
+import org.opendaylight.yangtools.binding.Key;
+import org.opendaylight.yangtools.binding.KeyAware;
+import org.opendaylight.yangtools.binding.KeyStep;
+
+final class DataObjectReferenceBuilder<T extends DataObject> extends AbstractDataObjectReferenceBuilder<T> {
+    DataObjectReferenceBuilder(final AbstractDataObjectReferenceBuilder<?> prev, final DataObjectStep<?> item) {
+        super(prev, item);
+    }
+
+    DataObjectReferenceBuilder(final DataObjectReference<T> base) {
+        super(base);
+    }
+
+    DataObjectReferenceBuilder(final DataObjectStep<?> item, final boolean wildcard) {
+        super(item, wildcard);
+    }
+
+    @Override
+    public DataObjectReference<T> build() {
+        final var steps = buildSteps();
+        return wildcard() ? new DataObjectReferenceImpl<>(steps) : new DataObjectIdentifierImpl<>(null, steps);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected <X extends DataObject> DataObjectReferenceBuilder<X> append(final DataObjectStep<X> step) {
+        appendItem(step);
+        return (DataObjectReferenceBuilder<X>) this;
+    }
+
+    @Override
+    protected <X extends DataObject & KeyAware<Y>, Y extends Key<X>> DataObjectReferenceBuilderWithKey<X, Y> append(
+            final KeyStep<Y, X> step) {
+        return new DataObjectReferenceBuilderWithKey<>(this, step);
+    }
+}
diff --git a/binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceBuilderWithKey.java b/binding/binding-spec/src/main/java/org/opendaylight/yangtools/binding/impl/DataObjectReferenceBuilderWithKey.java
new file mode 100644 (file)
index 0000000..556f495
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.binding.impl;
+
+import org.opendaylight.yangtools.binding.DataObject;
+import org.opendaylight.yangtools.binding.DataObjectReference;
+import org.opendaylight.yangtools.binding.DataObjectReference.Builder.WithKey;
+import org.opendaylight.yangtools.binding.DataObjectStep;
+import org.opendaylight.yangtools.binding.Key;
+import org.opendaylight.yangtools.binding.KeyAware;
+import org.opendaylight.yangtools.binding.KeyStep;
+
+public final class DataObjectReferenceBuilderWithKey<T extends KeyAware<K> & DataObject, K extends Key<T>>
+        extends AbstractDataObjectReferenceBuilder<T> implements WithKey<T, K> {
+    DataObjectReferenceBuilderWithKey(final DataObjectReferenceBuilder<?> prev, final DataObjectStep<?> item) {
+        super(prev, item);
+    }
+
+    DataObjectReferenceBuilderWithKey(final DataObjectReference.WithKey<T, K> base) {
+        super(base);
+    }
+
+    DataObjectReferenceBuilderWithKey(final KeyStep<K, T> item, final boolean wildcard) {
+        super(item, wildcard);
+    }
+
+    @Override
+    public DataObjectReference.WithKey<T, K> build() {
+        final var steps = buildSteps();
+        return wildcard() ? new DataObjectReferenceWithKey<>(steps) : new DataObjectIdentifierWithKey<>(null, steps);
+    }
+
+    @Override
+    protected <X extends DataObject> DataObjectReferenceBuilder<X> append(final DataObjectStep<X> step) {
+        return new DataObjectReferenceBuilder<>(this, step);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected <X extends DataObject & KeyAware<Y>, Y extends Key<X>> DataObjectReferenceBuilderWithKey<X, Y> append(
+            final KeyStep<Y, X> step) {
+        appendItem(step);
+        return (DataObjectReferenceBuilderWithKey<X, Y>) this;
+    }
+}
index 1e5c99921aa9e2294319b87aa8d46a97470ecaa3..cb5d9ab0bf06e4b68f83f6fccd4af768b612e6b1 100644 (file)
@@ -14,26 +14,28 @@ import java.io.ObjectOutputStream;
 import java.io.ObjectStreamException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.DataObject;
-import org.opendaylight.yangtools.binding.DataObjectReference;
 import org.opendaylight.yangtools.binding.DataObjectStep;
-import org.opendaylight.yangtools.binding.ExactDataObjectStep;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.binding.KeyStep;
 
-// FIXME: YANGTOOLS-1577: non-abstract
-public abstract sealed class DataObjectReferenceImpl<T extends DataObject>
+public sealed class DataObjectReferenceImpl<T extends DataObject>
         extends AbstractDataObjectReference<T, DataObjectStep<?>>
         permits DataObjectReferenceWithKey {
     @java.io.Serial
     private static final long serialVersionUID = 1L;
 
-    DataObjectReferenceImpl(final Iterable<? extends @NonNull ExactDataObjectStep<?>> steps) {
+    DataObjectReferenceImpl(final Iterable<? extends @NonNull DataObjectStep<?>> steps) {
         super(steps);
     }
 
-    public static final @NonNull DataObjectReference<?> ofUnsafeSteps(
+    public static final @NonNull DataObjectReferenceImpl<?> ofUnsafeSteps(
             final ImmutableList<? extends @NonNull DataObjectStep<?>> steps) {
-        // FIXNE: YANGTOOLS-1577: dispatch to this class
-        return InstanceIdentifier.unsafeOf(steps);
+        return steps.getLast() instanceof KeyStep ? new DataObjectReferenceWithKey<>(steps)
+            : new DataObjectReferenceImpl<>(steps);
+    }
+
+    @Override
+    public AbstractDataObjectReferenceBuilder<T> toBuilder() {
+        return new DataObjectReferenceBuilder<>(this);
     }
 
     @java.io.Serial
index 959041719b7180564bc2602ebf7da70998c350d2..f14534b1b6ca1b4bda16a08088856ffa95d4f25e 100644 (file)
@@ -14,26 +14,30 @@ import java.io.ObjectStreamException;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.binding.DataObject;
 import org.opendaylight.yangtools.binding.DataObjectReference.WithKey;
-import org.opendaylight.yangtools.binding.ExactDataObjectStep;
+import org.opendaylight.yangtools.binding.DataObjectStep;
 import org.opendaylight.yangtools.binding.Key;
 import org.opendaylight.yangtools.binding.KeyAware;
 import org.opendaylight.yangtools.binding.KeyStep;
 
-// FIXME: YANGTOOLS-1577: final
-public abstract non-sealed class DataObjectReferenceWithKey<T extends KeyAware<K> & DataObject, K extends Key<T>>
+public final class DataObjectReferenceWithKey<T extends KeyAware<K> & DataObject, K extends Key<T>>
         extends DataObjectReferenceImpl<T> implements WithKey<T, K> {
     @java.io.Serial
     private static final long serialVersionUID = 1L;
 
-    DataObjectReferenceWithKey(final Iterable<? extends @NonNull ExactDataObjectStep<?>> steps) {
+    DataObjectReferenceWithKey(final Iterable<? extends @NonNull DataObjectStep<?>> steps) {
         super(steps);
     }
 
     @Override
-    public final KeyStep<K, T> lastStep() {
+    public KeyStep<K, T> lastStep() {
         return getLast(steps());
     }
 
+    @Override
+    public DataObjectReferenceBuilderWithKey<T, K> toBuilder() {
+        return new DataObjectReferenceBuilderWithKey<>(this);
+    }
+
     @java.io.Serial
     private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
         throwNSE();
index f3585c593dccc8ef9c9af6e730dd0d3879833725..a82eb14a7921b307fa527d57c550507e85c135c0 100644 (file)
@@ -52,6 +52,6 @@ final class ORv1 implements Externalizable {
 
     @java.io.Serial
     private Object readResolve() throws ObjectStreamException {
-        return DataObjectReferenceImpl.ofUnsafeSteps(steps);
+        return DataObjectReference.ofUnsafeSteps(steps);
     }
 }
index 598150298ea875cad9d93181e722c9668a09e5d6..fb943cb3470255309c6025e7e66e2124276e1e2b 100644 (file)
@@ -12,7 +12,6 @@ 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.VerifyException;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -21,7 +20,6 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import org.eclipse.jdt.annotation.NonNull;
@@ -32,6 +30,7 @@ import org.opendaylight.yangtools.binding.ChildOf;
 import org.opendaylight.yangtools.binding.ChoiceIn;
 import org.opendaylight.yangtools.binding.DataObject;
 import org.opendaylight.yangtools.binding.DataObjectIdentifier;
+import org.opendaylight.yangtools.binding.DataObjectReference;
 import org.opendaylight.yangtools.binding.DataObjectStep;
 import org.opendaylight.yangtools.binding.DataRoot;
 import org.opendaylight.yangtools.binding.ExactDataObjectStep;
@@ -41,6 +40,7 @@ import org.opendaylight.yangtools.binding.KeyStep;
 import org.opendaylight.yangtools.binding.KeylessStep;
 import org.opendaylight.yangtools.binding.NodeStep;
 import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReference;
+import org.opendaylight.yangtools.binding.impl.AbstractDataObjectReferenceBuilder;
 import org.opendaylight.yangtools.concepts.HierarchicalIdentifier;
 
 /**
@@ -269,7 +269,7 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
      */
     public final <N extends ChildOf<? super T>> @NonNull InstanceIdentifier<N> child(
             final Class<@NonNull N> container) {
-        return childIdentifier(createStep(container));
+        return childIdentifier(DataObjectStep.of(container));
     }
 
     /**
@@ -303,7 +303,7 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
     // 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(createStep(caze, container));
+        return childIdentifier(DataObjectStep.of(caze, container));
     }
 
     /**
@@ -375,8 +375,8 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
      * @throws NullPointerException if {@code container} is null
      */
     public static <T extends ChildOf<? extends DataRoot>> @NonNull Builder<T> builder(
-            final Class<T> container) {
-        return new RegularBuilder<>(createStep(container));
+            final @NonNull Class<T> container) {
+        return new RegularBuilder<>(DataObjectStep.of(container));
     }
 
     /**
@@ -391,8 +391,8 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
      * @throws NullPointerException if any argument is null
      */
     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<>(createStep(caze, container));
+            @NonNull Builder<T> builder(final @NonNull Class<C> caze, final @NonNull Class<T> container) {
+        return new RegularBuilder<>(DataObjectStep.of(caze, container));
     }
 
     /**
@@ -426,15 +426,15 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
      */
     public static <C extends ChoiceIn<? extends DataRoot> & 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) {
+            @NonNull KeyedBuilder<N, K> builder(final @NonNull Class<C> caze, final @NonNull Class<N> listItem,
+                    final @NonNull K 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) {
+            @NonNull Builder<T> builderOfInherited(final @NonNull Class<R> root, final @NonNull Class<T> container) {
         // FIXME: we are losing root identity, hence namespaces may not work correctly
-        return new RegularBuilder<>(createStep(container));
+        return new RegularBuilder<>(DataObjectStep.of(container));
     }
 
     public static <R extends DataRoot & DataObject, C extends ChoiceIn<? super R> & DataObject,
@@ -442,13 +442,13 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
             @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<>(createStep(caze, container));
+        return new RegularBuilder<>(DataObjectStep.of(caze, container));
     }
 
     public static <R extends DataRoot & DataObject, N extends KeyAware<K> & ChildOf<? super R>,
             K extends Key<N>>
-            @NonNull KeyedBuilder<N, K> builderOfInherited(final Class<R> root,
-                final Class<N> listItem, final K listKey) {
+            @NonNull KeyedBuilder<N, K> builderOfInherited(final @NonNull Class<R> root,
+                final @NonNull Class<N> listItem, final @NonNull K listKey) {
         // FIXME: we are losing root identity, hence namespaces may not work correctly
         return new KeyedBuilder<>(new KeyStep<>(listItem, listKey));
     }
@@ -461,18 +461,6 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
         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);
-    }
-
     /**
      * Create an instance identifier for a very specific object type. This method implements {@link #create(Iterable)}
      * semantics, except it is used by internal callers, which have assured that the argument is an immutable Iterable.
@@ -545,7 +533,7 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
     @SuppressWarnings("unchecked")
     public static <T extends ChildOf<? extends DataRoot>> @NonNull InstanceIdentifier<T> create(
             final Class<@NonNull T> type) {
-        return (InstanceIdentifier<T>) internalCreate(ImmutableList.of(createStep(type)));
+        return (InstanceIdentifier<T>) internalCreate(ImmutableList.of(DataObjectStep.of(type)));
     }
 
     /**
@@ -668,7 +656,7 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
         @Override
         @SuppressWarnings({ "rawtypes", "unchecked" })
         final DataObjectStep<?> toStep() {
-            return createStep((Class) caseType(), type());
+            return DataObjectStep.of((Class) caseType(), type());
         }
 
         @Override
@@ -761,180 +749,62 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
      *
      * @param <T> Instance identifier target type
      */
-    public abstract static sealed class Builder<T extends DataObject> {
-        private final ArrayList<@NonNull DataObjectStep<?>> pathBuilder;
-        private final Iterable<? extends @NonNull DataObjectStep<?>> basePath;
-
-        private boolean wildcard;
-
+    public abstract static sealed class Builder<T extends DataObject> extends AbstractDataObjectReferenceBuilder<T> {
         Builder(final Builder<?> prev, final DataObjectStep<?> item) {
-            pathBuilder = prev.pathBuilder;
-            basePath = prev.basePath;
-            wildcard = prev.wildcard;
-            appendItem(item);
+            super(prev, item);
         }
 
         Builder(final InstanceIdentifier<T> identifier) {
-            pathBuilder = new ArrayList<>(4);
-            wildcard = identifier.isWildcarded();
-            basePath = identifier.steps();
+            super(identifier);
         }
 
         Builder(final DataObjectStep<?> item, final boolean wildcard) {
-            pathBuilder = new ArrayList<>(4);
-            basePath = null;
-            this.wildcard = wildcard;
-            appendItem(item);
+            super(item, wildcard);
         }
 
-        final boolean wildcard() {
-            return wildcard;
-        }
-
-        /**
-         * Build an identifier which refers to a specific augmentation of the current InstanceIdentifier referenced by
-         * the builder.
-         *
-         * @param container augmentation class
-         * @param <N> augmentation type
-         * @return this builder
-         * @throws NullPointerException if {@code container} is null
-         */
+        @Override
         public final <N extends DataObject & Augmentation<? super T>> Builder<N> augmentation(
-                final Class<N> container) {
-            return append(new NodeStep<>(container));
+                final Class<N> augmentation) {
+            return append(new NodeStep<>(augmentation));
         }
 
-        /**
-         * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. This
-         * method should be used when you want to build an instance identifier by appending top-level elements, for
-         * example
-         * <pre>
-         *     InstanceIdentifier.builder().child(Nodes.class).build();
-         * </pre>
-         *
-         * <p>
-         * NOTE :- The above example is only for illustration purposes InstanceIdentifier.builder() has been deprecated
-         * and should not be used. Use InstanceIdentifier.builder(Nodes.class) instead
-         *
-         * @param container Container to append
-         * @param <N> Container type
-         * @return this builder
-         * @throws NullPointerException if {@code container} is null
-         */
+        @Override
         public final <N extends ChildOf<? super T>> Builder<N> child(final Class<N> container) {
-            return append(createStep(container));
+            return append(DataObjectStep.of(container));
         }
 
-        /**
-         * Append the specified container as a child of the current InstanceIdentifier referenced by the builder. This
-         * method should be used when you want to build an instance identifier by appending a container node to the
-         * identifier and the {@code container} is defined in a {@code grouping} used in a {@code case} statement.
-         *
-         * @param caze Choice case class
-         * @param container Container to append
-         * @param <C> Case type
-         * @param <N> Container type
-         * @return this builder
-         * @throws NullPointerException if {@code container} is null
-         */
+        @Override
         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(createStep(caze, container));
+            return append(DataObjectStep.of(caze, container));
         }
 
-        /**
-         * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. This
-         * method should be used when you want to build an instance identifier by appending a specific list element to
-         * the identifier.
-         *
-         * @param listItem List to append
-         * @param listKey List key
-         * @param <N> List type
-         * @param <K> Key type
-         * @return this builder
-         * @throws NullPointerException if any argument is null
-         */
+        @Override
         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(new KeyStep<>(listItem, listKey));
         }
 
-        /**
-         * Append the specified listItem as a child of the current InstanceIdentifier referenced by the builder. This
-         * method should be used when you want to build an instance identifier by appending a specific list element to
-         * the identifier and the {@code list} is defined in a {@code grouping} used in a {@code case} statement.
-         *
-         * @param caze Choice case class
-         * @param listItem List to append
-         * @param listKey List key
-         * @param <C> Case type
-         * @param <N> List type
-         * @param <K> Key type
-         * @return this builder
-         * @throws NullPointerException if any argument is null
-         */
+        @Override
         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(new KeyStep<>(listItem, requireNonNull(caze), listKey));
         }
 
-        /**
-         * Build the instance identifier.
-         *
-         * @return Resulting {@link InstanceIdentifier}.
-         */
+        @Override
         public abstract @NonNull InstanceIdentifier<T> build();
 
-        final Iterable<? extends DataObjectStep<?>> buildSteps() {
-            final var prefix = basePath;
-            if (prefix == null) {
-                return pathBuilder.isEmpty() ? ImmutableList.of() : ImmutableList.copyOf(pathBuilder);
-            }
-
-            return switch (pathBuilder.size()) {
-                case 0 -> prefix;
-                case 1 -> concat(prefix, pathBuilder.getFirst());
-                default -> ImmutableList.<DataObjectStep<?>>builder().addAll(prefix).addAll(pathBuilder).build();
-            };
-        }
-
         @Override
-        public final int hashCode() {
-            int hash = 1;
-            for (var step : pathArguments()) {
-                hash = 31 * hash + step.hashCode();
-            }
-            return hash;
-        }
+        protected abstract <X extends DataObject> @NonNull RegularBuilder<X> append(DataObjectStep<X> step);
 
         @Override
-        public final boolean equals(final Object obj) {
-            return this == obj || obj instanceof Builder<?> other
-                && wildcard == other.wildcard && Iterables.elementsEqual(pathArguments(), other.pathArguments());
-        }
-
-        // Note: not suitable for use in result
-        private Iterable<? extends DataObjectStep<?>> pathArguments() {
-            return basePath == null ? pathBuilder : Iterables.concat(basePath, pathBuilder);
-        }
-
-        final void appendItem(final DataObjectStep<?> item) {
-            pathBuilder.add(requireNonNull(item));
-            if (!(item instanceof ExactDataObjectStep)) {
-                wildcard = true;
-            }
-        }
-
-        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(
+        protected 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> {
+            extends Builder<T> implements DataObjectReference.Builder.WithKey<T, K> {
         KeyedBuilder(final KeyStep<K, T> firstStep) {
             super(firstStep, false);
         }
@@ -958,13 +828,14 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
         }
 
         @Override
-        <X extends DataObject> @NonNull RegularBuilder<X> append(final DataObjectStep<X> step) {
+        protected <X extends DataObject> @NonNull RegularBuilder<X> append(final DataObjectStep<X> step) {
             return new RegularBuilder<>(this, step);
         }
 
         @Override
         @SuppressWarnings("unchecked")
-        <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(final KeyStep<Y, X> step) {
+        protected <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
+                final KeyStep<Y, X> step) {
             appendItem(step);
             return (KeyedBuilder<X, Y>) this;
         }
@@ -990,13 +861,13 @@ public sealed class InstanceIdentifier<T extends DataObject> extends AbstractDat
 
         @Override
         @SuppressWarnings("unchecked")
-        <X extends DataObject> RegularBuilder<X> append(final DataObjectStep<X> step) {
+        protected <X extends DataObject> RegularBuilder<X> append(final DataObjectStep<X> step) {
             appendItem(step);
             return (RegularBuilder<X>) this;
         }
 
         @Override
-        <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
+        protected <X extends DataObject & KeyAware<Y>, Y extends Key<X>> KeyedBuilder<X, Y> append(
                 final KeyStep<Y, X> item) {
             return new KeyedBuilder<>(this, item);
         }
index 27cbcaac6db88545b048e8d16bb858de5d41dea1..f8dffd87cccdd5d5e695669c47ef5100c56a5684 100644 (file)
@@ -155,7 +155,6 @@ public class InstanceIdentifierTest {
         assertNotNull(instanceIdentifier1.toString());
 
         final InstanceIdentifier.Builder instanceIdentifierBuilder = instanceIdentifier1.toBuilder();
-        assertEquals(instanceIdentifier1.hashCode(), instanceIdentifierBuilder.hashCode());
         assertNotNull(instanceIdentifierBuilder.augmentation(InstantiatedFoo.class));
         assertNotNull(instanceIdentifierBuilder.build());
     }
@@ -204,52 +203,6 @@ public class InstanceIdentifierTest {
         assertEquals(instanceIdentifier, deserialized);
     }
 
-    @Test
-    public void equalsTest() {
-        final InstanceIdentifier.Builder<FooRoot> builder1 = InstanceIdentifier.create(FooRoot.class).toBuilder();
-        final InstanceIdentifier.Builder<FooRoot> builder2 = InstanceIdentifier.create(FooRoot.class).toBuilder();
-        final InstanceIdentifier.Builder<Nodes> builder3 = InstanceIdentifier.create(Nodes.class).toBuilder();
-        final InstanceIdentifier.Builder<Nodes> builder4 = InstanceIdentifier.create(Nodes.class).toBuilder();
-        final Object obj = new Object();
-
-        assertTrue(builder1.equals(builder2));
-        assertTrue(builder2.equals(builder1));
-        assertTrue(builder2.equals(builder2));
-        assertTrue(builder3.equals(builder4));
-        assertTrue(builder4.equals(builder4));
-        assertFalse(builder3.equals(builder1));
-        assertFalse(builder3.equals(null));
-        assertFalse(builder4.equals(null));
-        assertFalse(builder1.equals(obj));
-
-        builder3.child(Node.class, new NodeKey(10));
-        assertFalse(builder3.equals(builder4));
-        assertFalse(builder4.equals(builder3));
-
-        builder4.child(Node.class, new NodeKey(20));
-        assertFalse(builder3.equals(builder4));
-        assertFalse(builder4.equals(builder3));
-    }
-
-    @Test
-    public void hashCodeTest() {
-        final InstanceIdentifier.Builder<FooRoot> builder1 = InstanceIdentifier.create(FooRoot.class).toBuilder();
-        final InstanceIdentifier.Builder<FooRoot> builder2 = InstanceIdentifier.create(FooRoot.class).toBuilder();
-        final InstanceIdentifier.Builder<Nodes> builder3 = InstanceIdentifier.create(Nodes.class).toBuilder();
-        final InstanceIdentifier.Builder<Nodes> builder4 = InstanceIdentifier.create(Nodes.class).toBuilder();
-        final Object obj = new Object();
-
-        assertTrue(builder1.hashCode() == builder2.hashCode());
-        assertTrue(builder1.hashCode() != builder3.hashCode());
-        assertTrue(builder3.hashCode() == builder4.hashCode());
-        assertTrue(builder2.hashCode() != builder4.hashCode());
-        assertTrue(builder1.hashCode() != obj.hashCode());
-
-        builder3.child(Node.class, new NodeKey(10));
-
-        assertTrue(builder3.hashCode() != builder4.hashCode());
-    }
-
     @Test
     public void verifyTargetTest() {
         final InstanceIdentifier<Nodes> nodeId = InstanceIdentifier.create(Nodes.class);