Remove API adjuster
Context: https://github.com/xamarin/xamarin-android/issues/5580
The current binding workflow with class-parse results in three api.xml files:
- The
class-parseoutput, inapi.xml.class-parse - The "adjusted" output, in
api.xml(viagenerator --only-xml-adjuster --xml-adjuster-output=api.xml) - The "fixed" output, after applying
Metadata.xmltoapi.xml, inapi.xml.fixed.
The problem is (2): it removes types present in (1).
Take for example xamarin/xamarin-android#5580, in which the HttpRequest..serializer type is not bound.
The problem is that it's removed by (2):
Error while processing type '[Class] com.vmware.chameleon.http.HttpRequest..serializer': Type 'kotlinx.serialization.internal.GeneratedSerializer' was not found. (TaskId:36)
and thus is not present in api.xml. Consequently, you can't write Metadata.xml transforms which attempt to reference the type, as the type doesn't exist when Metadata.xml is being processed.
The only workaround here is to use <add-node/> with Metadata.xml, copying the XML fragment from api.xml.class-parse, a'la
<add-node path="//package[@name='com.vmware.chameleon.http']">
<class
abstract="false"
deprecated="deprecated"
jni-extends="Ljava/lang/Object;"
extends="java.lang.Object"
extends-generic-aware="java.lang.Object"
final="true"
name="HttpRequest..serializer"
jni-signature="Lcom/vmware/chameleon/http/HttpRequest$$serializer;"
source-file-name="HttpRequest.kt"
static="true"
visibility="public">
<implements
name="kotlinx.serialization.internal.GeneratedSerializer"
name-generic-aware="kotlinx.serialization.internal.GeneratedSerializer<com.vmware.chameleon.http.HttpRequest>"
jni-type="Lkotlinx/serialization/internal/GeneratedSerializer<Lcom/vmware/chameleon/http/HttpRequest;>;" />
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="childSerializers"
native="false"
return="kotlinx.serialization.KSerializer<?>[]"
jni-return="[Lkotlinx/serialization/KSerializer<*>;"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="()[Lkotlinx/serialization/KSerializer;"
return-not-null="true" />
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="deserialize"
native="false"
return="com.vmware.chameleon.http.HttpRequest"
jni-return="Lcom/vmware/chameleon/http/HttpRequest;"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="(Lkotlinx/serialization/Decoder;)Lcom/vmware/chameleon/http/HttpRequest;"
return-not-null="true">
<parameter
name="decoder"
type="kotlinx.serialization.Decoder"
jni-type="Lkotlinx/serialization/Decoder;"
not-null="true" />
</method>
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="deserialize"
native="false"
return="java.lang.Object"
jni-return="Ljava/lang/Object;"
static="false"
synchronized="false"
visibility="public"
bridge="true"
synthetic="true"
jni-signature="(Lkotlinx/serialization/Decoder;)Ljava/lang/Object;">
<parameter
name="p0"
type="kotlinx.serialization.Decoder"
jni-type="Lkotlinx/serialization/Decoder;" />
</method>
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="getDescriptor"
native="false"
return="kotlinx.serialization.SerialDescriptor"
jni-return="Lkotlinx/serialization/SerialDescriptor;"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="()Lkotlinx/serialization/SerialDescriptor;"
return-not-null="true" />
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="patch"
native="false"
return="com.vmware.chameleon.http.HttpRequest"
jni-return="Lcom/vmware/chameleon/http/HttpRequest;"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="(Lkotlinx/serialization/Decoder;Lcom/vmware/chameleon/http/HttpRequest;)Lcom/vmware/chameleon/http/HttpRequest;"
return-not-null="true">
<parameter
name="this"
type="kotlinx.serialization.Decoder"
jni-type="Lkotlinx/serialization/Decoder;"
not-null="true" />
<parameter
name="decoder"
type="com.vmware.chameleon.http.HttpRequest"
jni-type="Lcom/vmware/chameleon/http/HttpRequest;"
not-null="true" />
</method>
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="patch"
native="false"
return="java.lang.Object"
jni-return="Ljava/lang/Object;"
static="false"
synchronized="false"
visibility="public"
bridge="true"
synthetic="true"
jni-signature="(Lkotlinx/serialization/Decoder;Ljava/lang/Object;)Ljava/lang/Object;">
<parameter
name="p0"
type="kotlinx.serialization.Decoder"
jni-type="Lkotlinx/serialization/Decoder;" />
<parameter
name="p1"
type="java.lang.Object"
jni-type="Ljava/lang/Object;" />
</method>
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="serialize"
native="false"
return="void"
jni-return="V"
static="false"
synchronized="false"
visibility="public"
bridge="false"
synthetic="false"
jni-signature="(Lkotlinx/serialization/Encoder;Lcom/vmware/chameleon/http/HttpRequest;)V">
<parameter
name="encoder"
type="kotlinx.serialization.Encoder"
jni-type="Lkotlinx/serialization/Encoder;"
not-null="true" />
<parameter
name="value"
type="com.vmware.chameleon.http.HttpRequest"
jni-type="Lcom/vmware/chameleon/http/HttpRequest;"
not-null="true" />
</method>
<method
abstract="false"
deprecated="not deprecated"
final="false"
name="serialize"
native="false"
return="void"
jni-return="V"
static="false"
synchronized="false"
visibility="public"
bridge="true"
synthetic="true"
jni-signature="(Lkotlinx/serialization/Encoder;Ljava/lang/Object;)V">
<parameter
name="p0"
type="kotlinx.serialization.Encoder"
jni-type="Lkotlinx/serialization/Encoder;" />
<parameter
name="p1"
type="java.lang.Object"
jni-type="Ljava/lang/Object;" />
</method>
<field
deprecated="not deprecated"
final="true"
name="INSTANCE"
static="true"
synthetic="false"
transient="false"
type="com.vmware.chameleon.http.HttpRequest..serializer"
type-generic-aware="com.vmware.chameleon.http.HttpRequest..serializer"
jni-signature="Lcom/vmware/chameleon/http/HttpRequest$$serializer;"
visibility="public"
volatile="false" />
</class>
</add-node>
Note: in the case of xamarin/xamarin-android#5580, the above <add-node/> does not work, because generator doesn't like .. in the name.
If I manually replace all instances of HttpRequest..serializer with HttpRequest._serializer, a HttpRequest._serializer binding is created. Unfortunately it's not valid, because the register attribute is wrong.
Instead, I can add managedName into the <add-node/> text, and then it works!
<class
abstract="false"
managedName="HttpRequest._Serializer"
…
Something I hadn't considered.
Regardless, generator should do more than "silently fail" when a type name has .. in it.
I just happened to notice the .. issue in generator. Leaving a link here for future me:
https://github.com/xamarin/java.interop/blob/main/tools/generator/Java.Interop.Tools.Generator.ObjectModel/GenBaseSupport.cs#L24-L27
@jpobst when is this planned... we are stuck with are release...
I'm not sure this really explains what the issue is, or what the desired fix is. Resolving all Java types and removing types and members that depend on types we cannot resolve is a needed step in the binding process, lest we create broken bindings.
I think we would need to explore:
- Cases where something is getting removed that shouldn't get removed
- What is the appropriate fix(es) to solve those cases
For example, in this reported case:
Error while processing type '[Class] com.vmware.chameleon.http.HttpRequest..serializer': Type 'kotlinx.serialization.internal.GeneratedSerializer' was not found.
Why is GeneratedSerializer not found? Why do we still want to bind HttpRequest..serializer if it requires the missing GeneratedSerializer?