Skip to content

Fix Java-generic name-clash in AdLoadCallback subclasses (issue #1491)#1492

Open
jonathanpeppers wants to merge 3 commits into
mainfrom
jonathanpeppers-fix-adloadcallback-generic-clash
Open

Fix Java-generic name-clash in AdLoadCallback subclasses (issue #1491)#1492
jonathanpeppers wants to merge 3 commits into
mainfrom
jonathanpeppers-fix-adloadcallback-generic-clash

Conversation

@jonathanpeppers

@jonathanpeppers jonathanpeppers commented Jul 1, 2026

Copy link
Copy Markdown
Member

Fixes #1491.

Problem

AdLoadCallback<AdT> declares public void onAdLoaded(AdT ad), which erases to onAdLoaded(Object) in bytecode. The binding therefore only exposes virtual OnAdLoaded(Java.Lang.Object p0) on every concrete subclass:

  • AdManagerInterstitialAdLoadCallback
  • InterstitialAdLoadCallback
  • RewardedAdLoadCallback
  • RewardedInterstitialAdLoadCallback
  • AppOpenAd.AppOpenAdLoadCallback

When a user overrides that in C#, the generated ACW Java stub emits public void onAdLoaded(java.lang.Object p0), and javac rejects it:

error: name clash: onAdLoaded(Object) in MyCallback and
onAdLoaded(AdManagerInterstitialAd) in AdLoadCallback have the same
erasure, yet neither overrides the other

After generic substitution the parent's real method is the specialized one, so the erased override doesn't satisfy javac.

Fix

For each concrete *AdLoadCallback subclass, add a specialized onAdLoaded(SpecificAd) method via <add-node> in the binding's Transforms/Metadata.xml. The binding now surfaces a properly-typed virtual OnAdLoaded(SpecificAd) with a specialized JNI registration, e.g.:

[Register("onAdLoaded", "(Lcom/google/android/gms/ads/admanager/AdManagerInterstitialAd;)V",
          "GetOnAdLoaded_Lcom_google_android_gms_ads_admanager_AdManagerInterstitialAd_Handler")]
public virtual unsafe void OnAdLoaded(AdManagerInterstitialAd p0) { ... }

Users override the specialized overload, and the resulting ACW stub emits the specialized Java signature that correctly overrides the parent — matching how Google's docs show the callback being subclassed in Java.

The same fix is applied in both bindings that ship these types:

  • play-services-ads-liteAndroid.Gms.Ads.* namespace (used by Xamarin.GooglePlayServices.Ads.Lite direct consumers).
  • play-services-ads-apiGoogle.Android.Gms.Ads.* namespace (pulled in transitively by Xamarin.GooglePlayServices.Ads, which is what the issue reporter uses).

Both .aars independently contain the *AdLoadCallback.class files and each produces its own set of .NET types, so the metadata must be added in both places.

Version bumps

  • Xamarin.GooglePlayServices.Ads.Lite: 124.0.0.6124.0.0.7
  • Xamarin.GooglePlayServices.Ads.Api: 125.4.0.1125.4.0.2
  • Xamarin.GooglePlayServices.Ads: 125.4.0.1125.4.0.2

User-facing migration

Users hitting javac.exe error JAVAC0000 from #1491 should change:

public override void OnAdLoaded(Java.Lang.Object p0) { ... }

to the specialized overload, e.g.:

public override void OnAdLoaded(AdManagerInterstitialAd p0) { ... }

Verification

  • dotnet cake --target=metadata-verify passes.
  • Built both com.google.android.gms.play-services-ads-lite and com.google.android.gms.play-services-ads-api locally (against a project-referenced Ads.Base since the published Ads.Base 124.0.0.1 NuGet does not yet target net10.0-android36) — build succeeded, 0 warnings, 0 errors.
  • Verified generated *AdLoadCallback.cs in each project's obj/ contains the specialized virtual void OnAdLoaded(SpecificAd p0) with the expected [Register("onAdLoaded", "(Lcom/.../SpecificAd;)V", ...)].
  • All 5 specialized overloads picked up in PublicAPI.Unshipped.txt for both packages by the analyzer.

The base `AdLoadCallback<AdT>` in play-services-ads-lite declares
`onAdLoaded(AdT)` which erases to `onAdLoaded(Object)` in bytecode.
The binding generator therefore exposes only
`virtual OnAdLoaded(Java.Lang.Object)` on every concrete subclass
(`AdManagerInterstitialAdLoadCallback`, `InterstitialAdLoadCallback`,
`RewardedAdLoadCallback`, `RewardedInterstitialAdLoadCallback`,
`AppOpenAd.AppOpenAdLoadCallback`).

When a user override that in C#, the generated Java ACW stub emits
`public void onAdLoaded(java.lang.Object p0)`, which javac rejects with

    error: name clash: onAdLoaded(Object) in MyCallback and
    onAdLoaded(AdManagerInterstitialAd) in AdLoadCallback have the same
    erasure, yet neither overrides the other

because after generic substitution the parent's method is the specialized
one.

Add a specialized `onAdLoaded(SpecificAd)` method on each concrete
subclass via <add-node> so the binding exposes a properly-typed
`virtual OnAdLoaded(SpecificAd)` with a specialized JNI registration.
Users can now override the specialized overload, and the resulting ACW
stub emits the specialized Java signature that correctly overrides the
parent -- matching how Google's docs show the callback being subclassed
in Java.

Fixes #1491.

Co-authored-by: Copilot App <[email protected]>
Copilot AI review requested due to automatic review settings July 1, 2026 14:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the play-services-ads-lite binding metadata to address a Java generic-erasure name-clash that prevents apps from compiling when users override AdLoadCallback<AdT>.onAdLoaded(...) via the currently-exposed OnAdLoaded(Java.Lang.Object) in C# (issue #1491). The approach is to inject properly-specialized onAdLoaded(SpecificAd) methods onto each concrete *AdLoadCallback subclass so the binding surfaces typed OnAdLoaded(SpecificAd) overloads with specialized JNI registrations.

Changes:

  • Add <add-node> metadata entries that introduce specialized onAdLoaded(SpecificAd) methods for each affected *AdLoadCallback concrete subclass.
  • Record the resulting new typed virtual overloads in PublicAPI.Unshipped.txt for API tracking.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
source/com.google.android.gms/play-services-ads-lite/Transforms/Metadata.xml Adds specialized onAdLoaded(SpecificAd) methods to concrete AdLoadCallback<AdT> subclasses to avoid Java name-clash from generic erasure.
source/com.google.android.gms/play-services-ads-lite/PublicAPI/PublicAPI.Unshipped.txt Captures the new typed OnAdLoaded(SpecificAd) virtual overloads as public API additions.

jonathanpeppers and others added 2 commits July 1, 2026 10:03
Ship the AdLoadCallback binding fix from the previous commit
(fixes #1491) as a new NuGet revision.

Co-authored-by: Copilot App <[email protected]>
The customer's project uses the Google.Android.Gms.Ads.* namespace, which
comes from Xamarin.GooglePlayServices.Ads.Api (transitively via
Xamarin.GooglePlayServices.Ads), not Xamarin.GooglePlayServices.Ads.Lite.

Apply the same <add-node> metadata fix to the -api binding so that the
five concrete AdLoadCallback<AdT> subclasses expose a specialized
OnAdLoaded(SpecificAd) overload, avoiding the javac name-clash on ACW
generation when users override the callback.

Also bump Xamarin.GooglePlayServices.Ads and Xamarin.GooglePlayServices.Ads.Api
by 0.0.0.1 so consumers pick up the fix.

Co-authored-by: Copilot App <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

the app will compile error with google mobile ad

2 participants