Sepultura Sepultura - 1 month ago 17
Java Question

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 :(

Answer

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^^