Implement `android_common.enable_implicit_sourceless_deps_exports_compatibility` in rules_java

Work towards dropping native `JavaInfo` provider wrappers.

PiperOrigin-RevId: 707431633
Change-Id: Iff76922764f76551ff7affea7bfbd3b9d495cf47
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
index d61be6c..d468b1b 100644
--- a/.bazelci/presubmit.yml
+++ b/.bazelci/presubmit.yml
@@ -25,6 +25,7 @@
 
 test_targets_bazel6: &test_targets_bazel6
   - "//java/test/..."
+  - "-//java/test/private/..."
 
 test_target_integration: &test_target_integration
   - "//:MyTest"
diff --git a/java/private/BUILD b/java/private/BUILD
index 94bae8d..020a4a7 100644
--- a/java/private/BUILD
+++ b/java/private/BUILD
@@ -44,6 +44,14 @@
     deps = ["@compatibility_proxy//:proxy_bzl"],
 )
 
+# Exposed for use by the android rules.
+bzl_library(
+    name = "android_support",
+    srcs = ["android_support.bzl"],
+    visibility = ["//visibility:public"],
+    deps = ["@compatibility_proxy//:proxy_bzl"],
+)
+
 filegroup(
     name = "srcs",
     srcs = glob(["**"]),
@@ -55,6 +63,7 @@
     testonly = 1,
     srcs = [
         "BUILD",
+        ":android_support",
         ":internals",
         ":native_bzl",
         ":proto_support",
diff --git a/java/private/android_support.bzl b/java/private/android_support.bzl
new file mode 100644
index 0000000..fa80a17
--- /dev/null
+++ b/java/private/android_support.bzl
@@ -0,0 +1,20 @@
+# Copyright 2024 The Bazel Authors. 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.
+"""Legacy support for the android rules."""
+
+load("@compatibility_proxy//:proxy.bzl", "java_info_to_implicit_exportable")
+
+android_support = struct(
+    enable_implicit_sourceless_deps_exports_compatibility = java_info_to_implicit_exportable,
+)
diff --git a/java/private/java_info.bzl b/java/private/java_info.bzl
index 8ba655e..3b68e69 100644
--- a/java/private/java_info.bzl
+++ b/java/private/java_info.bzl
@@ -248,6 +248,33 @@
     result.update(_is_binary = True)
     return _new_javainfo(**result)
 
+def to_implicit_exportable(java_info, neverlink = False):
+    result = {
+        "transitive_runtime_jars": depset() if neverlink else java_info.transitive_runtime_jars,
+        "transitive_compile_time_jars": java_info.transitive_compile_time_jars,
+        "compile_jars": java_info.compile_jars,
+        "full_compile_jars": java_info.full_compile_jars,
+        "_transitive_full_compile_time_jars": java_info._transitive_full_compile_time_jars,
+        "_compile_time_java_dependencies": java_info._compile_time_java_dependencies,
+        "_neverlink": neverlink,
+        # unset defaults
+        "source_jars": [],
+        "outputs": _JavaRuleOutputJarsInfo(jars = [], jdeps = None, native_headers = None),
+        "annotation_processing": None,
+        "runtime_output_jars": [],
+        "transitive_source_jars": depset(),
+        "transitive_native_libraries": depset(),
+        "cc_link_params_info": CcInfo(),
+        "module_flags_info": _EMPTY_MODULE_FLAGS_INFO,
+        "plugins": _EMPTY_PLUGIN_DATA,
+        "api_generating_plugins": _EMPTY_PLUGIN_DATA,
+        "java_outputs": [],
+        "compilation_info": None,
+        "_constraints": [],
+        "_is_binary": getattr(java_info, "_is_binary", False),
+    }
+    return _new_javainfo(**result)
+
 def _to_mutable_dict(java_info):
     return {
         key: getattr(java_info, key)
diff --git a/java/rules_java_deps.bzl b/java/rules_java_deps.bzl
index 98a2907..d97f56d 100644
--- a/java/rules_java_deps.bzl
+++ b/java/rules_java_deps.bzl
@@ -39,7 +39,8 @@
 load("@rules_java//java/common/rules:java_toolchain.bzl", _java_toolchain = "java_toolchain")
 load("@rules_java//java/private:java_common.bzl", _java_common = "java_common")
 load("@rules_java//java/private:java_common_internal.bzl", _java_common_internal_compile = "compile")
-load("@rules_java//java/private:java_info.bzl", _JavaInfo = "JavaInfo", _JavaPluginInfo = "JavaPluginInfo", _java_info_internal_merge = "merge")
+load("@rules_java//java/private:java_info.bzl", _JavaInfo = "JavaInfo", _JavaPluginInfo = "JavaPluginInfo",
+  _java_info_internal_merge = "merge", _java_info_to_implicit_exportable = "to_implicit_exportable")
 
 java_binary = _java_binary
 java_import = _java_import
@@ -54,6 +55,7 @@
 JavaPluginInfo = _JavaPluginInfo
 java_common_internal_compile = _java_common_internal_compile
 java_info_internal_merge = _java_info_internal_merge
+java_info_to_implicit_exportable = _java_info_to_implicit_exportable
 http_jar = _http_jar
             """,
         )
@@ -95,6 +97,8 @@
 JavaPluginInfo = NativeJavaPluginInfo
 java_common_internal_compile = None
 java_info_internal_merge = None
+# Not available before Bazel 7
+java_info_to_implicit_exportable = getattr(android_common, "enable_implicit_sourceless_deps_exports_compatibility", None)
 
 http_jar = _http_jar
             """,
diff --git a/java/test/private/BUILD b/java/test/private/BUILD
new file mode 100644
index 0000000..4938f73
--- /dev/null
+++ b/java/test/private/BUILD
@@ -0,0 +1,34 @@
+# Copyright 2021 The Bazel Authors. 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.
+
+load("//java:defs.bzl", "java_library", "java_plugin")
+load(":android_support_tests.bzl", "android_support_tests", "my_rule")
+
+java_plugin(
+    name = "my_plugin",
+    srcs = ["MyPlugin.java"],
+)
+
+java_library(
+    name = "foo",
+    srcs = ["Foo.java"],
+    exported_plugins = [":my_plugin"],
+)
+
+my_rule(
+    name = "bar",
+    dep = ":foo",
+)
+
+android_support_tests(name = "android_support_tests")
diff --git a/java/test/private/Foo.java b/java/test/private/Foo.java
new file mode 100644
index 0000000..4a2b44d
--- /dev/null
+++ b/java/test/private/Foo.java
@@ -0,0 +1 @@
+public class Foo {}
diff --git a/java/test/private/MyPlugin.java b/java/test/private/MyPlugin.java
new file mode 100644
index 0000000..2747e67
--- /dev/null
+++ b/java/test/private/MyPlugin.java
@@ -0,0 +1 @@
+public class MyPlugin {}
diff --git a/java/test/private/android_support_tests.bzl b/java/test/private/android_support_tests.bzl
new file mode 100644
index 0000000..91f38c0
--- /dev/null
+++ b/java/test/private/android_support_tests.bzl
@@ -0,0 +1,59 @@
+# Copyright 2021 The Bazel Authors. 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.
+"""Tests for //java/private:android_support.bzl"""
+
+load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
+load("//java/common:java_info.bzl", "JavaInfo")
+load("//java/private:android_support.bzl", "android_support")
+
+def _impl(ctx):
+    return [
+        android_support.enable_implicit_sourceless_deps_exports_compatibility(ctx.attr.dep[JavaInfo]),
+    ]
+
+my_rule = rule(
+    implementation = _impl,
+    attrs = {
+        "dep": attr.label(),
+    },
+)
+
+def _test_enable_implicit_sourceless_deps_exports_compatibility(name):
+    analysis_test(
+        name = name,
+        impl = _test_enable_implicit_sourceless_deps_exports_compatibility_impl,
+        targets = {
+            "foo": Label(":foo"),
+            "bar": Label(":bar"),
+        },
+    )
+
+def _test_enable_implicit_sourceless_deps_exports_compatibility_impl(env, targets):
+    # TODO(hvd): write a ProviderSubject for JavaInfo
+    foo_javainfo = targets.foo[JavaInfo]
+    bar_javainfo = targets.bar[JavaInfo]
+    for attr in ["transitive_runtime_jars", "compile_jars", "transitive_compile_time_jars", "full_compile_jars", "_transitive_full_compile_time_jars", "_compile_time_java_dependencies"]:
+        env.expect.that_bool(getattr(foo_javainfo, attr) == getattr(bar_javainfo, attr)).equals(True)
+    env.expect.that_depset_of_files(foo_javainfo.plugins.processor_jars).contains_exactly([
+        "java/test/private/libmy_plugin.jar",
+    ])
+    env.expect.that_depset_of_files(bar_javainfo.plugins.processor_jars).contains_exactly([])
+
+def android_support_tests(name):
+    test_suite(
+        name = name,
+        tests = [
+            _test_enable_implicit_sourceless_deps_exports_compatibility,
+        ],
+    )