import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.Serializable;
import java.lang.reflect.Array;
+import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Function;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.concepts.Builder;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.concepts.Path;
import org.opendaylight.yangtools.util.HashCodeBuilder;
import org.opendaylight.yangtools.util.ImmutableOffsetMap;
import org.opendaylight.yangtools.util.SharedSingletonMap;
+import org.opendaylight.yangtools.util.SingletonSet;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
*
* @see <a href="http://tools.ietf.org/html/rfc6020#section-9.13">RFC6020</a>
*/
-// FIXME: 3.0.0: this concept needs to be moved to yang-common, as parser components need the ability to refer
+// FIXME: 6.0.0: this concept needs to be moved to yang-common, as parser components need the ability to refer
// to data nodes -- most notably XPath expressions and {@code default} statement arguments need to be able
// to represent these.
-// FIXME: FixedYangInstanceIdentifier needs YangInstanceIdentifier initialized, but that includes initializing
-// this field. Figure out a way out of this pickle.
-@SuppressFBWarnings("IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION")
public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentifier>, Immutable, Serializable {
- /**
- * An empty {@link YangInstanceIdentifier}. It corresponds to the path of the conceptual root of the YANG namespace.
- */
- public static final YangInstanceIdentifier EMPTY = FixedYangInstanceIdentifier.EMPTY_INSTANCE;
-
private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, String> TOSTRINGCACHE_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, String.class, "toStringCache");
private static final long serialVersionUID = 4L;
this.hash = hash;
}
- @Nonnull abstract YangInstanceIdentifier createRelativeIdentifier(int skipFromRoot);
+ /**
+ * Return An empty {@link YangInstanceIdentifier}. It corresponds to the path of the conceptual root of the YANG
+ * namespace.
+ *
+ * @return An empty YangInstanceIdentifier
+ */
+ public static @NonNull YangInstanceIdentifier empty() {
+ return FixedYangInstanceIdentifier.EMPTY_INSTANCE;
+ }
+
+ abstract @NonNull YangInstanceIdentifier createRelativeIdentifier(int skipFromRoot);
- @Nonnull abstract Collection<PathArgument> tryPathArguments();
+ abstract @Nullable Collection<PathArgument> tryPathArguments();
- @Nonnull abstract Collection<PathArgument> tryReversePathArguments();
+ abstract @Nullable Collection<PathArgument> tryReversePathArguments();
/**
* Check if this instance identifier has empty path arguments, e.g. it is
- * empty and corresponds to {@link #EMPTY}.
+ * empty and corresponds to {@link #empty()}.
*
* @return True if this instance identifier is empty, false otherwise.
*/
* @return A optimized equivalent instance.
*/
@Beta
- public abstract YangInstanceIdentifier toOptimized();
+ public abstract @NonNull YangInstanceIdentifier toOptimized();
/**
* Return the conceptual parent {@link YangInstanceIdentifier}, which has
* one item less in {@link #getPathArguments()}.
*
- * @return Parent {@link YangInstanceIdentifier}, or null if this object is {@link #EMPTY}.
+ * @return Parent {@link YangInstanceIdentifier}, or null if this object is {@link #empty()}.
*/
- @Nullable public abstract YangInstanceIdentifier getParent();
+ public abstract @Nullable YangInstanceIdentifier getParent();
/**
* Return the ancestor {@link YangInstanceIdentifier} with a particular depth, e.g. number of path arguments.
* @return Ancestor {@link YangInstanceIdentifier}
* @throws IllegalArgumentException if the specified depth is negative or is greater than the depth of this object.
*/
- @Nonnull public abstract YangInstanceIdentifier getAncestor(int depth);
+ public abstract @NonNull YangInstanceIdentifier getAncestor(int depth);
/**
* Returns an ordered iteration of path arguments.
*
* @return Immutable iteration of path arguments.
*/
- public abstract List<PathArgument> getPathArguments();
+ public abstract @NonNull List<PathArgument> getPathArguments();
/**
* Returns an iterable of path arguments in reverse order. This is useful
*
* @return Immutable iterable of path arguments in reverse order.
*/
- public abstract List<PathArgument> getReversePathArguments();
+ public abstract @NonNull List<PathArgument> getReversePathArguments();
/**
* Returns the last PathArgument. This is equivalent of iterating
*/
public abstract PathArgument getLastPathArgument();
- public static YangInstanceIdentifier create(final Iterable<? extends PathArgument> path) {
+ public static @NonNull YangInstanceIdentifier create(final Iterable<? extends PathArgument> path) {
if (Iterables.isEmpty(path)) {
- return EMPTY;
+ return empty();
}
final HashCodeBuilder<PathArgument> hash = new HashCodeBuilder<>();
return FixedYangInstanceIdentifier.create(path, hash.build());
}
- public static YangInstanceIdentifier create(final PathArgument... path) {
+ public static @NonNull YangInstanceIdentifier create(final PathArgument... path) {
// We are forcing a copy, since we cannot trust the user
return create(Arrays.asList(path));
}
* @return A {@link YangInstanceIdentifier} instance
* @throws NullPointerException if {@code pathTowardsRoot} or any of its members is null
*/
- public static YangInstanceIdentifier createReverse(final Deque<PathArgument> pathTowardsRoot) {
+ public static @NonNull YangInstanceIdentifier createReverse(final Deque<PathArgument> pathTowardsRoot) {
final ImmutableList.Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(
pathTowardsRoot.size());
pathTowardsRoot.descendingIterator().forEachRemaining(builder::add);
* @return A {@link YangInstanceIdentifier} instance
* @throws NullPointerException if {@code pathTowardsRoot} is null
*/
- public static <T> YangInstanceIdentifier createReverse(final Deque<? extends T> stackTowardsRoot,
+ public static <T> @NonNull YangInstanceIdentifier createReverse(final Deque<? extends T> stackTowardsRoot,
final Function<T, PathArgument> function) {
final ImmutableList.Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(
stackTowardsRoot.size());
* @param name QName of {@link NodeIdentifier}
* @return Instance Identifier with additional path argument added to the end.
*/
- public final YangInstanceIdentifier node(final QName name) {
+ public final @NonNull YangInstanceIdentifier node(final QName name) {
return node(new NodeIdentifier(name));
}
* @param arg Path argument which should be added to the end
* @return Instance Identifier with additional path argument added to the end.
*/
- public final YangInstanceIdentifier node(final PathArgument arg) {
+ public final @NonNull YangInstanceIdentifier node(final PathArgument arg) {
return new StackedYangInstanceIdentifier(this, arg, HashCodeBuilder.nextHashCode(hash, arg));
}
*/
public Optional<YangInstanceIdentifier> relativeTo(final YangInstanceIdentifier ancestor) {
if (this == ancestor) {
- return Optional.of(EMPTY);
+ return Optional.of(empty());
}
if (ancestor.isEmpty()) {
return Optional.of(this);
return Optional.of(this);
}
if (!lit.hasNext()) {
- return Optional.of(EMPTY);
+ return Optional.of(empty());
}
return Optional.of(createRelativeIdentifier(common));
}
@Override
- public final boolean contains(@Nonnull final YangInstanceIdentifier other) {
+ public final boolean contains(final YangInstanceIdentifier other) {
if (this == other) {
return true;
}
return hash;
}
+ @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+ justification = "https://github.com/spotbugs/spotbugs/issues/811")
private static int hashCode(final Object value) {
if (value == null) {
return 0;
return Objects.hashCode(value);
}
+ final Object writeReplace() {
+ return new YIDv1(this);
+ }
+
// Static factories & helpers
/**
* @param name QName of first node identifier
* @return Instance Identifier with only one path argument of type {@link NodeIdentifier}
*/
- public static YangInstanceIdentifier of(final QName name) {
+ public static @NonNull YangInstanceIdentifier of(final QName name) {
return create(new NodeIdentifier(name));
}
*
* @return new builder for InstanceIdentifier with empty path arguments.
*/
- public static InstanceIdentifierBuilder builder() {
+ public static @NonNull InstanceIdentifierBuilder builder() {
return new YangInstanceIdentifierBuilder();
}
* @param origin InstanceIdentifier from which path arguments are copied.
* @return new builder for InstanceIdentifier with path arguments copied from original instance identifier.
*/
- public static InstanceIdentifierBuilder builder(final YangInstanceIdentifier origin) {
+ public static @NonNull InstanceIdentifierBuilder builder(final YangInstanceIdentifier origin) {
return new YangInstanceIdentifierBuilder(origin.getPathArguments(), origin.hashCode());
}
*/
public interface PathArgument extends Comparable<PathArgument>, Immutable, Serializable {
/**
- * If applicable returns unique QName of data node as defined in YANG
- * Schema.
- *
- * <p>
- * This method may return null, if the corresponding schema node, does
- * not have QName associated, such as in cases of augmentations.
+ * Returns unique QName of data node as defined in YANG Schema, if available.
*
* @return Node type
+ * @throws UnsupportedOperationException if node type is not applicable, for example in case of an augmentation.
*/
- QName getNodeType();
+ @NonNull QName getNodeType();
/**
* Return the string representation of this object for use in context
* @param previous Previous path argument
* @return String representation
*/
- String toRelativeString(PathArgument previous);
+ @NonNull String toRelativeString(PathArgument previous);
}
private abstract static class AbstractPathArgument implements PathArgument {
private static final long serialVersionUID = -4546547994250849340L;
- private final QName nodeType;
- private transient int hashValue;
- private transient volatile boolean hashGuard = false;
+ private final @NonNull QName nodeType;
+ private transient volatile int hashValue;
protected AbstractPathArgument(final QName nodeType) {
this.nodeType = requireNonNull(nodeType);
@Override
@SuppressWarnings("checkstyle:parameterName")
- public int compareTo(@Nonnull final PathArgument o) {
+ public int compareTo(final PathArgument o) {
return nodeType.compareTo(o.getNodeType());
}
protected int hashCodeImpl() {
- return 31 + getNodeType().hashCode();
+ return nodeType.hashCode();
}
@Override
public final int hashCode() {
- if (!hashGuard) {
- hashValue = hashCodeImpl();
- hashGuard = true;
- }
-
- return hashValue;
+ int local;
+ return (local = hashValue) != 0 ? local : (hashValue = hashCodeImpl());
}
@Override
return getNodeType().toString();
}
+
+ abstract Object writeReplace();
}
/**
private static final LoadingCache<QName, NodeIdentifier> CACHE = CacheBuilder.newBuilder().weakValues()
.build(new CacheLoader<QName, NodeIdentifier>() {
@Override
- public NodeIdentifier load(@Nonnull final QName key) {
+ public NodeIdentifier load(final QName key) {
return new NodeIdentifier(key);
}
});
* @param node Node's QName
* @return A {@link NodeIdentifier}
*/
- public static NodeIdentifier create(final QName node) {
+ public static @NonNull NodeIdentifier create(final QName node) {
return CACHE.getUnchecked(node);
}
+
+ @Override
+ Object writeReplace() {
+ return new NIv1(this);
+ }
}
/**
* Composite path argument identifying a {@link org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode} leaf
* overall data tree.
*/
- public static final class NodeIdentifierWithPredicates extends AbstractPathArgument {
- private static final long serialVersionUID = -4787195606494761540L;
+ public abstract static class NodeIdentifierWithPredicates extends AbstractPathArgument {
+ @Beta
+ public static final class Singleton extends NodeIdentifierWithPredicates {
+ private static final long serialVersionUID = 1L;
- private final Map<QName, Object> keyValues;
+ private final @NonNull QName key;
+ private final @NonNull Object value;
- public NodeIdentifierWithPredicates(final QName node) {
- super(node);
- this.keyValues = ImmutableMap.of();
+ Singleton(final QName node, final QName key, final Object value) {
+ super(node);
+ this.key = requireNonNull(key);
+ this.value = requireNonNull(value);
+ }
+
+ @Override
+ public SingletonSet<Entry<QName, Object>> entrySet() {
+ return SingletonSet.of(singleEntry());
+ }
+
+ @Override
+ public SingletonSet<QName> keySet() {
+ return SingletonSet.of(key);
+ }
+
+ @Override
+ public boolean containsKey(final QName qname) {
+ return key.equals(requireNonNull(qname));
+ }
+
+ @Override
+ public SingletonSet<Object> values() {
+ return SingletonSet.of(value);
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override
+ public ImmutableMap<QName, Object> asMap() {
+ return ImmutableMap.of(key, value);
+ }
+
+ /**
+ * Return the single entry contained in this object. This is equivalent to
+ * {@code entrySet().iterator().next()}.
+ *
+ * @return A single entry.
+ */
+ public @NonNull Entry<QName, Object> singleEntry() {
+ return new SimpleImmutableEntry<>(key, value);
+ }
+
+ @Override
+ boolean equalMapping(final NodeIdentifierWithPredicates other) {
+ final Singleton single = (Singleton) other;
+ return key.equals(single.key) && Objects.deepEquals(value, single.value);
+ }
+
+ @Override
+ Object keyValue(final QName qname) {
+ return key.equals(qname) ? value : null;
+ }
}
- public NodeIdentifierWithPredicates(final QName node, final Map<QName, Object> keyValues) {
- super(node);
- // Retains ImmutableMap for empty maps. For larger sizes uses a shared key set.
- this.keyValues = ImmutableOffsetMap.unorderedCopyOf(keyValues);
+ private static final class Regular extends NodeIdentifierWithPredicates {
+ private static final long serialVersionUID = 1L;
+
+ private final @NonNull Map<QName, Object> keyValues;
+
+ Regular(final QName node, final Map<QName, Object> keyValues) {
+ super(node);
+ this.keyValues = requireNonNull(keyValues);
+ }
+
+ @Override
+ public Set<Entry<QName, Object>> entrySet() {
+ return keyValues.entrySet();
+ }
+
+ @Override
+ public Set<QName> keySet() {
+ return keyValues.keySet();
+ }
+
+ @Override
+ public boolean containsKey(final QName qname) {
+ return keyValues.containsKey(requireNonNull(qname));
+ }
+
+ @Override
+ public Collection<Object> values() {
+ return keyValues.values();
+ }
+
+ @Override
+ public int size() {
+ return keyValues.size();
+ }
+
+ @Override
+ public Map<QName, Object> asMap() {
+ return keyValues;
+ }
+
+ @Override
+ Object keyValue(final QName qname) {
+ return keyValues.get(qname);
+ }
+
+ @Override
+ boolean equalMapping(final NodeIdentifierWithPredicates other) {
+ final Map<QName, Object> otherKeyValues = ((Regular) other).keyValues;
+ // TODO: benchmark to see if just calling equals() on the two maps is not faster
+ if (keyValues == otherKeyValues) {
+ return true;
+ }
+ if (keyValues.size() != otherKeyValues.size()) {
+ return false;
+ }
+
+ for (Entry<QName, Object> entry : entrySet()) {
+ final Object otherValue = otherKeyValues.get(entry.getKey());
+ if (otherValue == null || !Objects.deepEquals(entry.getValue(), otherValue)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
- public NodeIdentifierWithPredicates(final QName node, final ImmutableOffsetMap<QName, Object> keyValues) {
+ private static final long serialVersionUID = -4787195606494761540L;
+
+ NodeIdentifierWithPredicates(final QName node) {
super(node);
- this.keyValues = requireNonNull(keyValues);
}
- public NodeIdentifierWithPredicates(final QName node, final SharedSingletonMap<QName, Object> keyValues) {
- super(node);
- this.keyValues = requireNonNull(keyValues);
+ public static @NonNull NodeIdentifierWithPredicates of(final QName node) {
+ return new Regular(node, ImmutableMap.of());
}
- public NodeIdentifierWithPredicates(final QName node, final QName key, final Object value) {
- this(node, SharedSingletonMap.unorderedOf(key, value));
+ public static @NonNull NodeIdentifierWithPredicates of(final QName node, final QName key, final Object value) {
+ return new Singleton(node, key, value);
}
- public Map<QName, Object> getKeyValues() {
- return keyValues;
+ public static @NonNull NodeIdentifierWithPredicates of(final QName node, final Entry<QName, Object> entry) {
+ return of(node, entry.getKey(), entry.getValue());
}
- @Override
- protected int hashCodeImpl() {
- final int prime = 31;
- int result = super.hashCodeImpl();
- result = prime * result;
+ public static @NonNull NodeIdentifierWithPredicates of(final QName node, final Map<QName, Object> keyValues) {
+ return keyValues.size() == 1 ? of(keyValues, node)
+ // Retains ImmutableMap for empty maps. For larger sizes uses a shared key set.
+ : new Regular(node, ImmutableOffsetMap.unorderedCopyOf(keyValues));
+ }
+
+ public static @NonNull NodeIdentifierWithPredicates of(final QName node,
+ final ImmutableOffsetMap<QName, Object> keyValues) {
+ return keyValues.size() == 1 ? of(keyValues, node) : new Regular(node, keyValues);
+ }
+
+ @Deprecated
+ public static @NonNull NodeIdentifierWithPredicates of(final QName node,
+ final SharedSingletonMap<QName, Object> keyValues) {
+ return of(node, keyValues.getEntry());
+ }
- for (Entry<QName, Object> entry : keyValues.entrySet()) {
- result += Objects.hashCode(entry.getKey()) + YangInstanceIdentifier.hashCode(entry.getValue());
+ private static @NonNull NodeIdentifierWithPredicates of(final Map<QName, Object> keyValues, final QName node) {
+ return of(node, keyValues.entrySet().iterator().next());
+ }
+
+ /**
+ * Return the set of predicates keys and values. Keys are guaranteeed to be unique.
+ *
+ * @return Predicate set.
+ */
+ @Beta
+ public abstract @NonNull Set<Entry<QName, Object>> entrySet();
+
+ /**
+ * Return the predicate key in the iteration order of {@link #entrySet()}.
+ *
+ * @return Predicate values.
+ */
+ @Beta
+ public abstract @NonNull Set<QName> keySet();
+
+ /**
+ * Determine whether a particular predicate key is present.
+ *
+ * @param key Predicate key
+ * @return True if the predicate is present, false otherwise
+ * @throws NullPointerException if {@code key} is null
+ */
+ @Beta
+ public abstract boolean containsKey(QName key);
+
+ /**
+ * Return the predicate values in the iteration order of {@link #entrySet()}.
+ *
+ * @return Predicate values.
+ */
+ @Beta
+ public abstract @NonNull Collection<Object> values();
+
+ @Beta
+ public final @Nullable Object getValue(final QName key) {
+ return keyValue(requireNonNull(key));
+ }
+
+ @Beta
+ public final <T> @Nullable T getValue(final QName key, final Class<T> valueClass) {
+ return valueClass.cast(getValue(key));
+ }
+
+ /**
+ * Return the number of predicates present.
+ *
+ * @return The number of predicates present.
+ */
+ @Beta
+ public abstract int size();
+
+ /**
+ * A Map-like view of this identifier's predicates. The view is expected to be stable and effectively-immutable.
+ *
+ * @return Map of predicates.
+ * @deprecated This method in a provisional one. It can be used in the code base, but users requiring it should
+ * contact <a href="mailto:yangtools-dev@lists.opendaylight.org">yangtools-dev</a> for migration
+ * guidelines. Callers are strongly encouraged to explore {@link #entrySet()}, {@link #size()},
+ * {@link #values()} and {@link #keySet()} as an alternative.
+ */
+ @Beta
+ @Deprecated
+ // FIXME: 6.0.0: evaluate the real usefulness of this. The problem here is Map.hashCode() and Map.equals(),
+ // which limits our options.
+ public abstract @NonNull Map<QName, Object> asMap();
+
+ @Override
+ protected final int hashCodeImpl() {
+ int result = 31 * super.hashCodeImpl();
+ for (Entry<QName, Object> entry : entrySet()) {
+ result += entry.getKey().hashCode() + YangInstanceIdentifier.hashCode(entry.getValue());
}
return result;
}
@Override
@SuppressWarnings("checkstyle:equalsHashCode")
- public boolean equals(final Object obj) {
- if (!super.equals(obj)) {
- return false;
- }
-
- final Map<QName, Object> otherKeyValues = ((NodeIdentifierWithPredicates) obj).keyValues;
-
- // TODO: benchmark to see if just calling equals() on the two maps is not faster
- if (keyValues == otherKeyValues) {
- return true;
- }
- if (keyValues.size() != otherKeyValues.size()) {
- return false;
- }
+ public final boolean equals(final Object obj) {
+ return super.equals(obj) && equalMapping((NodeIdentifierWithPredicates) obj);
+ }
- for (Entry<QName, Object> entry : keyValues.entrySet()) {
- if (!otherKeyValues.containsKey(entry.getKey())
- || !Objects.deepEquals(entry.getValue(), otherKeyValues.get(entry.getKey()))) {
+ abstract boolean equalMapping(NodeIdentifierWithPredicates other);
- return false;
- }
- }
+ abstract @Nullable Object keyValue(@NonNull QName qname);
- return true;
+ @Override
+ public final String toString() {
+ return super.toString() + '[' + asMap() + ']';
}
@Override
- public String toString() {
- return super.toString() + '[' + keyValues + ']';
+ public final String toRelativeString(final PathArgument previous) {
+ return super.toRelativeString(previous) + '[' + asMap() + ']';
}
@Override
- public String toRelativeString(final PathArgument previous) {
- return super.toRelativeString(previous) + '[' + keyValues + ']';
+ final Object writeReplace() {
+ return new NIPv2(this);
}
}
@Override
protected int hashCodeImpl() {
- final int prime = 31;
- int result = super.hashCodeImpl();
- result = prime * result + YangInstanceIdentifier.hashCode(value);
- return result;
+ return 31 * super.hashCodeImpl() + YangInstanceIdentifier.hashCode(value);
}
@Override
public String toRelativeString(final PathArgument previous) {
return super.toRelativeString(previous) + '[' + value + ']';
}
+
+ @Override
+ Object writeReplace() {
+ return new NIVv1(this);
+ }
}
/**
*/
public static final class AugmentationIdentifier implements PathArgument {
private static final long serialVersionUID = -8122335594681936939L;
- private final ImmutableSet<QName> childNames;
+
+ private static final LoadingCache<ImmutableSet<QName>, AugmentationIdentifier> CACHE = CacheBuilder.newBuilder()
+ .weakValues().build(new CacheLoader<ImmutableSet<QName>, AugmentationIdentifier>() {
+ @Override
+ public AugmentationIdentifier load(final ImmutableSet<QName> key) {
+ return new AugmentationIdentifier(key);
+ }
+ });
+
+ private final @NonNull ImmutableSet<QName> childNames;
@Override
public QName getNodeType() {
throw new UnsupportedOperationException("Augmentation node has no QName");
}
+ /**
+ * Construct new augmentation identifier using supplied set of possible
+ * child nodes.
+ *
+ * @param childNames
+ * Set of possible child nodes.
+ */
+ public AugmentationIdentifier(final ImmutableSet<QName> childNames) {
+ this.childNames = requireNonNull(childNames);
+ }
+
/**
* Construct new augmentation identifier using supplied set of possible
* child nodes.
this.childNames = ImmutableSet.copyOf(childNames);
}
+ /**
+ * Return an AugmentationIdentifier for a particular set of QNames. Unlike the constructor, this factory method
+ * uses a global instance cache, resulting in object reuse for equal inputs.
+ *
+ * @param childNames Set of possible child nodes
+ * @return An {@link AugmentationIdentifier}
+ */
+ public static @NonNull AugmentationIdentifier create(final ImmutableSet<QName> childNames) {
+ return CACHE.getUnchecked(childNames);
+ }
+
+ /**
+ * Return an AugmentationIdentifier for a particular set of QNames. Unlike the constructor, this factory method
+ * uses a global instance cache, resulting in object reuse for equal inputs.
+ *
+ * @param childNames Set of possible child nodes
+ * @return An {@link AugmentationIdentifier}
+ */
+ public static @NonNull AugmentationIdentifier create(final Set<QName> childNames) {
+ final AugmentationIdentifier existing = CACHE.getIfPresent(childNames);
+ return existing != null ? existing : create(ImmutableSet.copyOf(childNames));
+ }
+
/**
* Returns set of all possible child nodes.
*
* @return set of all possible child nodes.
*/
- public Set<QName> getPossibleChildNames() {
+ public @NonNull Set<QName> getPossibleChildNames() {
return childNames;
}
@Override
@SuppressWarnings("checkstyle:parameterName")
- public int compareTo(@Nonnull final PathArgument o) {
+ public int compareTo(final PathArgument o) {
if (!(o instanceof AugmentationIdentifier)) {
return -1;
}
return -1;
}
}
+
+ private Object writeReplace() {
+ return new AIv1(this);
+ }
}
/**
* @param arg A {@link PathArgument} to be added
* @return this builder
*/
- InstanceIdentifierBuilder node(PathArgument arg);
+ @NonNull InstanceIdentifierBuilder node(PathArgument arg);
/**
* Adds {@link NodeIdentifier} with supplied QName to path arguments of resulting instance identifier.
* @param nodeType QName of {@link NodeIdentifier} which will be added
* @return this builder
*/
- InstanceIdentifierBuilder node(QName nodeType);
+ @NonNull InstanceIdentifierBuilder node(QName nodeType);
/**
* Adds {@link NodeIdentifierWithPredicates} with supplied QName and key values to path arguments of resulting
* @param keyValues Map of key components and their respective values for {@link NodeIdentifierWithPredicates}
* @return this builder
*/
- InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues);
+ @NonNull InstanceIdentifierBuilder nodeWithKey(QName nodeType, Map<QName, Object> keyValues);
/**
* Adds {@link NodeIdentifierWithPredicates} with supplied QName and key, value.
* @param value value of key which will be added
* @return this builder
*/
- InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);
+ @NonNull InstanceIdentifierBuilder nodeWithKey(QName nodeType, QName key, Object value);
/**
* Adds a collection of {@link PathArgument}s to path arguments of resulting instance identifier.
* @throws NullPointerException if any of the arguments is null
*/
@Beta
- InstanceIdentifierBuilder append(Collection<? extends PathArgument> args);
+ @NonNull InstanceIdentifierBuilder append(Collection<? extends PathArgument> args);
/**
* Adds a collection of {@link PathArgument}s to path arguments of resulting instance identifier.
* @throws NullPointerException if any of the arguments is null
*/
@Beta
- default InstanceIdentifierBuilder append(final PathArgument... args) {
+ default @NonNull InstanceIdentifierBuilder append(final PathArgument... args) {
return append(Arrays.asList(args));
}