jd-opensource/joyagent-jdgenie · error · JdbcBizException

JdbcDialectFactory无实现类

Error message

JdbcDialectFactory无实现类

What it means

JdbcDialectLoader.load() resolves a JdbcDialect for a JDBC URL via SPI. It first discovers all JdbcDialectFactory implementations through ServiceLoader; if none are found on the classpath it throws this JdbcBizException, meaning no dialect provider is registered at all.

Solutions

  1. Add the dialect provider dependency (the jar containing JdbcDialectFactory implementations and its META-INF/services/com.jd.genie.data.jdbc.dialect.JdbcDialectFactory file) to the classpath
  2. Verify the shaded/fat jar includes META-INF/services entries (check with jar tf or unzip -l) and re-enable service-file merging in the shade plugin (ServicesResourceTransformer)
  3. Ensure the context ClassLoader is set correctly (Thread.currentThread().setContextClassLoader) in plugin/classloader-isolated environments
  4. Check ServiceLoader registration file exists with the fully-qualified implementation class name

Example fix

// before (pom.xml missing dialect module)
<dependencies>
  <dependency>com.jd.genie:genie-data-core</dependency>
</dependencies>
// after
<dependencies>
  <dependency>com.jd.genie:genie-data-core</dependency>
  <dependency>com.jd.genie:genie-data-jdbc-mysql</dependency>
</dependencies>
Defensive patterns

Strategy: try-catch

Validate before calling

List<JdbcDialectFactory> factories = ServiceLoader.load(JdbcDialectFactory.class,
    Thread.currentThread().getContextClassLoader()).stream().toList();
if (factories.isEmpty()) throw new IllegalStateException("No JdbcDialectFactory on classpath");

Type guard

boolean hasDialectFactory() {
    return ServiceLoader.load(JdbcDialectFactory.class,
        Thread.currentThread().getContextClassLoader()).iterator().hasNext();
}

Try / catch

try {
    JdbcDialect dialect = JdbcDialectLoader.load(url);
} catch (JdbcBizException e) {
    log.error("No JdbcDialectFactory registered; check dialect dependency and META-INF/services", e);
    throw new IllegalStateException("Dialect provider missing on classpath", e);
}

Prevention

When it happens

Trigger: Calling JdbcDialectLoader.load(url) (directly or via JdbcConnectionFactory/data-source creation) when the classpath contains no JdbcDialectFactory implementation — i.e. no META-INF/services file registering one and no dialect jar dependency.

Common situations: Missing the JDBC/dialect module dependency in the build; shade/plugin fat-jar that strips META-INF/services entries; custom ServiceLoader-unaware classloader (e.g. plugin sandbox) that cannot see the provider; running with a stripped classpath.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of jd-opensource/joyagent-jdgenie@2417e0b8b6 (2026-09-08). Data as JSON: /api/errors/bc6fb4b82e5a4f0a. Report an issue: GitHub.

Appendix: source

Thrown at genie-backend/src/main/java/com/jd/genie/data/jdbc/dialect/JdbcDialectLoader.java:23

import java.util.LinkedList;
import java.util.List;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;

@Slf4j
public final class JdbcDialectLoader {

    private JdbcDialectLoader() {
    }


    public static JdbcDialect load(String url) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        List<JdbcDialectFactory> foundFactories = discoverFactories(cl);

        if (foundFactories.isEmpty()) {
            throw new JdbcBizException("JdbcDialectFactory无实现类");
        }

        final List<JdbcDialectFactory> matchingFactories =
                foundFactories.stream().filter(f -> f.acceptsURL(url)).toList();

        if (matchingFactories.isEmpty()) {
            throw new JdbcBizException(String.format("未找到支持%s的JdbcDialectFactory实现类", url));
        }

        return matchingFactories.get(0).create();
    }

    private static List<JdbcDialectFactory> discoverFactories(ClassLoader classLoader) {
        try {
            final List<JdbcDialectFactory> result = new LinkedList<>();
            ServiceLoader.load(JdbcDialectFactory.class, classLoader)
                    .iterator()
                    .forEachRemaining(result::add);

View on GitHub (pinned to 2417e0b8b6)