Simplify SchemaNodeIdentifier class hierarchy
[yangtools.git] / model / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / stmt / SchemaNodeIdentifier.java
index 7439f4c50aba6434cf7cf5d1e3ecdf5ec3cc6a6f..c69d85054aa7abfdff19ade060f8cb2a861677de 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.model.api.stmt;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.MoreObjects;
@@ -15,7 +14,6 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Interner;
 import com.google.common.collect.Interners;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
@@ -31,9 +29,17 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
     /**
      * An absolute schema node identifier.
      */
-    public abstract static sealed class Absolute extends SchemaNodeIdentifier {
+    public static final class Absolute extends SchemaNodeIdentifier {
         private static final Interner<@NonNull Absolute> INTERNER = Interners.newWeakInterner();
 
+        private Absolute(final ImmutableList<QName> qnames) {
+            super(qnames);
+        }
+
+        private Absolute(final QName qname) {
+            super(qname);
+        }
+
         /**
          * Create an absolute schema node identifier composed of a single node identifier.
          *
@@ -42,7 +48,7 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          * @throws NullPointerException if {@code nodeIdentifier} is null
          */
         public static @NonNull Absolute of(final QName nodeIdentifier) {
-            return new AbsoluteSingle(nodeIdentifier);
+            return new Absolute(nodeIdentifier);
         }
 
         /**
@@ -54,7 +60,7 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          * @throws IllegalArgumentException if {@code nodeIdentifiers} is empty
          */
         public static @NonNull Absolute of(final QName... nodeIdentifiers) {
-            return of(Arrays.asList(nodeIdentifiers));
+            return of(ImmutableList.copyOf(nodeIdentifiers));
         }
 
         /**
@@ -66,8 +72,8 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          * @throws IllegalArgumentException if {@code nodeIdentifiers} is empty
          */
         public static @NonNull Absolute of(final Collection<QName> nodeIdentifiers) {
-            final var qnames = checkQNames(nodeIdentifiers);
-            return qnames.size() == 1 ? of(qnames.get(0)) : new AbsoluteMultiple(qnames);
+            final var qnames = ImmutableList.copyOf(nodeIdentifiers);
+            return qnames.size() == 1 ? of(qnames.get(0)) : new Absolute(qnames);
         }
 
         /**
@@ -75,20 +81,23 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          *
          * @return An interned reference, or this object if it was previously interned.
          */
-        public final @NonNull Absolute intern() {
+        public @NonNull Absolute intern() {
             return INTERNER.intern(this);
         }
-
-        @Override
-        final String className() {
-            return "Absolute";
-        }
     }
 
     /**
      * A descendant schema node identifier.
      */
-    public abstract static sealed class Descendant extends SchemaNodeIdentifier {
+    public static final class Descendant extends SchemaNodeIdentifier {
+        private Descendant(final ImmutableList<QName> qnames) {
+            super(qnames);
+        }
+
+        private Descendant(final QName qname) {
+            super(qname);
+        }
+
         /**
          * Create a descendant schema node identifier composed of a single node identifier.
          *
@@ -97,7 +106,7 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          * @throws NullPointerException if {@code nodeIdentifier} is null
          */
         public static @NonNull Descendant of(final QName nodeIdentifier) {
-            return new DescendantSingle(nodeIdentifier);
+            return new Descendant(nodeIdentifier);
         }
 
         /**
@@ -109,7 +118,7 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          * @throws IllegalArgumentException if {@code nodeIdentifiers} is empty
          */
         public static @NonNull Descendant of(final QName... nodeIdentifiers) {
-            return of(Arrays.asList(nodeIdentifiers));
+            return of(ImmutableList.copyOf(nodeIdentifiers));
         }
 
         /**
@@ -121,117 +130,35 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
          * @throws IllegalArgumentException if {@code nodeIdentifiers} is empty
          */
         public static @NonNull Descendant of(final Collection<QName> nodeIdentifiers) {
-            final var qnames = checkQNames(nodeIdentifiers);
-            return qnames.size() == 1 ? of(qnames.get(0)) : new DescandantMultiple(qnames);
-        }
-
-        @Override
-        final String className() {
-            return "Descendant";
-        }
-    }
-
-    private static final class AbsoluteSingle extends Absolute {
-        private final @NonNull QName qname;
-
-        AbsoluteSingle(final QName qname) {
-            this.qname = requireNonNull(qname);
-        }
-
-        @Override
-        public ImmutableList<QName> getNodeIdentifiers() {
-            return ImmutableList.of(qname);
-        }
-
-        @Override
-        public QName firstNodeIdentifier() {
-            return qname;
-        }
-
-        @Override
-        public QName lastNodeIdentifier() {
-            return qname;
-        }
-
-        @Override
-        Object pathObject() {
-            return qname;
-        }
-    }
-
-    private static final class AbsoluteMultiple extends Absolute {
-        private final @NonNull ImmutableList<QName> qnames;
-
-        AbsoluteMultiple(final ImmutableList<QName> qnames) {
-            this.qnames = requireNonNull(qnames);
-        }
-
-        @Override
-        public ImmutableList<QName> getNodeIdentifiers() {
-            return qnames;
-        }
-
-        @Override
-        Object pathObject() {
-            return qnames;
+            final var qnames = ImmutableList.copyOf(nodeIdentifiers);
+            return qnames.size() == 1 ? of(qnames.get(0)) : new Descendant(qnames);
         }
     }
 
-    private static final class DescendantSingle extends Descendant {
-        private final @NonNull QName qname;
-
-        DescendantSingle(final QName qname) {
-            this.qname = requireNonNull(qname);
-        }
-
-        @Override
-        public ImmutableList<QName> getNodeIdentifiers() {
-            return ImmutableList.of(qname);
-        }
+    private final @NonNull Object pathObj;
 
-        @Override
-        public QName firstNodeIdentifier() {
-            return qname;
-        }
-
-        @Override
-        public QName lastNodeIdentifier() {
-            return qname;
-        }
+    // Cached hashCode
+    private volatile int hash;
 
-        @Override
-        Object pathObject() {
-            return qname;
-        }
+    private SchemaNodeIdentifier(final QName qname) {
+        pathObj = requireNonNull(qname);
     }
 
-    private static final class DescandantMultiple extends Descendant {
-        private final @NonNull ImmutableList<QName> qnames;
-
-        DescandantMultiple(final ImmutableList<QName> qnames) {
-            this.qnames = requireNonNull(qnames);
-        }
-
-        @Override
-        public ImmutableList<QName> getNodeIdentifiers() {
-            return qnames;
-        }
-
-        @Override
-        Object pathObject() {
-            return qnames;
+    private SchemaNodeIdentifier(final ImmutableList<QName> qnames) {
+        if (qnames.isEmpty()) {
+            throw new IllegalArgumentException("SchemaNodeIdentifier has to have at least one node identifier");
         }
+        pathObj = qnames;
     }
 
-    // Cached hashCode
-    private volatile int hash;
-
     /**
      * Return the non-empty sequence of node identifiers which constitute this schema node identifier.
      *
      * @return Non-empty sequence of node identifiers
      */
-    public abstract @NonNull List<QName> getNodeIdentifiers();
+    public final @NonNull List<QName> getNodeIdentifiers() {
+        return pathObj instanceof QName qname ? ImmutableList.of(qname) : coerceList();
+    }
 
     /**
      * Return the first node identifier. This method is equivalent to {@code getNodeIdentifiers().get(0)}, but is
@@ -239,8 +166,8 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
      *
      * @return The first node identifier
      */
-    public @NonNull QName firstNodeIdentifier() {
-        return getNodeIdentifiers().get(0);
+    public final @NonNull QName firstNodeIdentifier() {
+        return pathObj instanceof QName qname ? qname : coerceList().get(0);
     }
 
     /**
@@ -249,44 +176,35 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
      *
      * @return The last node identifier
      */
-    public @NonNull QName lastNodeIdentifier() {
-        final var local = getNodeIdentifiers();
-        return local.get(local.size() - 1);
+    public final @NonNull QName lastNodeIdentifier() {
+        if (pathObj instanceof QName qname) {
+            return qname;
+        }
+        final var list = coerceList();
+        return list.get(list.size() - 1);
     }
 
     @Override
     public final int hashCode() {
         final int local;
-        return (local = hash) != 0 ? local : (hash = pathObject().hashCode());
+        return (local = hash) != 0 ? local : (hash = pathObj.hashCode());
     }
 
     @Override
     public final boolean equals(final Object obj) {
         return this == obj || obj != null && getClass() == obj.getClass()
-                && pathObject().equals(((SchemaNodeIdentifier) obj).pathObject());
+            && pathObj.equals(((SchemaNodeIdentifier) obj).pathObj);
     }
 
     @Override
     public final String toString() {
-        return MoreObjects.toStringHelper(className()).add("qnames", toStringQNames()).toString();
+        return MoreObjects.toStringHelper(this)
+            .add("qnames", pathObj instanceof QName qname ? ImmutableList.of(qname) : simpleQNames())
+            .toString();
     }
 
-    abstract @NonNull Object pathObject();
-
-    abstract @NonNull String className();
-
-    private List<?> toStringQNames() {
-        final var ids = getNodeIdentifiers();
-        return ids.size() < 2 ? ids : simplifyQNames(ids);
-    }
-
-    private static ImmutableList<QName> checkQNames(final Collection<QName> qnames) {
-        final var ret = ImmutableList.copyOf(qnames);
-        checkArgument(!ret.isEmpty(), "SchemaNodeIdentifier has to have at least one node identifier");
-        return ret;
-    }
-
-    private static List<?> simplifyQNames(final List<QName> qnames) {
+    private List<?> simpleQNames() {
+        final var qnames = coerceList();
         final var ret = new ArrayList<>(qnames.size());
 
         QNameModule prev = null;
@@ -298,4 +216,9 @@ public abstract sealed class SchemaNodeIdentifier implements Immutable {
 
         return ret;
     }
+
+    @SuppressWarnings("unchecked")
+    private ImmutableList<QName> coerceList() {
+        return (ImmutableList<QName>) pathObj;
+    }
 }