1

I am very new to java and on a steep learning curve. I have a legacy ColdFusion 10 application and I am wanting to incrementally use Java classes instead of ColdFusion CFCs as a way to migrate out of CF land. I can get all that to work for the classes I have written so far.

I am now up to the point of testing how to interact with the mySql database using the same java connector that CF is using (mysql-connector-java-commercial-5.1.25-bin.jar in this case, as used on my localhost dev machine).

For the sake of simplicity for the test, both my test class and the connector jar are in the same folder (Windows machine).

The issue is with this statement: Class.forName("com.mysql.jdbc.Driver"); - I am getting Exception in thread "main" java.lang.ClassNotFoundException: com.mysql.jdbc.Driver.

Now, if I unzip the connector jar so the folders are present in my test folder: com\mysql\jdbc\Driver.class (as well as all the other files that were in the jar), my test class works fine and records are being inserted into my db table. Cool!

But, if I remove the actual folders and depend upon the jar itself, that is when I get the ClassNotFoundException.

In my other learning / tests (with my self generated jar files) a relevant class is being pulled from the jar as it should. But with this specific jar for this mysql test it is not.

What should I be looking out for - clearly I have missed something?

Thanks. I am really looking forward to moving into Java land. :-)

Murray

leonheess
  • 16,068
  • 14
  • 77
  • 112
Murrah
  • 1,508
  • 1
  • 13
  • 26
  • Are you writing a plain-vanilla Java app, or a web app using JSPs or Servlets or such? That is, are you using servlet container such as Jetty or Tomcat or Glassfish? – Basil Bourque Nov 18 '20 at 04:08
  • Thanks. Plain vanilla. No dependencies. Basically a proof-of-concept (as much for my programming skills as anything else;-) ) – Murrah Nov 18 '20 at 04:25
  • 1
    Using `Class.forName` to load JDBC drivers has been obsolete since the release of Java 6 in 2006. Additionally, use Maven or Gradle; this is their job. – chrylis -cautiouslyoptimistic- Nov 18 '20 at 04:44
  • Yep. That's the version I need to use for now. See my comment below. Thanks. – Murrah Nov 18 '20 at 05:02

3 Answers3

2

It's not enough to have the JAR file in your current directory. You have to tell java to include the mysql jar file in the classpath. This can be done by either specifying it on the java command line with the -cp parameter, or by the CLASSPATH environment variable.

schtever
  • 3,210
  • 16
  • 25
  • Thanks. I did see other answers like that but could not make it work. When running with folder structure (not jar), I do this: `C:\mypath\JavaTest\mySqlTest>java MySQLAccessMain` which works. I tried using `java -classpath etc` but obviously got the syntax wrong. So, how should it be, please? `C:\mypath\JavaTest\mySqlTest>java -classpath mysql-connector-java-commercial-5.1.25-bin.jar MySQLAccessMain` throws `Error: Could not find or load main class MySQLAccessMain` and my various attempts to get the path right all fail. :-( – Murrah Nov 18 '20 at 04:34
  • Use `java -classpath .;mysql-connector-java-commercial-5.1.25-bin.jar MySQLAccessMain`. The ".;" at the start tells java also search the current directory for `.class` files, which is where it will find `MySQLAccessMain`. – schtever Nov 18 '20 at 04:42
  • That's it! Thank you so much! I will post the full answer below for other CF refugees. ;-) – Murrah Nov 18 '20 at 04:47
  • Actually, this is really just a "Java 101" problem: how to add an external library to the runtime classpath. – Stephen C Nov 18 '20 at 04:54
  • Yes, I am sure, and I am only 2 days in so am at Java 100 , I reckon. ;-) Made more complicated by working out how to do it in a ColdFusion environment. Thanks! – Murrah Nov 18 '20 at 05:01
1

I use Postgres & H2 rather than MySQL. So I do not know for sure what your problem may be with regard to MySQL. But I was able to just now create a new project with your MySQL driver made available at runtime. Read on to follow my example.

Maven-driven project example

Java projects nowadays are commonly managed by a dependency management and build automation tool such as Maven, Gradle, or Ivy.

I started a new Java project using the Maven Quickstart Archetype.

In the POM file provided by that archetype, I made two changes:

  • Changed the <maven.compiler.source> & <maven.compiler.target> from 1.7 to 11 to use Java 11, the current long-term support version.
  • Added a dependency for what seemed close to the JDBC driver you mentioned:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>

Then I added a line to the App class’ main method.

        try
        {
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("Found class for JDBC driver.");
        }
        catch ( ClassNotFoundException e )
        {
            e.printStackTrace();
        }
        System.out.println( "Hello World!" );

When I ran this, no exception was thrown. So the class seemed to be found successfully.

Complete POM:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns = "http://maven.apache.org/POM/4.0.0"
         xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>work.basil.example</groupId>
    <artifactId>jdbc-driver-in-jar</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>jdbc-driver-in-jar</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>


    </dependencies>

    <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Complete app class:

package work.basil.example;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        try
        {
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("Found class for JDBC driver.");
        }
        catch ( ClassNotFoundException e )
        {
            e.printStackTrace();
        }
        System.out.println( "Hello World!" );
    }
}

Some notes:

I noticed in the console output saying that particular JDBC driver is obsolete. You should investigate proper JDBC driver to be using nowadays.

Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

Class.forName is the old-school way to load a JDBC driver, and is no longer needed. JDBC driver loading was much improved some years back. Today’s JDBC drivers are loaded via Java’s Service Provider Interface (SPI) facility. But that Class.forName code may still be useful for exploring this problem of yours, to verify the class can be found on your classpath.

Generally best to use a DataSource for getting database connections. Your JDBC driver likely offers an implementation of DataSource. This class will hold the info needed to make a connection to the database server, such as address to find the database server, and a username and password to authenticate with the database server.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Wow! Thanks Basil for your detailed answer. The reason I am using legacy mysql connector is my ColdFusion host company only offer CF10 and Java 1.6. There are a very large number of CFC files and I cannot afford to convert them all to Java at once. With CF being built on Java it is possible to mix-and-match CF and Java so my idea was to work with what I have (Java 1.6) and incrementally convert the business logic to Java classes until I get to the point of abandoning CF altogether and doing it all with Java. At that point I can move up to contemporary tooling. :-) – Murrah Nov 18 '20 at 04:41
  • @Murrah By the way, I enjoy using http://www.Vaadin.com/ for building web apps in pure Java on the server-side, to automatically render the UI in standard web technologies (HTML, CSS, JavaScript) on the client side. – Basil Bourque Nov 18 '20 at 17:11
  • Thanks, I will check that out – Murrah Nov 18 '20 at 19:01
1

Ok. Thanks for all your fast, helpful and interesting input! :-)

Two things:

  1. The run using java answer from @schtever works: java -classpath .;mysql-connector-java-commercial-5.1.25-bin.jar MySQLAccessMain. I did not know about the .; syntax. Thank you.

  2. Since I will be ultimately executing the class within the ColdFusion context (for now, at least) the following CFM works because, of course, ColdFusion handles the classpath to its pile of jars.

This is the java test class

public class MySQLAccessMain {
  public static void main(String[] args) throws Exception {
    MySQLAccess dao = new MySQLAccess();
    dao.readDataBase(); // Run some fixed SELECT and INSERT tests
  }
}

This is the CFM version

var dao = createObject("java","MySQLAccess");
dao.readDataBase();

and of course in application.cfc:

this.javaSettings = {
    loadPaths: [
        "/myjava"  // Where MySQLAccess.class goes
    ]
    ,loadColdFusionClassPath: true // If this is true you can also use the coldfusion builtin java classes
    ,reloadOnChange = true
    ,watchInterval = 2
};

:-) Happy camper! Thanks again.

Murrah
  • 1,508
  • 1
  • 13
  • 26
  • One final comment - that semicolon is platform dependent. On *nix systems, it's a colon. Also, can I ask that you accept my answer? Thanks! – schtever Nov 18 '20 at 16:38
  • Thanks again. Done. Sorry, I thought I had accepted. Much appreciated. – Murrah Nov 18 '20 at 18:52