Search code examples
javamysqlintellij-ideaosgiapache-felix

MySQL Connector in OSGi Environment (Gradle): NoClassDefFoundError


I'm trying to use the mysql-connector in an OSGi-Bundle to connect to a MySQL database. Unfortunately I'm always getting the NoClassDefFoundError when I'm trying to obtain the database driver in my bundle.

I'm already sitting here for two days, banging my head against the wall. I tried everything I found (I know there are already similar questions on stackoverflow) but I'm completely lost now.

The project is a gradle project and I'm using Intellij. Here is the build.gradle of the bundle:

defaultTasks 'clean', 'build'

apply plugin: 'java'
apply plugin: 'osgi'
apply plugin: 'maven'

sourceCompatibility = 1.6
targetCompatibility = 1.6

version = '0.0.1'

def bundleSymbolicName = 'at.my.test.drivers.mysqldb'
def bundleName = 'Driver - MySql Database Drive'

repositories {
    mavenCentral()
}

configurations {
    embed
}

dependencies {
    compile group: 'org.osgi', name: 'org.osgi.core', version: '4.3.1'
    compile group: 'org.osgi', name: 'org.osgi.compendium', version: '4.3.1'
    compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.2'

    compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.35'
    embed group: 'mysql', name: 'mysql-connector-java', version: '5.1.35'
}

jar {
    into('lib') {
        from configurations.embed
    }
}

jar {
    manifest {

        version = project.version.replace('-','.');
        symbolicName = bundleSymbolicName
        name = bundleName

        instruction 'Bundle-ClassPath', '.,lib/mysql-connector-java-5.1.35.jar'
        instruction 'Service-Component', 'OSGI-INF/components.xml'
    }
}

The mysql-connector-java-5.1.35.jar file gets correctly downloaded by gradle and is added as a dependency of the module:

module settings That's how I try to create a database connection:

try {

    Class.forName("com.mysql.jdbc.Driver").newInstance();
    sqlConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","usr","pwd");

}
catch(Exception e) {
    e.printStackTrace();
    logger.error("unable to create database connection");
}

When I try to start the module, I only get this exception:

java.sql.SQLException: java.lang.NoClassDefFoundError: javax/naming/RefAddr
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:904)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:894)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
        at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:399)
        at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java
:

please help :(


Solution

  • oh my gosh PRAISE THE SUN, I got it working now. I don't know if it's done this way or if there is better way but this is how I have done it:

    EDIT: If you download the mysql-connector-java-5.1.35-bin.jar it should work out of the box, since it is already an OSGi-Bundle ... so you can skip step 1) and 2)

    1) Create an OSGi-Bundle with the JDBC driver (just follow this tutorial: https://wiki.eclipse.org/Create_and_Export_MySQL_JDBC_driver_bundle) these are the steps:

    • Download the mysql-connector-java-xxx-bin.jar
    • Open Eclipse (I have used Lunar SR2) -> open the New Project wizard and select Plug-in from existing JAR archives:
    • Add external JAR and select the mysql-connector jar
    • Add following information:enter image description here
    • Press Finish and export the project as a Deployable plug-ins and fragments (in the export wizard)
    • After that a JAR-file should have been created (e.g com.mysql.jdbc_5.1.6.jar)

    2) Now unzip the created JAR file and open the MANIFEST.MF in the META-INF folder and add the following Export-Package and Import-Package definitions:

    Export-Package: com.mysql.jdbc;version="5.1.35";uses:="com.mysql.jdbc.
     log,javax.naming,javax.net.ssl,javax.xml.transform,org.xml.sax",com.m
     ysql.jdbc.jdbc2.optional;version="5.1.35";uses:="com.mysql.jdbc,com.m
     ysql.jdbc.log,javax.naming,javax.sql,javax.transaction.xa",com.mysql.
     jdbc.log;version="5.1.35",com.mysql.jdbc.profiler;version="5.1.35";us
     es:="com.mysql.jdbc",com.mysql.jdbc.util;version="5.1.35";uses:="com.
     mysql.jdbc.log",com.mysql.jdbc.exceptions;version="5.1.35",com.mysql.
     jdbc.exceptions.jdbc4;version="5.1.35";uses:="com.mysql.jdbc",com.mys
     ql.jdbc.interceptors;version="5.1.35";uses:="com.mysql.jdbc",com.mysq
     l.jdbc.integration.c3p0;version="5.1.35",com.mysql.jdbc.integration.j
     boss;version="5.1.35",com.mysql.jdbc.configs;version="5.1.35",org.gjt
     .mm.mysql;version="5.1.35"
    
    Import-Package: javax.net,javax.net.ssl;version="[1.0.1, 2.0.0)";resol
     ution:=optional,javax.xml.parsers, javax.xml.stream,javax.xml.transfo
     rm,javax.xml.transform.dom,javax.xml.transform.sax,javax.xml.transfor
     m.stax,javax.xml.transform.stream,org.w3c.dom,org.xml.sax,org.xml.sax
     .helpers;resolution:=optional,javax.naming,javax.naming.spi,javax.sql
     ,javax.transaction.xa;version="[1.0.1, 2.0.0)";resolution:=optional,c
     om.mchange.v2.c3p0;version="[0.9.1.2, 1.0.0)";resolution:=optional,or
     g.jboss.resource.adapter.jdbc;resolution:=optional,org.jboss.resource
     .adapter.jdbc.vendor;resolution:=optional
    

    my complete manifest file looks like this:

    Manifest-Version: 1.0
    Ant-Version: Apache Ant 1.8.2
    Created-By: 1.5.0_22-b03 (Sun Microsystems Inc.)
    Built-By: pb2user
    Specification-Title: JDBC
    Specification-Version: 4.0
    Specification-Vendor: Oracle Corporation
    Implementation-Title: MySQL Connector Java
    Implementation-Version: 5.1.35
    Implementation-Vendor-Id: com.mysql
    Implementation-Vendor: Oracle
    Bundle-Vendor: Oracle Corporation
    Bundle-Classpath: .
    Bundle-Version: 5.1.35
    Bundle-Name: Oracle Corporation's JDBC Driver for MySQL
    Bundle-ManifestVersion: 2
    Bundle-SymbolicName: com.mysql.jdbc
    Export-Package: com.mysql.jdbc;version="5.1.35";uses:="com.mysql.jdbc.
     log,javax.naming,javax.net.ssl,javax.xml.transform,org.xml.sax",com.m
     ysql.jdbc.jdbc2.optional;version="5.1.35";uses:="com.mysql.jdbc,com.m
     ysql.jdbc.log,javax.naming,javax.sql,javax.transaction.xa",com.mysql.
     jdbc.log;version="5.1.35",com.mysql.jdbc.profiler;version="5.1.35";us
     es:="com.mysql.jdbc",com.mysql.jdbc.util;version="5.1.35";uses:="com.
     mysql.jdbc.log",com.mysql.jdbc.exceptions;version="5.1.35",com.mysql.
     jdbc.exceptions.jdbc4;version="5.1.35";uses:="com.mysql.jdbc",com.mys
     ql.jdbc.interceptors;version="5.1.35";uses:="com.mysql.jdbc",com.mysq
     l.jdbc.integration.c3p0;version="5.1.35",com.mysql.jdbc.integration.j
     boss;version="5.1.35",com.mysql.jdbc.configs;version="5.1.35",org.gjt
     .mm.mysql;version="5.1.35"
    Import-Package: javax.net,javax.net.ssl;version="[1.0.1, 2.0.0)";resol
     ution:=optional,javax.xml.parsers, javax.xml.stream,javax.xml.transfo
     rm,javax.xml.transform.dom,javax.xml.transform.sax,javax.xml.transfor
     m.stax,javax.xml.transform.stream,org.w3c.dom,org.xml.sax,org.xml.sax
     .helpers;resolution:=optional,javax.naming,javax.naming.spi,javax.sql
     ,javax.transaction.xa;version="[1.0.1, 2.0.0)";resolution:=optional,c
     om.mchange.v2.c3p0;version="[0.9.1.2, 1.0.0)";resolution:=optional,or
     g.jboss.resource.adapter.jdbc;resolution:=optional,org.jboss.resource
     .adapter.jdbc.vendor;resolution:=optional
    

    The exported packages can then be used by other bundles (that's the point). After saving the manifest file, zip everthing and change the file extension to .jar and put the .jar file into the bundles folder of the Felix OSGi environment (or whatever you use), it is important that the bundle gets installed and is available:

    enter image description here

    3) After that, you can import the com.mysql.jdbc package in any other bundle you have created, you just need do import the package in the manifest:

    Import-Package: com.mysql.jdbc;version="5.1.35"
    

    Or if you are using gradle add the following in the build.gradle:

    jar {
        manifest {
            version = project.version.replace('-','.');
            symbolicName = bundleSymbolicName
            name = bundleName
    
            instruction 'Bundle-ClassPath', '.'
            instruction 'Import-Package', 'com.mysql.jdbc;version="5.1.35"'
            instruction 'Service-Component', 'OSGI-INF/components.xml'
        }
    }
    

    4) and FINALLY you can use ist:

    try {
    
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        sqlConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","usr","pwd");
    
    }
    catch(Exception e) {
        e.printStackTrace();
        logger.error("unable to create database connection");
    }
    

    Hope this helps someone, I spend two days figuring out how that stuff works^^