diff --git a/WORKSPACE b/WORKSPACE
index 57995ea5d1283ce54303ea8de883c5fe757635cc..bc1577c199e8a5402b616554cf4397593c98a481 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -541,11 +541,3 @@ http_archive(
 load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
 go_rules_dependencies()
 go_register_toolchains()
-
-#-----------------------------------------------------------------------------
-# jarjar
-#-----------------------------------------------------------------------------
-
-load("//tools:jarjar.bzl", "jarjar_deps")
-
-jarjar_deps()
diff --git a/apps/paymentmethodtoken/BUILD.bazel b/apps/paymentmethodtoken/BUILD.bazel
index 47f9dcc53ec2cb867b6c97b3bf2aab3315607925..4026fc2b8d5bd887a1533fb9c84e7b564f1958e8 100644
--- a/apps/paymentmethodtoken/BUILD.bazel
+++ b/apps/paymentmethodtoken/BUILD.bazel
@@ -41,18 +41,13 @@ java_binary(
 
 # Maven Jars
 
-load("//tools:javadoc.bzl", "javadoc_library")
+load("//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
 
-javadoc_library(
-    name = "libpaymentmethodtoken-javadoc",
-    srcs = [":srcs"],
+gen_maven_jar_rules(
+    name = "maven",
     doctitle = "Tink Cryptography API for Google Payment Method Token",
-    root_packages = [
-        "com.google.crypto.tink.apps.paymentmethodtoken",
-    ],
-    deps = [
-        ":paymentmethodtoken"
-    ],
+    root_packages = ["com.google.crypto.tink.apps.paymentmethodtoken"],
+    deps = [":paymentmethodtoken"],
 )
 
 # Tests
diff --git a/apps/paymentmethodtoken/README.md b/apps/paymentmethodtoken/README.md
index 93d35cfd5469f67674f7374ab6ecf7578b5588ba..51bf6bdc3b6e8c1703ab8b151615318219ebbf86 100644
--- a/apps/paymentmethodtoken/README.md
+++ b/apps/paymentmethodtoken/README.md
@@ -2,8 +2,10 @@
 
 ## Latest release
 
-The most recent release is [1.0.0](https://github.com/google/tink/releases/tag/v1.0.0),
-released 2017-09-08.
+The most recent release is
+[1.0.0](https://github.com/google/tink/releases/tag/v1.0.0), released
+2017-09-08. API docs can be found
+[here](https://google.github.com/tink/javadoc/apps-paymentmethodtoken/1.0.0).
 
 The Maven group ID is `com.google.crypto.tink`, and the artifact ID is
 `apps-paymentmethodtoken`.
@@ -20,8 +22,9 @@ To add a dependency using Maven:
 
 ## Snapshots
 
-Snapshots of this app built from the master branch are available through
-Maven using version `HEAD-SNAPSHOT`.
+Snapshots of this app built from the master branch are available through Maven
+using version `HEAD-SNAPSHOT`. API docs can be found
+[here](https://google.github.com/tink/javadoc/apps-paymentmethodtoken/HEAD-SNAPSHOT).
 
 To add a dependency using Maven:
 
diff --git a/apps/rewardedads/BUILD.bazel b/apps/rewardedads/BUILD.bazel
index 09610f701ccfe21d9fb48f7aeca2c639a19775dc..59a2cc67a0c12fd4276627e78365290780aed628 100644
--- a/apps/rewardedads/BUILD.bazel
+++ b/apps/rewardedads/BUILD.bazel
@@ -1,3 +1,64 @@
-package(default_visibility = ["//tools/build_defs:internal_pkg"])
+package(default_visibility = ["//visibility:public"])
 
 licenses(["notice"])  # Apache 2.0
+
+load("//tools/build_defs:javac.bzl", "JAVACOPTS")
+
+filegroup(
+    name = "srcs",
+    srcs = glob(
+        [
+            "src/main/**/*.java",
+        ],
+    ),
+)
+
+java_library(
+    name = "rewardedads",
+    srcs = [":srcs"],
+    javacopts = JAVACOPTS,
+    deps = [
+        "//java",
+        "@com_google_http_client",
+        "@org_json//jar",
+    ],
+)
+
+# Maven Jars
+
+load("//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
+
+gen_maven_jar_rules(
+    name = "maven",
+    doctitle = "Tink Cryptography API for Google Mobile Rewarded Video Ads SSV",
+    root_packages = ["com.google.crypto.tink.apps.rewardedads"],
+    deps = [":rewardedads"],
+)
+
+# Tests
+
+load("//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
+
+java_library(
+    name = "generator_test",
+    testonly = 1,
+    srcs = glob([
+        "src/test/**/*.java",
+    ]),
+    deps = [
+        ":java",
+        "//java:testonly",
+        "@com_google_http_client",
+        "@junit",
+        "@org_json//jar",
+    ],
+)
+
+gen_java_test_rules(
+    test_files = glob([
+        "src/test/**/*Test.java",
+    ]),
+    deps = [
+        ":generator_test",
+    ],
+)
diff --git a/apps/rewardedads/README.md b/apps/rewardedads/README.md
index 28dd7299b07d314645779dd402781e0f793cef50..0650c2f0a43163baf5ca459a1579bdbe4793d28d 100644
--- a/apps/rewardedads/README.md
+++ b/apps/rewardedads/README.md
@@ -1,15 +1,16 @@
 # An implementation of Google AdMob Rewarded Ads
 
-This app implements the verifier side of Server-Side Verification of
-Google AdMob Rewarded Ads.
+This app implements the verifier side of Server-Side Verification of Google
+AdMob Rewarded Ads.
 
 ## Snapshots
 
-This app has yet not been released, though you can still play with it
-using snapshot versions.
+This app has yet not been released, though you can still play with it using
+snapshot versions.
 
-Snapshots of this app built from the master branch are available through
-Maven using version `HEAD-SNAPSHOT`.
+Snapshots of this app built from the master branch are available through Maven
+using version `HEAD-SNAPSHOT`. API docs can be found
+[here](https://google.github.com/tink/javadoc/apps-rewardedads/HEAD-SNAPSHOT).
 
 To add a dependency using Maven:
 
diff --git a/apps/rewardedads/java/BUILD.bazel b/apps/rewardedads/java/BUILD.bazel
deleted file mode 100644
index 7f9376c9a150323d86618c9d29af344235857869..0000000000000000000000000000000000000000
--- a/apps/rewardedads/java/BUILD.bazel
+++ /dev/null
@@ -1,69 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-licenses(["notice"])  # Apache 2.0
-
-load("//tools/build_defs:javac.bzl", "JAVACOPTS")
-
-filegroup(
-    name = "srcs",
-    srcs = glob(
-        [
-            "src/main/**/*.java",
-        ],
-    ),
-)
-
-java_library(
-    name = "java",
-    srcs = [":srcs"],
-    javacopts = JAVACOPTS,
-    deps = [
-        "//java",
-        "@com_google_http_client",
-        "@org_json//jar",
-    ],
-)
-
-# Maven Jars
-
-load("//tools:javadoc.bzl", "javadoc_library")
-
-javadoc_library(
-    name = "librewardedads-javadoc",
-    srcs = [":srcs"],
-    doctitle = "Tink Cryptography API for Google Mobile Rewarded Video Ads SSV",
-    root_packages = [
-        "com.google.crypto.tink.apps.rewardedads",
-    ],
-    deps = [
-        ":java"
-    ],
-)
-
-# Tests
-
-load("//tools:gen_java_test_rules.bzl", "gen_java_test_rules")
-
-java_library(
-    name = "generator_test",
-    testonly = 1,
-    srcs = glob([
-        "src/test/**/*.java",
-    ]),
-    deps = [
-        ":java",
-        "//java:testonly",
-        "@com_google_http_client",
-        "@junit",
-        "@org_json//jar",
-    ],
-)
-
-gen_java_test_rules(
-    test_files = glob([
-        "src/test/**/*Test.java",
-    ]),
-    deps = [
-        ":generator_test",
-    ],
-)
diff --git a/apps/rewardedads/java/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java b/apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java
similarity index 100%
rename from apps/rewardedads/java/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java
rename to apps/rewardedads/src/main/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifier.java
diff --git a/apps/rewardedads/java/src/test/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifierTest.java b/apps/rewardedads/src/test/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifierTest.java
similarity index 100%
rename from apps/rewardedads/java/src/test/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifierTest.java
rename to apps/rewardedads/src/test/java/com/google/crypto/tink/apps/rewardedads/RewardedAdsVerifierTest.java
diff --git a/doc/JAVA-HOWTO.md b/doc/JAVA-HOWTO.md
index 36b2118786ddf37749cfcf17b45735d055d2d656..a7ded766048880c60dbdb452e3f02b2a1bce99d9 100644
--- a/doc/JAVA-HOWTO.md
+++ b/doc/JAVA-HOWTO.md
@@ -13,6 +13,10 @@ Tink for Java comes in two flavors:
 Tink can be installed with Maven or Gradle. The Maven group ID is
 `com.google.crypto.tink`, and the artifact ID is `tink`.
 
+The most recent release is
+[1.0.0](https://github.com/google/tink/releases/tag/v1.0.0), released
+2017-09-08.
+
 To add a dependency using Maven:
 
 ```xml
@@ -82,6 +86,15 @@ dependencies {
 }
 ```
 
+## API docs
+
+*   Java:
+    *   [1.0.0](https://google.github.com/tink/javadoc/tink/1.0.0)
+    *   [HEAD-SNAPSHOT](https://google.github.com/tink/javadoc/tink/HEAD-SNAPSHOT)
+*   Android:
+    *   [1.0.0](https://google.github.com/tink/javadoc/tink-android/1.0.0)
+    *   [HEAD-SNAPSHOT](https://google.github.com/tink/javadoc/tink-android/HEAD-SNAPSHOT)
+
 ## Important Warnings
 
 Do not use APIs including fields and methods marked with the `@Alpha` annotation.
diff --git a/java/BUILD.bazel b/java/BUILD.bazel
index 5a0aeb61c415ea2304dc1ea1acb8ed58e8ce120a..0b9a55d6d8d380bb5632dc70e935cf38abbb6442 100644
--- a/java/BUILD.bazel
+++ b/java/BUILD.bazel
@@ -2,64 +2,7 @@ package(default_visibility = ["//tools/build_defs:internal_pkg"])
 
 licenses(["notice"])  # Apache 2.0
 
-# PUBLIC
-
-java_library(
-    name = "java",
-    visibility = ["//visibility:public"],
-    exports = [
-        ":subtle",
-        "//java/src/main/java/com/google/crypto/tink",
-        "//java/src/main/java/com/google/crypto/tink/aead",
-        "//java/src/main/java/com/google/crypto/tink/config",
-        "//java/src/main/java/com/google/crypto/tink/daead",
-        "//java/src/main/java/com/google/crypto/tink/hybrid",
-        "//java/src/main/java/com/google/crypto/tink/integration/awskms",
-        "//java/src/main/java/com/google/crypto/tink/integration/gcpkms",
-        "//java/src/main/java/com/google/crypto/tink/mac",
-        "//java/src/main/java/com/google/crypto/tink/signature",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead",
-        "//java/src/main/java/com/google/crypto/tink/util",
-    ],
-)
-
-# like :java, but for Android
-android_library(
-    name = "android",
-    visibility = ["//visibility:public"],
-    exports = [
-        ":subtle",
-        "//java/src/main/java/com/google/crypto/tink:android",
-        "//java/src/main/java/com/google/crypto/tink/aead:android",
-        "//java/src/main/java/com/google/crypto/tink/config:android",
-        "//java/src/main/java/com/google/crypto/tink/daead:android",
-        "//java/src/main/java/com/google/crypto/tink/hybrid:android",
-        "//java/src/main/java/com/google/crypto/tink/integration/android",
-        "//java/src/main/java/com/google/crypto/tink/mac:android",
-        "//java/src/main/java/com/google/crypto/tink/signature:android",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead:android",
-    ],
-)
-
-java_library(
-    name = "subtle",
-    visibility = ["//visibility:public"],
-    exports = [
-        "//java/src/main/java/com/google/crypto/tink:primitives",
-        "//java/src/main/java/com/google/crypto/tink/subtle",
-        "//java/src/main/java/com/google/crypto/tink/subtle:aead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:daead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:hybrid",
-        "//java/src/main/java/com/google/crypto/tink/subtle:mac",
-        "//java/src/main/java/com/google/crypto/tink/subtle:signature",
-        "//java/src/main/java/com/google/crypto/tink/subtle:streaming",
-        "//java/src/main/java/com/google/crypto/tink/subtle:x25519",
-    ],
-)
-
-# RESTRICTED
-
-full_protos = [
+full_proto_deps = [
     "//proto:aes_ctr_hmac_aead_java_proto",
     "//proto:aes_ctr_hmac_streaming_java_proto",
     "//proto:aes_ctr_java_proto",
@@ -79,7 +22,7 @@ full_protos = [
     "//proto:tink_java_proto",
 ]
 
-lite_protos = [
+lite_proto_deps = [
     "//proto:aes_ctr_hmac_aead_java_proto_lite",
     "//proto:aes_ctr_hmac_streaming_java_proto_lite",
     "//proto:aes_ctr_java_proto_lite",
@@ -99,192 +42,109 @@ lite_protos = [
     "//proto:tink_java_proto_lite",
 ]
 
+subtle_deps = [
+    "//java/src/main/java/com/google/crypto/tink:primitives",
+    "//java/src/main/java/com/google/crypto/tink/subtle",
+    "//java/src/main/java/com/google/crypto/tink/subtle:aead",
+    "//java/src/main/java/com/google/crypto/tink/subtle:daead",
+    "//java/src/main/java/com/google/crypto/tink/subtle:hybrid",
+    "//java/src/main/java/com/google/crypto/tink/subtle:mac",
+    "//java/src/main/java/com/google/crypto/tink/subtle:signature",
+    "//java/src/main/java/com/google/crypto/tink/subtle:streaming",
+    "//java/src/main/java/com/google/crypto/tink/subtle:x25519",
+]
+
+java_deps = subtle_deps + [
+    "//java/src/main/java/com/google/crypto/tink",
+    "//java/src/main/java/com/google/crypto/tink/aead",
+    "//java/src/main/java/com/google/crypto/tink/config",
+    "//java/src/main/java/com/google/crypto/tink/daead",
+    "//java/src/main/java/com/google/crypto/tink/hybrid",
+    "//java/src/main/java/com/google/crypto/tink/integration/awskms",
+    "//java/src/main/java/com/google/crypto/tink/integration/gcpkms",
+    "//java/src/main/java/com/google/crypto/tink/mac",
+    "//java/src/main/java/com/google/crypto/tink/signature",
+    "//java/src/main/java/com/google/crypto/tink/streamingaead",
+    "//java/src/main/java/com/google/crypto/tink/util",
+]
+
+android_deps = subtle_deps + [
+    "//java/src/main/java/com/google/crypto/tink:android",
+    "//java/src/main/java/com/google/crypto/tink/aead:android",
+    "//java/src/main/java/com/google/crypto/tink/config:android",
+    "//java/src/main/java/com/google/crypto/tink/daead:android",
+    "//java/src/main/java/com/google/crypto/tink/hybrid:android",
+    "//java/src/main/java/com/google/crypto/tink/integration/android",
+    "//java/src/main/java/com/google/crypto/tink/mac:android",
+    "//java/src/main/java/com/google/crypto/tink/signature:android",
+    "//java/src/main/java/com/google/crypto/tink/streamingaead:android",
+]
+
+cleartext_deps = [
+    "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
+]
+
+cleartext_android_deps = [
+    "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
+]
+
+# PUBLIC
+
+java_library(
+    name = "java",
+    visibility = ["//visibility:public"],
+    exports = java_deps,
+)
+
+# like :java, but for Android
+android_library(
+    name = "android",
+    visibility = ["//visibility:public"],
+    exports = android_deps,
+)
+
+java_library(
+    name = "subtle",
+    visibility = ["//visibility:public"],
+    exports = subtle_deps,
+)
+
+# RESTRICTED
+
 java_library(
     name = "protos",
-    exports = full_protos,
+    exports = full_proto_deps,
 )
 
 java_library(
     name = "protos_android",
-    exports = lite_protos,
+    exports = lite_proto_deps,
 )
 
 java_library(
     name = "cleartext_keyset_handle",
-    exports = [
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
-    ],
+    exports = cleartext_deps
 )
 
 java_library(
     name = "cleartext_keyset_handle_android",
-    exports = [
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
-    ],
+    exports = cleartext_android_deps
 )
 
 # Maven jars
 
-load("//tools:jarjar.bzl", "jarjar_library")
-load("//tools:javadoc.bzl", "javadoc_library")
+load("//tools:gen_maven_jar_rules.bzl", "gen_maven_jar_rules")
 
-jarjar_library(
-    name = "libtink",
-    rules_file = "//tools:merge_all_rules.txt",
-    deps = full_protos + [
-        "//java/src/main/java/com/google/crypto/tink/subtle",
-        "//java/src/main/java/com/google/crypto/tink/subtle:aead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:daead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:hybrid",
-        "//java/src/main/java/com/google/crypto/tink/subtle:mac",
-        "//java/src/main/java/com/google/crypto/tink/subtle:signature",
-        "//java/src/main/java/com/google/crypto/tink/subtle:streaming",
-        "//java/src/main/java/com/google/crypto/tink/subtle:x25519",
-        "//java/src/main/java/com/google/crypto/tink",
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
-        "//java/src/main/java/com/google/crypto/tink/aead",
-        "//java/src/main/java/com/google/crypto/tink/config",
-        "//java/src/main/java/com/google/crypto/tink/daead",
-        "//java/src/main/java/com/google/crypto/tink/hybrid",
-        "//java/src/main/java/com/google/crypto/tink/integration/awskms",
-        "//java/src/main/java/com/google/crypto/tink/integration/gcpkms",
-        "//java/src/main/java/com/google/crypto/tink/mac",
-        "//java/src/main/java/com/google/crypto/tink/signature",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead",
-        "//java/src/main/java/com/google/crypto/tink/util",
-    ],
-)
-
-javadoc_library(
-    name = "libtink-javadoc",
-    srcs = [
-        "//java/src/main/java/com/google/crypto/tink:srcs",
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_srcs",
-        "//java/src/main/java/com/google/crypto/tink/aead:srcs",
-        "//java/src/main/java/com/google/crypto/tink/config:srcs",
-        "//java/src/main/java/com/google/crypto/tink/daead:srcs",
-        "//java/src/main/java/com/google/crypto/tink/hybrid:srcs",
-        "//java/src/main/java/com/google/crypto/tink/integration/awskms:srcs",
-        "//java/src/main/java/com/google/crypto/tink/integration/gcpkms:srcs",
-        "//java/src/main/java/com/google/crypto/tink/mac:srcs",
-        "//java/src/main/java/com/google/crypto/tink/signature:srcs",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead:srcs",
-        "//java/src/main/java/com/google/crypto/tink/subtle:srcs",
-        "//java/src/main/java/com/google/crypto/tink/util:srcs",
-    ],
+gen_maven_jar_rules(
+    name = "maven",
+    deps = full_proto_deps + java_deps + cleartext_deps,
     doctitle = "Tink Cryptography API",
-    root_packages = [
-        "com.google.crypto.tink",
-        "com.google.crypto.tink.aead",
-        "com.google.crypto.tink.config",
-        "com.google.crypto.tink.dead",
-        "com.google.crypto.tink.hybrid",
-        "com.google.crypto.tink.integration.awskms",
-        "com.google.crypto.tink.integration.gcpkms",
-        "com.google.crypto.tink.mac",
-        "com.google.crypto.tink.signature",
-        "com.google.crypto.tink.subtle",
-        "com.google.crypto.tink.streamingaead",
-        "com.google.crypto.tink.util",
-    ],
-    deps = [
-        "//java/src/main/java/com/google/crypto/tink/subtle",
-        "//java/src/main/java/com/google/crypto/tink/subtle:aead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:daead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:hybrid",
-        "//java/src/main/java/com/google/crypto/tink/subtle:mac",
-        "//java/src/main/java/com/google/crypto/tink/subtle:signature",
-        "//java/src/main/java/com/google/crypto/tink/subtle:streaming",
-        "//java/src/main/java/com/google/crypto/tink/subtle:x25519",
-        "//java/src/main/java/com/google/crypto/tink",
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle",
-        "//java/src/main/java/com/google/crypto/tink/aead",
-        "//java/src/main/java/com/google/crypto/tink/config",
-        "//java/src/main/java/com/google/crypto/tink/daead",
-        "//java/src/main/java/com/google/crypto/tink/hybrid",
-        "//java/src/main/java/com/google/crypto/tink/integration/awskms",
-        "//java/src/main/java/com/google/crypto/tink/integration/gcpkms",
-        "//java/src/main/java/com/google/crypto/tink/mac",
-        "//java/src/main/java/com/google/crypto/tink/signature",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead",
-        "//java/src/main/java/com/google/crypto/tink/util",
-    ],
 )
 
-jarjar_library(
-    name = "libtink-android",
-    rules_file = "//tools:merge_all_rules.txt",
-    deps = lite_protos + [
-        "//java/src/main/java/com/google/crypto/tink/subtle",
-        "//java/src/main/java/com/google/crypto/tink/subtle:aead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:daead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:hybrid",
-        "//java/src/main/java/com/google/crypto/tink/subtle:mac",
-        "//java/src/main/java/com/google/crypto/tink/subtle:signature",
-        "//java/src/main/java/com/google/crypto/tink/subtle:streaming",
-        "//java/src/main/java/com/google/crypto/tink/subtle:x25519",
-        "//java/src/main/java/com/google/crypto/tink:android",
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
-        "//java/src/main/java/com/google/crypto/tink/aead:android",
-        "//java/src/main/java/com/google/crypto/tink/config:android",
-        "//java/src/main/java/com/google/crypto/tink/daead:android",
-        "//java/src/main/java/com/google/crypto/tink/hybrid:android",
-        "//java/src/main/java/com/google/crypto/tink/integration/android",
-        "//java/src/main/java/com/google/crypto/tink/mac:android",
-        "//java/src/main/java/com/google/crypto/tink/signature:android",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead:android",
-    ],
-)
-
-javadoc_library(
-    name = "libtink-android-javadoc",
-    srcs = [
-        "//java/src/main/java/com/google/crypto/tink:srcs",
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_srcs",
-        "//java/src/main/java/com/google/crypto/tink/aead:srcs",
-        "//java/src/main/java/com/google/crypto/tink/config:srcs",
-        "//java/src/main/java/com/google/crypto/tink/daead:srcs",
-        "//java/src/main/java/com/google/crypto/tink/hybrid:srcs",
-        "//java/src/main/java/com/google/crypto/tink/integration/android:srcs",
-        "//java/src/main/java/com/google/crypto/tink/mac:srcs",
-        "//java/src/main/java/com/google/crypto/tink/signature:srcs",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead:srcs",
-        "//java/src/main/java/com/google/crypto/tink/subtle:srcs",
-    ],
+gen_maven_jar_rules(
+    name = "maven-android",
+    deps = lite_proto_deps + android_deps + cleartext_android_deps,
     doctitle = "Tink Cryptography API for Android",
-    root_packages = [
-        "com.google.crypto.tink",
-        "com.google.crypto.tink.aead",
-        "com.google.crypto.tink.config",
-        "com.google.crypto.tink.dead",
-        "com.google.crypto.tink.hybrid",
-        "com.google.crypto.tink.integration.android",
-        "com.google.crypto.tink.mac",
-        "com.google.crypto.tink.signature",
-        "com.google.crypto.tink.subtle",
-        "com.google.crypto.tink.streamingaead",
-    ],
-    android_api_level = 23,
-    deps = lite_protos + [
-        "//java/src/main/java/com/google/crypto/tink/subtle",
-        "//java/src/main/java/com/google/crypto/tink/subtle:aead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:daead",
-        "//java/src/main/java/com/google/crypto/tink/subtle:hybrid",
-        "//java/src/main/java/com/google/crypto/tink/subtle:mac",
-        "//java/src/main/java/com/google/crypto/tink/subtle:signature",
-        "//java/src/main/java/com/google/crypto/tink/subtle:streaming",
-        "//java/src/main/java/com/google/crypto/tink/subtle:x25519",
-        "//java/src/main/java/com/google/crypto/tink:android",
-        "//java/src/main/java/com/google/crypto/tink:cleartext_keyset_handle_android",
-        "//java/src/main/java/com/google/crypto/tink/aead:android",
-        "//java/src/main/java/com/google/crypto/tink/config:android",
-        "//java/src/main/java/com/google/crypto/tink/daead:android",
-        "//java/src/main/java/com/google/crypto/tink/hybrid:android",
-        "//java/src/main/java/com/google/crypto/tink/integration/android",
-        "//java/src/main/java/com/google/crypto/tink/mac:android",
-        "//java/src/main/java/com/google/crypto/tink/signature:android",
-        "//java/src/main/java/com/google/crypto/tink/streamingaead:android",
-    ],
 )
 
 # TEST
diff --git a/maven/README.md b/maven/README.md
index 8e80d5fa594983e8f49a49d0060fdb60de351c54..4d6e12abe4885fec04b35515654a005280e89553 100644
--- a/maven/README.md
+++ b/maven/README.md
@@ -4,5 +4,8 @@
 ./maven/publish-snapshot.sh
 ```
 
+This command publishes latest snapshots to Maven, and their Javadocs to
+https://google.github.com/tink.
+
 Snapshots are also automatically published for every new commit to
 the master branch of https://github.com/google/tink.
diff --git a/maven/execute-deploy.sh b/maven/execute-deploy.sh
index 5ffb7841742f3c5b2966c038d1b326af1a9d6e69..9682b587c8daaf5679e921b947665edcee2fb0a7 100755
--- a/maven/execute-deploy.sh
+++ b/maven/execute-deploy.sh
@@ -1,7 +1,3 @@
-#!/bin/sh
-
-# Copyright 2017 Google Inc.
-#
 # 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
@@ -13,7 +9,9 @@
 # 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.
-####################################################################################
+################################################################################
+
+#!/bin/sh
 
 # Fail on any error.
 set -e
@@ -32,6 +30,9 @@ then
   exit 1
 fi
 
+git config --global user.email "noreply@google.com"
+git config --global user.name "Tink Team"
+
 library_output_file() {
   library=$1
   library_output=bazel-bin/$library
@@ -46,10 +47,12 @@ library_output_file() {
 }
 
 deploy_library() {
-  library=$1
-  javadoc=$2
-  pomfile=$3
-  bazel build $library $javadoc
+  library_name=$1
+  library=$2
+  srcjar=$3
+  javadoc=$4
+  pomfile=$5
+  bazel build $library $srcjar $javadoc
 
   # Update the version
   sed -i \
@@ -58,6 +61,7 @@ deploy_library() {
 
   mvn $MVN_GOAL \
     -Dfile=$(library_output_file $library) \
+    -Dsources=$(library_output_file $srcjar) \
     -Djavadoc=$(library_output_file $javadoc) \
     -DpomFile=$pomfile \
     "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
@@ -66,24 +70,67 @@ deploy_library() {
   sed -i \
     's/'"$VERSION"'/VERSION_PLACEHOLDER/' \
     $pomfile
+
+  publish_javadoc_to_github_pages $library_name $javadoc
+}
+
+publish_javadoc_to_github_pages() {
+  library_name=$1
+  javadoc=$(library_output_file $2)
+
+  git_url=git@github.com:google/tink.git
+  if [ -n $KOKORO_ROOT ]; then
+    git_url=https://github.com/google/tink.git
+  fi
+
+  rm -rf gh-pages
+  git clone --quiet --branch=gh-pages $git_url gh-pages > /dev/null
+
+  cd gh-pages
+  if [ -d javadoc/$library_name/$VERSION ]; then
+    git rm -rf javadoc/$library_name/$VERSION
+  fi
+  mkdir -p javadoc/$library_name/$VERSION
+
+  unzip ../$javadoc -d javadoc/$library_name/$VERSION
+  rm -rf javadoc/$library_name/$VERSION/META-INF/
+  git add -f javadoc/$library_name/$VERSION
+  if [[ `git status --porcelain` ]]; then
+    # Changes
+    git commit -m "${library_name}-${VERSION} Javadoc auto-pushed to gh-pages"
+    git push -fq origin gh-pages > /dev/null
+    echo -e "Published Javadoc to gh-pages.\n"
+  else
+    # No changes
+    echo -e "No changes in ${library_name}-${VERSION} Javadoc.\n"
+  fi
+  cd ..
 }
 
 deploy_library \
-  java/libtink.jar \
-  java/libtink-javadoc.jar \
+  tink \
+  java/maven.jar \
+  java/maven-src.jar \
+  java/maven-javadoc.jar \
   $(dirname $0)/tink.pom.xml
 
 deploy_library \
-  java/libtink-android.jar \
-  java/libtink-android-javadoc.jar \
+  tink-android \
+  java/maven-android.jar \
+  java/maven-android-src.jar \
+  java/maven-android-javadoc.jar \
   $(dirname $0)/tink-android.pom.xml
 
 deploy_library \
-  apps/paymentmethodtoken/libpaymentmethodtoken.jar \
-  apps/paymentmethodtoken/libpaymentmethodtoken-javadoc.jar \
+  apps-paymentmethodtoken \
+  apps/paymentmethodtoken/maven.jar \
+  apps/paymentmethodtoken/maven-src.jar \
+  apps/paymentmethodtoken/maven-javadoc.jar \
   $(dirname $0)/apps-paymentmethodtoken.pom.xml
 
 deploy_library \
-  apps/rewardedads/java/libjava.jar \
-  apps/rewardedads/java/librewardedads-javadoc.jar \
+  apps-rewardedads \
+  apps/rewardedads/maven.jar \
+  apps/rewardedads/maven-src.jar \
+  apps/rewardedads/maven-javadoc.jar \
   $(dirname $0)/apps-rewardedads.pom.xml
diff --git a/maven/publish-snapshot.sh b/maven/publish-snapshot.sh
index fff0d64f4a567bfceee4f07f04b71d0da5207a35..3cc951086b91ecf5c6836f0ce3ac66cd9d1c1e18 100755
--- a/maven/publish-snapshot.sh
+++ b/maven/publish-snapshot.sh
@@ -31,7 +31,3 @@ bash $(dirname $0)/execute-deploy.sh \
   --settings=$(dirname $0)/settings.xml
 
 echo -e "Published Maven snapshot"
-
-echo -e "Testing new Maven snapshot"
-
-mvn compile -DpomFile=examples/helloworld/java/pom.xml
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
index 3eba93942f170c5a0c0e1b4b30ac77f79da83e90..09610f701ccfe21d9fb48f7aeca2c639a19775dc 100644
--- a/tools/BUILD.bazel
+++ b/tools/BUILD.bazel
@@ -1,34 +1,3 @@
 package(default_visibility = ["//tools/build_defs:internal_pkg"])
 
 licenses(["notice"])  # Apache 2.0
-
-exports_files(["merge_all_rules.txt"])
-
-sh_binary(
-    name = "jarjar_library_impl",
-    srcs = ["jarjar_library_impl.sh"],
-)
-
-java_binary(
-    name = "jarjar",
-    main_class = "org.pantsbuild.jarjar.Main",
-    runtime_deps = [
-        "@javax_annotation_jsr250_api//jar",
-        "@javax_enterprise_cdi_api//jar",
-        "@javax_inject_javax_inject//jar",
-        "@org_apache_ant_ant//jar",
-        "@org_apache_ant_ant_launcher//jar",
-        "@org_apache_maven_maven_artifact//jar",
-        "@org_apache_maven_maven_model//jar",
-        "@org_apache_maven_maven_plugin_api//jar",
-        "@org_codehaus_plexus_plexus_classworlds//jar",
-        "@org_codehaus_plexus_plexus_component_annotations//jar",
-        "@org_codehaus_plexus_plexus_utils//jar",
-        "@org_eclipse_sisu_org_eclipse_sisu_inject//jar",
-        "@org_eclipse_sisu_org_eclipse_sisu_plexus//jar",
-        "@org_ow2_asm_asm//jar",
-        "@org_ow2_asm_asm_commons//jar",
-        "@org_ow2_asm_asm_tree//jar",
-        "@org_pantsbuild_jarjar//jar",
-    ],
-)
diff --git a/tools/gen_maven_jar_rules.bzl b/tools/gen_maven_jar_rules.bzl
new file mode 100644
index 0000000000000000000000000000000000000000..776830f5b584d3f1c775195f7d2122687c5bdb96
--- /dev/null
+++ b/tools/gen_maven_jar_rules.bzl
@@ -0,0 +1,70 @@
+# 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.
+
+""" Definition of gen_maven_jar_rules. """
+
+load("//tools:java_single_jar.bzl", "java_single_jar")
+load("//tools:javadoc.bzl", "javadoc_library")
+
+_EXTERNAL_JAVADOC_LINKS = [
+    "https://docs.oracle.com/javase/7/docs/api/",
+    "https://developer.android.com/reference/",
+]
+
+_TINK_PACKAGES  = [
+    "com.google.crypto.tink",
+]
+
+def gen_maven_jar_rules(name,
+                        deps=[],
+                        root_packages=_TINK_PACKAGES,
+                        exclude_packages=[],
+                        doctitle="",
+                        android_api_level=23,
+                        bottom_text="",
+                        external_javadoc_links=_EXTERNAL_JAVADOC_LINKS):
+  """
+  Generates rules that generate Maven jars for a given package.
+
+  Args:
+    name: Given a name, this function generates 3 rules: a compiled package
+      name.jar, a source package name-src.jar and a Javadoc package
+      name-javadoc.jar.
+    deps: A combination of the deps of java_single_jar and javadoc_library
+    root_packages: See javadoc_library
+    exclude_packages: See javadoc_library
+    doctitle: See javadoc_library
+    android_api_level: See javadoc_library
+    bottom_text: See javadoc_library
+    external_javadoc_links: See javadoc_library
+  """
+
+  java_single_jar(name=name,
+                  deps=deps,
+                  root_packages=root_packages)
+
+  source_jar_name = name+"-src"
+  java_single_jar(name=source_jar_name,
+                  deps=deps,
+                  root_packages=root_packages,
+                  source_jar=True)
+
+  javadoc_name = name+"-javadoc"
+  javadoc_library(name=javadoc_name,
+                  deps=deps,
+                  root_packages=root_packages,
+                  srcs=[":%s" % source_jar_name],
+                  doctitle=doctitle,
+                  exclude_packages=exclude_packages,
+                  android_api_level=android_api_level,
+                  bottom_text=bottom_text,
+                  external_javadoc_links=external_javadoc_links)
diff --git a/tools/jarjar.bzl b/tools/jarjar.bzl
deleted file mode 100644
index 2fc59bc317bfc62df817a371f91f0df792f3cbde..0000000000000000000000000000000000000000
--- a/tools/jarjar.bzl
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# 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.
-
-"""Combine a bunch of jars into one single jar.
-
-"""
-
-def jarjar_deps():
-  """
-  Deps that are necessary to build jarjar_binary().
-
-  These deps aren't used in the regular build process for Tink, so they are
-  organized separately from the workspace file.
-  """
-
-  native.maven_jar(
-      name = "org_codehaus_plexus_plexus_utils",
-      artifact = "org.codehaus.plexus:plexus-utils:3.0.20",
-      sha1 = "e121ed37af8ee3928952f6d8a303de24e019aab0",
-  )
-
-  native.maven_jar(
-      name = "org_eclipse_sisu_org_eclipse_sisu_plexus",
-      artifact = "org.eclipse.sisu:org.eclipse.sisu.plexus:0.3.0",
-      sha1 = "3f53953a998d03b9b0f7d5098f63119e434af0ef",
-  )
-
-  native.maven_jar(
-      name = "org_apache_ant_ant_launcher",
-      artifact = "org.apache.ant:ant-launcher:1.9.6",
-      sha1 = "d75dd4c39ba06401f20e7afffb861d268baec6bc",
-  )
-
-  native.maven_jar(
-      name = "org_apache_maven_maven_plugin_api",
-      artifact = "org.apache.maven:maven-plugin-api:3.3.3",
-      sha1 = "3b78a7e40707be313c4d5449ba514c9747e1c731",
-  )
-
-  native.maven_jar(
-      name = "org_eclipse_sisu_org_eclipse_sisu_inject",
-      artifact = "org.eclipse.sisu:org.eclipse.sisu.inject:0.3.0",
-      sha1 = "6c25adce9ca9af097728ed57834e8807e3b6e2b5",
-  )
-
-  native.maven_jar(
-      name = "org_ow2_asm_asm",
-      artifact = "org.ow2.asm:asm:5.0.4",
-      sha1 = "0da08b8cce7bbf903602a25a3a163ae252435795",
-  )
-
-  native.maven_jar(
-      name = "org_ow2_asm_asm_tree",
-      artifact = "org.ow2.asm:asm-tree:5.0.4",
-      sha1 = "396ce0c07ba2b481f25a70195c7c94922f0d1b0b",
-  )
-
-  native.maven_jar(
-      name = "javax_annotation_jsr250_api",
-      artifact = "javax.annotation:jsr250-api:1.0",
-      sha1 = "5025422767732a1ab45d93abfea846513d742dcf",
-  )
-
-  native.maven_jar(
-      name = "javax_inject_javax_inject",
-      artifact = "javax.inject:javax.inject:1",
-      sha1 = "6975da39a7040257bd51d21a231b76c915872d38",
-  )
-
-  native.maven_jar(
-      name = "javax_enterprise_cdi_api",
-      artifact = "javax.enterprise:cdi-api:1.0",
-      sha1 = "44c453f60909dfc223552ace63e05c694215156b",
-  )
-
-  native.maven_jar(
-      name = "org_ow2_asm_asm_commons",
-      artifact = "org.ow2.asm:asm-commons:5.0.4",
-      sha1 = "5a556786086c23cd689a0328f8519db93821c04c",
-  )
-
-  native.maven_jar(
-      name = "org_apache_maven_maven_model",
-      artifact = "org.apache.maven:maven-model:3.3.3",
-      sha1 = "73ba535c2e3a1381aeab131598010b3a723d4b47",
-  )
-
-  native.maven_jar(
-      name = "org_apache_maven_maven_artifact",
-      artifact = "org.apache.maven:maven-artifact:3.3.3",
-      sha1 = "d9f439dfef726e54eebb390ff38dd27356901528",
-  )
-
-  native.maven_jar(
-      name = "org_pantsbuild_jarjar",
-      artifact = "org.pantsbuild:jarjar:1.6.3",
-      sha1 = "cf54d4b142f5409c394095181c8d308a81869622",
-  )
-
-  native.maven_jar(
-      name = "org_codehaus_plexus_plexus_classworlds",
-      artifact = "org.codehaus.plexus:plexus-classworlds:2.5.2",
-      sha1 = "4abb111bfdace5b8167db4c0ef74644f3f88f142",
-  )
-
-  native.maven_jar(
-      name = "org_apache_ant_ant",
-      artifact = "org.apache.ant:ant:1.9.6",
-      sha1 = "80e2063b01bab3c79c2d84e4ed5e73868394c85a",
-  )
-
-  native.maven_jar(
-      name = "org_codehaus_plexus_plexus_component_annotations",
-      artifact = "org.codehaus.plexus:plexus-component-annotations:1.5.5",
-      sha1 = "c72f2660d0cbed24246ddb55d7fdc4f7374d2078",
-  )
-
-def jarjar_library(name, deps, rules_file):
-  """
-  Combines `deps` into `name`.jar with the rules specified in `rules_file`.
-
-  See: https://github.com/pantsbuild/jarjar.
-
-  Args:
-    name: the output jar
-    deps: the input jars
-    rules_file: the jarjar rules
-
-  """
-  native.genrule(
-      name = name,
-      srcs = deps + [
-          rules_file,
-          "//tools:jarjar_deploy.jar",
-      ],
-      tools = [
-          "//tools:jarjar_library_impl",
-          "@local_jdk//:bin/jar",
-          "@local_jdk//:bin/java",
-          "@local_jdk//:jre",
-      ],
-      outs = [name + ".jar"],
-      cmd = """
-      export JAVA_HOME=$(JAVABASE)
-      $(location //tools:jarjar_library_impl) $@ "{deps}" {rules} \
-        $(location //tools:jarjar_deploy.jar) \
-        $$(readlink $(location @local_jdk//:bin/jar)) \
-        $$(readlink $(location @local_jdk//:bin/java)) \
-        $(@D)
-      """.format(
-          deps=" ".join(["$(locations %s)" % dep for dep in deps]),
-          rules="$(location %s)" % rules_file),
-      toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"],
-  )
diff --git a/tools/jarjar_library_impl.sh b/tools/jarjar_library_impl.sh
deleted file mode 100755
index 26dfeb4bf749c64bfa29b1a436b3f8dfdc99992e..0000000000000000000000000000000000000000
--- a/tools/jarjar_library_impl.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# 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.
-
-if [[ ! $JAVA_HOME =~ ^/ ]]; then
-  JAVA_HOME=$(readlink -f $JAVA_HOME)
-fi
-
-OUT=$1
-DEPS=$2
-RULES_FILE=$3
-JARJAR=$4
-JAR_BINARY=$5
-JAVA_BINARY=$6
-TMPDIR=$7/combined
-
-mkdir -p $TMPDIR
-for dep in $DEPS; do
-  unzip -qq -B $dep -d $TMPDIR
-done
-pushd $TMPDIR &>/dev/null
-
-# Concatenate similar files in META-INF/services
-for file in META-INF/services/*; do
-  original=$(echo $file | sed s/"~[0-9]*$"//)
-  if [[ "$file" != "$original" ]]; then
-    cat $file >> $original
-    rm $file
-  fi
-done
-
-rm META-INF/MANIFEST.MF*
-rm -rf META-INF/maven/
-
-duplicate_files=$(find * -type f -regex ".*~[0-9]*$")
-for file in $duplicate_files; do
-  rm $file;
-done
-
-java_files=$(find * -type f -name "*.java")
-for file in $java_files; do
-  rm $file;
-done
-
-$JAR_BINARY cf combined.jar *
-
-popd &>/dev/null
-
-$JAVA_BINARY -jar $JARJAR process $RULES_FILE $TMPDIR/combined.jar $OUT
-rm -rf $TMPDIR
diff --git a/tools/java_single_jar.bzl b/tools/java_single_jar.bzl
new file mode 100644
index 0000000000000000000000000000000000000000..ebfbd79a3ec49de90e49e38e73c7554c83a51e30
--- /dev/null
+++ b/tools/java_single_jar.bzl
@@ -0,0 +1,109 @@
+# 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.
+
+""" Definition of java_single_jar. """
+
+def _check_non_empty(value, name):
+  if not value:
+    fail("%s must be non-empty" % name)
+
+def _java_single_jar(ctx):
+  _check_non_empty(ctx.attr.root_packages, "root_packages")
+
+  inputs = depset()
+  source_jars = depset()
+  for dep in ctx.attr.deps:
+    inputs = depset(transitive=[inputs, dep.java.transitive_runtime_deps])
+    source_jars = depset(transitive=[source_jars, dep.java.source_jars])
+    for td in dep.java.transitive_runtime_deps:
+      if hasattr(td, "java"):
+        source_jars = depset(transitive=[source_jars, td.java.source_jars])
+
+  compress = ""
+  if ctx.attr.compress == "preserve":
+    compress = "--dont_change_compression"
+  elif ctx.attr.compress == "yes":
+    compress = "--compression"
+  elif ctx.attr.compress == "no":
+    pass
+  else:
+    fail("\"compress\" attribute (%s) must be: yes, no, preserve." % ctx.attr.compress)
+
+  if ctx.attr.source_jar:
+    inputs = source_jars
+    compress = ""
+
+  args = ctx.actions.args()
+  args.add("--sources")
+  args.add(inputs)
+  args.use_param_file(
+      "@%s",
+      use_always=True,
+  )
+  args.set_param_file_format("multiline")
+
+  include_prefixes = " ".join([x.replace(".", "/") for x in ctx.attr.root_packages])
+
+  ctx.actions.run(
+      inputs=inputs,
+      outputs=[ctx.outputs.jar],
+      arguments=[
+          args,
+          "--output", ctx.outputs.jar.path,
+          "--include_prefixes", include_prefixes,
+          "--normalize",
+      ]
+      # Deal with limitation of singlejar flags: tool's default behavior is
+      # "no", but you get that behavior only by absence of compression flags.
+      + ([] if not compress else [compress]),
+      progress_message="Merging into %s" % ctx.outputs.jar.short_path,
+      mnemonic="JavaSingleJar",
+      executable=ctx.executable._singlejar,
+  )
+
+java_single_jar = rule(
+    attrs = {
+        "deps": attr.label_list(providers = ["java"]),
+        "_singlejar": attr.label(
+            default = Label("@bazel_tools//tools/jdk:singlejar"),
+            cfg="host",
+            allow_single_file = True,
+            executable = True,
+        ),
+        "source_jar": attr.bool(default=False),
+        "compress": attr.string(default="preserve"),
+        "root_packages": attr.string_list(),
+    },
+    outputs = {
+        "jar": "%{name}.jar",
+    },
+    implementation = _java_single_jar,
+)
+"""
+Collects Java dependencies and jar files into a single jar
+
+Args:
+  deps: The Java targets (including java_import and java_library) to collect
+      transitive dependencies from. Both compile-time dependencies (deps,
+      exports) and runtime dependencies (runtime_deps) are collected.
+      Resources are also collected. Native cc_library or java_wrap_cc
+      dependencies are not.
+  compress: Whether to always deflate ("yes"), always store ("no"), or pass
+      through unmodified ("preserve"). The default is "preserve", and is the
+      most efficient option -- no extra work is done to inflate or deflate.
+  source_jar: Whether to combine the source jars of input to create a single
+      output source jar.
+  root_packages: Java packages to include in generated jar.
+
+Outputs:
+  {name}.jar: A single jar containing all of the input.
+"""
diff --git a/tools/javadoc.bzl b/tools/javadoc.bzl
index 66f481c4edf815257cfac9bd36ded7a6420eb9ef..981803cb96ed2c7ac26399c86a769f2606d5aece 100644
--- a/tools/javadoc.bzl
+++ b/tools/javadoc.bzl
@@ -1,5 +1,3 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
 # 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
@@ -12,25 +10,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""
-Generates a Javadoc jar path/to/target/<name>.jar.
-
-Arguments:
-  srcs: source files to process
-  deps: targets that contain references to other types referenced in Javadoc. This can be the
-      java_library/android_library target(s) for the same sources
-  root_packages: Java packages to include in generated Javadoc. Any subpackages not listed in
-      exclude_packages will be included as well
-  exclude_packages: Java packages to exclude from generated Javadoc
-  android_api_level: If Android APIs are used, the API level to compile against to generate
-      Javadoc
-  doctitle: title for Javadoc's index.html. See javadoc -doctitle
-"""
-
-_EXTERNAL_JAVADOC_LINKS = [
-    "https://docs.oracle.com/javase/7/docs/api/",
-    "https://developer.android.com/reference/",
-]
+""" Definition of javadoc_library. """
 
 def _check_non_empty(value, name):
   if not value:
@@ -44,31 +24,21 @@ def _android_jar(android_api_level):
 def _javadoc_library(ctx):
   _check_non_empty(ctx.attr.root_packages, "root_packages")
 
-  inputs = []
-  for src_attr in ctx.attr.srcs:
-    inputs.extend(src_attr.files.to_list())
-
-  classpath = depset()
-  for dep in ctx.attr.deps:
-    for transitive_dep in dep.java.transitive_deps:
-      tmp = depset([transitive_dep])
-      classpath = depset(transitive=[classpath, tmp])
+  transitive_deps = [dep.java.transitive_deps for dep in ctx.attr.deps]
   if ctx.attr._android_jar:
-    classpath = depset(transitive=[classpath, ctx.attr._android_jar.files])
+    transitive_deps.append(ctx.attr._android_jar.files)
 
-  inputs += classpath.to_list()
+  classpath = depset([], transitive = transitive_deps).to_list()
 
-  include_packages = " ".join(ctx.attr.root_packages)
+  include_packages = ":".join(ctx.attr.root_packages)
   javadoc_command = [
       ctx.file._javadoc_binary.path,
-      '-sourcepath $(find * -type d -name "*java" -print0 | tr "\\0" :)',
-      include_packages,
+      '-sourcepath srcs',
       "-use",
       "-subpackages", include_packages,
       "-encoding UTF8",
-      "-classpath", ":".join([jar.path for jar in classpath.to_list()]),
+      "-classpath", ":".join([jar.path for jar in classpath]),
       "-notimestamp",
-      '-bottom "Copyright &copy; Google Inc. All rights reserved."',
       "-d tmp",
       "-Xdoclint:-missing",
       "-quiet",
@@ -80,14 +50,31 @@ def _javadoc_library(ctx):
   if ctx.attr.exclude_packages:
     javadoc_command.append("-exclude %s" % ":".join(ctx.attr.exclude_packages))
 
-  for link in _EXTERNAL_JAVADOC_LINKS:
+  for link in ctx.attr.external_javadoc_links:
     javadoc_command.append("-linkoffline {0} {0}".format(link))
 
+  if ctx.attr.bottom_text:
+    javadoc_command.append("-bottom '%s'" % ctx.attr.bottom_text)
+
+  srcs = depset(transitive = [src.files for src in ctx.attr.srcs]).to_list()
+  prepare_srcs_command = "mkdir srcs && "
+  path_prefixes = [x.replace(".", "/") for x in ctx.attr.root_packages]
+  for path_prefix in path_prefixes:
+    prepare_srcs_command = "mkdir -p srcs/%s && " % (path_prefix)
+
+  for src in srcs:
+    if src.path.endswith(".jar"):
+      prepare_srcs_command += "unzip -qq -B %s -d srcs && " % src.path
+    elif src.path.endswith(".java"):
+      for path_prefix in path_prefixes:
+        if path_prefix in src.path:
+          prepare_srcs_command += "cp %s srcs/%s && " % (src.path, path_prefix)
+
   jar_command = "%s cf %s -C tmp ." % (ctx.file._jar_binary.path, ctx.outputs.jar.path)
 
   ctx.actions.run_shell(
-      inputs = inputs + ctx.files._jdk,
-      command = "%s && %s" % (" ".join(javadoc_command), jar_command),
+      inputs = srcs + classpath + ctx.files._jdk,
+      command = "%s %s && %s" % (prepare_srcs_command, " ".join(javadoc_command), jar_command),
       outputs = [ctx.outputs.jar])
 
 javadoc_library = rule(
@@ -98,6 +85,8 @@ javadoc_library = rule(
         "root_packages": attr.string_list(),
         "exclude_packages": attr.string_list(),
         "android_api_level": attr.int(default = -1),
+        "bottom_text": attr.string(default = ""),
+        "external_javadoc_links": attr.string_list(),
         "_android_jar": attr.label(
             default = _android_jar,
             allow_single_file = True,
@@ -118,3 +107,20 @@ javadoc_library = rule(
     outputs = {"jar": "%{name}.jar"},
     implementation = _javadoc_library,
 )
+"""
+Generates a Javadoc jar path/to/target/<name>.jar.
+
+Arguments:
+  srcs: source files to process. This might contain .java files or gen_rule that
+      generates source jars.
+  deps: targets that contain references to other types referenced in Javadoc. This can be the
+      java_library/android_library target(s) for the same sources
+  root_packages: Java packages to include in generated Javadoc. Any subpackages not listed in
+      exclude_packages will be included as well
+  exclude_packages: Java packages to exclude from generated Javadoc
+  android_api_level: If Android APIs are used, the API level to compile against to generate
+      Javadoc
+  doctitle: title for Javadoc's index.html. See javadoc -doctitle
+  bottom_text: text passed to javadoc's `-bottom` flag
+  external_javadoc_links: a list of URLs that are passed to Javadoc's `-linkoffline` flag
+"""
diff --git a/tools/merge_all_rules.txt b/tools/merge_all_rules.txt
deleted file mode 100644
index 345c532e88c028e1b38c108a6c536f6b14d32afd..0000000000000000000000000000000000000000
--- a/tools/merge_all_rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-# an empty rules file causes jarjar to merge all of the jar contents without any renaming