David Gregory
08/07/2023, 9:30 AMdata field that is used for language- or runtime-specific data.
/** Language-specific metadata about this target.
* See ScalaBuildTarget as an example. */
data?: BuildTargetData;
This language-specific data can be absolutely anything, i.e. in the spec it's defined like this:
export type BuildTargetData = any;
As a result, my tooling model defines this field like so:
Serializable data();
Unfortunately, this poses a problem for me at the client side of the Tooling API interface, because now I need to perform casts to handle certain cases.
It seems that the tooling models are loaded into a custom classloader somewhere within the Tooling API client implementation, and this means that if I do instanceof somewhere in my own code, then my models are not instanceof their own class at the client side of the connection, and can't be cast to their interface type.
This is because the model I receive from the tooling API is loaded in one classloader, and the (identical) class that I'm casting it to was loaded separately in my app's classloader, causing them to be unrelated from the JVM's perspective.
The instanceof part is not such a big deal, because the spec also gives me a dataKind field to allow me to figure out what I've been given, but being unable to cast to the correct type is really painful and all of the workarounds I have seen (reflection, serialize-then-deserialize, etc...) seem either fragile or painful to implement.
Is this an expected aspect of using the Tooling API? Has anyone found a workaround for this other than using reflection? Should I be doing something different with classloaders to mitigate this? Perhaps there is a way to make sure that my app classloader and the tooling client classloader are in the same hierarchy?