Android Question javaObject getMetaData exception

Patrick Clark

Active Member
Licensed User
I have taken a bit of the jRDC2 code from the b4J library and implemented it in my SQL handler.

The code is the stuff that converts a sql ResultSet to a DBResult Type

The DBResult Type is
B4X:
    Type DBResult ( _
        Columns As Map, _
        Rows As List, _
        Cursor As Int, _
        NoRows As Int)

The code is below.

This all works fine in B4J but when I try and use it in B4A I get an exception at line 3
B4X:
Dim rsmd As JavaObject = jrs.RunMethod("getMetaData", Null)

The exception is:
java.lang.RuntimeException: Method: getMetaData not found in: android.database.sqlite.SQLiteCursor
The caught exception (Try/Catch) is (RuntimeException) java.lang.RuntimeException: Method: getMetaData not found in: android.database.sqlite.SQLiteCursor
The full log is at the end of this post.

Can anybody help me understand what is going wrong?

Thanks


B4X:
Private Sub rs2DBResult(rs As ResultSet) As DBResult
    Dim limit As Double = 10000
    Dim jrs As JavaObject = rs
    Dim rsmd As JavaObject = jrs.RunMethod("getMetaData", Null)
    Dim cols As Int = rs.ColumnCount
    Dim res As DBResult
    res.Initialize
    res.columns.Initialize
'    res.Tag = Null 'without this the Tag properly will not be serializable.
    For i = 0 To cols - 1
        res.columns.Put(i,rs.GetColumnName(i).ToLowerCase)
    Next
    res.Rows.Initialize
    Do While rs.NextRow And limit > 0
        Dim row(cols) As Object
        For i = 0 To cols - 1
            Dim ct As Int = rsmd.RunMethod("getColumnType", Array(i + 1))
            'check whether it is a blob field
            If ct = -2 Or ct = 2004 Or ct = -3 Or ct = -4 Then
                row(i) = rs.GetBlob2(i)
            Else if ct = 2 Or ct = 3 Then
                row(i) = rs.GetDouble2(i)
            Else If DateTimeMethods.ContainsKey(ct) Then
                Dim SQLTime As JavaObject = jrs.RunMethodJO(DateTimeMethods.Get(ct), Array(i + 1))
                If SQLTime.IsInitialized Then
                    row(i) = SQLTime.RunMethod("getTime", Null)
                Else
                    row(i) = Null
                End If
            Else
                row(i) = jrs.RunMethod("getObject", Array(i + 1))
            End If
        Next
        res.Rows.Add(row)
    Loop
    res.Cursor = 0
    res.NoRows = res.Columns.Size
    Return res
End Sub


Full Exception Log:
Rich (BB code):
java.lang.RuntimeException: Method: getMetaData not found in: android.database.sqlite.SQLiteCursor
    at anywheresoftware.b4j.object.JavaObject$MethodCache.getMethod(JavaObject.java:366)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:119)
    at b4a.example.sqle._rs2dbresult(sqle.java:480)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:176)
    at anywheresoftware.b4a.shell.DebugResumableSub$RemoteResumableSub.resume(DebugResumableSub.java:22)
    at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:250)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:137)
    at anywheresoftware.b4a.BA$2.run(BA.java:370)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7709)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
 
Last edited:

OliverA

Expert
Licensed User
Longtime User
Can anybody help me understand what is going wrong?
Android's ResultSet does not support all functionality of Java's ResultSet. The only workaround that I can think of is to try to use the JdbcSQL library on Android (it's a port of B4J's jSQL library). Then use that libraries SQL object and the InitializeSQLite method to open your SQLite database. You should then be able to use the getMetaData method of the underlying ResultSet Java object. I did not realize you would try to use this on Android when you requested a solution to your problem here: https://www.b4x.com/android/forum/threads/sending-resultset-over-network-connection.118501/.

Note: Please change the title. This has nothing to do with jRDC2 itself. jRDC2 is designed to run under systems that are supported by B4J, not B4A.

Link to JdbcSQL: https://www.b4x.com/android/forum/t...ly-connect-to-remote-databases.84016/#content
 
Upvote 0

Patrick Clark

Active Member
Licensed User
Android's ResultSet does not support all functionality of Java's ResultSet. The only workaround that I can think of is to try to use the JdbcSQL library on Android (it's a port of B4J's jSQL library). Then use that libraries SQL object and the InitializeSQLite method to open your SQLite database. You should then be able to use the getMetaData method of the underlying ResultSet Java object. I did not realize you would try to use this on Android when you requested a solution to your problem here: https://www.b4x.com/android/forum/threads/sending-resultset-over-network-connection.118501/.

Note: Please change the title. This has nothing to do with jRDC2 itself. jRDC2 is designed to run under systems that are supported by B4J, not B4A.

Link to JdbcSQL: https://www.b4x.com/android/forum/t...ly-connect-to-remote-databases.84016/#content

Thanks I thought that might be the case.

I have looked at jdbcSQL but I don't want remote access to the database.

Is the source available?
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Upvote 0

Patrick Clark

Active Member
Licensed User
Then I don't understand this in the example code
B4X:
    Private jdbcUrl As String = "jdbc:mysql://192.168.0.6/test"
    Private Username As String = "username"
    Private Password As String = "password"
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Then I don't understand this in the example code
That's for the Initialize2 method of the JdbcSQL SQL object. Do something like
B4X:
Dim SQL1 As JdbcSQL
SQL1.InitializeSQLite(File.DirApp, "MyDb.db", True)
JdbcSQL's InitializeSQLite method is the same as B4A's standard Initialize method
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Silly question of me 🤭:
This all works fine in B4J but when I try and use it in B4A I get an exception at line 3
B4X:
    Dim rsmd As JavaObject = jrs.RunMethod("getMetaData", Null)

The exception is:
java.lang.RuntimeException: Method: getMetaData not found in: android.database.sqlite.SQLiteCursor
The RunMethod is points to a Java routine 'getMetaData', which is not included in the given source.
I wonder 🤔 : does B4A say that the Java code is not present in your program (like in your given code in your post 😳), or is there an error in the java code itself because the java code doesn't return an object?
By the way, debugging 'RunMethod' is a hard job. Mostly I add BA.Log("Step x"); to see what goes good.
 
Upvote 0

Patrick Clark

Active Member
Licensed User
Ok thanks, I'll give it a try.

Do you know if the source is available?
Silly question of me 🤭:

The RunMethod is points to a Java routine 'getMetaData', which is not included in the given source.
I wonder 🤔 : does B4A say that the Java code is not present in your program (like in your given code in your post 😳), or is there an error in the java code itself because the java code doesn't return an object?
By the way, debugging 'RunMethod' is a hard job. Mostly I add BA.Log("Step x"); to see what goes good.
Hi

No everything is present, all libraries loaded. OliverA has pointed out that Android ResultSet doesn't support full functionality so all is fine with B4J but not with B4A
 
Upvote 0

Patrick Clark

Active Member
Licensed User
That's for the Initialize2 method of the JdbcSQL SQL object. Do something like
B4X:
Dim SQL1 As JdbcSQL
SQL1.InitializeSQLite(File.DirApp, "MyDb.db", True)
JdbcSQL's InitializeSQLite method is the same as B4A's standard Initialize method

I am getting an error saying can't find "libsqlitejdbc.so" or at least that's what I think it's telling me, when i try to initializeSQLLite
Rich (BB code):
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/b4a.example-v0U-Lsrfwxi_KKcpIcGAww==/base.apk"],nativeLibraryDirectories=[/data/app/b4a.example-v0U-Lsrfwxi_KKcpIcGAww==/lib/arm64, /system/lib64, /product/lib64]]] couldn't find "libsqlitejdbc.so"

B4X:
#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
    #AdditionalJar: sqlite-jdbc-3.7.2
#End Region

Sub Process_Globals
End Sub

Sub Globals
End Sub

Sub Activity_Create(FirstTime As Boolean)

    Dim s As JdbcSQL
    Dim rs As JdbcResultSet
    Dim rp As RuntimePermissions
    Dim dir As String = rp.GetSafeDirDefaultExternal("")
    
    s.InitializeSQLite(dir, "MQTTServer.db", False)
    rs = s.ExecQuery("select * from TestData")
    Log(rs.ColumnCount)   

End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I am getting an error saying can't find "libsqlitejdbc.so" or at least that's what I think it's telling me, when i try to initializeSQLLite
I'm running into the same issue and this may be a dead end (unless someone else comes up with a work around to this). On the Android side, you may have to use
PRAGMA table_info to retrieve the column types. See: https://www.sqlite.org/pragma.html

Link:
 
Upvote 0

Patrick Clark

Active Member
Licensed User
@OliverA

Hi

As you had helped so much I thought I would let you know I have it sorted.

It is a bit convoluted but I now have a portable SQL wrapper that works on both Android and Windows and results can be passed over the nework

What I ended up doing was creating a temporary view from the query rather that actually executing it

Then run "PRAGMA table_info (viewname)" into a resultset.

Then use this information to determine the Types of each column.

Finally I am able to build a DBResult from the temporary view which I then drop.

Just though you might like to know :)
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
@OliverA

Hi

As you had helped so much I thought I would let you know I have it sorted.

It is a bit convoluted but I now have a portable SQL wrapper that works on both Android and Windows and results can be passed over the nework

What I ended up doing was creating a temporary view from the query rather that actually executing it

Then run "PRAGMA table_info (viewname)" into a resultset.

Then use this information to determine the Types of each column.

Finally I am able to build a DBResult from the temporary view which I then drop.

Just though you might like to know :)

But why no any code example ? Please, share
 
Upvote 0
Top