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.
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).
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.
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.
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.
Related
My goal here is to eventually develop an installation for Windows, OSX and Linux distributions that will register a custom JDBC driver on the customer's computers, so that they can use it when they are using their favourite SQL tool.
I know some of the tools provide you with a way to manually add a jar, but I was wondering if there is an official way of registering a JDBC driver in each of the operation systems.
You don't register a JDBC driver in the operating system, you need to put it on the class path of the application that needs to use the driver.
The CLASSPATH environment variable is ignored by most non-trivial Java applications.
Before Java 9, you could try to put the driver in the lib/ext folder of the Java installation. But this is a very bad idea (eg conflicting dependencies with specific application requirements, etc), and it has been deprecated in Java 8 and removed in Java 9.
How an application configures its class path depends very much on the application: some only use a specific set of jar files and you can't add others, other applications will scan a folder in their application for jar files (so dropping the jar file into that folder will be enough), or require a configuration or launcher file to be changed to add the specific jar file to their class path.
This means that there is no general way to do it.
If you are talking about the automatic driver loading mechanism of JDBC, then look at the documentation of java.sql.DriverManager, specifically about the META-INF/services/java.sql.Driver file. This still requires that the jar file of the driver is properly added to the class path of the application.
A little while ago I asked a question about a no driver error. I was able to figure it out by adding the C:\Program Files\Java\jdk1.8.0_112\db\lib directory to my eclipse project manually. I'm just wondering why it does. Especially when it seems like all of the other jar files in JDK 8 run automatically. Maybe.
First, you are correct that you need to add the Driver JAR file to your classpath. The Oracle documentation for JavaDB says so: see http://docs.oracle.com/javadb/10.10.1.2/getstart/twwdactivity4.html for example.
Why? Well this is conjecture, but suppose that you wanted to run a Java program that talked to a MySQL database. If the JAR files containing the Derby drivers were added to the JVM's bootstrap classpath automatically, then the Derby Driver classes would typically be loaded (by the DriverManager framework), even though it is only the MySQL Driver class that you want to use. Many people would consider loading unwanted drivers to be a defect ... if the JVM did that.
I'm trying to make an servlets application with java and oracle10g and I've had it well so far until I need some specific values from some the database, for wich I have a DAO class that handles the connection for retrieving data. I have the following issue.
First off, I excecute a main() method in this class that is suposed to retrieve all entries in some table an print the name of each one in console. I works perfectly.
then I want to return an ArrayList of all those names in order to use them in the servlet. So I make a method just like the one in the main() with the only difference that instead of printing the names, I add each one to an ArrayList which is returned after closing the conection. Well, It gets ClassNotFoundException in the line Class.forName("oracle.jdbc.driver.OracleDriver")
If it helps, I'm guided with this tutorial to connect java applications to oracle databases.
Any help would be appreciated
Put ojdbc14.jar inside your war file at WEB-INF/lib/ directory. You can use ANT task to do this. If you are unfamiliar with ANT, you can just copy the jar file inside WEB-INF/lib/ directory under your project and just zip it using Windows explorer or WinZip or anything else that works for you. Then rename the .zip file to .war and deploy on Tomcat server.
If you want some quick fix just copy the ojdbc jar file to server/lib directory under tomcat and restart tomcat. It should work.
EDIT: refer the comment below. While personally I have not seen any unexpected behavior with JDBC drivers in web-app classloader, but, it is recommended to keep driver jars under Server lib.
in my Java project I am using an H2 in-memory database, for which I have to load the JDBC driver when I initialize my application. I want/need to load the H2 .jar file dynamically, so I do the following:
String classname = "org.h2.Driver";
URL u = new URL("jar:file:libs/h2.jar!/");
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Driver d = (Driver) Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverShim(d));
When I put the H2 .jar file into a "libs" folder outside my Java source code folder (that is, in Eclipse, this "libs" directory is on the same level as the "src" folder), then this approach works fine. However, unfortunately I have to put this H2 .jar file into a folder within the source code folder tree, but below the main class folder.
For example, my Java package structure looks like this in Eclipse:
<project>/src/my/app/MyApp.java // main class of my application
<project>/src/my/app/sub/package/h2.jar // how to access this?
<project>/libs/h2.jar // loading from here works
I know this is stupid, but unfortunately I have to work with this strange setup. But what I don't know: how can I edit my Java code (listed above) in order to work with this setup?
EDIT: This has to work outside Eclipse as well, so adding the JAR file to the Java Build Path in Eclipse is no option for me.
EDIT2: I already tried to load "jar:file:my/app/sub/package/h2.jar!/", but that did not work for me.
Thanks in advance for all helpful ideas!
Kind regards, Matthias
In some frameworks referring to files inside JARs can be done using the classpath: prefix. I doubt URLClassLoader supports it natively, but it's worth a try (e.g. classpath:/my/app/sub/package/h2.jar). But since that doesn't work with URLClassLoader, here are other ways:
One way to do it would be to write your own ClassLoader which reads the JAR file from classpath (using getResourceAsStream), uncompresses it (using ZipInputStream) to memory (e.g. a map of byte arrays) and loads the classes from there.
Another, slightly easier way, is to read the JAR file from classpath and write it into a temporary file. Then you can use the plain URLClassLoader to load classes from it. This has the disadvantage that the file must be written to a file and the file probably cannot be removed until the JVM exits (unless using Java 7 or higher).
I'm using the second approach (copying to a temp file) in one project, though I'm using it to launch an external process. I would be curious to hear why you have such a requirement. If it's just a matter of having the whole application in one JAR, there are numerous simpler methods for achieving that (Maven Assembly Plugin, Maven Shade Plugin, Jar Jar Links, One-JAR to name a few).
No it's not a homework, but an online build system that uses my classes under my/app/* and several other classes (not from me) to automatically build the whole solution. Anyway, I can't give you more details on the internals of this system, as I don't know them. As said, I simply have to live with it, and that is why I am asking here...
Sounds like you are working in a WTF environment (does it have a name?), so here are some ways to start hacking around it:
Find out more about your environment, especially absolute file paths of the following: directory where the source files are saved, directory where the generated .class files are saved, and the current working directory when the program is run.
If you can get any kind of output of what your program prints during runtime, you can put into your application some debug code where you use File.listFiles() to crawl the machine's directory trees. If you can get output only from what happens when compiling, it might be possible to execute your own code during compile by creating your own annotation processor (apt is part of javac since Java 6), though I'm not sure whether the annotation processor must be compiled first separately.
The working directory can be read from the user.dir system property and the location of class files can be probably gotten from the java.class.path system property (unless custom class loaders are used). There is no guarantee that a JAR file in the source directory would be copied to the classpath, so you might need to do some looking around.
Then when you know the file path of the JAR file, then you can get an URL to it using new File("path/to/h2.jar").toURI().toURL() which you can then pass to URLClassLoader.
If nothing else works, upload the source code of the libraries and compile them together with your project.
In the long run, try to replace the WTF build environment with one that uses a standard build tool (such as Maven) and a common CI server (such as Jenkins). It's normal for projects to have lots of library dependencies, so you shouldn't need to hack around a build environment to use them.
Ok I am on Win Vista and correctly set my MAVEN_HOME, JAVA_HOME stuff. but I do not have a class path yet. I have also installed MySQL. now I have opened a Hibernate book and at the very first pages it says "make sure the jdbc driver is in your classpath" . I have also downloaded some Zip file that is ConnectorJ or some name like that which is basically the mySql driver for java... but my problem for now is this sentence that I have no clue how to do it: "make sure the jdbc driver is in your classpath"
would you please help me about this classpath thing?
thanks
Here is a good tutorial regarding, setting the class path. Further you might like to read Managing the Java classpath (Windows).
Having said that, you should not set the classpath for your driver in Windows environment variable. Instead, you should include that driver jar inside your IDE under project properties. But I noticed that you are actually using Maven. In this case you should look for the driver under Maven in order to fulfil that dependency. Maven will download the driver jar, if doesn't exist, and make it local.
In case, you are not using any IDE, then you can create a lib directory and tell the compiler that all required jars are in there, at the time of compilation/execution. You can find HOW, in the former link given above.
Since you are using Maven, you just need to put the JDBC driver as a dependency in your pom.xml file. Maven will add it to the classpath whenever it compiles/runs your application.
What you do when deploying your application is dependent on the technologies in use.
If it's a command line application create a %CLASSPATH% variable or add the path to the jdbc.jar file using the java -cp {path\to\jdbc.jar} option.
If it's a web application, you'll need to package the driver jar in your .war/.ear/.sar (the maven assembly plugin can do this) or include it in the ./lib folder of the application container and declare it as scope=provided in maven.
Steps to setup JDBC for Eclipse projects
Download JDBC zip archive from
https://dev.mysql.com/downloads/connector/j/5.0.html
Extract the file and copy the executable jar file to program files->Java->jdk->bin
Right click on the project and select Buildpath->Add external archives->(Jar file)
Compile the program
you can directly connect database by following steps:
1) download mysql-connector-java 5.0.8 and extract the files.
2) then place the folder in program files.
3) then simply add this library on your project by right clicking on it.
4) and here you go. Run your app with db connectivity.