Skip to content

Allow for bulk namespace changes #727

@jpobst

Description

@jpobst

Today, when generator creates a .NET namespace from a Java package, it applies a simple pascal case transformation to make the namespace match established .NET naming standards.

For example: package android.database becomes namespace Android.Database.

However there are a few scenarios that this is not a good fit for.

(1) Words where Pascal case is not desired: androidx -> AndroidX
(2) Java package names are often longer than C# namespaces: com.google.android.material.animation -> Google.Android.Material.Animation.

Both of these scenarios can lead to many repeated metadata lines to fix:

<attr path="/api/package[@name='androidx.core.accessibilityservice']" name="managedName">AndroidX.Core.AccessibilityService</attr>
<attr path="/api/package[@name='androidx.core.app']" name="managedName">AndroidX.Core.App</attr>
<attr path="/api/package[@name='androidx.core.content']" name="managedName">AndroidX.Core.Content</attr>
<attr path="/api/package[@name='androidx.core.database']" name="managedName">AndroidX.Core.Database</attr>
<attr path="/api/package[@name='androidx.core.graphics']" name="managedName">AndroidX.Core.Graphics</attr>
<attr path="/api/package[@name='androidx.core.graphics.drawable']" name="managedName">AndroidX.Core.Graphics.Drawable</attr>
<attr path="/api/package[@name='androidx.core.hardware.display']" name="managedName">AndroidX.Core.Hardware.Display</attr>
<attr path="/api/package[@name='androidx.core.hardware.fingerprint']" name="managedName">AndroidX.Core.Hardware.Fingerprint</attr>
<attr path="/api/package[@name='androidx.core.internal']" name="managedName">AndroidX.Core.Internal</attr>
<attr path="/api/package[@name='androidx.core.internal.view']" name="managedName">AndroidX.Core.Internal.View</attr>
etc..

(Source)

Proposal

To help these scenarios, we could introduce a new MSBuild item that would allow simple replacements. Using MSBuild gives users the flexibility of MSBuild like conditionally specifying replacements based on target framework or importing it to multiple projects via Directory.Build.targets. Additionally it might spare some users from the complexity of metadata.

Examples:

<ItemGroup>
  <AndroidNamespaceReplacement Include='Androidx' Replacement='AndroidX' />
  <AndroidNamespaceReplacement Include='Com' Replacement='' />
  <AndroidNamespaceReplacement Include='Com.Google.' Replacement='Google' />
</ItemGroup>

Implementation Notes

These replacements would only be run for <package> elements that do not specify a @managedName attribute. If you use @managedName you are opting to provide the exact name, we will not process it further.

Unlike unused metadata, these replacement will not raise a warning if they are unused.

Case Sensitivity

Replacements take place after the automatic Pascal case transform, but the compare is case-insensitive.

Thus, both of the following are equivalent:

<AndroidNamespaceReplacement Include='Androidx' Replacement='AndroidX' />
<AndroidNamespaceReplacement Include='androidx' Replacement='AndroidX' />

Word Bounds

Replacements take place only on full words (namespace parts).

Thus,

<AndroidNamespaceReplacement Include='Com' Replacement='' />

Matches matches Com.Google.Library, but not Common.Google.Library or Google.Imaging.Dicom.

Multiple full words can be used:

<AndroidNamespaceReplacement Include='Com.Google' Replacement='Google' />
<AndroidNamespaceReplacement Include='Com.Androidx' Replacement='Xamarin.AndroidX' />

Word Position

The word part match can be constrained to the beginning or end of a namespace by appending a . or prepending a ., respectively.

<AndroidNamespaceReplacement Include='Androidx.' Replacement='Xamarin.AndroidX' />

matches Androidx.Core, but not Square.OkHttp.Androidx.

Similarly,

<AndroidNamespaceReplacement Include='.Compose' Replacement='ComposeUI' />

matches Google.AndroidX.Compose, but not Google.Compose.Writer.

Replacement Order

Replacements run in the order specified by the <ItemGroup>, however adding to this group at different times may result in an unintended order.

Replacements are run sequentially, and multiple replacements may affect a single namespace.

<AndroidNamespaceReplacement Include='Androidx' Replacement='Xamarin.AndroidX' />
<AndroidNamespaceReplacement Include='View' Replacement='Views' />

changes Androidx.View to Xamarin.AndroidX.Views.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementProposed change to current functionalitygeneratorIssues binding a Java library (generator, class-parse, etc.)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions