Repository navigation
[Bug] ServiceConfigBase.checkRef throws NullPointerException instead of reporting the unimplemented interface #16493
Description
Pre-check
- I am sure that all the content I provide is in English.
Search before asking
- I had searched in the issues and found no similar issues.
Apache Dubbo Component
Java SDK (apache/dubbo)
Dubbo Version
Dubbo Java 3.3.6, OpenJDK 21 (Amazon Corretto 21.0.5), macOS 15.6 (OS-independent)
Steps to reproduce this issue
ServiceConfigBase.checkRef reports a service whose ref does not implement the declared
interface. Its message is built by getClassDesc, which dereferences Class#getClassLoader():
private String getClassDesc(Class clazz) {
ClassLoader classLoader = clazz.getClassLoader();
return clazz.getName() + "[classloader=" + classLoader.getClass().getName() + "@"
+ classLoader.hashCode() + "]";
}Class#getClassLoader() returns null for any bootstrap-loaded class, i.e. every JDK type. So
when a JDK type is on either side of the mismatch, the check throws NullPointerException from
inside its own diagnostic and the real misconfiguration is never reported.
Export a service whose declared interface is a JDK type that the ref does not implement. This is a
complete main, with a dubbo dependency and nothing else — no registry or other infrastructure:
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
public class JavaRepro {
public static void main(String[] args) {
ServiceConfig<Object> service = new ServiceConfig<>();
service.setInterface(Runnable.class); // GreeterServiceImpl does not implement Runnable
service.setRef(new GreeterServiceImpl());
DubboBootstrap.newInstance()
.application(new ApplicationConfig("java-repro"))
.registry(new RegistryConfig("N/A"))
.protocol(new ProtocolConfig("dubbo", 20896))
.service(service)
.start();
}
}Result on 3.3.6:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "classLoader" is null
at org.apache.dubbo.config.ServiceConfigBase.getClassDesc(ServiceConfigBase.java:162)
at org.apache.dubbo.config.ServiceConfigBase.checkRef(ServiceConfigBase.java:156)
at org.apache.dubbo.config.ServiceConfig.checkAndUpdateSubConfigs(ServiceConfig.java:508)
at org.apache.dubbo.config.ServiceConfig.postProcessRefresh(ServiceConfig.java:549)
at org.apache.dubbo.config.AbstractConfig.refresh(AbstractConfig.java:734)
...
at org.apache.dubbo.config.bootstrap.DubboBootstrap.start(DubboBootstrap.java:219)
Note it surfaces during application start, several frames from the config that caused it, with
nothing naming the service or the interface.
Substituting a user-defined wrong interface reports correctly, because its loader is non-null:
java.lang.IllegalStateException: The class ergo.GreeterServiceImpl[classloader=jdk.internal.loader.ClassLoaders$AppClassLoader@746933701]
unimplemented interface ergo.UnrelatedService[classloader=jdk.internal.loader.ClassLoaders$AppClassLoader@746933701]!
That contrast is what narrows the bug to a JDK type being on either side.
What you expected to happen
checkRef should report the misconfiguration it was written to report, regardless of which loader
the classes came from:
The class ergo.GreeterServiceImpl[classloader=jdk.internal.loader.ClassLoaders$AppClassLoader@746933701]
unimplemented interface java.lang.Runnable[classloader=bootstrap]!
That is what a local build of the fix produces for the same main.
Anything else
I kinda added new term bootstrap to the API, so user may be surprised by that. I think if you have a better name, it could be replaced (I was about no-classloader or just default)
Do you have a (mini) reproduction demo?
- Yes, I have a minimal reproduction demo to help resolve this issue more effectively!
Are you willing to submit a pull request to fix on your own?
- Yes I am willing to submit a pull request on my own!
Code of Conduct
- I agree to follow this project's Code of Conduct
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity
LI123456mo commentedon Oct 7, 2026
What about no-classloader? I think it's a bit more self-explanatory than bootstrap for someone who doesn't already know that term — it directly says "there's no classloader object here" rather than requiring the reader to know what 'bootstrap classloader' means.