J2SE interfaces specifications and implementations of those interfaces - java

I was looking at rt.jar for some reasons and there i saw some packages like java.sql.* among others.
In a typical jdbc program we write (for Connection class, for example):
import java.sql.Connection;
As per the docs, java.sql.Connection is interface, not concrete implementation, and java.sql.Connection is in rt.jar.
When we write jdbc program, we need jdbc drivers, and from what i read jdbc drivers implement interfaces (e.g. java.sql.Connection).
So when we write in typical java program: (and load the jdbc drivers)
import java.sql.Connection;
--> does java.sql.Connection come from rt.jar or from the driver classes.
From what i guess, in this case java.sql.Connection has to come from rt.jar (as interface), and actual implementation comes from driver classes.
If my assumption is correct, in general do we need to include the jar's which have interface definitions in order to include the import.
For example, consider this situation:
package com.vipin.myinterface;
public interface Interface1 {
public void print();
}
And if we package above interface as interface1.jar.
Suppose Concrete1.java implements this interface:
package com.vipin.concrete1;
public class Concrete1 implements Interface1 {
public void print () {
//code
}
}
And this packaged in jar --> concrete1.jar.
Now, suppose i am writing an application which uses print() method, so do i need to include both these jar's?

The case for java.sql.Connection is that the driver provides the implementation classes for this and other interfaces like java.sql.Statement, java.sql.ResultSet, and on. All the magic of binding the interface to the proper class implementation happens in the method DriverManager#getConnection, which calls an internal method private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException that will initialize the proper instance of java.sql.Connection.
Of course, you can use a similar approach in your code that will use reflection to:
Find the proper implementation of the interface
If there's a proper implementation, create an instance of this class.
Return the instance of this class once initialized and running.
Throw proper exception(s) if the class cannot be found or if it has any initialization issue.
Please do not think that just creating a jar containing the interfaces and another containing the implementation classes of this interfaces will automatically wire up on the fly for you, that doesn't happen.

Related

JDBC Driver implementation and class loading

Not a long time ago I was implementing JDBC driver. But before jumping into work I've studied some MySQL JDBC driver sources and found out that they contain two implementations of the java.sql.Driver interface: com.mysql.jdbc.Driver and com.mysql.jdbc.NonRegisteringDriver, where Driver also extends NonRegisteringDriver.
The Driver class only contains a static block that calls DriverManager.registerDriver() to register the class:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
While NonRegisteringDriver implements all the java.sql.Driver interface methods.
My first thought was, that by implementing a driver this way developers of MySQL driver are following java.sql.Driver guidlines that state the following:
It is strongly recommended that each Driver class should be small and standalone so that the Driver class can be loaded and queried without bringing in vast quantities of supporting code.
But if I understand Java classloading correctly, there is absolutely no point in having separate com.mysql.jdbc.Driver class, as its parent with all the realisation code will be loaded anyway before execution of the static block.
Am I missing something here?
No, actually without com.mysql.jdbc.Driver class present implementation of mysql JDBC driver will not satisfy java.sql.Driver agreement, which claims:
When a Driver class is loaded, it should create an instance of
itself and register it with the DriverManager. This means that a user can load and register a driver by calling
Class.forName("foo.bah.Driver")}
com.mysql.jdbc.NonRegisteringDriver class doesn't contain this part of creating self-instance and registering it.
Why did mysql developers decided to distinguish implementation itself from class which essentially registers its instance? Hard to say exactly, but it could be convenient in case if they will decide to provide several implementations in same package. Then class com.mysql.jdbc.Driver will extend default one.
UPDATE: Essenstially things are as I described above. There are at least 3 derived classes which extend com.mysql.jdbc.NonRegisteringDriver:
com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver
com.mysql.jdbc.NonRegisteringReplicationDriver
While com.mysql.jdbc.Driver is default implementation, others overrides some methods from base class. If NonRegisteringDriver would contain static block for creation its instance and registering it, it would be not possible to have exactly one needed mysql driver in memory with deriving classes.
But in general there is no strong reasons for that. For example org.postgresql.Driver implementation contains full implementation of java.sql.Driver in itself.

Java DAO pattern and runtime dependencies

We have implemented a typical DAO/Abstract Factory pattern. The design is like this:
DAOFactory - that returns either an instance of MySQLFactory / SQLiteFactory
MySQLFactory - returns DAOs that talks to MySQL DB
SQLiteFactory - returns DAOs that talks to SQLite DB
Things are fine. However, we need to create two executables: The one that is provided to customers uses the SQLiteFactory instance and relevant DAOs. In that executable, we don't want to include any class related to MySQLFactory. If I delete those classes then we see a ClassNotFoundException at run time when DAOFactory class is being loaded by class loader.
How can we implement our DAOFactory so that MySQLFactory is not required at runtime ? The same problem also exists for certain other classes i.e. certain classes are required only for in-house version of the app. What is a good way of implementation so that we can exclude classes from the software that is shipped to customers ?
Thanks
Deep
You can use Class.forName to load classes at runtime. For example:
public class DAOFactoryLoader {
public static DAOFactory loadMySQLFactory() {
return (DAOFactory) Class.forName("your.package.MySQLFactory").newInstance();
}
public static DAOFactory loadSQLiteFactory() {
return (DAOFactory) Class.forName("your.package.SQLiteFactory").newInstance();
}
}
Then you can call the right method for the specific version of your software, i.e. loadMySQLFactory when you bundle the MySQL implementation and loadSQLiteFactory when you bundle the SQLite implementation.
You can even pass the class name as a JVM property, for eg. -DdaoFactory=your.package.MySQLFactory and then use this to load the right class:
return (DAOFactory) Class.forName(System.getProperty("daoFactory")).newInstance();

Loading JDBC driver

I am told that the prefered method to load the JDBC driver is :
Class.forName(driverName);
I understand that this is better for a dynamic decision between multiple drivers maybe read from an XML config file or user input. The thing I am curious about is how does invoking this statement loads the stated driver into the environment where we are not even storing the resultant "Class" object anywhere. The JavaDocs entry says:
public static Class forName(String className)
throws ClassNotFoundExceptionReturns
returns the Class object associated with the class or interface with the given string name
In that case, how do the Java developers managed to facilitate the existence of driver object with merely this statement?
The Class#forName() runs the static initializers (you know, static applies to the class, not to the instance). The JDBC driver implementation should register itself in the static initializer.
public class SomeDriver implements Driver {
static {
DriverManager.registerDriver(new SomeDriver());
}
}
Note that there exist buggy JDBC drivers such as org.gjt.mm.mysql.Driver which incorrectly registers itself inside the constructor instead. That's why you need a newInstance() call afterwards on such drivers to get them to register themselves.

How does Class.forName() work?

I just learned about java.sql package. It uses Class.forName() to dynamically load the driver which extends DriverManager.
Then we get connection using DriverManager.getConnection() method.
So how does the entire thing work?
How does DriverManager class know how to get the connection without using class name of the actual driver.
Also can we use Class.forName() for custom applications... if this is explained with an example I will be very happy.
Class.forName simply loads a class, including running its static initializers, like this:
class Foo {
static {
System.out.println("Foo initializing");
}
}
public class Test {
public static void main(String [] args) throws Exception {
Class.forName("Foo");
}
}
All the rest of the procedure you're talking about is JDBC-specific. The driver - which implements Driver, it doesn't extend DriverManager - simply registers an appropriate instance using DriverManager.registerDriver. Then when DriverManager needs to find a driver for a particular connection string, it calls connect on each registered driver in turn until one succeeds and returns a non-null connection.
Note that this way of registering drivers is reasonably old-fashioned - look at the docs for DriverManager for more modern ways of getting at a data source.
When we create an instace of a class using new operator, it does two things
Load the class in to memory, if it is not loaded -
which means creating in-memory representation of the class from the .class file so that an instance can be created out of it. This includes initializing static variables (resolving of that class)
create an instance of that class and store the reference to the variable.
Class.forName does only the first thing.
It loads the class in to memory and return that reference as an instance of Class. If we want to create an instance then, we can call newInstance method of that class. which will invoke the default constructor (no argument constructor).
Note that if the default constructor is not accessible, then newInstance method will throw an IllegalAccessException. and if the class is an abstract class or interface or it does not have a default constructor, then it will throw an InstantiationException. If any exception araises during resolving of that class, it will throw an ExceptionInInitializerError.
If the default constructor is not defined, then we have to invoke the defiend constructor using reflection API.
But the main advantage with Class.forName is, it can accept the class name as a String argument. So we can pass the class name dynamically. But if we create an instance of a class using new operator, the class name can't be changed dynamically.
Class.forName() inturn will call loadClass method of the caller ClassLoader (ClassLoder of the class from where Class.forName is invoked).
By default, the Class.forName() resolve that class. which means, initialize all static variables inside that class.
same can be changed using the overloaded method of Class.forName(String name,boolean initialize,ClassLoader loader)
The main reason for loading jdbc driver using Class.forName() is, the driver can change dynamically.
in the static block all Drivers will create an instance of itself and register that class with DriverManager using DriverManager.registerDriver() method. Since the Class.forName(String className) by default resolve the class, it will initialize the static initializer.
So when we call Class.forName("com.sun.jdbc.odbc.JdbcOdbcDriver"),
the Driver class will be loaded, instanciated and registers with DriverManager
So if you are using new Operator you have to do the following things.
Code:
Driver drv = new com.sun.jdbc.odbc.JdbcOdbcDriver();
DriverManager.registerDriver(drv);
Class.forName(..) loads and initializes the target class. This in turn means that the static initializer blocks are invoked (code defined in static { .. }.
If you look at, for example, MySQL's driver, in that static block the driver is registering itself: DriverManager.registerDriver(new Driver());
You can omit the Class.forName(..) and register the driver yourself if you can "afford" the compile-time dependency on MySQL's driver.
That said, it will rarely be relevant to use Class.forName(..) to initialize classes from your application, because compile-time dependency is not an issue there.
Also note that Class.forName(..) is no longer required for JDBC since version 4. By using the service provider mechanism you can instruct the driver manager what to load by a system property.
The reason why Class.forName() is frequently mentioned in SQL examples, is because there was no magic to tell the JDBC DriverManager how to map the JDBC URL provided to a real driver.
E.g. "mysql" should map to a given MySQL class, "thin" maps to the Oracle class, "as400" maps to the DB2/400 class.
By explicitly loading the class, this allowed the code within the class registering itself with the DriverManager to be run.
These days the magic hooks are present allowing the JVM to autodiscover the drivers (if new enough) so the call is superfluous, but out of habit many still use it.

Define Implementation for abstract Object

I am looking for a way to do the following:
A Project :
Defines an abstract class that is called when some events happen (event handler if you will)
Defines the engine that will fire the events using the event handler above
B Project:
Defines the implementation for the abstract class
Runs the engine.
How can i register the implementation class and make sure that is the one being called when the engine runs.
EDIT 1: By register i mean i must somehow define which is the implementation that should be called for that given abstract object
Sorry if the question isn't too clear, let me know if you need some more details
Something like this?
class A implements EventHandlerForB {
...
}
public class B {
private EventHandlerForB eventHandler;
public void registerEventHandler(EventHandlerForB eventHandler) {
this.eventHandler = eventHandler;
}
...
}
public interface EventHandlerForB {
...
}
At runtime, you can have the name of the implementation passed in your A project (with a properties file or a Java system property).
Then you find this class in the classpath with class.forName() and instantiate it with newInstance().
But you'd prefer using a framework like Guice or Spring, that will allow you to glue stuff together in a clean way.
there are several "patterns" that try to address this issue. Using only JDK (6 or above) classes you may want to take a look at java.util.ServiceLoader

Categories

Resources