Edmundo Del Gusto
Edmundo Del Gusto

Reputation: 388

Connect Android App to Bluemix db2 database using JDBC (NoClassDefFoundError:)

First: I have some experience in Java but its my first time creating an Android-App. I am using the Bluemix IoT-Foundation-Service and got a Bluemix-DB2-SQL-Database. (My RasPi2 is collecting some sensor datas, publish them via MQTT and an Application running on bluemix that subscribes to this datas, stores them into the DB2-Database).

Now I want to code an Android app, that connects to my database and do some database-things. I started with an simple app. Just a button that adds something on my DB2-TodoList-Table.

Code:

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import java.sql.*;
public class MainActivity extends AppCompatActivity {

static Connection       con;
static Statement        stmt;
static Statement        stmt1;
static DatabaseMetaData dmd;


private static String user = "user*****";
private static String password = "L***********";
private static String url = "jdbc:db2://*.**.*****:50001/SQLDB";


public void connect(){
    java.util.Properties properties = new java.util.Properties();

    properties.put("user", user);
    properties.put("password", password);
    properties.put("sslConnection", "true");

    try {
        Class.forName("com.ibm.db2.jcc.DB2Driver");
    con = DriverManager.getConnection(url, properties);
    stmt = con.createStatement();

    } catch (ClassNotFoundException e) {
       // e.printStackTrace();
    } catch (SQLException e) {
      //  e.printStackTrace();
    }
}
public void close() throws SQLException, ClassNotFoundException{
    stmt.close();
    con.close();
}

public static void addSomethingToMyToDoList(int ID, String something) throws SQLException{
    if(con != null)
        stmt.executeUpdate("INSERT INTO TODOLIST VALUES (" + ID + " , '" + something +"')");
    con.commit();
}

public void addSomethingToDatabase(View v){
    connect();
    int sampleID = 1233;
    try {
        addSomethingToMyToDoList(sampleID, "testTest");
         close();
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

I drag and dropped the db2jcc.jar into the /app/libs folder and did right-click + Add as library

I use Android Studio

I've read that db2jcc.jar doesn't work with jdk 1.8 thats why I installed jdk 1.7 (Did File->Project Structure -> SDK Location -> changed JDK location to my jdk1.7.0 directory)

the build.gradle file contains:

defaultConfig {
    [...]
    multiDexEnabled true
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile files('libs/db2jcc.jar')
testCompile 'junit:junit:4.12'
compile 'com.android.support:design:23.1.1'
compile 'com.android.support:multidex:1.0.1'
compile 'com.android.support:appcompat-v7:23.1.1'
}

When I run my Application (on AVD) and click on the Button the my app chrashes an I get this message:

Caused by: java.lang.NoClassDefFoundError: com.ibm.db2.jcc.DB2SimpleDataSource

Full error log:

FATAL EXCEPTION: main Process: com.example.egebert.datanbank, PID: 7125 java.lang.IllegalStateException: Could not execute method for android:onClick at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:275) at android.view.View.performClick(View.java:5198) at android.view.View$PerformClick.run(View.java:21147) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270) at android.view.View.performClick(View.java:5198)  at android.view.View$PerformClick.run(View.java:21147)  at android.os.Handler.handleCallback(Handler.java:739)  at android.os.Handler.dispatchMessage(Handler.java:95)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:5417)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)  Caused by: java.lang.NoClassDefFoundError: com.ibm.db2.jcc.DB2SimpleDataSource at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:324) at java.lang.Class.forName(Class.java:285) at com.ibm.db2.jcc.am.GlobalProperties.d(Unknown Source) at com.ibm.db2.jcc.am.GlobalProperties.a(Unknown Source) at com.ibm.db2.jcc.am.GlobalProperties.c(Unknown Source) at com.ibm.db2.jcc.am.GlobalProperties.a(Unknown Source) at com.ibm.db2.jcc.am.hb.j(Unknown Source) at com.ibm.db2.jcc.am.hb.(Unknown Source) at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:324) at java.lang.Class.forName(Class.java:285) at com.ibm.db2.jcc.DB2BaseDataSource.class$(Unknown Source) at com.ibm.db2.jcc.DB2BaseDataSource.(Unknown Source) at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:324) at java.lang.Class.forName(Class.java:285) at com.ibm.db2.jcc.DB2Driver.class$(Unknown Source) at com.ibm.db2.jcc.DB2Driver.(Unknown Source) at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:324) at java.lang.Class.forName(Class.java:285) at com.example.egebert.datanbank.MainActivity.connect(MainActivity.java:40) at com.example.egebert.datanbank.MainActivity.addSomethingToDatabase(MainActivity.java:78) at java.lang.reflect.Method.invoke(Native Method)  at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270)  at android.view.View.performClick(View.java:5198)  at android.view.View$PerformClick.run(View.java:21147)  at android.os.Handler.handleCallback(Handler.java:739)  at android.os.Handler.dispatchMessage(Handler.java:95)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:5417)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

I tried

Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();

instead of

Class.forName("com.ibm.db2.jcc.DB2Driver");

too.

Is there no way to get the JDBC-db2Driver work on Android? Just found This stackoverflow question telling me, that you can't connect to an bluemix-db2-server using android. Is this right? Or is there a way to fix the NoClassDefFoundError?

THANK YOU

Upvotes: 1

Views: 597

Answers (1)

v.bontempi
v.bontempi

Reputation: 1562

The error is pretty clear, your application cannot find the db2 modules. Check that you are importing correctly these modules into your application library and that the drivers added into lib are providing the classes you are using for datasource.

Anyway I would avoid to make your application to directly connect to an external database for several reasons:

  • db connections are usually limited and using them for each application instance will make the db instance going out of available connections quickly, especially if the db interactions aren't really short and if the connections aren't correctly released
  • network connection of a portable device isn't stable and you could lose your connection while running db operations

Usually a better solution should be adding an integration layer like a webservice, managing all the db interactions included the db connections, and exposing some endpoints for the application integration.

Upvotes: 0

Related Questions