Skip to content

Commit 64cbe4d

Browse files
[TrimmableTypeMap] Add typed logger interface
Replace Action<string> log callback with ITrimmableTypeMapLogger interface in TrimmableTypeMapGenerator. This enables structured logging with typed methods instead of free-form string messages, making it easier to extend with new log categories (e.g., warnings) in follow-up PRs. No behavioral changes — pure refactoring. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c2bdc5b commit 64cbe4d

4 files changed

Lines changed: 66 additions & 13 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace Microsoft.Android.Sdk.TrimmableTypeMap;
2+
3+
public interface ITrimmableTypeMapLogger
4+
{
5+
void LogNoJavaPeerTypesFound ();
6+
void LogJavaPeerScanInfo (int assemblyCount, int peerCount);
7+
void LogGeneratingJcwFilesInfo (int jcwPeerCount, int totalPeerCount);
8+
void LogDeferredRegistrationTypesInfo (int typeCount);
9+
void LogGeneratedTypeMapAssemblyInfo (string assemblyName, int typeCount);
10+
void LogGeneratedRootTypeMapInfo (int assemblyReferenceCount);
11+
void LogGeneratedTypeMapAssembliesInfo (int assemblyCount);
12+
void LogGeneratedJcwFilesInfo (int sourceCount);
13+
}

src/Microsoft.Android.Sdk.TrimmableTypeMap/TrimmableTypeMapGenerator.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
99

1010
public class TrimmableTypeMapGenerator
1111
{
12-
readonly Action<string> log;
12+
readonly ITrimmableTypeMapLogger? logger;
1313

14-
public TrimmableTypeMapGenerator (Action<string> log)
14+
public TrimmableTypeMapGenerator (ITrimmableTypeMapLogger? logger = null)
1515
{
16-
this.log = log ?? throw new ArgumentNullException (nameof (log));
16+
this.logger = logger;
1717
}
1818

1919
/// <summary>
@@ -34,15 +34,15 @@ public TrimmableTypeMapResult Execute (
3434

3535
var (allPeers, assemblyManifestInfo) = ScanAssemblies (assemblies);
3636
if (allPeers.Count == 0) {
37-
log ("No Java peer types found, skipping typemap generation.");
37+
logger?.LogNoJavaPeerTypesFound ();
3838
return new TrimmableTypeMapResult ([], [], allPeers);
3939
}
4040

4141
var generatedAssemblies = GenerateTypeMapAssemblies (allPeers, systemRuntimeVersion);
4242
var jcwPeers = allPeers.Where (p =>
4343
!frameworkAssemblyNames.Contains (p.AssemblyName)
4444
|| p.JavaName.StartsWith ("mono/", StringComparison.Ordinal)).ToList ();
45-
log ($"Generating JCW files for {jcwPeers.Count} types (filtered from {allPeers.Count} total).");
45+
logger?.LogGeneratingJcwFilesInfo (jcwPeers.Count, allPeers.Count);
4646
var generatedJavaSources = GenerateJcwJavaSources (jcwPeers);
4747

4848
// Collect Application/Instrumentation types that need deferred registerNatives
@@ -51,7 +51,7 @@ public TrimmableTypeMapResult Execute (
5151
.Select (p => JniSignatureHelper.JniNameToJavaName (p.JavaName))
5252
.ToList ();
5353
if (appRegTypes.Count > 0) {
54-
log ($"Found {appRegTypes.Count} Application/Instrumentation types for deferred registration.");
54+
logger?.LogDeferredRegistrationTypesInfo (appRegTypes.Count);
5555
}
5656

5757
var manifest = manifestConfig is not null
@@ -102,7 +102,7 @@ GeneratedManifest GenerateManifest (List<JavaPeerInfo> allPeers, AssemblyManifes
102102
using var scanner = new JavaPeerScanner ();
103103
var peers = scanner.Scan (assemblies);
104104
var manifestInfo = scanner.ScanAssemblyManifestInfo ();
105-
log ($"Scanned {assemblies.Count} assemblies, found {peers.Count} Java peer types.");
105+
logger?.LogJavaPeerScanInfo (assemblies.Count, peers.Count);
106106
return (peers, manifestInfo);
107107
}
108108

@@ -120,23 +120,23 @@ List<GeneratedAssembly> GenerateTypeMapAssemblies (List<JavaPeerInfo> allPeers,
120120
generator.Generate (peers, stream, assemblyName);
121121
stream.Position = 0;
122122
generatedAssemblies.Add (new GeneratedAssembly (assemblyName, stream));
123-
log ($" {assemblyName}: {peers.Count} types");
123+
logger?.LogGeneratedTypeMapAssemblyInfo (assemblyName, peers.Count);
124124
}
125125
var rootStream = new MemoryStream ();
126126
var rootGenerator = new RootTypeMapAssemblyGenerator (systemRuntimeVersion);
127127
rootGenerator.Generate (perAssemblyNames, rootStream);
128128
rootStream.Position = 0;
129129
generatedAssemblies.Add (new GeneratedAssembly ("_Microsoft.Android.TypeMaps", rootStream));
130-
log ($" Root: {perAssemblyNames.Count} per-assembly refs");
131-
log ($"Generated {generatedAssemblies.Count} typemap assemblies.");
130+
logger?.LogGeneratedRootTypeMapInfo (perAssemblyNames.Count);
131+
logger?.LogGeneratedTypeMapAssembliesInfo (generatedAssemblies.Count);
132132
return generatedAssemblies;
133133
}
134134

135135
List<GeneratedJavaSource> GenerateJcwJavaSources (List<JavaPeerInfo> allPeers)
136136
{
137137
var jcwGenerator = new JcwJavaSourceGenerator ();
138138
var sources = jcwGenerator.GenerateContent (allPeers);
139-
log ($"Generated {sources.Count} JCW Java source files.");
139+
logger?.LogGeneratedJcwFilesInfo (sources.Count);
140140
return sources.ToList ();
141141
}
142142
}

src/Xamarin.Android.Build.Tasks/Tasks/GenerateTrimmableTypeMap.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@ namespace Xamarin.Android.Tasks;
1515

1616
public class GenerateTrimmableTypeMap : AndroidTask
1717
{
18+
sealed class MSBuildTrimmableTypeMapLogger (TaskLoggingHelper log) : ITrimmableTypeMapLogger
19+
{
20+
public void LogNoJavaPeerTypesFound () =>
21+
log.LogMessage (MessageImportance.Low, "No Java peer types found, skipping typemap generation.");
22+
public void LogJavaPeerScanInfo (int assemblyCount, int peerCount) =>
23+
log.LogMessage (MessageImportance.Low, $"Scanned {assemblyCount} assemblies, found {peerCount} Java peer types.");
24+
public void LogGeneratingJcwFilesInfo (int jcwPeerCount, int totalPeerCount) =>
25+
log.LogMessage (MessageImportance.Low, $"Generating JCW files for {jcwPeerCount} types (filtered from {totalPeerCount} total).");
26+
public void LogDeferredRegistrationTypesInfo (int typeCount) =>
27+
log.LogMessage (MessageImportance.Low, $"Found {typeCount} Application/Instrumentation types for deferred registration.");
28+
public void LogGeneratedTypeMapAssemblyInfo (string assemblyName, int typeCount) =>
29+
log.LogMessage (MessageImportance.Low, $" {assemblyName}: {typeCount} types");
30+
public void LogGeneratedRootTypeMapInfo (int assemblyReferenceCount) =>
31+
log.LogMessage (MessageImportance.Low, $" Root: {assemblyReferenceCount} per-assembly refs");
32+
public void LogGeneratedTypeMapAssembliesInfo (int assemblyCount) =>
33+
log.LogMessage (MessageImportance.Low, $"Generated {assemblyCount} typemap assemblies.");
34+
public void LogGeneratedJcwFilesInfo (int sourceCount) =>
35+
log.LogMessage (MessageImportance.Low, $"Generated {sourceCount} JCW Java source files.");
36+
}
37+
1838
public override string TaskPrefix => "GTT";
1939

2040
[Required]
@@ -94,7 +114,7 @@ public override bool RunTask ()
94114
ApplicationJavaClass: ApplicationJavaClass);
95115
}
96116

97-
var generator = new TrimmableTypeMapGenerator (msg => Log.LogMessage (MessageImportance.Low, msg));
117+
var generator = new TrimmableTypeMapGenerator (new MSBuildTrimmableTypeMapLogger (Log));
98118

99119
XDocument? manifestTemplate = null;
100120
if (!ManifestTemplate.IsNullOrEmpty () && File.Exists (ManifestTemplate)) {

tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TrimmableTypeMapGeneratorTests.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ public class TrimmableTypeMapGeneratorTests : FixtureTestBase
1212
{
1313
readonly List<string> logMessages = new ();
1414

15+
sealed class TestTrimmableTypeMapLogger (List<string> logMessages) : ITrimmableTypeMapLogger
16+
{
17+
public void LogNoJavaPeerTypesFound () =>
18+
logMessages.Add ("No Java peer types found, skipping typemap generation.");
19+
public void LogJavaPeerScanInfo (int assemblyCount, int peerCount) =>
20+
logMessages.Add ($"Scanned {assemblyCount} assemblies, found {peerCount} Java peer types.");
21+
public void LogGeneratingJcwFilesInfo (int jcwPeerCount, int totalPeerCount) =>
22+
logMessages.Add ($"Generating JCW files for {jcwPeerCount} types (filtered from {totalPeerCount} total).");
23+
public void LogDeferredRegistrationTypesInfo (int typeCount) =>
24+
logMessages.Add ($"Found {typeCount} Application/Instrumentation types for deferred registration.");
25+
public void LogGeneratedTypeMapAssemblyInfo (string assemblyName, int typeCount) =>
26+
logMessages.Add ($" {assemblyName}: {typeCount} types");
27+
public void LogGeneratedRootTypeMapInfo (int assemblyReferenceCount) =>
28+
logMessages.Add ($" Root: {assemblyReferenceCount} per-assembly refs");
29+
public void LogGeneratedTypeMapAssembliesInfo (int assemblyCount) =>
30+
logMessages.Add ($"Generated {assemblyCount} typemap assemblies.");
31+
public void LogGeneratedJcwFilesInfo (int sourceCount) =>
32+
logMessages.Add ($"Generated {sourceCount} JCW Java source files.");
33+
}
34+
1535
[Fact]
1636
public void Execute_EmptyAssemblyList_ReturnsEmptyResults ()
1737
{
@@ -79,7 +99,7 @@ public void Execute_JavaSourcesHaveCorrectStructure ()
7999
Assert.Contains ("class ", source.Content);
80100
}
81101

82-
TrimmableTypeMapGenerator CreateGenerator () => new (msg => logMessages.Add (msg));
102+
TrimmableTypeMapGenerator CreateGenerator () => new (new TestTrimmableTypeMapLogger (logMessages));
83103

84104
static PEReader CreateTestFixturePEReader ()
85105
{

0 commit comments

Comments
 (0)