Java Question How use b4xMap in java?

behnam_tr

Active Member
Licensed User
Longtime User
I want to send a list containing map from b4j to Java and use it (Preferably use b4xmap)
Sample code on the b4x side

B4X:
    Dim bodylist As List
    bodylist.Initialize
   
    Dim bodymap As Map
    bodymap.Initialize
    bodymap.Put("id","10")
    bodymap.Put("name","testname10")
    bodymap.Put("price","10000")
   
    bodylist.Add(map1)

    Log(myclass.testlist(bodylist))

java code:
 public static String testlist(ArrayList cars){

        for(int i= 0; i< cars.size(); i++) {
            anywheresoftware.b4a.objects.collections.Map map1 = new anywheresoftware.b4a.objects.collections.Map();
            map1.Initialize();
            map1= (Map) cars.get(i);

            return map1.Get("id").toString() + map1.Get("name").toString()+map1.Get("price").toString();
        }
       return null;
    }

Error:
Waiting for debugger to connect...
Program started.
1712928404207
Error occurred on line: 99 (Main)
java.lang.ClassCastException: class anywheresoftware.b4a.objects.collections.Map$MyMap cannot be cast to class anywheresoftware.b4a.objects.collections.Map (anywheresoftware.b4a.objects.collections.Map$MyMap and anywheresoftware.b4a.objects.collections.Map are in unnamed module of loader 'app')
    at mypackage.TaxApiSDKV1.testlist(TaxApiSDKV1.java:489)
    at b4j.example.main._button1_click(main.java:238)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:234)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
    at anywheresoftware.b4a.BA$1.run(BA.java:236)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
 

JohnC

Expert
Licensed User
Longtime User
ChatGPT says...

The error you're encountering in your Java code is due to a type mismatch when casting objects passed from B4J to Java. Specifically, the ClassCastException indicates that Java is unable to cast the object of anywheresoftware.b4a.objects.collections.Map$MyMap to anywheresoftware.b4a.objects.collections.Map.

The problem arises because the object you receive in Java (cars.get(i)) is of a type internal to the B4A Map class (like a private subclass), and not directly the Map class itself. To fix this issue, you will need to handle the casting or conversion differently.

One way to address this is to utilize Java's HashMap instead of B4A's Map when fetching the map from the list in Java. You can convert the received object to a HashMap in Java, which is more generic and should work smoothly for key-value pair manipulations. Here is the corrected Java code:

B4X:
import java.util.ArrayList;
import java.util.HashMap;

public static String testlist(ArrayList cars) {
    StringBuilder result = new StringBuilder();

    for (int i = 0; i < cars.size(); i++) {
        HashMap map1 = (HashMap) cars.get(i);

        String id = map1.get("id").toString();
        String name = map1.get("name").toString();
        String price = map1.get("price").toString();

        result.append(id).append(name).append(price);
    }
    return result.toString();
}
Make sure that the data passed from B4J are HashMaps in Java compatible format. In your B4X code, the transmission of data appears to be correct, but ensure the map you add to bodylist is indeed bodymap (you have a typo using map1 instead of bodymap).

Here's a corrected version of your B4X code with minor adjustments for clarity and correctness:

B4X:
Dim bodylist As List
bodylist.Initialize

Dim bodymap As Map
bodymap.Initialize
bodymap.Put("id", "10")
bodymap.Put("name", "testname10")
bodymap.Put("price", "10000")

bodylist.Add(bodymap)  ' Ensure correct map is added

Log(myclass.testlist(bodylist))
With these changes, your code should successfully pass the map from B4J to Java and handle it correctly in Java without casting errors.
 

TILogistic

Expert
Licensed User
Longtime User
or see: (It will give you an idea.)
 

behnam_tr

Active Member
Licensed User
Longtime User
Thank you, none of them helped
For now, I solved the problem with Jason, but I would like to know the solution of using maps
 

Daestrum

Expert
Licensed User
Longtime User
maybe
B4X:
...
    Dim bodylist As List
    bodylist.Initialize
  
    Dim bodymap As Map
    bodymap.Initialize
    bodymap.Put("id","10")
    bodymap.Put("name","testname10")
    bodymap.Put("price","10000")
  
    bodylist.Add(bodymap)

    Log((Me).As(JavaObject).RunMethod("testlist",Array(bodylist)))
End Sub
#If java
import java.util.*;

public static String testlist(ArrayList cars){

        for(int i= 0; i< cars.size(); i++) {
            Map map1 = new HashMap();
            map1 = (Map) cars.get(i);

            return (map1.get("id").toString()+ " " + map1.get("name").toString() + " " + map1.get("price").toString());
        }
       return null;
    }
#End If
You can shorten the java by having
B4X:
 Map map1 = new HashMap((Map)cars.get(i));
instead of
B4X:
            Map map1 = new HashMap();
            map1 = (Map) cars.get(i);
 

Daestrum

Expert
Licensed User
Longtime User
There's a logic flaw in the code, it will only ever return the first map items.
You need something like
B4X:
public static String[] testlist(ArrayList cars){
        String reply[] = new String[cars.size()];
        for(int i= 0; i< cars.size(); i++) {
            Map map1 = new HashMap((Map)cars.get(i));
            reply[i] = (map1.get("id").toString()+ " " + map1.get("name").toString() + " " + map1.get("price").toString());
        }
       return reply;
    }

Called like
B4X:
    Dim rep() As String = (Me).As(JavaObject).RunMethod("testlist",Array(bodylist))
    For Each s As String In rep
        Log(s)
    Next
 
Top