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

Commit 267c3f3

Browse files
authored
[generator] Support XML defined enums with no JNI info (#659)
Fixes: #515 Our `.csv` format for specifying enums allows creating enum fields that do not map to a JNI field. This is often used to add a `None` enum field to a Java `[Flags]` enum: 0,,0,Android.AccessibilityServices.AccessibilityServiceCapabilities,None However our XML format does not support this because it considers the (`//mapping/@jni-class` or `//mapping/@jni-interface`) and `//mapping/@jni-name` attributes to be mandatory when translating the XML format to `.csv` format. We can remove this restriction and correctly generate the needed `.csv` format so that users using the XML format can add arbitrary enums that `generator` knows about, permitting: <mapping clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'> <field clr-name='Name' value='0' /> <field clr-name='Id' value='1' /> <field clr-name='Tag' value='2' /> </mapping> in addition to the previously required: <mapping jni-interface='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'> <field jni-name='Fragment_name' clr-name='Name' value='0' /> <field jni-name='Fragment_id' clr-name='Id' value='1' /> <field jni-name='Fragment_tag' clr-name='Tag' value='2' /> </mapping>
1 parent 5dcf896 commit 267c3f3

2 files changed

Lines changed: 120 additions & 15 deletions

File tree

‎src/utils/EnumMappings.Xml.cs‎

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,33 @@ internal static TextReader FieldXmlToCsv (string file)
2323
if(file==null)
2424
returnnull;
2525

26+
returnFieldXmlToCsv(XDocument.Load(file,LoadOptions.SetBaseUri|LoadOptions.SetLineInfo));
27+
}
28+
29+
internalstaticTextReaderFieldXmlToCsv(XDocumentdoc)
30+
{
2631
varsw=newStringWriter();
27-
vardoc=XDocument.Load(file,LoadOptions.SetBaseUri|LoadOptions.SetLineInfo);
2832

2933
foreach(vareindoc.XPathSelectElements("/enum-field-mappings/mapping")){
30-
stringenu=GetMandatoryAttribute(e,"clr-enum-type");
31-
stringjni_type=e.Attribute("jni-class")!=null
32-
?e.XGetAttribute("jni-class")
33-
:e.Attribute("jni-interface")!=null
34-
?"I:"+e.XGetAttribute("jni-interface")
35-
:GetMandatoryAttribute(e,"jni-class or jni-interface");
36-
boolbitfield=e.Attribute("bitfield")!=null&&e.XGetAttribute("bitfield")=="true";
34+
35+
varenu=GetMandatoryAttribute(e,"clr-enum-type");
36+
varjni_type=e.XGetAttribute("jni-class")??"I:"+e.XGetAttribute("jni-interface");
37+
38+
// If neither jni was specified leave it blank
39+
if(jni_type=="I:")
40+
jni_type=string.Empty;
41+
42+
varbitfield=e.XGetAttribute("bitfield")=="true";
43+
3744
foreach(varmine.XPathSelectElements("field")){
38-
stringverstr=m.Attribute("api-level")!=null
39-
?m.XGetAttribute("api-level")
40-
:"0";
41-
stringmember=GetMandatoryAttribute(m,"clr-name");
42-
stringjni_name=GetMandatoryAttribute(m,"jni-name");
43-
stringvalue=GetMandatoryAttribute(m,"value");
44-
sw.WriteLine("{0}, {1}, {2}, {3}, {4}{5}",verstr,enu,member,jni_type+'.'+jni_name,value,bitfield?", Flags":null);
45+
varverstr=m.XGetAttribute("api-level")??"0";
46+
varmember=GetMandatoryAttribute(m,"clr-name");
47+
varjni_name=m.XGetAttribute("jni-name");
48+
varvalue=GetMandatoryAttribute(m,"value");
49+
50+
varjni_member=string.IsNullOrWhiteSpace(jni_name)?string.Empty:jni_type+'.'+jni_name;
51+
52+
sw.WriteLine("{0}, {1}, {2}, {3}, {4}{5}",verstr,enu,member,jni_member,value,bitfield?", Flags":null);
4553
}
4654
}
4755

‎tests/generator-Tests/Unit-Tests/EnumMappingsTests.cs‎

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
usingSystem.Linq;
55
usingSystem.Text;
66
usingSystem.Threading.Tasks;
7+
usingSystem.Xml.Linq;
78
usingMonoDroid.Generation;
89
usingNUnit.Framework;
910

@@ -284,5 +285,101 @@ public void TransientEnumificationV2Test ()
284285
Assert.AreEqual("[Cdsect, I:org/xmlpull/v1/XmlPullParser.CDSECT]",enums.First().Value.JniNames.Single().ToString());
285286
Assert.AreEqual("[Cdsect, 5]",enums.First().Value.Members.Single().ToString());
286287
}
288+
289+
[Test]
290+
publicvoidXmlEnumMapWithJNI()
291+
{
292+
varxml=@"<enum-field-mappings>
293+
<mapping jni-class='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType'>
294+
<field jni-name='Fragment_name' clr-name='Name' value='0' />
295+
<field jni-name='Fragment_id' clr-name='Id' value='1' />
296+
<field jni-name='Fragment_tag' clr-name='Tag' value='2' />
297+
</mapping>
298+
</enum-field-mappings>";
299+
300+
vardoc=XDocument.Parse(xml,LoadOptions.SetBaseUri|LoadOptions.SetLineInfo);
301+
varsr=EnumMappings.FieldXmlToCsv(doc);
302+
303+
varlines=sr.ReadToEnd().Split(new[]{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries);
304+
varexpected=new[]{
305+
"0, Android.Support.V4.App.FragmentTagType, Name, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_name, 0",
306+
"0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1",
307+
"0, Android.Support.V4.App.FragmentTagType, Tag, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_tag, 2"
308+
};
309+
310+
Assert.AreEqual(expected,lines);
311+
}
312+
313+
[Test]
314+
publicvoidXmlEnumMapWithInterfaceJNI()
315+
{
316+
varxml=@"<enum-field-mappings>
317+
<mapping jni-interface='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'>
318+
<field jni-name='Fragment_name' clr-name='Name' value='0' />
319+
<field jni-name='Fragment_id' clr-name='Id' value='1' />
320+
<field jni-name='Fragment_tag' clr-name='Tag' value='2' />
321+
</mapping>
322+
</enum-field-mappings>";
323+
324+
vardoc=XDocument.Parse(xml,LoadOptions.SetBaseUri|LoadOptions.SetLineInfo);
325+
varsr=EnumMappings.FieldXmlToCsv(doc);
326+
327+
varlines=sr.ReadToEnd().Split(new[]{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries);
328+
varexpected=new[]{
329+
"0, Android.Support.V4.App.FragmentTagType, Name, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_name, 0, Flags",
330+
"0, Android.Support.V4.App.FragmentTagType, Id, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags",
331+
"0, Android.Support.V4.App.FragmentTagType, Tag, I:android/support/v4/app/FragmentActivity$FragmentTag.Fragment_tag, 2, Flags"
332+
};
333+
334+
Assert.AreEqual(expected,lines);
335+
}
336+
337+
[Test]
338+
publicvoidXmlEnumMapWithoutJNI()
339+
{
340+
varxml=@"<enum-field-mappings>
341+
<mapping clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'>
342+
<field clr-name='Name' value='0' />
343+
<field clr-name='Id' value='1' />
344+
<field clr-name='Tag' value='2' />
345+
</mapping>
346+
</enum-field-mappings>";
347+
348+
vardoc=XDocument.Parse(xml,LoadOptions.SetBaseUri|LoadOptions.SetLineInfo);
349+
varsr=EnumMappings.FieldXmlToCsv(doc);
350+
351+
varlines=sr.ReadToEnd().Split(new[]{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries);
352+
varexpected=new[]{
353+
"0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags",
354+
"0, Android.Support.V4.App.FragmentTagType, Id, , 1, Flags",
355+
"0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags"
356+
};
357+
358+
Assert.AreEqual(expected,lines);
359+
}
360+
361+
[Test]
362+
publicvoidXmlEnumMapWithMixedJNI()
363+
{
364+
varxml=@"<enum-field-mappings>
365+
<mapping jni-class='android/support/v4/app/FragmentActivity$FragmentTag' clr-enum-type='Android.Support.V4.App.FragmentTagType' bitfield='true'>
366+
<field clr-name='Name' value='0' />
367+
<field jni-name='Fragment_id' clr-name='Id' value='1' />
368+
<field clr-name='Tag' value='2' />
369+
</mapping>
370+
</enum-field-mappings>";
371+
372+
vardoc=XDocument.Parse(xml,LoadOptions.SetBaseUri|LoadOptions.SetLineInfo);
373+
varsr=EnumMappings.FieldXmlToCsv(doc);
374+
375+
varlines=sr.ReadToEnd().Split(new[]{Environment.NewLine},StringSplitOptions.RemoveEmptyEntries);
376+
varexpected=new[]{
377+
"0, Android.Support.V4.App.FragmentTagType, Name, , 0, Flags",
378+
"0, Android.Support.V4.App.FragmentTagType, Id, android/support/v4/app/FragmentActivity$FragmentTag.Fragment_id, 1, Flags",
379+
"0, Android.Support.V4.App.FragmentTagType, Tag, , 2, Flags"
380+
};
381+
382+
Assert.AreEqual(expected,lines);
383+
}
287384
}
288385
}

0 commit comments

Comments
 (0)