ClassNotFoundException is thrown when code explicitly asks for a class by its name string, through Class.forName(...), a framework's configuration, or a driver manager, and the class loader cannot find it. The overwhelmingly common case is a JDBC driver: Class.forName("com.mysql.cj.jdbc.Driver") or a datasource configuration naming a driver whose jar was never added to the project. The class name in the message, character for character, is the first thing to verify.
com.mysql.cj.jdbc.Driver in Connector/J 8, the old com.mysql.jdbc.Driver belongs to version 5. A name copied from an old tutorial into a new project fails exactly like this.mvn dependency:tree, Gradle's dependencies report, or inspect the deployed lib folder) and find the artifact that contains the class.Class.forName is often unnecessary, and removing the call plus having the jar present is enough. If it still fails, the jar truly is absent.jar tf driver.jar | grep Driver) to see the real path.How is this different from NoClassDefFoundError? This exception is thrown by an explicit by-name lookup and is checked, the calling code must handle it. NoClassDefFoundError is raised by the JVM itself when compiled code references a class that cannot load. The missing jar is often the same; the doorway differs.
The driver worked before I upgraded the database connector, why now? The upgrade renamed the driver class (MySQL's move from com.mysql.jdbc.Driver to com.mysql.cj.jdbc.Driver is the famous case). Update the configured name to match the new jar.
Do I still need Class.forName for JDBC? Usually not with current drivers, which auto-register. The call survives in old code and tutorials. Its failure is still useful: it proves the jar is missing or the name is wrong before any connection is attempted.