Skip to content

Commit bc44f08

Browse files
authored
[JavaCallableWrappers] Add XML import/export. (#1317)
Context: dotnet/android#9893 Create XML import/export adapters for Java Callable Wrappers (JCWs). This allows us to serialize the JCWs we find in the new `FindJavaObjectsStep` linker step (dotnet/android#9893) to disk that, and later use that serialized data in `_GenerateJavaStubs`. This file also allows us to cache the assembly scanning to disk so we don't need to rerun it on incremental builds. This format is likely a "work in progress". As we move other `Java.Lang.Object`-related scanning to linker steps we will likely find additional data they require that needs to go into this file, or that this format isn't even suitable and we use something else instead. Sample JCW XML content: <types was_scanned="true"> <type name="MainActivity" package="crc645107ba1b8b6ee4d3" application_java_class="android.app.Application" mono_runtime_initialization="mono.MonoPackageManager.LoadApplication (context);" extends_type="android.app.Activity" partial_assembly_qualified_name="tempbuild.MainActivity, tempbuild"> <constructors> <constructor name="MainActivity" method="n_.ctor:()V:" jni_signature="()V" managed_parameters="" retval="void" is_dynamically_registered="True" /> </constructors> <methods> <method name="clone" method="n_clone:()Ljava/lang/Object;:GetCloneHandler" jni_signature="()Ljava/lang/Object;" retval="java.lang.Object" /> <method name="onCreate" method="n_onCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler" jni_signature="(Landroid/os/Bundle;)V" params="android.os.Bundle p0" retval="void" super_call="p0" activate_call="p0" /> </methods> </type> </types> Most XML attributes correspond to members on `CallableWrapperType`, `CallableWrapperMethod`, etc. The XML file is a *per-assembly* data store; `//types/@was_scanned` specifies whether or not the assembly was scanned for JCWs. If the assembly did not contain JCWs (e.g. `System.Private.CoreLib.dll`), then `was_scanned` will be False.
1 parent c1cd06d commit bc44f08

File tree

3 files changed

+430
-0
lines changed

3 files changed

+430
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Xml;
3+
using System.Xml.Linq;
4+
5+
namespace Java.Interop.Tools.JavaCallableWrappers.Extensions;
6+
7+
static class XmlExtensions
8+
{
9+
public static T GetAttributeOrDefault<T> (this XElement xml, string name, T defaultValue)
10+
{
11+
var value = xml.Attribute (name)?.Value;
12+
13+
if (string.IsNullOrWhiteSpace (value))
14+
return defaultValue;
15+
16+
return (T) Convert.ChangeType (value, typeof (T));
17+
}
18+
19+
public static string GetRequiredAttribute (this XElement xml, string name)
20+
{
21+
var value = xml.Attribute (name)?.Value;
22+
23+
if (string.IsNullOrWhiteSpace (value))
24+
throw new InvalidOperationException ($"Missing required attribute '{name}'");
25+
26+
return value!; // NRT - Guarded by IsNullOrWhiteSpace check above
27+
}
28+
29+
public static void WriteAttributeStringIfNotNull (this XmlWriter xml, string name, string? value)
30+
{
31+
if (value is not null)
32+
xml.WriteAttributeString (name, value);
33+
}
34+
35+
public static void WriteAttributeStringIfNotFalse (this XmlWriter xml, string name, bool value)
36+
{
37+
// If value is false, don't write the attribute, we'll default to false on import
38+
if (value)
39+
xml.WriteAttributeString (name, value.ToString ());
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Xml;
7+
using Java.Interop.Tools.JavaCallableWrappers.CallableWrapperMembers;
8+
using Java.Interop.Tools.JavaCallableWrappers.Extensions;
9+
10+
namespace Java.Interop.Tools.JavaCallableWrappers.Adapters;
11+
12+
public static class XmlExporter
13+
{
14+
static XmlWriterSettings settings = new XmlWriterSettings {
15+
Indent = true,
16+
NewLineOnAttributes = false,
17+
OmitXmlDeclaration = true,
18+
};
19+
20+
public static void Export (string filename, IEnumerable<CallableWrapperType> types, bool wasScanned)
21+
{
22+
using (var sw = new StreamWriter (filename, false, Encoding.UTF8))
23+
Export (sw, types, wasScanned);
24+
}
25+
26+
public static void Export (TextWriter sw, IEnumerable<CallableWrapperType> types, bool wasScanned)
27+
{
28+
using (var xml = XmlWriter.Create (sw, settings))
29+
Export (xml, types, wasScanned);
30+
}
31+
32+
public static void Export (XmlWriter xml, IEnumerable<CallableWrapperType> types, bool wasScanned)
33+
{
34+
ExportTypes (xml, types, wasScanned);
35+
}
36+
37+
static void ExportTypes (XmlWriter xml, IEnumerable<CallableWrapperType> types, bool wasScanned)
38+
{
39+
xml.WriteStartElement ("types");
40+
xml.WriteAttributeString ("was_scanned", wasScanned.ToString ());
41+
42+
foreach (var type in types)
43+
ExportType (xml, type);
44+
45+
xml.WriteEndElement ();
46+
}
47+
48+
public static void ExportType (XmlWriter xml, CallableWrapperType type)
49+
{
50+
xml.WriteStartElement ("type");
51+
xml.WriteAttributeString ("name", type.Name);
52+
xml.WriteAttributeString ("package", type.Package);
53+
xml.WriteAttributeStringIfNotFalse ("is_abstract", type.IsAbstract);
54+
xml.WriteAttributeStringIfNotNull ("application_java_class", type.ApplicationJavaClass);
55+
xml.WriteAttributeStringIfNotFalse ("generate_on_create_overrides", type.GenerateOnCreateOverrides);
56+
xml.WriteAttributeStringIfNotNull ("mono_runtime_initialization", type.MonoRuntimeInitialization);
57+
xml.WriteAttributeStringIfNotNull ("extends_type", type.ExtendsType);
58+
xml.WriteAttributeStringIfNotFalse ("is_application", type.IsApplication);
59+
xml.WriteAttributeStringIfNotFalse ("is_instrumentation", type.IsInstrumentation);
60+
xml.WriteAttributeString ("partial_assembly_qualified_name", type.PartialAssemblyQualifiedName);
61+
xml.WriteAttributeStringIfNotFalse ("has_export", type.HasExport);
62+
63+
if (type.ApplicationConstructor is not null)
64+
xml.WriteAttributeString ("application_constructor", type.ApplicationConstructor.Name);
65+
66+
ExportAnnotations (xml, type.Annotations);
67+
ExportImplementedInterfaces (xml, type.ImplementedInterfaces);
68+
ExportConstructors (xml, type.Constructors);
69+
ExportFields (xml, type.Fields);
70+
ExportMethods (xml, type.Methods);
71+
ExportNestedTypes (xml, type.NestedTypes);
72+
73+
xml.WriteEndElement ();
74+
}
75+
76+
static void ExportAnnotations (XmlWriter writer, IEnumerable<CallableWrapperTypeAnnotation> annotations)
77+
{
78+
if (annotations.Count () == 0)
79+
return;
80+
81+
writer.WriteStartElement ("annotations");
82+
83+
foreach (var annotation in annotations) {
84+
writer.WriteStartElement ("annotation");
85+
writer.WriteAttributeString ("name", annotation.Name);
86+
87+
foreach (var property in annotation.Properties) {
88+
writer.WriteStartElement ("property");
89+
writer.WriteAttributeString ("name", property.Key);
90+
writer.WriteAttributeString ("value", property.Value);
91+
writer.WriteEndElement ();
92+
}
93+
94+
writer.WriteEndElement ();
95+
}
96+
97+
writer.WriteEndElement ();
98+
}
99+
100+
static void ExportImplementedInterfaces (XmlWriter writer, List<string> interfaces)
101+
{
102+
if (interfaces.Count == 0)
103+
return;
104+
105+
writer.WriteStartElement ("implemented_interfaces");
106+
107+
foreach (var @interface in interfaces) {
108+
writer.WriteStartElement ("interface");
109+
writer.WriteAttributeString ("name", @interface);
110+
writer.WriteEndElement ();
111+
}
112+
113+
writer.WriteEndElement ();
114+
}
115+
116+
static void ExportConstructors (XmlWriter xml, IEnumerable<CallableWrapperConstructor> constructors)
117+
{
118+
if (constructors.Count () == 0)
119+
return;
120+
121+
xml.WriteStartElement ("constructors");
122+
123+
foreach (var constructor in constructors)
124+
ExportMethod (xml, constructor);
125+
126+
xml.WriteEndElement ();
127+
}
128+
129+
static void ExportFields (XmlWriter xml, IEnumerable<CallableWrapperField> fields)
130+
{
131+
if (fields.Count () == 0)
132+
return;
133+
134+
xml.WriteStartElement ("fields");
135+
136+
foreach (var field in fields) {
137+
xml.WriteStartElement ("field");
138+
xml.WriteAttributeString ("name", field.FieldName);
139+
xml.WriteAttributeString ("type", field.TypeName);
140+
xml.WriteAttributeString ("visibility", field.Visibility);
141+
xml.WriteAttributeStringIfNotFalse ("is_static", field.IsStatic);
142+
xml.WriteAttributeString ("initializer_name", field.InitializerName);
143+
ExportAnnotations (xml, field.Annotations);
144+
xml.WriteEndElement ();
145+
}
146+
147+
xml.WriteEndElement ();
148+
}
149+
150+
static void ExportMethods (XmlWriter xml, IEnumerable<CallableWrapperMethod> methods)
151+
{
152+
if (methods.Count () == 0)
153+
return;
154+
155+
xml.WriteStartElement ("methods");
156+
157+
foreach (var method in methods)
158+
ExportMethod (xml, method);
159+
160+
xml.WriteEndElement ();
161+
}
162+
163+
static void ExportMethod (XmlWriter xml, CallableWrapperMethod method)
164+
{
165+
xml.WriteStartElement (method is CallableWrapperConstructor ? "constructor" : "method");
166+
xml.WriteAttributeString ("name", method.Name);
167+
xml.WriteAttributeString ("method", method.Method);
168+
xml.WriteAttributeString ("jni_signature", method.JniSignature);
169+
xml.WriteAttributeStringIfNotNull ("managed_parameters", method.ManagedParameters);
170+
xml.WriteAttributeStringIfNotNull ("java_name_override", method.JavaNameOverride);
171+
xml.WriteAttributeStringIfNotNull ("params", method.Params);
172+
xml.WriteAttributeStringIfNotNull ("retval", method.Retval);
173+
xml.WriteAttributeStringIfNotNull ("java_access", method.JavaAccess);
174+
xml.WriteAttributeStringIfNotFalse ("is_export", method.IsExport);
175+
xml.WriteAttributeStringIfNotFalse ("is_static", method.IsStatic);
176+
xml.WriteAttributeStringIfNotFalse ("is_dynamically_registered", method.IsDynamicallyRegistered);
177+
xml.WriteAttributeStringIfNotNull ("thrown_type_names", method.ThrownTypeNames != null ? string.Join (", ", method.ThrownTypeNames) : null);
178+
xml.WriteAttributeStringIfNotNull ("super_call", method.SuperCall);
179+
xml.WriteAttributeStringIfNotNull ("activate_call", method.ActivateCall);
180+
181+
ExportAnnotations (xml, method.Annotations);
182+
183+
xml.WriteEndElement ();
184+
}
185+
186+
static void ExportNestedTypes (XmlWriter xml, IEnumerable<CallableWrapperType> nestedTypes)
187+
{
188+
if (nestedTypes.Count () == 0)
189+
return;
190+
191+
xml.WriteStartElement ("nested_types");
192+
193+
foreach (var nestedType in nestedTypes)
194+
ExportType (xml, nestedType);
195+
196+
xml.WriteEndElement ();
197+
}
198+
}

0 commit comments

Comments
 (0)