We pass `null` for the class name here:

https://github.com/elastic/elasticsearch/blob/f086dd18ddc705bf84a1ff99d35196ec2498fd52/server/src/main/java/org/elasticsearch/plugins/PluginDescriptor.java#L261

However the class name is mandatory for the transport protocol today:

https://github.com/elastic/elasticsearch/blob/f086dd18ddc705bf84a1ff99d35196ec2498fd52/server/src/main/java/org/elasticsearch/plugins/PluginDescriptor.java#L156

This prevents various APIs from working in a cluster with stable plugins installed.
server/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java
});
        assertThat(
            e,
            hasToString(
                containsString(
                    "failed to create extension ["
                        + ThrowingConstructorExtension.class.getName()
                        + "] of type ["
                        + TestExtensionPoint.class.getName()
                        + "]"
                )
            )
        );
        assertThat(e.getCause(), instanceOf(InvocationTargetException.class));
        assertThat(e.getCause().getCause(), instanceOf(IllegalArgumentException.class));
        assertThat(e.getCause().getCause(), hasToString(containsString("test constructor failure")));
    }
    private URLClassLoader buildTestProviderPlugin(String name) throws Exception {
        Map<String, CharSequence> sources = Map.of("r.FooPlugin", """
            package r;
            import org.elasticsearch.plugins.ActionPlugin;
            import org.elasticsearch.plugins.Plugin;
            public final class FooPlugin extends Plugin implements ActionPlugin { }
            """, "r.FooTestService", Strings.format("""
            package r;
            import org.elasticsearch.plugins.spi.TestService;
            public final class FooTestService implements TestService {
                @Override
                public String name() {
                    return "%s";