0

I have implemented a simple plugin based application with Java. Main plugin class is derived from and abstract class called "Plugin". The application reads that class from JAR file and runs the plugin by creating an instance of the class. Standard procedure I guess :)

Everything forks fine until now. But the problem occurs when I include a library to my plugin, like MySQL Connector. The exception NoClassDefFoundError and ClassNotFoundException are thrown after execution. I am overcoming the problem by adding MySQL connector library to the main application but what is the point then? :)

I am not a Java expert so I am not sure of any alternative solutions like defining a classpath for libraries etc.

Here is my plugin loader: http://pastebin.com/90rQ9NfJ

And here is my plugin base class: http://pastebin.com/Juuicwkm

I am executing from a GUI:

    private void jButtonAddActionPerformed(java.awt.event.ActionEvent evt) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setFileFilter(new FileNameExtensionFilter("JTask Plugin (*.JAR)", "JAR"));

        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
        {
            File pluginFile = fileChooser.getSelectedFile();
            PluginLoader pluginLoader = new PluginLoader();
            Plugin plugin = pluginLoader.loadPlugin(pluginFile);
            if (plugin != null)
                jPanelPlugins.add(new PluginControl(jPanelPlugins, plugin));
        }
    }
Selçuk Öztürk
  • 975
  • 1
  • 14
  • 23

2 Answers2

0

You should really include your source code as well.

How are you executing the class i.e. via command line or from a GUI? If from the command line, then the MySQLConnector libraries, along with any other dependent library must be included in the classpath (java -classpath). The top answer to this question should help you- Java: how to import a jar file from command line

Community
  • 1
  • 1
Gavin
  • 349
  • 4
  • 10
  • Thank you. I have found something about updateing manifest in the jar file http://java.sun.com/developer/Books/javaprogramming/JAR/basics/update.html but it still looks too much detailed. I am looking for something that doesn't need to change main application outside. – Selçuk Öztürk Apr 16 '12 at 21:53
0

if the case, your class is a Mysql Driver you have to exclude (at the time the class is calling) classes that are not available. In the Folder of your .jar file there is one with the name "integration" it contains "jboss" and "c3p0" which are not present at this time.

while (en.hasMoreElements()) { 
                JarEntry entry = new JarEntry(en.nextElement());
                String name = entry.getName();
                if (name.contains("/integration/")) {
                  continue;
                } else {
                 if (!entry.isDirectory() && name.toLowerCase().endsWith(".class"))
                 {
                    classList.add(name.replace(".class", ""));
                 }
                }
}

This should load a mysql.xxx.jar file. Try This


dynamicload.java


package dynamicloading;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 *
 * @author Administrator
 */
class com_mysql_jdbc_Driver implements Driver {
    private Driver driver;
    com_mysql_jdbc_Driver(Driver cmjd) {
        this.driver = cmjd;
    }
    @Override
    public boolean acceptsURL(String aurlS) throws SQLException {
        return this.driver.acceptsURL(aurlS);
    }
    @Override
    public Connection connect(String aurlS, Properties pP) throws SQLException {
        return this.driver.connect(aurlS, pP);
    }
    @Override
    public int getMajorVersion() {
        return this.driver.getMajorVersion();
    }
    @Override
    public int getMinorVersion() {
        return this.driver.getMinorVersion();
    }
    @Override
    public DriverPropertyInfo[] getPropertyInfo(String aurlS, Properties pP) throws SQLException {
        return this.driver.getPropertyInfo(aurlS, pP);
    }
    @Override
    public boolean jdbcCompliant() {
        return this.driver.jdbcCompliant();
    }
}

public class DynMain {

    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) throws Exception {
        /* please set to your path*/
        File file = new File("U:/mozsamples/mysql-connector-java-5.1.19-bin.jar");
        Driver cmjdD;
        String aktCS;
        String urlS = "jdbc:mysql://localhost/db";
        String userS = "must-be-set";
        String passS = "must-be-set";
        Connection con;
        Statement stmt;
        URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});
        JarFile jarFile = new JarFile(file);
        Enumeration<JarEntry> entries = jarFile.entries();

        while (entries.hasMoreElements()) {
            JarEntry element = entries.nextElement();
            if (element.getName().endsWith(".class")) {
                String name = element.getName();
                if (name.contains("/integration/")) {
                  System.out.println( "ignored: " + name );
                  continue;
                } else
                {
                try {    
                    aktCS = element.getName().replaceAll(".class", "").replaceAll("/", ".");
                    clazzLoader.loadClass(aktCS);
                    if (name.contains("com/mysql/jdbc/Driver")) {
                        cmjdD = (Driver)Class.forName(aktCS, true, clazzLoader).newInstance();
                        try {
                        DriverManager.registerDriver(new com_mysql_jdbc_Driver(cmjdD));
                        System.out.println( "register Class: " + aktCS );
                        } catch (SQLException e) {
                          e.printStackTrace();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                }
            }
        } 
    try {
    con = DriverManager.getConnection(urlS,userS,passS);
    stmt = con.createStatement();
    /*ResultSet rs = stmt.executeQuery("select * from idcart where ID=255"); */

    stmt.close();
    } catch (SQLException esql) {
        esql.printStackTrace();
    }
   int j=0 ;
   System.out.println("loaded Driver----------------------------------");
   for( Enumeration en = DriverManager.getDrivers() ; en.hasMoreElements() ; j++)
         System.out.println( en.nextElement().getClass().getName() );

   if (j==0) { System.out.println("Driverlist empty"); }

    System.out.println("-----------------------------------------------");
    }
}

Output:

register Class: com.mysql.jdbc.Driver
ignored: com/mysql/jdbc/integration/c3p0/MysqlConnectionTester.class
ignored: com/mysql/jdbc/integration/jboss/ExtendedMysqlExceptionSorter.class
ignored: com/mysql/jdbc/integration/jboss/MysqlValidConnectionChecker.class
loaded Driver----------------------------------
sun.jdbc.odbc.JdbcOdbcDriver
dynamicloading.com_mysql_jdbc_Driver
-----------------------------------------------

OK ???

moskito-x
  • 11,832
  • 5
  • 47
  • 60
  • Unfortunately there is no such "integration" folder inside the JAR structure. – Selçuk Öztürk Apr 18 '12 at 01:01
  • I found id in "mysql-connector-java-5.0.4-bin.jar" and "mysql-connector-java-5.1.6-bin.jar". Please tell me the name of your .jar file. – moskito-x Apr 18 '12 at 01:24
  • And it is in just downloaded [MySql download](http://dev.mysql.com/downloads/mirror.php?id=407253) – moskito-x Apr 18 '12 at 01:44
  • I am using "mysql-connector-java-5.1.19-bin.jar" – Selçuk Öztürk Apr 18 '12 at 08:39
  • I added code look above. Change your settings and run. There is a "com/mysql/jdbc/integration/" folder. You can trust me ;) – moskito-x Apr 18 '12 at 09:34
  • OK but what if I have to use, let's say PostgreSQL, or some other library? Do I have to change the loader code every time for every library? The main goal of this application is to write it once and leave other extensions to other developers and not to touch the main code as much as possible. At first it didn't look so hard :( – Selçuk Öztürk Apr 18 '12 at 20:40
  • What is the sense ? Open a jar file only load the classes. Driver: it's useless you did not register the driver. Nobody can use the classes for other purpose. Open a jarfile to get a "modal.dialog" to use it in your window all the buttons, inputfields and checkgroups are stored together in the jarfile. The only thing you must call his main.class. No need to register or other things. It's important to know what is in the jarfile and then you must handle this. PostgreSQL: register the driver same as the mysql.driver. If you load 100 jarfiles maybe you have to implement 100 routines. Good luck! – moskito-x Apr 18 '12 at 21:56
  • sorry for late reply moskito-x. I am too busy recently I will let you know when I do it :) – Selçuk Öztürk Apr 27 '12 at 09:42