diff --git a/android/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java b/android/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java
index 4bb0031dc2b0..925db1a027eb 100644
--- a/android/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java
+++ b/android/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java
@@ -69,6 +69,13 @@ byte crc32Checksum(int reps) throws Exception {
return result;
}
+ // CRC32C
+
+ @Benchmark
+ byte crc32cHashFunction(int reps) {
+ return runHashFunction(reps, Hashing.crc32c());
+ }
+
// Adler32
@Benchmark
diff --git a/android/guava/src/com/google/common/hash/IgnoreJRERequirement.java b/android/guava/src/com/google/common/hash/IgnoreJRERequirement.java
new file mode 100644
index 000000000000..0de7c9a92439
--- /dev/null
+++ b/android/guava/src/com/google/common/hash/IgnoreJRERequirement.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 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.hash;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Target;
+
+/**
+ * Disables Animal Sniffer's checking of compatibility with older versions of Java/Android.
+ *
+ *
Each package's copy of this annotation needs to be listed in our {@code pom.xml}.
+ */
+@Target({METHOD, CONSTRUCTOR, TYPE})
+@ElementTypesAreNonnullByDefault
+@interface IgnoreJRERequirement {}
diff --git a/android/pom.xml b/android/pom.xml
index e14bb1967dc0..c57f5846c067 100644
--- a/android/pom.xml
+++ b/android/pom.xml
@@ -176,7 +176,7 @@
animal-sniffer-maven-plugin
1.23
- com.google.common.io.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement
+ com.google.common.hash.IgnoreJRERequirement,com.google.common.io.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement
true
org.codehaus.mojo.signature
diff --git a/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java b/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java
index 4bb0031dc2b0..925db1a027eb 100644
--- a/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java
+++ b/guava-tests/benchmark/com/google/common/hash/ChecksumBenchmark.java
@@ -69,6 +69,13 @@ byte crc32Checksum(int reps) throws Exception {
return result;
}
+ // CRC32C
+
+ @Benchmark
+ byte crc32cHashFunction(int reps) {
+ return runHashFunction(reps, Hashing.crc32c());
+ }
+
// Adler32
@Benchmark
diff --git a/guava/src/com/google/common/hash/Hashing.java b/guava/src/com/google/common/hash/Hashing.java
index c348e6c29fa0..f2ec72f389ab 100644
--- a/guava/src/com/google/common/hash/Hashing.java
+++ b/guava/src/com/google/common/hash/Hashing.java
@@ -16,8 +16,13 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.throwIfUnchecked;
+import static java.lang.invoke.MethodType.methodType;
import com.google.errorprone.annotations.Immutable;
+import com.google.j2objc.annotations.J2ObjCIncompatible;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.security.Key;
import java.util.ArrayList;
import java.util.Arrays;
@@ -399,6 +404,13 @@ public static HashFunction crc32c() {
@Immutable
private enum Crc32CSupplier implements ImmutableSupplier {
+ @J2ObjCIncompatible
+ JAVA_UTIL_ZIP {
+ @Override
+ public HashFunction get() {
+ return ChecksumType.CRC_32C.hashFunction;
+ }
+ },
ABSTRACT_HASH_FUNCTION {
@Override
public HashFunction get() {
@@ -406,7 +418,26 @@ public HashFunction get() {
}
};
- static final HashFunction HASH_FUNCTION = values()[0].get();
+ static final HashFunction HASH_FUNCTION = pickFunction().get();
+
+ private static Crc32CSupplier pickFunction() {
+ Crc32CSupplier[] functions = values();
+
+ if (functions.length == 1) {
+ // We're running under J2ObjC.
+ return functions[0];
+ }
+
+ // We can't refer to JAVA_UTIL_ZIP directly at compile time because of J2ObjC.
+ Crc32CSupplier javaUtilZip = functions[0];
+
+ try {
+ Class.forName("java.util.zip.CRC32C");
+ return javaUtilZip;
+ } catch (ClassNotFoundException runningUnderJava8) {
+ return ABSTRACT_HASH_FUNCTION;
+ }
+ }
}
/**
@@ -449,6 +480,13 @@ public Checksum get() {
return new CRC32();
}
},
+ @J2ObjCIncompatible
+ CRC_32C("Hashing.crc32c()") {
+ @Override
+ public Checksum get() {
+ return Crc32cMethodHandles.newCrc32c();
+ }
+ },
ADLER_32("Hashing.adler32()") {
@Override
public Checksum get() {
@@ -463,6 +501,52 @@ public Checksum get() {
}
}
+ @J2ObjCIncompatible
+ @SuppressWarnings("unused")
+ private static final class Crc32cMethodHandles {
+ private static final MethodHandle CONSTRUCTOR = crc32cConstructor();
+
+ @IgnoreJRERequirement // https://github.com/mojohaus/animal-sniffer/issues/67
+ static Checksum newCrc32c() {
+ try {
+ return (Checksum) CONSTRUCTOR.invokeExact();
+ } catch (Throwable e) {
+ throwIfUnchecked(e);
+ // That constructor has no `throws` clause.
+ throw newLinkageError(e);
+ }
+ }
+
+ private static MethodHandle crc32cConstructor() {
+ try {
+ Class> clazz = Class.forName("java.util.zip.CRC32C");
+ /*
+ * We can't cast to CRC32C at the call site because we support building with Java 8
+ * (https://github.com/google/guava/issues/6549). So we have to use asType() to change from
+ * CRC32C to Checksum. This may carry some performance cost
+ * (https://stackoverflow.com/a/22321671/28465), but I'd have to benchmark more carefully to
+ * even detect it.
+ */
+ return MethodHandles.lookup()
+ .findConstructor(clazz, methodType(void.class))
+ .asType(methodType(Checksum.class));
+ } catch (ClassNotFoundException e) {
+ // We check that the class is available before calling this method.
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ // That API is public.
+ throw newLinkageError(e);
+ } catch (NoSuchMethodException e) {
+ // That constructor exists.
+ throw newLinkageError(e);
+ }
+ }
+
+ private static LinkageError newLinkageError(Throwable cause) {
+ return new LinkageError(cause.toString(), cause);
+ }
+ }
+
/**
* Returns a hash function implementing FarmHash's Fingerprint64, an open-source algorithm.
*
diff --git a/guava/src/com/google/common/hash/IgnoreJRERequirement.java b/guava/src/com/google/common/hash/IgnoreJRERequirement.java
new file mode 100644
index 000000000000..0de7c9a92439
--- /dev/null
+++ b/guava/src/com/google/common/hash/IgnoreJRERequirement.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 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.hash;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Target;
+
+/**
+ * Disables Animal Sniffer's checking of compatibility with older versions of Java/Android.
+ *
+ * Each package's copy of this annotation needs to be listed in our {@code pom.xml}.
+ */
+@Target({METHOD, CONSTRUCTOR, TYPE})
+@ElementTypesAreNonnullByDefault
+@interface IgnoreJRERequirement {}
diff --git a/pom.xml b/pom.xml
index 352fb25404e3..5ee5d050f768 100644
--- a/pom.xml
+++ b/pom.xml
@@ -177,7 +177,7 @@
animal-sniffer-maven-plugin
1.23
- com.google.common.io.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement
+ com.google.common.hash.IgnoreJRERequirement,com.google.common.io.IgnoreJRERequirement,com.google.common.reflect.IgnoreJRERequirement,com.google.common.testing.IgnoreJRERequirement
true
org.codehaus.mojo.signature