Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Commit 3e4a3c4

Browse files
authored
[Java.Interop.Tools.JavaCallableWrappers] JavaCallableMethodClassifier (#998)
Context: dotnet/android#7123 Context: fb94d59 Instead of having `JavaCallableWrapperGenerator` care about and collect marshal methods override information, introduce a new `JavaCallableMethodClassifier` type, and use that as the integration point: public abstract partial class JavaCallableMethodClassifier { public abstract bool ShouldBeDynamicallyRegistered TypeDefinition topType, MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute registerAttribute ); } An instance of `JavaCallableMethodClassifier` can now be provided to the `JavaCallableWrapperGenerator` constructor. If provided, then `ShouldBeDynamicallyRegistered()` will be used to control which methods are added to `__md_methods` and `Runtime.register()`. If a type `JavaCallableWrapperGenerator` is processing doesn't have any dynamically registered methods, then the code to register them is no longer generated.
1 parent c942ab6 commit 3e4a3c4

2 files changed

Lines changed: 83 additions & 61 deletions

File tree

‎src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
usingSystem;
22

3+
usingMono.Cecil;
4+
35
namespaceAndroid.Runtime{
46

57
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Constructor|AttributeTargets.Field|AttributeTargets.Interface|AttributeTargets.Method|AttributeTargets.Property)]
@@ -23,6 +25,21 @@ public RegisterAttribute (string name, string signature, string connector)
2325
this.connector=connector;
2426
this.signature=signature;
2527
}
28+
#if HAVE_CECIL
29+
publicRegisterAttribute(stringname,CustomAttributeoriginAttribute)
30+
:this(name)
31+
{
32+
OriginAttribute=originAttribute;
33+
}
34+
35+
publicRegisterAttribute(stringname,stringsignature,stringconnector,CustomAttributeoriginAttribute)
36+
:this(name,signature,connector)
37+
{
38+
OriginAttribute=originAttribute;
39+
}
40+
41+
publicCustomAttributeOriginAttribute{get;}
42+
#endif // HAVE_CECIL
2643

2744
publicstringConnector{
2845
get{returnconnector;}

‎src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs‎

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,40 +25,9 @@ public enum JavaPeerStyle {
2525
JavaInterop1,
2626
}
2727

28-
publicclassOverriddenMethodDescriptor
28+
publicabstractclassJavaCallableMethodClassifier
2929
{
30-
staticreadonlychar[]methodDescSplitChars=newchar[]{':'};
31-
32-
publicstringJavaPackageName{get;}
33-
publicstringNativeName{get;}
34-
publicstringJniSignature{get;}
35-
publicstringConnector{get;}
36-
publicstringManagedTypeName{get;}
37-
publicstringOriginalDescString{get;}
38-
39-
publicOverriddenMethodDescriptor(stringjavaPackageName,stringmethodDescription,stringfallbackManagedTypeName)
40-
{
41-
OriginalDescString=methodDescription;
42-
JavaPackageName=javaPackageName;
43-
string[]parts=methodDescription.Split(methodDescSplitChars,4);
44-
45-
if(parts.Length<2){
46-
thrownewInvalidOperationException($"Unexpected format for method description. Expected at least 2 parts, got {parts.Length} from: '{methodDescription}'");
47-
}
48-
49-
NativeName=parts[0];
50-
JniSignature=parts[1];
51-
if(parts.Length>2){
52-
Connector=parts[2];
53-
if(parts.Length>3){
54-
ManagedTypeName=TypeDefinitionRocks.CecilTypeNameToReflectionTypeName(parts[3]);
55-
}
56-
}
57-
58-
if(String.IsNullOrEmpty(ManagedTypeName)){
59-
ManagedTypeName=fallbackManagedTypeName;
60-
}
61-
}
30+
publicabstractboolShouldBeDynamicallyRegistered(TypeDefinitiontopType,MethodDefinitionregisteredMethod,MethodDefinitionimplementedMethod,CustomAttributeregisterAttribute);
6231
}
6332

6433
publicclassJavaCallableWrapperGenerator{
@@ -95,36 +64,47 @@ public string GetJavaAccess ()
9564
List<Signature>methods=newList<Signature>();
9665
List<Signature>ctors=newList<Signature>();
9766
List<JavaCallableWrapperGenerator>children;
98-
List<OverriddenMethodDescriptor>overriddenMethodDescriptors;
67+
9968
readonlyIMetadataResolvercache;
69+
readonlyJavaCallableMethodClassifiermethodClassifier;
10070

10171
[Obsolete("Use the TypeDefinitionCache overload for better performance.")]
10272
publicJavaCallableWrapperGenerator(TypeDefinitiontype,Action<string,object[]>log)
103-
:this(type,null,log,resolver:null)
73+
:this(type,log,resolver:null,methodClassifier:null)
10474
{}
10575

10676
publicJavaCallableWrapperGenerator(TypeDefinitiontype,Action<string,object[]>log,TypeDefinitionCachecache)
107-
:this(type,log,(IMetadataResolver)cache)
77+
:this(type,log,(IMetadataResolver)cache,methodClassifier:null)
78+
{}
79+
80+
publicJavaCallableWrapperGenerator(TypeDefinitiontype,Action<string,object[]>log,TypeDefinitionCachecache,JavaCallableMethodClassifiermethodClassifier)
81+
:this(type,log,(IMetadataResolver)cache,methodClassifier)
10882
{
10983
}
11084

11185
publicJavaCallableWrapperGenerator(TypeDefinitiontype,Action<string,object[]>log,IMetadataResolverresolver)
112-
:this(type,null,log,resolver)
86+
:this(type,log,resolver,methodClassifier:null)
87+
{}
88+
89+
publicJavaCallableWrapperGenerator(TypeDefinitiontype,Action<string,object[]>log,IMetadataResolverresolver,JavaCallableMethodClassifiermethodClassifier)
90+
:this(type,null,log,resolver,methodClassifier)
11391
{
11492
if(type.HasNestedTypes){
11593
children=newList<JavaCallableWrapperGenerator>();
11694
AddNestedTypes(type);
11795
}
11896
}
11997

120-
publicIList<OverriddenMethodDescriptor>OverriddenMethodDescriptors=>overriddenMethodDescriptors;
12198
publicstringApplicationJavaClass{get;set;}
12299
publicJavaPeerStyleCodeGenerationTarget{get;set;}
123100

124101
publicboolGenerateOnCreateOverrides{get;set;}
125102

126103
publicboolHasExport{get;privateset;}
127104

105+
// If there are no methods, we need to generate "empty" registration because of backward compatibility
106+
publicboolHasDynamicallyRegisteredMethods=>methods.Count==0||methods.Any((Signaturesig)=>sig.IsDynamicallyRegistered);
107+
128108
/// <summary>
129109
/// The Java source code to be included in Instrumentation.onCreate
130110
///
@@ -152,8 +132,9 @@ void AddNestedTypes (TypeDefinition type)
152132
HasExport|=children.Any(t =>t.HasExport);
153133
}
154134

155-
JavaCallableWrapperGenerator(TypeDefinitiontype,stringouterType,Action<string,object[]>log,IMetadataResolverresolver)
135+
JavaCallableWrapperGenerator(TypeDefinitiontype,stringouterType,Action<string,object[]>log,IMetadataResolverresolver,JavaCallableMethodClassifiermethodClassifier=null)
156136
{
137+
this.methodClassifier=methodClassifier;
157138
this.type=type;
158139
this.log=log;
159140
this.cache=resolver??newTypeDefinitionCache();
@@ -366,12 +347,13 @@ internal static RegisterAttribute ToRegisterAttribute (CustomAttribute attr)
366347
// attr.Resolve ();
367348
RegisterAttributer=null;
368349
if(attr.ConstructorArguments.Count==1)
369-
r=newRegisterAttribute((string)attr.ConstructorArguments[0].Value);
350+
r=newRegisterAttribute((string)attr.ConstructorArguments[0].Value,attr);
370351
elseif(attr.ConstructorArguments.Count==3)
371352
r=newRegisterAttribute(
372353
(string)attr.ConstructorArguments[0].Value,
373354
(string)attr.ConstructorArguments[1].Value,
374-
(string)attr.ConstructorArguments[2].Value);
355+
(string)attr.ConstructorArguments[2].Value,
356+
attr);
375357
if(r!=null){
376358
varv=attr.Properties.FirstOrDefault(p =>p.Name=="DoNotGenerateAcw");
377359
r.DoNotGenerateAcw=v.Name==null?false:(bool)v.Argument.Value;
@@ -384,7 +366,7 @@ internal static RegisterAttribute RegisterFromJniTypeSignatureAttribute (CustomA
384366
// attr.Resolve ();
385367
RegisterAttributer=null;
386368
if(attr.ConstructorArguments.Count==1)
387-
r=newRegisterAttribute((string)attr.ConstructorArguments[0].Value);
369+
r=newRegisterAttribute((string)attr.ConstructorArguments[0].Value,attr);
388370
if(r!=null){
389371
varv=attr.Properties.FirstOrDefault(p =>p.Name=="GenerateJavaPeer");
390372
if(v.Name==null){
@@ -403,7 +385,8 @@ internal static RegisterAttribute RegisterFromJniMethodSignatureAttribute (Custo
403385
if(attr.ConstructorArguments.Count==2)
404386
r=newRegisterAttribute((string)attr.ConstructorArguments[0].Value,
405387
(string)attr.ConstructorArguments[1].Value,
406-
"");
388+
"",
389+
attr);
407390
returnr;
408391
}
409392

@@ -467,7 +450,8 @@ void AddMethod (MethodDefinition registeredMethod, MethodDefinition implementedM
467450
if(attr.Name.Contains("-impl")||(attr.Name.Length>7&&attr.Name[attr.Name.Length-8]=='-'))
468451
Diagnostic.Error(4217,LookupSource(implementedMethod),Localization.Resources.JavaCallableWrappers_XA4217,attr.Name);
469452

470-
varmsig=newSignature(implementedMethod,attr);
453+
boolshouldBeDynamicallyRegistered=methodClassifier?.ShouldBeDynamicallyRegistered(type,registeredMethod,implementedMethod,attr.OriginAttribute)??true;
454+
varmsig=newSignature(implementedMethod,attr,shouldBeDynamicallyRegistered);
471455
if(!registeredMethod.IsConstructor&&!methods.Any(m =>m.Name==msig.Name&&m.Params==msig.Params))
472456
methods.Add(msig);
473457
}
@@ -542,21 +526,38 @@ public void Generate (TextWriter writer)
542526

543527
GenerateHeader(writer);
544528

545-
writer.WriteLine("/** @hide */");
546-
writer.WriteLine("\tpublic static final String __md_methods;");
547-
if(children!=null){
548-
foreach(variinEnumerable.Range(1,children.Count))
549-
writer.WriteLine("\tstatic final String __md_{0}_methods;",i);
529+
boolneedCtor=false;
530+
if(HasDynamicallyRegisteredMethods){
531+
needCtor=true;
532+
writer.WriteLine("/** @hide */");
533+
writer.WriteLine("\tpublic static final String __md_methods;");
550534
}
551-
writer.WriteLine("\tstatic {");
552-
GenerateRegisterType(writer,this,"__md_methods");
535+
553536
if(children!=null){
554-
for(inti=0;i<children.Count;++i){
555-
stringmethods=string.Format("__md_{0}_methods",i+1);
556-
GenerateRegisterType(writer,children[i],methods);
537+
for(inti=0;i<children.Count;i++){
538+
if(!children[i].HasDynamicallyRegisteredMethods){
539+
continue;
540+
}
541+
needCtor=true;
542+
writer.WriteLine("\tstatic final String __md_{0}_methods;",i+1);
557543
}
558544
}
559-
writer.WriteLine("\t}");
545+
546+
if(needCtor){
547+
writer.WriteLine("\tstatic {");
548+
549+
if(HasDynamicallyRegisteredMethods){
550+
GenerateRegisterType(writer,this,"__md_methods");
551+
}
552+
553+
if(children!=null){
554+
for(inti=0;i<children.Count;++i){
555+
stringmethods=string.Format("__md_{0}_methods",i+1);
556+
GenerateRegisterType(writer,children[i],methods);
557+
}
558+
}
559+
writer.WriteLine("\t}");
560+
}
560561

561562
GenerateBody(writer);
562563

@@ -710,16 +711,18 @@ void GenerateBody (TextWriter sw)
710711

711712
voidGenerateRegisterType(TextWritersw,JavaCallableWrapperGeneratorself,stringfield)
712713
{
713-
if(overriddenMethodDescriptors==null){
714-
overriddenMethodDescriptors=newList<OverriddenMethodDescriptor>();
714+
if(!self.HasDynamicallyRegisteredMethods){
715+
return;
715716
}
716717

717718
sw.WriteLine("\t\t{0} = ",field);
718719
stringmanagedTypeName=self.type.GetPartialAssemblyQualifiedName(cache);
719720
stringjavaTypeName=$"{package}.{name}";
721+
720722
foreach(Signaturemethodinself.methods){
721-
sw.WriteLine("\t\t\t\"{0}\\n\" +",method.Method);
722-
overriddenMethodDescriptors.Add(newOverriddenMethodDescriptor(javaTypeName,method.Method,managedTypeName));
723+
if(method.IsDynamicallyRegistered){
724+
sw.WriteLine("\t\t\t\"{0}\\n\" +",method.Method);
725+
}
723726
}
724727
sw.WriteLine("\t\t\t\"\";");
725728
if(CannotRegisterInStaticConstructor(self.type))
@@ -772,12 +775,13 @@ bool CannotRegisterInStaticConstructor (TypeDefinition type)
772775

773776
classSignature{
774777

775-
publicSignature(MethodDefinitionmethod,RegisterAttributeregister):this(method,register,null,null){}
778+
publicSignature(MethodDefinitionmethod,RegisterAttributeregister,boolshouldBeDynamicallyRegistered=true):this(method,register,null,null,shouldBeDynamicallyRegistered){}
776779

777-
publicSignature(MethodDefinitionmethod,RegisterAttributeregister,stringmanagedParameters,stringouterType)
780+
publicSignature(MethodDefinitionmethod,RegisterAttributeregister,stringmanagedParameters,stringouterType,boolshouldBeDynamicallyRegistered=true)
778781
:this(register.Name,register.Signature,register.Connector,managedParameters,outerType,null)
779782
{
780783
Annotations=JavaCallableWrapperGenerator.GetAnnotationsString("\t",method.CustomAttributes);
784+
IsDynamicallyRegistered=shouldBeDynamicallyRegistered;
781785
}
782786

783787
publicSignature(MethodDefinitionmethod,ExportAttributeexport,IMetadataResolvercache)
@@ -880,6 +884,7 @@ public string ThrowsDeclaration {
880884
publicreadonlystringMethod;
881885
publicreadonlyboolIsExport;
882886
publicreadonlyboolIsStatic;
887+
publicreadonlyboolIsDynamicallyRegistered=true;
883888
publicreadonlystring[]ThrownTypeNames;
884889
publicreadonlystringAnnotations;
885890
}

0 commit comments

Comments
 (0)