1

I am not much familiar with Java but I try to accomplish this task in R (my fav)!

There is this Java library called Jackcess. I want to connect to this library and open an MS Access 2003 .mdb file in it. Jackcess cookbook tells me the first step to using this library is this:

Database db = DatabaseBuilder.open(new File("mydb.mdb"));

or as @Gord suggests,

File file = new File("C:/Users/Public/jackcessTest.mdb");
DatabaseBuilder dbbo = new DatabaseBuilder();
dbbo.setFile(file);
Database db = dbbo.open();

but I'm stuck at this very first step.

I have installed Java and rJava and set up everything about directories. This is my code in R

library(rJava)

.jinit()
.jaddClassPath("java/jackcess-2.1.2.jar") # there I have put the downloaded jar file of Jackcess

# .jaddClassPath("java/commons-logging-1.2.jar") # this is the commons-logging class that Jackcess depends on, commented to replicate problem 2] in my question.



file.name <- "D:/63.mdb" # some data base .mdb file (containing only tables)

file <- .jnew("java/io/File",file.name)
dbbo <- .jnew("com/healthmarketscience/jackcess/DatabaseBuilder")

[Edit: I found out I had two problems, one solved, one still not.] up to this part everything is ok, but I have some problems from now on:

1] Correctly calling a method from Jackcess without signature mismatch, neither of these work:

dbbo <- .jcall(dbbo,"L<DatabaseBuilder>","setFile",file)
dbbo <- .jcall(dbbo,"Lcom/healthmarketscience/jackcess/DatabaseBuilder","setFile",file)

I get this error:

Error in .jcall(dbbo, "Lcom/healthmarketscience/jackcess/DatabaseBuilder",  : 
method setFile with signature (Ljava/io/File;)Lcom/healthmarketscience/jackcess/DatabaseBuilder not found

well I found the answer to this step, I just needed a semicolon (;) at the end of class definition string.

dbbo <- .jcall(dbbo,"Lcom/healthmarketscience/jackcess/DatabaseBuilder;","setFile",file)

2] Calling the open method correctly, my first round of try:

 db <- .jcall(dbbo,"Lcom/healthmarketscience/jackcess/Database;","open",evalArray = FALSE,evalString = FALSE)

and I get this error:

 Error in .jcall(dbbo, "Lcom/healthmarketscience/jackcess/Database;", "open",  : 
 java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

I googled and found out that Jackcess depends on some library called commons-logging, so downloading and adding it to classpath solves THAT problem

3] Calling the open method correctly, my second round of try: with commons-logging in classpath

db <- .jcall(dbbo,"Lcom/healthmarketscience/jackcess/Database;","open",evalArray = FALSE,evalString = FALSE)

this gives me this error:

Error in .jcall(dbbo, "Lcom/healthmarketscience/jackcess/Database;", "open",  : 
java.lang.NoClassDefFoundError: Could not initialize class com.healthmarketscience.jackcess.impl.DatabaseImpl

Any Ideas for this error?

[NOTE]: some answers were suggested before my edits, so they may seem irrelevant now, but I have used them in the steps I explained above.

MEcon
  • 395
  • 4
  • 23
  • In this question I use low level rJava functions that need explicit type specification in JNI. It is recommended that beginners use higher level functions like J() in rJava package. I think rJava needs a good vignette! – MEcon Aug 24 '15 at 18:34

2 Answers2

0

The following code shows an alternate approach in Java using the .setFile and .open methods of a "real" DatabaseBuilder object:

File file = new File("C:/Users/Public/jackcessTest.mdb");
DatabaseBuilder dbbo = new DatabaseBuilder();
dbbo.setFile(file);
Database db = dbbo.open();

Try something similar in rJava and see if it works for you.

Edit re: updated question

You mentioned that you added Apache commons-logging to your CLASSPATH, but Jackcess also relies on Apache commons-lang v2.x (not v3.x), so try downloading that and including it in your CLASSPATH as well.

Gord Thompson
  • 116,920
  • 32
  • 215
  • 418
  • The problem seems to lie in matching signatures. for example I tried to run your 3rd line in rJava: .jcall(dbbo,method = "setFile","L",file), anything I write, the signiture does not match. – MEcon Aug 19 '15 at 06:08
  • .jmethods(dbbo,"setFile") [1] "public com.healthmarketscience.jackcess.DatabaseBuilder com.healthmarketscience.jackcess.DatabaseBuilder.setFile(java.io.File)", so what should my .jcall be? – MEcon Aug 19 '15 at 06:18
  • I had added some commons logging v.2.0 back sometime, but I had other errors, and I deleted it. But yes, your edit solves the last problem remained in my question. – MEcon Aug 24 '15 at 08:30
0

3 suggestions:

Include commons-lang-2.0.jar in your classPath, similarly to

rJava::.jaddClassPath("commons-lang-2.0.jar")

The easy way is to try calling with J() like so:

dbb <- rJava::.jnew("com/healthmarketscience/jackcess/DatabaseBuilder")
dbjfile <- rJava::.jnew('java/io/File', "D:/63.mdb")
dbop <- rJava::J(dbb, "open", dbjfile)

For what it's worth, if you really want to do it the low-level way, this is one way to try:

dbop <- .jcall(
    "RJavaTools"
  , "Ljava/lang/Object;"
  , "invokeMethod"
  , .jcall(dbb, "Ljava/lang/Class;", "getClass")
  , .jcast(dbb, "java/lang/Object")
  , .jnew("java/lang/String", "open")
  , .jarray(list(dbjfile), "java/lang/Object", dispatch = FALSE)
  , .jarray(rJava:::._java_class_list(list(dbjfile)), "java/lang/Class", dispatch = FALSE)
  , use.true.class = TRUE
  , evalString = TRUE
  , evalArray = FALSE
  )
Jozef
  • 2,617
  • 14
  • 19