I have a method that works perfectly fine in the IDE, but fails once compiled. The error is
_VariantString cannot be cast to JSONItem
Here is the method:
// This method will get a distance from the Google Routes API.
Var LoSource As String = Officiel.Longitude
Var LaSource As String = Officiel.latitude
Var LoDest As String = Site.Longitude
Var LaDest As String = Site.latitude
Var GetDistance as New URLConnection
Var Request as string = "{""origin"":{""location"":{""latLng"":{""latitude"": " + LaSource + ",""longitude"": " + LoSource + "}}},""destination"":{""location"":{""latLng"":{""latitude"":" + LaDest +",""longitude"":" + LoDest + "}}},""travelMode"": ""DRIVE"",""routingPreference"": ""TRAFFIC_UNAWARE"",""computeAlternativeRoutes"": false,""routeModifiers"": {""avoidTolls"": false,""avoidHighways"": false,""avoidFerries"": false},""languageCode"": ""fr-CA"",""units"": ""METRIC""}"
GetDistance.RequestHeader("X-Goog-Api-Key") = APIKeyG.left(APIKeyG.length-2)
GetDistance.RequestHeader("X-Goog-FieldMask") = "routes.distanceMeters"
GetDistance.SetRequestContent(Request, "application/json")
Var Response As String = GetDistance.SendSync("POST", "https://routes.googleapis.com/directions/v2:computeRoutes", 5)
'system.debuglog Response
Var Resp as New JSONItem
Resp.Load(Response)
Var RespRoutes as New JSONItem
RespRoutes = Resp.lookup("routes", "Erreur")
Var Route as New JSONItem
Route = RespRoutes.Valueat(0) ' always select the default (preferred) route
Var Dist as Variant
Dist = Route.value("distanceMeters")
Return Dist.IntegerValue
'System.debuglog Dist.stringvalue
Is this something I am doing wrong, or did I stumble on a bug? It puzzles me somewhat that the same method works fine in the IDE, and fails once compiled.
I am developing on Windows 11, but compiling for Linux X64. This is with 2024 R4.1.
Which line is highlighted when you get the RuntimeException?
Edit: Add some debug logging to signal to yourself where the exception is getting raised. The Stack would take us to this code, but it doesn’t tell us whether the Request or the Response is the one being malformed. We need to know whether it’s your request or the response causing this message.
I don’t think that the JSONItems are malformed, since the method does return the correct value when I run the program from the IDE. The error happens only when I run the compiled application on the Linux server.
But yes, I am trying to get as much logging as possible. This is a web application. Remote debugging fails miserably for me between my dev computer and the linux server. That makes it a bit more complicated.
Based on the error, I suspect the error is occurrring here:
Var Dist as Variant
Dist = Route.value(“distanceMeters”)
If Dist is declared as a String instead, I get the same error.(but with string instead of variant)
I am still not on a public server, and still not using Lifeboat. I will have to do it the hard way.
The error does not seem to occurr where I expected it. I changed Dist to be an Integer (the value is an integer). In the IDE, the method works still just fine, but I ger the casting error regardless.
I will now encapsulate every step in try-catch traps to see where it occurs.
is not a JSON Array; It is a JSON Object, which contains an Array named “routes”.
To extract the data, you would need to use this syntax:
Var RouteArray as JSONItem
Var Route as JSONItem
RouteArray = RespRoutes.Value("routes")
Route = RouteArray.valueAt(0)
This works, the result:
Edit to add: I see now you didn’t include all the code in your second example, so it’s possible RespRoutes may in fact be the Array you extracted? I’m not clear - can you please post a tiny sample project (you can upload a zipped Xojo project file here).
Nevermind my prior response, I think the problem may be here:
Var RespRoutes as New JSONItem
RespRoutes = Resp.lookup("routes", "Erreur")
Var Route as New JSONItem
If your response fails to include a “routes” object, then Resp.lookup() will not return a JSONItem but rather the string “Erreur” stored in a Variant).
Trying to cast the variant string “Erreur” to a JSONItem will fail exactly as you see:
_VariantString cannot be cast to JSONItem
So as written, your code is not going to properly handle the case when the URLConnection response doesn’t include the “routes” object.
Why is it failing on Linux? Perhaps something about your Linux machine is getting a different response from googleapis ?
You could harden your code a bit by changing the “Erreur” string like this:
Var RespRoutes as New JSONItem
RespRoutes = Resp.lookup("routes", "[\"distanceMeters\": -999]")
so as to return valid JSON syntax containing an array with an invalid -999 value.
Or even better:
Var RespRoutes as JSONItem
RespRoutes = Resp.lookup("routes", nil)
if RespRoutes = nil then
// There is no array of routes, so we need to handle the error condition here
end if
So, I traced the issue to another part of the program where Officiel is managed. When not running on my development machine, the incorrect locale would be used and the longitude and latitude data would not be loaded. A very old bug that did not affect much until now.
It had nothing to do with the retrieved JSON ddata, it had everything to do with the correct management of an object created elsewhere in the program.