B4J Question java.lang.ClassCastException

Nandosta

Member
When building a simple List I intended to use for testing I got following error:

java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String;

The strange thing is that when I step through the For .. Next loop code line by line, the error does not show.

Code: Copy
'Non-UI application (console / server application)
#Region Project Attributes
    #CommandLineArgs:
    #MergeLibraries: True
#End Region

Sub Process_Globals
   
End Sub

Sub AppStart (Args() As String)

    Private Fruit_List As List
    Private Fruit_Array(2) As String
   
    Fruit_List.Initialize
    Fruit_List.Add(Array("banana", "1.49", "kg"))
    Fruit_List.Add(Array("lemon",  "1.69", "pc"))
    Fruit_List.Add(Array("apple",  "2.29", "kg"))
       
    For i = 0 To (Fruit_List.Size - 1)
        Fruit_Array = Fruit_List.Get(i)
        Log("(" & i & ") = " & Fruit_Array(0) & " " & Fruit_Array(1) & " " & Fruit_Array(2))
    Next
   
End Sub

Code: Copy
Waiting for debugger to connect...
Program started.
Error occurred on line: 22 (Main)
java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; ([Ljava.lang.Object; and [Ljava.lang.String; are in module java.base of loader 'bootstrap')
    at b4j.example.main._appstart(main.java:90)
    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:632)
    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:108)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:95)
    at b4j.example.main.main(main.java:29)
Program terminated (StartMessageLoop was not called).
 
Fruit_Array is an array of Strings, not an Array of string arrays which I don't think is possible in B4X. You are probably better using a custom type.
B4X: Copy
Sub Class_Globals   
    Type Fruit (Name As String, price As String, unit As String)   
End Sub

Public Sub CreateFruit (Name As String, price As String, unit As String) As Fruit
    Dim t1 As Fruit
    t1.Initialize
    t1.Name = Name
    t1.price = price
    t1.unit = unit
    Return t1
End Sub


Private Sub Button1_Click
    Private Fruit_List As List   
    Fruit_List.Initialize
    Fruit_List.Add(CreateFruit("banana", "1.49", "kg"))
    Fruit_List.Add(CreateFruit("lemon",  "1.69", "pc"))
    Fruit_List.Add(CreateFruit("apple",  "2.29", "kg"))
  
    Dim Item As Fruit 
    For i = 0 To (Fruit_List.Size - 1)
        Item = Fruit_List.Get(i)
        Log("(" & i & ") = " & Item.Name  & " " & Item.price & " " & Item.unit)       
    Next
nd Sub
 
Upvote 1
B4X: Copy
    Private Fruit_List As List
    Private Fruit_Array() As Object    '<--you are using this as an object array with dimensions to be determined (which is fine)
  
    Fruit_List.Initialize
    Fruit_List.Add(Array("banana", "1.49", "kg"))
    Fruit_List.Add(Array("lemon",  "1.69", "pc"))
    Fruit_List.Add(Array("apple",  "2.29", "kg"))
      
    For i = 0 To (Fruit_List.Size - 1)
        Fruit_Array = Fruit_List.Get(i)
        Log("(" & i & ") = " & Fruit_Array(0) & " " & Fruit_Array(1) & " " & Fruit_Array(2))
    Next
 
Upvote 1
Object arrays can not be assigned to String arrays.
As for it working in the stepping process in debug mode, I would guess that some intermediate internal assignment masks the problem.
 
Upvote 0
Both answers are correct. Your options:

1. Change Fruit_Array type to String.
2. Array = Array As Object. You can add arrays of strings instead:
Code: Copy
Fruit_List.Add(Array As String("banana", "1.49", "kg"))
3. Use a custom type <--- best option

When you step by step, the code is executed in a different pipeline that is more lenient in regarding to type checking.
 
Upvote 0
As an observation
Code: Copy
 Private Fruit_Array(2) As String
Has a dimension of 2 so cannot hold the three values (name, cost, weight) returned from the list.
 
Upvote 0
Solved.

Code: Copy
' Changing this line'
Fruit_List.Add(Array("banana", "1.49", "kg"))
' into
Fruit_List.Add(Array As String("banana", "1.49", "kg"))
' makes it run OK

Thanks to all of you who took the time to look into this.
B4A is only my 14th (or 15th?, lost count) development environment, so I will need some more time to get used to it.
 
Upvote 0
Back
Top