From dbe3357c23420a450f3044c0bc93cda713dbee90 Mon Sep 17 00:00:00 2001
From: soberich <25544967+soberich@users.noreply.github.com>
Date: Fri, 30 Nov 2018 00:15:30 +0300
Subject: [PATCH] Rebase on upstream master, resolve errorprone. Shadow Google
 classes. Use diamonds from Java 7.

---
 project.gradle                                |   4 +-
 .../com/github/fge/jackson/JacksonUtils.java  |   4 +-
 .../com/github/fge/jackson/JsonNumEquals.java |  69 +---
 .../java/com/github/fge/jackson/NodeType.java |   4 +-
 .../com/google/common/base/Equivalence.java   | 333 ++++++++++++++++++
 .../com/google/common/base/Function.java      |  64 ++++
 .../common/base/FunctionalEquivalence.java    |  77 ++++
 .../common/base/PairwiseEquivalence.java      |  79 +++++
 .../com/google/common/base/Predicate.java     |  62 ++++
 .../fge/jackson/jsonpointer/JsonPointer.java  |   8 +-
 .../fge/jackson/jsonpointer/TreePointer.java  |   6 +-
 .../fge/jackson/JsonNodeReaderTest.java       |   9 +-
 .../github/fge/jackson/JsonNumEqualsTest.java |   2 +-
 .../fge/jackson/SampleNodeProvider.java       |   6 +-
 .../jsonpointer/JsonNodeResolverTest.java     |   2 +-
 .../jackson/jsonpointer/JsonPointerTest.java  |   6 +-
 .../jackson/jsonpointer/TreePointerTest.java  |   4 +-
 17 files changed, 649 insertions(+), 90 deletions(-)
 create mode 100644 src/main/java/com/github/fge/jackson/com/google/common/base/Equivalence.java
 create mode 100644 src/main/java/com/github/fge/jackson/com/google/common/base/Function.java
 create mode 100644 src/main/java/com/github/fge/jackson/com/google/common/base/FunctionalEquivalence.java
 create mode 100644 src/main/java/com/github/fge/jackson/com/google/common/base/PairwiseEquivalence.java
 create mode 100644 src/main/java/com/github/fge/jackson/com/google/common/base/Predicate.java

diff --git a/project.gradle b/project.gradle
index d93a5be..eb944d3 100644
--- a/project.gradle
+++ b/project.gradle
@@ -31,8 +31,8 @@ targetCompatibility = JavaVersion.VERSION_1_7; // defaults to sourceCompatibilit
 dependencies {
     implementation(group: "com.fasterxml.jackson.core", name: "jackson-databind", version: "2.9.9");
     implementation(group: "com.github.fge", name: "msg-simple", version: "1.1");
-    implementation(group: "com.google.code.findbugs", name: "jsr305", version: "2.0.1");
-    testImplementation(group: "org.testng", name: "testng", version: "6.8.7") {
+    implementation(group: "com.google.code.findbugs", name: "jsr305", version: "3.0.2");
+    testImplementation(group: "org.testng", name: "testng", version: "7.0.0-beta1") {
         exclude(group: "junit", module: "junit");
         exclude(group: "org.beanshell", module: "bsh");
         exclude(group: "org.yaml", module: "snakeyaml");
diff --git a/src/main/java/com/github/fge/jackson/JacksonUtils.java b/src/main/java/com/github/fge/jackson/JacksonUtils.java
index 85c41ff..5750d77 100644
--- a/src/main/java/com/github/fge/jackson/JacksonUtils.java
+++ b/src/main/java/com/github/fge/jackson/JacksonUtils.java
@@ -99,7 +99,7 @@ public static Map<String, JsonNode> asMap(final JsonNode node)
             return Collections.emptyMap();
 
         final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();
-        final Map<String, JsonNode> ret = new HashMap<String, JsonNode>();
+        final Map<String, JsonNode> ret = new HashMap<>();
 
         Map.Entry<String, JsonNode> entry;
 
@@ -108,7 +108,7 @@ public static Map<String, JsonNode> asMap(final JsonNode node)
             ret.put(entry.getKey(), entry.getValue());
         }
 
-        return ret;
+        return Collections.unmodifiableMap(ret);
     }
 
     /**
diff --git a/src/main/java/com/github/fge/jackson/JsonNumEquals.java b/src/main/java/com/github/fge/jackson/JsonNumEquals.java
index f098d4b..e061c8e 100644
--- a/src/main/java/com/github/fge/jackson/JsonNumEquals.java
+++ b/src/main/java/com/github/fge/jackson/JsonNumEquals.java
@@ -20,8 +20,8 @@
 package com.github.fge.jackson;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import com.github.fge.jackson.com.google.common.base.Equivalence;
 
-import javax.annotation.Nullable;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
@@ -41,50 +41,21 @@
  * kind of equality.</p>
  */
 public final class JsonNumEquals
+    extends Equivalence<JsonNode>
 {
-    private static final JsonNumEquals INSTANCE
+    private static final Equivalence<JsonNode> INSTANCE
         = new JsonNumEquals();
 
     private JsonNumEquals()
     {
     }
 
-    public static JsonNumEquals getInstance()
+    public static Equivalence<JsonNode> getInstance()
     {
         return INSTANCE;
     }
 
-    /**
-     * Returns {@code true} if the given objects are considered equivalent.
-     *
-     * <p>The {@code equivalent} method implements an equivalence relation on object references:
-     *
-     * <ul>
-     * <li>It is <i>reflexive</i>: for any reference {@code x}, including null, {@code
-     *     equivalent(x, x)} returns {@code true}.
-     * <li>It is <i>symmetric</i>: for any references {@code x} and {@code y}, {@code
-     *     equivalent(x, y) == equivalent(y, x)}.
-     * <li>It is <i>transitive</i>: 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}.
-     * <li>It is <i>consistent</i>: 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).
-     * </ul>
-     * @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}.
-     *
-     * <p>The {@code hash} has the following properties:
-     * <ul>
-     * <li>It is <i>consistent</i>: 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.
-     * <li>It is <i>distributable across equivalence</i>: for any references {@code x} and {@code y},
-     *     if {@code equivalent(x, y)}, then {@code hash(x) == hash(y)}. It is <i>not</i> necessary
-     *     that the hash be distributable across <i>inequivalence</i>. If {@code equivalence(x, y)}
-     *     is false, {@code hash(x) == hash(y)} may still be true.
-     * <li>{@code hash(null)} is {@code 0}.
-     * </ul>
-     * @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)
     {
         /*
@@ -236,7 +183,7 @@ private boolean objectEquals(final JsonNode a, final JsonNode b)
         /*
          * Grab the key set from the first node
          */
-        final Set<String> keys = new HashSet<String>();
+        final Set<String> keys = new HashSet<>();
         Iterator<String> iterator1 = a.fieldNames();
         while (iterator1.hasNext()) {
             final String next = iterator1.next();
@@ -251,7 +198,7 @@ private boolean objectEquals(final JsonNode a, final JsonNode b)
          * Grab the key set from the second node, and see if both sets are the
          * same. If not, objects are not equal, no need to check for children.
          */
-        final Set<String> set = new HashSet<String>();
+        final Set<String> set = new HashSet<>();
         Iterator<String> iterator2 = b.fieldNames();
         while (iterator2.hasNext()) {
             final String next = iterator2.next();
diff --git a/src/main/java/com/github/fge/jackson/NodeType.java b/src/main/java/com/github/fge/jackson/NodeType.java
index ea15551..67ddf86 100644
--- a/src/main/java/com/github/fge/jackson/NodeType.java
+++ b/src/main/java/com/github/fge/jackson/NodeType.java
@@ -86,7 +86,7 @@ public enum NodeType
      * #getNodeType(JsonNode)})
      */
     private static final Map<JsonToken, NodeType> TOKEN_MAP
-        = new EnumMap<JsonToken, NodeType>(JsonToken.class);
+        = new EnumMap<>(JsonToken.class);
 
     static {
         TOKEN_MAP.put(JsonToken.START_ARRAY, ARRAY);
@@ -99,7 +99,7 @@ public enum NodeType
         TOKEN_MAP.put(JsonToken.VALUE_STRING, STRING);
 
         final Map<String, NodeType> builder
-            = new HashMap<String, NodeType>();
+            = new HashMap<>();
 
         for (final NodeType type: NodeType.values())
             builder.put(type.name, type);
diff --git a/src/main/java/com/github/fge/jackson/com/google/common/base/Equivalence.java b/src/main/java/com/github/fge/jackson/com/google/common/base/Equivalence.java
new file mode 100644
index 0000000..11633dc
--- /dev/null
+++ b/src/main/java/com/github/fge/jackson/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.github.fge.jackson.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 <a href="mailto:43personal@gmail.com">soberich</a> on 29-Nov-18
+ */
+public abstract class Equivalence<T> {
+    /**
+     * Constructor for use by subclasses.
+     */
+    protected Equivalence() {}
+
+    /**
+     * Returns {@code true} if the given objects are considered equivalent.
+     *
+     * <p>The {@code equivalent} method implements an equivalence relation on object references:
+     *
+     * <ul>
+     * <li>It is <i>reflexive</i>: for any reference {@code x}, including null, {@code
+     *     equivalent(x, x)} returns {@code true}.
+     * <li>It is <i>symmetric</i>: for any references {@code x} and {@code y}, {@code
+     *     equivalent(x, y) == equivalent(y, x)}.
+     * <li>It is <i>transitive</i>: 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}.
+     * <li>It is <i>consistent</i>: 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).
+     * </ul>
+     */
+    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.
+     *
+     * <p>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}.
+     *
+     * <p>The {@code hash} has the following properties:
+     * <ul>
+     * <li>It is <i>consistent</i>: 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.
+     * <li>It is <i>distributable across equivalence</i>: for any references {@code x} and {@code y},
+     *     if {@code equivalent(x, y)}, then {@code hash(x) == hash(y)}. It is <i>not</i> necessary
+     *     that the hash be distributable across <i>inequivalence</i>. If {@code equivalence(x, y)}
+     *     is false, {@code hash(x) == hash(y)} may still be true.
+     * <li>{@code hash(null)} is {@code 0}.
+     * </ul>
+     */
+    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}.
+     *
+     * <p>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.
+     *
+     * <p>For example:
+     *
+     * <pre>   {@code
+     *    Equivalence<Person> SAME_AGE = Equivalence.equals().onResultOf(GET_PERSON_AGE);}</pre>
+     *
+     * <p>{@code function} will never be invoked with a null value.
+     *
+     * <p>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 <F> Equivalence<F> onResultOf(Function<F, ? extends T> 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 <S extends T> Wrapper<S> wrap(@Nullable S reference) {
+        return new Wrapper<S>(this, reference);
+    }
+
+    /**
+     * Wraps an object so that {@link #equals(Object)} and {@link #hashCode()} delegate to an
+     * {@link Equivalence}.
+     *
+     * <p>For example, given an {@link Equivalence} for {@link String strings} named {@code equiv}
+     * that tests equivalence using their lengths:
+     *
+     * <pre>   {@code
+     *   equiv.wrap("a").equals(equiv.wrap("b")) // true
+     *   equiv.wrap("a").equals(equiv.wrap("hello")) // false}</pre>
+     *
+     * <p>Note in particular that an equivalence wrapper is never equal to the object it wraps.
+     *
+     * <pre>   {@code
+     *   equiv.wrap(obj).equals(obj) // always false}</pre>
+     */
+    public static final class Wrapper<T> 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<T>
+
+                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<Object> equivalence = (Equivalence<Object>) this.equivalence;
+                    return equivalence.equivalent(this.reference, that.reference);
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns the result of {@link Equivalence#hash(Object)} applied to the wrapped reference.
+         */
+        @Override public int hashCode() {
+            return equivalence.hash(reference);
+        }
+
+        /**
+         * Returns a string representation for this equivalence wrapper. The form of this string
+         * representation is not specified.
+         */
+        @Override public String toString() {
+            return equivalence + ".wrap(" + reference + ")";
+        }
+
+        private static final long serialVersionUID = 0;
+    }
+
+    /**
+     * Returns an equivalence over iterables based on the equivalence of their elements.  More
+     * specifically, two iterables are considered equivalent if they both contain the same number of
+     * elements, and each pair of corresponding elements is equivalent according to
+     * {@code this}.  Null iterables are equivalent to one another.
+     *
+     * <p>Note that this method performs a similar function for equivalences as {@code
+     * com.google.common.collect.Ordering#lexicographical} does for orderings.
+     */
+    public final <S extends T> Equivalence<Iterable<S>> pairwise() {
+        // Ideally, the returned equivalence would support Iterable<? extends T>. However,
+        // the need for this is so rare that it's not worth making callers deal with the ugly wildcard.
+        return new PairwiseEquivalence<>(this);
+    }
+
+    /**
+     * Returns a predicate that evaluates to true if and only if the input is
+     * equivalent to {@code target} according to this equivalence relation.
+     */
+    public final Predicate<T> equivalentTo(@Nullable T target) {
+        return new EquivalentToPredicate<>(this, target);
+    }
+
+    private static final class EquivalentToPredicate<T> implements Predicate<T>, Serializable {
+
+        private final Equivalence<T> equivalence;
+        @Nullable private final T target;
+
+        EquivalentToPredicate(Equivalence<T> equivalence, @Nullable T target) {
+            if (equivalence == null) {
+                throw new NullPointerException();
+            }
+            this.equivalence = equivalence;
+            this.target = target;
+        }
+
+        @Override public boolean apply(@Nullable T input) {
+            return equivalence.equivalent(input, target);
+        }
+
+        @Override public boolean equals(@Nullable Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof EquivalentToPredicate) {
+                EquivalentToPredicate<?> that = (EquivalentToPredicate<?>) obj;
+                return (equivalence.equals(that.equivalence)
+                        && (target == that.target)) || ((target != null) && target.equals(that.target));
+            }
+            return false;
+        }
+
+        @Override public int hashCode() {
+            return Arrays.hashCode(new Object[]{equivalence, target});
+        }
+
+        @Override public String toString() {
+            return equivalence + ".equivalentTo(" + target + ")";
+        }
+
+        private static final long serialVersionUID = 0;
+    }
+
+    /**
+     * Returns an equivalence that delegates to {@link Object#equals} and {@link Object#hashCode}.
+     * {@link Equivalence#equivalent} returns {@code true} if both values are null, or if neither
+     * value is null and {@link Object#equals} returns {@code true}. {@link Equivalence#hash} returns
+     * {@code 0} if passed a null value.
+     */
+    public static Equivalence<Object> equals() {
+        return Equals.INSTANCE;
+    }
+
+    /**
+     * Returns an equivalence that uses {@code ==} to compare values and {@link
+     * System#identityHashCode(Object)} to compute the hash code.  {@link Equivalence#equivalent}
+     * returns {@code true} if {@code a == b}, including in the case that a and b are both null.
+     */
+    public static Equivalence<Object> identity() {
+        return Identity.INSTANCE;
+    }
+
+    static final class Equals extends Equivalence<Object>
+            implements Serializable {
+
+        static final Equals INSTANCE = new Equals();
+
+        @Override protected boolean doEquivalent(Object a, Object b) {
+            return a.equals(b);
+        }
+        @Override public int doHash(Object o) {
+            return o.hashCode();
+        }
+
+        private Object readResolve() {
+            return INSTANCE;
+        }
+        private static final long serialVersionUID = 1;
+    }
+
+    static final class Identity extends Equivalence<Object>
+            implements Serializable {
+
+        static final Identity INSTANCE = new Identity();
+
+        @Override protected boolean doEquivalent(Object a, Object b) {
+            return false;
+        }
+
+        @Override protected int doHash(Object o) {
+            return System.identityHashCode(o);
+        }
+
+        private Object readResolve() {
+            return INSTANCE;
+        }
+        private static final long serialVersionUID = 1;
+    }
+}
diff --git a/src/main/java/com/github/fge/jackson/com/google/common/base/Function.java b/src/main/java/com/github/fge/jackson/com/google/common/base/Function.java
new file mode 100644
index 0000000..fb53cd2
--- /dev/null
+++ b/src/main/java/com/github/fge/jackson/com/google/common/base/Function.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 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.github.fge.jackson.com.google.common.base;
+
+import javax.annotation.Nullable;
+
+/**
+ * Determines an output value based on an input value.
+ *
+ * <p>The {@code com.google.common.base.Functions} class provides common functions and related utilites.
+ *
+ * <p>See the Guava User Guide article on <a href=
+ * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code
+ * Function}</a>.
+ *
+ * @author Kevin Bourrillion
+ * @author <a href="mailto:43personal@gmail.com">soberich</a> on 29-Nov-18
+ * @since 1.10 (imported from Google Collections Library)
+ */
+public interface Function<F, T> {
+    /**
+     * Returns the result of applying this function to {@code input}. This method is <i>generally
+     * expected</i>, but not absolutely required, to have the following properties:
+     *
+     * <ul>
+     * <li>Its execution does not cause any observable side effects.
+     * <li>The computation is <i>consistent with equals</i>; that is, {@code com.google.common.base.Objects#equal
+     *     Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a),
+     *     function.apply(b))}.
+     * </ul>
+     *
+     * @throws NullPointerException if {@code input} is null and this function does not accept null
+     *     arguments
+     */
+    @Nullable
+    T apply(@Nullable F input);
+
+    /**
+     * Indicates whether another object is equal to this function.
+     *
+     * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}.
+     * However, an implementation may also choose to return {@code true} whenever {@code object} is a
+     * {@link Function} that it considers <i>interchangeable</i> with this one. "Interchangeable"
+     * <i>typically</i> means that {@code Objects.equal(this.apply(f), that.apply(f))} is true for all
+     * {@code f} of type {@code F}. Note that a {@code false} result from this method does not imply
+     * that the functions are known <i>not</i> to be interchangeable.
+     */
+    @Override
+    boolean equals(@Nullable Object object);
+}
diff --git a/src/main/java/com/github/fge/jackson/com/google/common/base/FunctionalEquivalence.java b/src/main/java/com/github/fge/jackson/com/google/common/base/FunctionalEquivalence.java
new file mode 100644
index 0000000..423a096
--- /dev/null
+++ b/src/main/java/com/github/fge/jackson/com/google/common/base/FunctionalEquivalence.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 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.github.fge.jackson.com.google.common.base;
+
+import javax.annotation.Nullable;
+import java.io.Serializable;
+import java.util.Arrays;
+
+/**
+ * Equivalence applied on functional result.
+ *
+ * @author Bob Lee
+ * @author <a href="mailto:43personal@gmail.com">soberich</a> on 29-Nov-18
+ * @since 1.10
+ */
+final class FunctionalEquivalence<F, T> extends Equivalence<F>
+        implements Serializable {
+
+    private static final long serialVersionUID = 0;
+
+    private final Function<F, ? extends T> function;
+    private final Equivalence<T> resultEquivalence;
+
+    FunctionalEquivalence(
+            Function<F, ? extends T> function, Equivalence<T> resultEquivalence) {
+        if (function == null) {
+            throw new NullPointerException();
+        }
+        this.function = function;
+        if (resultEquivalence == null) {
+            throw new NullPointerException();
+        }
+        this.resultEquivalence = resultEquivalence;
+    }
+
+    @Override protected boolean doEquivalent(F a, F b) {
+        return resultEquivalence.equivalent(function.apply(a), function.apply(b));
+    }
+
+    @Override protected int doHash(F a) {
+        return resultEquivalence.hash(function.apply(a));
+    }
+
+    @Override public boolean equals(@Nullable Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof FunctionalEquivalence) {
+            FunctionalEquivalence<?, ?> that = (FunctionalEquivalence<?, ?>) obj;
+            return function.equals(that.function)
+                    && resultEquivalence.equals(that.resultEquivalence);
+        }
+        return false;
+    }
+
+    @Override public int hashCode() {
+        return Arrays.hashCode(new Object[]{function, resultEquivalence});
+    }
+
+    @Override public String toString() {
+        return resultEquivalence + ".onResultOf(" + function + ")";
+    }
+}
diff --git a/src/main/java/com/github/fge/jackson/com/google/common/base/PairwiseEquivalence.java b/src/main/java/com/github/fge/jackson/com/google/common/base/PairwiseEquivalence.java
new file mode 100644
index 0000000..d1d2f19
--- /dev/null
+++ b/src/main/java/com/github/fge/jackson/com/google/common/base/PairwiseEquivalence.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 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.github.fge.jackson.com.google.common.base;
+
+import javax.annotation.Nullable;
+import java.io.Serializable;
+import java.util.Iterator;
+
+final class PairwiseEquivalence<T> extends Equivalence<Iterable<T>>
+        implements Serializable {
+
+    final Equivalence<? super T> elementEquivalence;
+
+    PairwiseEquivalence(Equivalence<? super T> elementEquivalence) {
+        if (elementEquivalence == null) {
+            throw new NullPointerException();
+        }
+        this.elementEquivalence = elementEquivalence;
+    }
+
+    @Override
+    protected boolean doEquivalent(Iterable<T> iterableA, Iterable<T> iterableB) {
+        Iterator<T> iteratorA = iterableA.iterator();
+        Iterator<T> iteratorB = iterableB.iterator();
+
+        while (iteratorA.hasNext() && iteratorB.hasNext()) {
+            if (!elementEquivalence.equivalent(iteratorA.next(), iteratorB.next())) {
+                return false;
+            }
+        }
+
+        return !iteratorA.hasNext() && !iteratorB.hasNext();
+    }
+
+    @Override
+    protected int doHash(Iterable<T> iterable) {
+        int hash = 78721;
+        for (T element : iterable) {
+            hash = hash * 24943 + elementEquivalence.hash(element);
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object object) {
+        if (object instanceof PairwiseEquivalence) {
+            PairwiseEquivalence<?> that = (PairwiseEquivalence<?>) object;
+            return this.elementEquivalence.equals(that.elementEquivalence);
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return elementEquivalence.hashCode() ^ 0x46a3eb07;
+    }
+
+    @Override
+    public String toString() {
+        return elementEquivalence + ".pairwise()";
+    }
+
+    private static final long serialVersionUID = 1;
+}
diff --git a/src/main/java/com/github/fge/jackson/com/google/common/base/Predicate.java b/src/main/java/com/github/fge/jackson/com/google/common/base/Predicate.java
new file mode 100644
index 0000000..6ffa6d0
--- /dev/null
+++ b/src/main/java/com/github/fge/jackson/com/google/common/base/Predicate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 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.github.fge.jackson.com.google.common.base;
+
+import javax.annotation.Nullable;
+
+/**
+ * Determines a true or false value for a given input.
+ *
+ * <p>The {@code com.google.common.base.Predicates} class provides common predicates and related utilities.
+ *
+ * <p>See the Guava User Guide article on <a href=
+ * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code
+ * Predicate}</a>.
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+public interface Predicate<T> {
+    /**
+     * Returns the result of applying this predicate to {@code input}. This method is <i>generally
+     * expected</i>, but not absolutely required, to have the following properties:
+     *
+     * <ul>
+     * <li>Its execution does not cause any observable side effects.
+     * <li>The computation is <i>consistent with equals</i>; that is, {@code com.google.common.base.Objects#equal
+     *     Objects.equal}{@code (a, b)} implies that {@code predicate.apply(a) ==
+     *     predicate.apply(b))}.
+     * </ul>
+     *
+     * @throws NullPointerException if {@code input} is null and this predicate does not accept null
+     *     arguments
+     */
+    boolean apply(@Nullable T input);
+
+    /**
+     * Indicates whether another object is equal to this predicate.
+     *
+     * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}.
+     * However, an implementation may also choose to return {@code true} whenever {@code object} is a
+     * {@link Predicate} that it considers <i>interchangeable</i> with this one. "Interchangeable"
+     * <i>typically</i> means that {@code this.apply(t) == that.apply(t)} for all {@code t} of type
+     * {@code T}). Note that a {@code false} result from this method does not imply that the
+     * predicates are known <i>not</i> to be interchangeable.
+     */
+    @Override
+    boolean equals(@Nullable Object object);
+}
diff --git a/src/main/java/com/github/fge/jackson/jsonpointer/JsonPointer.java b/src/main/java/com/github/fge/jackson/jsonpointer/JsonPointer.java
index 670e50b..0aae6a5 100644
--- a/src/main/java/com/github/fge/jackson/jsonpointer/JsonPointer.java
+++ b/src/main/java/com/github/fge/jackson/jsonpointer/JsonPointer.java
@@ -72,7 +72,7 @@ public static JsonPointer empty()
      */
     public static JsonPointer of(final Object first, final Object... other)
     {
-        final List<ReferenceToken> tokens = new ArrayList<ReferenceToken>();
+        final List<ReferenceToken> tokens = new ArrayList<>();
 
         tokens.add(ReferenceToken.fromRaw(first.toString()));
 
@@ -120,7 +120,7 @@ public JsonPointer append(final String raw)
         final ReferenceToken refToken = ReferenceToken.fromRaw(raw);
         final JsonNodeResolver resolver = new JsonNodeResolver(refToken);
         final List<TokenResolver<JsonNode>> list
-            = new ArrayList<TokenResolver<JsonNode>>();
+            = new ArrayList<>();
         for (final TokenResolver<JsonNode> tokenResolver : tokenResolvers) {
             if (tokenResolver != null) {
                 list.add(tokenResolver);
@@ -154,7 +154,7 @@ public JsonPointer append(final JsonPointer other)
     {
         BUNDLE.checkNotNull(other, "nullInput");
         final List<TokenResolver<JsonNode>> list
-            = new ArrayList<TokenResolver<JsonNode>>();
+            = new ArrayList<>();
         for (final TokenResolver<JsonNode> tokenResolver : tokenResolvers) {
             if (tokenResolver != null) {
                 list.add(tokenResolver);
@@ -191,7 +191,7 @@ public JsonPointer parent()
     private static List<TokenResolver<JsonNode>> fromTokens(
         final List<ReferenceToken> tokens)
     {
-        final List<TokenResolver<JsonNode>> list = new ArrayList<TokenResolver<JsonNode>>();
+        final List<TokenResolver<JsonNode>> list = new ArrayList<>();
         for (final ReferenceToken token: tokens)
             list.add(new JsonNodeResolver(token));
         return list;
diff --git a/src/main/java/com/github/fge/jackson/jsonpointer/TreePointer.java b/src/main/java/com/github/fge/jackson/jsonpointer/TreePointer.java
index df82ef8..8d6daee 100644
--- a/src/main/java/com/github/fge/jackson/jsonpointer/TreePointer.java
+++ b/src/main/java/com/github/fge/jackson/jsonpointer/TreePointer.java
@@ -92,7 +92,7 @@ protected TreePointer(final T missing,
         final List<TokenResolver<T>> tokenResolvers)
     {
         this.missing = missing;
-        this.tokenResolvers = Collections.unmodifiableList(new ArrayList<TokenResolver<T>>(tokenResolvers));
+        this.tokenResolvers = Collections.unmodifiableList(new ArrayList<>(tokenResolvers));
     }
 
     /**
@@ -174,7 +174,7 @@ public final boolean equals(final Object obj)
             return false;
         if (this == obj)
             return true;
-        if (getClass() != obj.getClass())
+        if (!(obj instanceof TreePointer))
             return false;
         final TreePointer<?> other = (TreePointer<?>) obj;
         return tokenResolvers.equals(other.tokenResolvers);
@@ -206,7 +206,7 @@ protected static List<ReferenceToken> tokensFromInput(final String input)
         throws JsonPointerException
     {
         String s = BUNDLE.checkNotNull(input, "nullInput");
-        final List<ReferenceToken> ret = new ArrayList<ReferenceToken>();
+        final List<ReferenceToken> ret = new ArrayList<>();
         String cooked;
         int index;
         char c;
diff --git a/src/test/java/com/github/fge/jackson/JsonNodeReaderTest.java b/src/test/java/com/github/fge/jackson/JsonNodeReaderTest.java
index 7a60cd4..2965822 100644
--- a/src/test/java/com/github/fge/jackson/JsonNodeReaderTest.java
+++ b/src/test/java/com/github/fge/jackson/JsonNodeReaderTest.java
@@ -33,6 +33,7 @@
 import java.io.Reader;
 import java.io.StringReader;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -70,7 +71,7 @@ public void readerIsClosedOnRead()
     @DataProvider
     public Iterator<Object[]> getMalformedData()
     {
-        final List<Object[]> list = new ArrayList<Object[]>();
+        final List<Object[]> list = new ArrayList<>();
 
         list.add(new Object[] { "", "read.noContent"});
         list.add(new Object[] { "[]{}", "read.trailingData"});
@@ -104,11 +105,7 @@ private static Supplier<InputStream> provideInputStream(final String input)
             @Override
             public InputStream get()
             {
-                try {
-                    return new ByteArrayInputStream(input.getBytes("UTF-8"));
-                } catch (UnsupportedEncodingException e) {
-                    throw new RuntimeException("Unhandled exception", e);
-                }
+                return new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8));
             }
         };
     }
diff --git a/src/test/java/com/github/fge/jackson/JsonNumEqualsTest.java b/src/test/java/com/github/fge/jackson/JsonNumEqualsTest.java
index cecb942..af4d068 100644
--- a/src/test/java/com/github/fge/jackson/JsonNumEqualsTest.java
+++ b/src/test/java/com/github/fge/jackson/JsonNumEqualsTest.java
@@ -49,7 +49,7 @@ public void initData()
     @DataProvider
     public Iterator<Object[]> getInputs()
     {
-        final List<Object[]> list = new ArrayList<Object[]>();
+        final List<Object[]> list = new ArrayList<>();
 
         JsonNode reference;
 
diff --git a/src/test/java/com/github/fge/jackson/SampleNodeProvider.java b/src/test/java/com/github/fge/jackson/SampleNodeProvider.java
index ec03e32..23817f7 100644
--- a/src/test/java/com/github/fge/jackson/SampleNodeProvider.java
+++ b/src/test/java/com/github/fge/jackson/SampleNodeProvider.java
@@ -35,7 +35,7 @@ private SampleNodeProvider()
     }
 
     static {
-        SAMPLE_DATA = new EnumMap<NodeType, JsonNode>(NodeType.class);
+        SAMPLE_DATA = new EnumMap<>(NodeType.class);
 
         SAMPLE_DATA.put(NodeType.ARRAY, FACTORY.arrayNode());
         SAMPLE_DATA.put(NodeType.BOOLEAN, FACTORY.booleanNode(true));
@@ -52,10 +52,10 @@ private SampleNodeProvider()
     // differ...
     public static Iterator<Object[]> getSamples(final EnumSet<NodeType> types)
     {
-        final Map<NodeType, JsonNode> map = new EnumMap<NodeType, JsonNode>(SAMPLE_DATA);
+        final Map<NodeType, JsonNode> map = new EnumMap<>(SAMPLE_DATA);
         map.keySet().retainAll(types);
 
-        final ArrayList<Object[]> samples = new ArrayList<Object[]>();
+        final List<Object[]> samples = new ArrayList<>();
         for (final JsonNode input : map.values()) {
             samples.add(new Object[] { input });
         }
diff --git a/src/test/java/com/github/fge/jackson/jsonpointer/JsonNodeResolverTest.java b/src/test/java/com/github/fge/jackson/jsonpointer/JsonNodeResolverTest.java
index d4a042f..6f22fda 100644
--- a/src/test/java/com/github/fge/jackson/jsonpointer/JsonNodeResolverTest.java
+++ b/src/test/java/com/github/fge/jackson/jsonpointer/JsonNodeResolverTest.java
@@ -104,7 +104,7 @@ public void resolvingArrayIndicesWorks()
     @DataProvider
     public Iterator<Object[]> invalidIndices()
     {
-        final List<Object[]> list = new ArrayList<Object[]>();
+        final List<Object[]> list = new ArrayList<>();
 
         list.add(new Object[] { "-1" });
         list.add(new Object[] { "232398087298731987987232" });
diff --git a/src/test/java/com/github/fge/jackson/jsonpointer/JsonPointerTest.java b/src/test/java/com/github/fge/jackson/jsonpointer/JsonPointerTest.java
index c04fded..be19a61 100644
--- a/src/test/java/com/github/fge/jackson/jsonpointer/JsonPointerTest.java
+++ b/src/test/java/com/github/fge/jackson/jsonpointer/JsonPointerTest.java
@@ -66,7 +66,7 @@ public void cannotAppendNullPointer()
     @DataProvider
     public Iterator<Object[]> rawPointers()
     {
-        final List<Object[]> list = new ArrayList<Object[]>();
+        final List<Object[]> list = new ArrayList<>();
         final JsonNode testNode = testData.get("pointers");
         final Map<String, JsonNode> map = JacksonUtils.asMap(testNode);
 
@@ -89,7 +89,7 @@ public void rawPointerResolvingWorks(final String input,
     @DataProvider
     public Iterator<Object[]> uriPointers()
     {
-        final List<Object[]> list = new ArrayList<Object[]>();
+        final List<Object[]> list = new ArrayList<>();
         final JsonNode testNode = testData.get("uris");
         final Map<String, JsonNode> map = JacksonUtils.asMap(testNode);
 
@@ -181,7 +181,7 @@ public void staticConstructionFromTokensWorks()
     @DataProvider
     public Iterator<Object[]> parentTestData()
     {
-        final List<Object[]> list = new ArrayList<Object[]>();
+        final List<Object[]> list = new ArrayList<>();
 
         // Empty
         list.add(new Object[] { JsonPointer.empty(), JsonPointer.empty() });
diff --git a/src/test/java/com/github/fge/jackson/jsonpointer/TreePointerTest.java b/src/test/java/com/github/fge/jackson/jsonpointer/TreePointerTest.java
index a42a406..2edc050 100644
--- a/src/test/java/com/github/fge/jackson/jsonpointer/TreePointerTest.java
+++ b/src/test/java/com/github/fge/jackson/jsonpointer/TreePointerTest.java
@@ -154,7 +154,7 @@ public void gettingPathOfMissingNodeReturnsMissingNode()
     @Test
     public void treePointerCanTellWhetherItIsEmpty()
     {
-        final List<TokenResolver<TreeNode>> list = new ArrayList<TokenResolver<TreeNode>>();
+        final List<TokenResolver<TreeNode>> list = new ArrayList<>();
 
         assertTrue(new DummyPointer(null, list).isEmpty());
 
@@ -168,7 +168,7 @@ public void treePointerCanTellWhetherItIsEmpty()
     @Test
     public void treeIsUnalteredWhenOriginalListIsAltered()
     {
-        final List<TokenResolver<TreeNode>> list = new ArrayList<TokenResolver<TreeNode>>();
+        final List<TokenResolver<TreeNode>> list = new ArrayList<>();
         final DummyPointer dummy = new DummyPointer(null, list);
 
         @SuppressWarnings("unchecked")