views:

640

answers:

4

I'm working on a small Java project that now connects to a MS SQL Server 2000 database, but will be shortly connecting to MS SQL Server 2005 database. I'm creating a single jar for ease of deployment. I was trying to set it up so I could just change a configuration file and change drivers (as I would in .NET). However, because of the limitations of Java's Jar embedded classpath, and the lack of the wildcard character on the embedded classpath(1). Is there any way to get around this problem without referencing every driver jar explicitly? If I have to do that I'll have to recompile every time the database changes ...

(1): However, class path wildcards are not honored in the Class-Path jar-manifest header.

A: 

You could include the information about which driver to use in e.g. a config file. Or in the manifest of the JAR file itself. Simply include all JAR files when starting your application but load the driver’s name from the configuration.

Bombe
A: 

I would say that it is not the Java way (as in the standard practice) to include third party code in the same Jar as you are deploying. However a jar is just a zip file, so in most cases (excepting some fancy stuff going on in the manifests) you can combine them, if you need to.

That being said, you can include in your jar file a classpath reference to all potential JDBC driver jars, or simply call the JDBC driver jar the right way. Then have a configuration file in the same directory (be sure to include . in your JAR's classpath) and then read the driver name from that, and use Class.forName() to load the driver.

You can do fancier things (like find the right jar at runtime and dynamically load it even though it wasn't on the classpath) but those things are a bit complicated, so something simple like the above should work.

You should never have to recompile. You aren't really doing JDBC right if you have to recompile when you change drivers.

Yishai
Can I do Class.ForName() on a class that's in a Jar that's not on my ClassPath? If not, then I'm still limited to the Jars that are specifically listed on the classpath, and still have to recompile (re-jar?) when a new driver jar comes out.
C. Ross
The Class.forName has to be on the classpath runtime. No need to recompile. When a new jar comes out, you just replace the file, no need to recompile.
Yishai
Microsoft has a wonderful habit of naming their driver jar files differently.
C. Ross
You can always rename it.
Yishai
A: 

You have to seperate the driver jar file and the actual name of the JDBC driver for the particular provider.

I would really encourage to not to include jdbc driver jars in your own jar. Just at them to the path at runtime. Similarly you can get the name of the JDBC driver manager from the system properties during runtime, or even a config file.

So running app like this:

java -jar myapp.jar -cp sqlserver.jar -DdriverManager=com.microsoft.sqlserver.jdbc.SQLServerDriver -DdbUrl=jdbc:some:url

and in your application, do something like this (I leave out exception handling):

Class.forName(System.getProperty("driverManager"));
Connection conn = DriverManager.getConnection(System.getProperty("dbUrl"))

;

This way you can change drivers simply by adding appropriate jar file to the classpath and changing the driverManager and dbUrl properties. This way you don't have to recompile to support new drivers.

That's the simplest solution that I can think of.

krzyk
Can I do Class.ForName() on a class that's in a Jar that's not on my ClassPath? If not, then I'm still limited to the Jars that are specifically listed on the classpath, and still have to recompile (re-jar?) when a new driver jar comes out.
C. Ross
In Class.forName() you provide a string, so you can put there anything you want, and catch exception to see if something was found.BUT. Why do you want to hardcode Class.forName() ? The above solution provided allows you to change it at runtime, so this way your application can support any database, as long as the correct driverManager and db url is provided (and a jar with database driver is in classpath).
krzyk
+1  A: 

Generally, you can modify the classpath at runtime. Approaches like this are the general way to deal with "plugin" type jars in Java (very similar requirements to your case).

jsight