+ public abstract static class NodeIdentifierWithPredicates extends AbstractPathArgument {
+ private static final class Singleton extends NodeIdentifierWithPredicates {
+ private static final long serialVersionUID = 1L;
+
+ private final @NonNull QName key;
+ private final @NonNull Object value;
+
+ 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(new SimpleImmutableEntry<>(key, value));
+ }
+
+ @Override
+ public SingletonSet<QName> keySet() {
+ return SingletonSet.of(key);
+ }
+
+ @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);
+ }
+
+ @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;
+ }
+ }
+
+ 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 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;
+ }
+ }