*/
public final class JsonNumEquals
+ extends Equivalence
{
- private static final JsonNumEquals INSTANCE
+ private static final Equivalence INSTANCE
= new JsonNumEquals();
private JsonNumEquals()
{
}
- public static JsonNumEquals getInstance()
+ public static Equivalence getInstance()
{
return INSTANCE;
}
- /**
- * Returns {@code true} if the given objects are considered equivalent.
- *
- *
The {@code equivalent} method implements an equivalence relation on object references:
- *
- *
- *
It is reflexive: for any reference {@code x}, including null, {@code
- * equivalent(x, x)} returns {@code true}.
- *
It is symmetric: for any references {@code x} and {@code y}, {@code
- * equivalent(x, y) == equivalent(y, x)}.
- *
It is transitive: for any references {@code x}, {@code y}, and {@code z}, if
- * {@code equivalent(x, y)} returns {@code true} and {@code equivalent(y, z)} returns {@code
- * true}, then {@code equivalent(x, z)} returns {@code true}.
- *
It is consistent: for any references {@code x} and {@code y}, multiple invocations
- * of {@code equivalent(x, y)} consistently return {@code true} or consistently return {@code
- * false} (provided that neither {@code x} nor {@code y} is modified).
- *
- * @param a x
- * @param b y
- * @return whether nodes are equal according to IETF RFCs
- */
- public final boolean equivalent(@Nullable JsonNode a, @Nullable JsonNode b) {
- if (a == b) {
- return true;
- }
- if (a == null || b == null) {
- return false;
- }
- return doEquivalent(a, b);
- }
-
+ @Override
protected boolean doEquivalent(final JsonNode a, final JsonNode b)
{
/*
@@ -122,31 +93,7 @@ protected boolean doEquivalent(final JsonNode a, final JsonNode b)
return typeA == NodeType.ARRAY ? arrayEquals(a, b) : objectEquals(a, b);
}
- /**
- * Returns a hash code for {@code t}.
- *
- *
The {@code hash} has the following properties:
- *
- *
It is consistent: for any reference {@code x}, multiple invocations of
- * {@code hash(x}} consistently return the same value provided {@code x} remains unchanged
- * according to the definition of the equivalence. The hash need not remain consistent from
- * one execution of an application to another execution of the same application.
- *
It is distributable across equivalence: for any references {@code x} and {@code y},
- * if {@code equivalent(x, y)}, then {@code hash(x) == hash(y)}. It is not necessary
- * that the hash be distributable across inequivalence. If {@code equivalence(x, y)}
- * is false, {@code hash(x) == hash(y)} may still be true.
- *
{@code hash(null)} is {@code 0}.
- *
- * @param t node to hash
- * @return hash
- */
- public final int hash(@Nullable JsonNode t) {
- if (t == null) {
- return 0;
- }
- return doHash(t);
- }
-
+ @Override
protected int doHash(final JsonNode t)
{
/*
diff --git a/src/main/java/com/google/common/base/Equivalence.java b/src/main/java/com/google/common/base/Equivalence.java
new file mode 100644
index 0000000..5175b0f
--- /dev/null
+++ b/src/main/java/com/google/common/base/Equivalence.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.base;
+
+import javax.annotation.Nullable;
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * A strategy for determining whether two instances are considered equivalent. Examples of
+ * equivalences are the {@linkplain #identity() identity equivalence} and {@linkplain #equals equals
+ * equivalence}.
+ *
+ * @author Bob Lee
+ * @author Ben Yu
+ * @author Gregory Kick
+ * @author soberich on 29-Nov-18
+ */
+public abstract class Equivalence {
+ /**
+ * Constructor for use by subclasses.
+ */
+ protected Equivalence() {}
+
+ /**
+ * Returns {@code true} if the given objects are considered equivalent.
+ *
+ *
The {@code equivalent} method implements an equivalence relation on object references:
+ *
+ *
+ *
It is reflexive: for any reference {@code x}, including null, {@code
+ * equivalent(x, x)} returns {@code true}.
+ *
It is symmetric: for any references {@code x} and {@code y}, {@code
+ * equivalent(x, y) == equivalent(y, x)}.
+ *
It is transitive: for any references {@code x}, {@code y}, and {@code z}, if
+ * {@code equivalent(x, y)} returns {@code true} and {@code equivalent(y, z)} returns {@code
+ * true}, then {@code equivalent(x, z)} returns {@code true}.
+ *
It is consistent: for any references {@code x} and {@code y}, multiple invocations
+ * of {@code equivalent(x, y)} consistently return {@code true} or consistently return {@code
+ * false} (provided that neither {@code x} nor {@code y} is modified).
+ *
+ */
+ public final boolean equivalent(@Nullable T a, @Nullable T b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return doEquivalent(a, b);
+ }
+
+ /**
+ * Returns {@code true} if {@code a} and {@code b} are considered equivalent.
+ *
+ *
Called by {@link #equivalent}. {@code a} and {@code b} are not the same
+ * object and are not nulls.
+ */
+ protected abstract boolean doEquivalent(T a, T b);
+
+ /**
+ * Returns a hash code for {@code t}.
+ *
+ *
The {@code hash} has the following properties:
+ *
+ *
It is consistent: for any reference {@code x}, multiple invocations of
+ * {@code hash(x}} consistently return the same value provided {@code x} remains unchanged
+ * according to the definition of the equivalence. The hash need not remain consistent from
+ * one execution of an application to another execution of the same application.
+ *
It is distributable across equivalence: for any references {@code x} and {@code y},
+ * if {@code equivalent(x, y)}, then {@code hash(x) == hash(y)}. It is not necessary
+ * that the hash be distributable across inequivalence. If {@code equivalence(x, y)}
+ * is false, {@code hash(x) == hash(y)} may still be true.
+ *
{@code hash(null)} is {@code 0}.
+ *
+ */
+ public final int hash(@Nullable T t) {
+ if (t == null) {
+ return 0;
+ }
+ return doHash(t);
+ }
+
+ /**
+ * Returns a hash code for non-null object {@code t}.
+ *
+ *
Called by {@link #hash}.
+ */
+ protected abstract int doHash(T t);
+
+ /**
+ * Returns a new equivalence relation for {@code F} which evaluates equivalence by first applying
+ * {@code function} to the argument, then evaluating using {@code this}. That is, for any pair of
+ * non-null objects {@code x} and {@code y}, {@code
+ * equivalence.onResultOf(function).equivalent(a, b)} is true if and only if {@code
+ * equivalence.equivalent(function.apply(a), function.apply(b))} is true.
+ *
+ *
{@code function} will never be invoked with a null value.
+ *
+ *
Note that {@code function} must be consistent according to {@code this} equivalence
+ * relation. That is, invoking {@code com.google.common.base.Function#apply} multiple times for a given value must return
+ * equivalent results.
+ * For example, {@code Equivalence.identity().onResultOf(Functions.toStringFunction())} is broken
+ * because it's not guaranteed that {@link Object#toString}) always returns the same string
+ * instance.
+ */
+ public final Equivalence onResultOf(Function function) {
+ return new FunctionalEquivalence(function, this);
+ }
+
+ /**
+ * Returns a wrapper of {@code reference} that implements
+ * {@link Wrapper#equals(Object) Object.equals()} such that
+ * {@code wrap(a).equals(wrap(b))} if and only if {@code equivalent(a, b)}.
+ */
+ public final Wrapper wrap(@Nullable S reference) {
+ return new Wrapper(this, reference);
+ }
+
+ /**
+ * Wraps an object so that {@link #equals(Object)} and {@link #hashCode()} delegate to an
+ * {@link Equivalence}.
+ *
+ *
For example, given an {@link Equivalence} for {@link String strings} named {@code equiv}
+ * that tests equivalence using their lengths:
+ *
+ *
+ */
+ public static final class Wrapper implements Serializable {
+ private final Equivalence super T> equivalence;
+ @Nullable private final T reference;
+
+ private Wrapper(Equivalence super T> equivalence, @Nullable T reference) {
+ if (equivalence == null) {
+ throw new NullPointerException();
+ }
+ this.equivalence = equivalence;
+ this.reference = reference;
+ }
+
+ /** Returns the (possibly null) reference wrapped by this instance. */
+ @Nullable public T get() {
+ return reference;
+ }
+
+ /**
+ * Returns {@code true} if {@link Equivalence#equivalent(Object, Object)} applied to the wrapped
+ * references is {@code true} and both wrappers use the {@link Object#equals(Object) same}
+ * equivalence.
+ */
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Wrapper) {
+ Wrapper> that = (Wrapper>) obj; // note: not necessarily a Wrapper
+
+ if (this.equivalence.equals(that.equivalence)) {
+ /*
+ * We'll accept that as sufficient "proof" that either equivalence should be able to
+ * handle either reference, so it's safe to circumvent compile-time type checking.
+ */
+ @SuppressWarnings("unchecked")
+ Equivalence