2

I am using grails 2.3.3 in a development and I'm having a problem working with a 2 dimensional array that has been taken from a json web page. The particular problem occurs when there are null values in 3rd column of the 2D array.

Here is an overview of the workflow in grails:

The json object is first rendered:

    render ( ['P' : jsonObject.picId, 'A' : jsonObject.audioId, 'C' : jsonObject.caption, 'V' : jsonObject.vidTemplateId ] as JSON)

It is then recast into a 2D array to pass in a storeVideoSlotData service:

def vidpNmList = [][]
vidpNmList[0] = jsonObject.picId
vidpNmList[1] = jsonObject.audioId
vidpNmList[2] = jsonObject.caption

Then a call to the service which passes vidpNmList:

def vsaInst = vdSlotService.storeVideoSlotData( vidpNmList, session)

Within the service it gets recast again into it's three separate components:

def picId = vidpNmList[0]
def audioId = vidpNmList[1]
def caption = vidpNmList[2]

Here is a listing of the two forms of the data:

vidpNmList: [[331, 332, 334, null, null, null, null, null, null, null, null, null], [null, null, null, null, null, null, null, null, null, null, null, null], [null, Input Caption Data, Input Caption Data, null, null, null, null, null, null, null, null]]

picId: [331, 332, 334, null, null, null, null, null, null, null, null, null]

audioId:[null, null, null, null, null, null, null, null, null, null, null, null]

Captions: [null, Input Caption Data, Input Caption Data, null, null, null, null, null, null, null, null]

Within this service any reference to specific values in this caption column that contain null values causes an error:

When caption[currSlotNo] has a null value this line causes an error:

if(!(caption[currSlotNo]) ) {
    log.debug(" caption is null and cannot be displayed. ")

}

The error being:

homevu1.VdSlotService updVideoSlotData pictureInst : 331 picId[currSlotNo]: 331 homevu1.VdSlotService updVideoSlotData picMK: 331

homevu1.VdSlotService updVideoSlotData audMK: null

errors.GrailsExceptionResolver JSONException occurred when processing request: [POST] /HomeVu1/videoShr/getJsVidCoords

JSONArray[0] not found.. Stacktrace follows: org.codehaus.groovy.grails.web.json.JSONException: JSONArray[0] not found.

The same error occurs if I refer to the value of the element within the vidpNmList array.

What am I doing wrong or perhaps there is some work around?

Here is a workaround I've introduced with a 'try/catch' construct whcih leaves the 'captionVal' as null:

        def captionVal = null
        try{ captionVal = caption[currSlotNo] 

            log.debug(" ${functionName} caption value assigned correctly ")
        }
        catch (Exception eWrite)
        {       
            //      fails - can only trap and work around the error atm.
                log.debug(" ${functionName} caption value fails to assign correctly - remains at null default - Error Message: $eWrite")                                
        }

Code showing resetting the json object caption element from a "null" string to an actual null prior to assigning it to vidpNmList:

        for (def iC = 0; iC < jsonObject.caption.size() ; iC++)
        {
            String currCap = jsonObject.caption[iC]
            if( currCap == "null") 
            {
                log.debug(" getJsVisCoords null value iC: $iC " + " caption[iC]: " + jsonObject.caption[iC] + " currCap Length: " + currCap.length())
                jsonObject.caption[iC] = null
            }
            else
            {
                log.debug(" getJsVisCoords Non null value iC: $iC " + " caption[iC]: " + jsonObject.caption[iC] + " currCap Length: " + currCap.length())
            }

        }
        vidpNmList[2] = jsonObject.caption

-mike

mikek
  • 169
  • 1
  • 14
  • I don't think that error message relates to the log.debug line at all. they look like different logs. the actual message isn't even in that message. JSON objects in groovy can be difficult to capture nulls. I would try checking if (JSONObject.NULL.equals(i.fieldName) { i.fieldName=null} . where i is your iteration fieldName would in your case be the catual index i.e [indexId] and then set i[indexId]=null to set it a real groovy null value from a JSON null value – V H Mar 24 '16 at 21:49
  • @vahid I've corrected the error log to match the data - to explain as I was running various versions of the data I must have pulled out the incorrect log. The corrected log displays the picture and audio values for the 0th element correctly but fails when trying to reference the 0th element of the captions array which is null. The key thing here is that the audio value is also null but there is no problem in referring to this value. The behavior does seem inconsistent. Will look at trying your suggestion asap. – mikek Mar 25 '16 at 13:57
  • I've shown a try/catch workaround I've introduced above in the main question which works well. However, I would like to understand what is going wrong here in order to get a better understanding of json. Dare I say it could be a bug? – mikek Mar 25 '16 at 14:26
  • I was going to write back about checking length - length and size are different : http://stackoverflow.com/questions/28920603/jsonarray-error-org-json-jsonexception-jsonarray1-not-found I have started doing similar stuff myself to catch other array issues https://github.com/vahidhedayati/mailinglist/blob/master/src/groovy/grails/plugin/mailinglist/core/ScheduleBaseBean.groovy#L72. You could try https://github.com/vahidhedayati/mailinglist/blob/master/src/groovy/grails/plugin/mailinglist/core/ScheduleBaseBean.groovy#L88-L90 something like this instead of try catch which is obviously more expe – V H Mar 25 '16 at 14:40
  • also one last check you say their both nulls from two different sets can you check the null actual types in each row to see if their identical so println "${caption[currSlotNo].getClass()} --" and do that for your other row that has nulls and compare both null classes ensure their same for a start. Was thinking if that proves a waste why not duplicate a record but have 2nd row be the 3rd too - to see if its more a bug than data – V H Mar 25 '16 at 23:32
  • @vahid As you suggest when setting up the json webpage I have swapped the captions dataset (which fails) and audio dataset (which works). The error still occurs in accessing null captions elements whichever order you use to setup the json web page. WRT the class type the failing captions is a 'string' class type whereas the other two are of class type 'integer'. I can see that it would be difficult to apply length/size dimensions of an array being passed through JSON. Are there some guidlines when handling 'nullable' string datasets through a json web page? – mikek Mar 29 '16 at 17:20
  • difficult to say, firstly not being an expert in the subject and secondly the unknown of what is producing the json data ? a java script ? or it actually looks like a controller action. Anyway I found this http://stackoverflow.com/questions/21120999/representing-null-in-json which may be of use. Right at the end it talks about null strings probably being better presented as something else - although those nulls are "" rather than actual null – V H Mar 29 '16 at 19:01
  • @vahid I have other problems with the null values of json strings to and from web/js and server/controllers. The null gets changed in the render process to a string of "null". To resolve this I explicitly define nulls when the caption is blank in both the GET server code when setting up the json Within the web js where a caption may be edited to blank and I trap them and set them to be null. In the POST code of the controller I look for all null" values in the JSON caption array and force them to be null again. I still use the try/catch to avoid the error: "JSONArray[] not found" appears. – mikek Mar 31 '16 at 18:34
  • @vahid I have tried .get() as you suggested but still getting the same error. To clarify the vidpNmList is assigned from the json object: vidpNmList[2] = jsonObject.caption - I guess it assigns a pointer. Prior to making this assignment I loop through the caption part of the json object to identify captions that have a "null" string and force them to be actually null : jsonObject.caption[iC] = null (In the question above I've added code of this). Perhaps rather than setting the actual value to null I'm setting the pointer to the value to null which is causing the jsonarray expection error. – mikek Apr 01 '16 at 16:45
  • ok looking further unsure about that for loop usually def iC=0; int iC=0; should be declared outside of for loop. I will write it another way in the answer below and it maybe the problem is in this for loop.... – V H Apr 01 '16 at 16:58

1 Answers1

0

Unsure where the JSON gets involved in this scenario but looking at you code above you have other choices:

Up to where you have these Lists collected as caption audioId picId

def picId = vidpNmList[0]
def audioId = vidpNmList[1]
def caption = vidpNmList[2]

You showed an output closed to this:

def picId=[331, 332, 334, null, null, null, null, null, null, null, null, null]
    def audioId=[null, null, null, null, null, null, null, null, null, null, null, null]
    def Captions=[null, 333, 333, null, null, null, null, null, null, null, null]

Now this is me playing around with the list:

    / you are current failing on this
    def pic=picId[0]


    //instead of above element[id] try .get(id)
    def cap=Captions.get(2)
    println "--- ${pic} @@@ ${cap}"

    //Then you can test by saying 
    if (cap&&something&&somethingEls) { 
        doSomething
    }

I get back

--- 331  @@@ 333

Anyways to find out more above lists If that is what you are getting back in those objects have a look here Take a look here: http://mrhaki.blogspot.co.uk/2009/10/groovy-goodness-finding-data-in.html

Edited to add in regards to the for loop:

  for (def iC = 0; iC < jsonObject.caption.size() ; iC++)

Typically in groovy the for loop should be expressed like this:

int iC=0
for (iC < jsonObject.caption.size() ; iC++) {

Anyways try this:

jsonObject?.caption?.eachWithIndex{ item, i ->
   if (JSONObject.NULL.equals(item) { 
      item=null
   } 
}
vidpNmList[2] = jsonObject.caption

If that fails you could try iterating it to a new list although I doubt it will really be required:

def finalList=[]
jsonObject?.caption?.eachWithIndex{ item, i ->
   if (JSONObject.NULL.equals(item) { 
      item=null
   } 
  finalList << item
}
vidpNmList[2] = finalList

much shorter and easier to follow than your for loop version :) I added withIndex and i and in your case if be item[i] but there is no need since you are already iterating through each element so you could even cut it down further to :

jsonObject?.caption?.each{ item ->
   if (JSONObject.NULL.equals(item) { 
      item=null
   } 
}
vidpNmList[2] = jsonObject.caption

You may need to tweak this if (JSONObject.NULL.equals(item) { in all of the above examples since thinking about it, this is no longer json so to something like this:

if (!item ||(item && item=='null')) { 
 item=null
}
V H
  • 8,382
  • 2
  • 28
  • 48