HttpPost Params Map

Good day,

I am trying to add an HttpPost to a Device driver code and am at a lost as to what the issue may be. This may be more of a Java/Groovy problem, but as I need to use Hubitat's flavor of HttpPost and the restriction of use of other libraries, here I am. The exception I'm catching is:
*** Exception: java.lang.ClassCastException: class java.lang.String cannot be cast to class java.util.Map (java.lang.String and java.util.Map are in module java.base of loader 'bootstrap')*

Follows is the pertinent code snippet I've put together. It 'compiles' clean in Device code.


accessToken = "6d51**redacted**81d7160f5a"
vehicleID = "af12b**redacted**7655ef474"

// Making a JSON array for the data/body of the HttpPost request, per API spec

def request = [
	[getPath:{'/battery'}],
	[getPath:{'/location'}],
	[getPath:{'/charge'}]	
]

def myJsonBuilder = new groovy.json.JsonBuilder()

myJsonBuilder {
    requests request.collect { 
        [ 
            path: it.getPath() 
         ] 
    }
}

// Building the Map Params for the HttpPost request

String myURI = "https://api.<domain>.com/v2.0/vehicles/$vehicleID/batch"
String myHeader = "Authorization: Bearer $accessToken"
	
Map<String, String> params = new HashMap<String, String>();
params.put("uri", myURI);
params.put("headers", myHeader);
params.put("contentType", "application/json");
params.put("requestContentType", "application/json");
params.put("body", myJsonBuilder);

// Catch 'params' value for display on Device page
state.lastResp = params
	
try{
    httpPost(params) { resp ->
		state.lastResp = resp.data
		log.debug "Response: $resp"
		slurper = new JsonSlurper().parseText(state.lastResp)
		String myLat=Float.toString(slurper.latitude) 
		String myLong=Float.toString(slurper.longitude) 
		sendEvent(name: "csGeoLocation", value: myLat + "|" + myLong)
		String myIsPluggedIn = slurper.isPluggedIn
		String myState = slurper.State
		sendEvent(name: "csPluggedInStatus", value: myIsPluggedIn)
		sendEvent(name: "csChargeState", value: myState)
		Integer myPercentRemaining = slurper.percentRemaining * 100
		sendEvent(name: "csBatteryChargeLevel", value: myPercentRemaining)
}
		 }   catch (Exception e) {
            log.debug "** Exception: $e"
        }

The value of 'params' that I display on the Device page is:

*headers=Authorization: Bearer 6d51**redacted**81d7160f5a, body={content={requests=[{path=/battery}, {path=/location}, {path=/charge}]}}, uri=https://api.<domain>.com/v2.0/vehicles/af12b**redacted**7655ef474/batch, contentType=application/json, requestContentType=application/json}*

..which is more or less what I'd expect given my limited understanding of Maps (although I have no idea where the '{content=' in the 'body' parameter comes from).

When I do a .getclass() on 'params' (outside of Hubitat (Groovy console)....but running same code through to 'params' definition), I get... class java.util.HashMap

Alas, I don't know what the exception is telling me as to the problem. Any insights/recommendations would be appreciated.

Thanks

1 Like

I would just capture the response data in the try {} block and move everything else outside of it. Then you will get a better error that should tell you the actual line number of the problem.

You can initialize a variable to null before the try, then after the catch if its still null then it failed, if not null then you can process it.

Here is a slightly different example, it is an async http but I wrapped the JSON parse with a try in case it fails. I am just parsing the response and then doing the rest of my tasks afterwards.

You could also try my catch line below, it attempts to get the line number of the error to narrow it down more. (credit to someone else on here for posting that tip originally)

void zwDetailsUpdateAsync() {
    params = [
            uri    : "http://127.0.0.1:8080",
            path   : "/hub/zwaveDetails/json",
    ]
    logTrace "zwDetailsUpdateAsync ${params}"
    asynchttpGet("zwDetailsHandler", params)
}

void zwDetailsHandler(resp, data) {
    logTrace "Processing Z-Wave Details Response"
    Map respData = [:]
    try {
        def jSlurp = new JsonSlurper()
        respData = jSlurp.parseText(resp.data as String) as Map
    } catch (Exception e) {
        logErr "EXCEPTION CAUGHT: ${e.message} ON LINE ${e.stackTrace.find{it.className.contains("user_")}?.lineNumber}"
    }
    state.zwDevices = respData.zwDevices as Map
    state.zwNodes = respData.nodes as List
    logDebug "zwDetailsHandler Found ${state.zwDevices?.size() ?: 0} devices and ${state.zwNodes?.size() ?: 0} nodes"
}
1 Like

Thanks for the reply and the tip re: getting to a line number on the exception...I'll give it a try and see where it gets me.