Italian java.lang.RuntimeException: JSON Array expected.

MARCO C.

Active Member
Licensed User
Buongiorno,
sapete come filtrare questo tipo di errore su Sub JobDone(Job As HttpJob) ?

Ho notato che mi segnala questo quando ho problemi di rete o wifi . Se cambio wifi con connessione più forte , ho notato che l'errore scompare .

upload_2019-12-8_14-39-1.png


la Query la lancio tramite il seguente codice, tramite il routine in php presente sul server

B4X:
Sub ExecuteRemoteQuery(Query As String, JobName As String)
    
    Dim job As HttpJob
    job.Initialize(JobName, Me)
    job.PostString("https://appmacro.netsons.org/app/connessione.php", Query)
End Sub

*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
JAVA [Initialize] eventname = objWFI
Ver. 1.94
ExecuteRemoteQuery 350
FetchCountriesList 218
ExecuteRemoteQuery 350
FetchCountriesList-----
Network WIFI connected
WifiAvailable:true
WifiConnected:true
Ping not available in Demo Version.** DONATIONWARE **
MobileAvailable:true
BroadcastReceiver::eek:nReceive::android.net.conn.CONNECTIVITY_CHANGE
*** Service (httputils2service) Create ***
** Service (httputils2service) Start **
** Service (httputils2service) Start **
---- AppUpdating.ReadWebVN
*** Service (httputils2service) Create ***
** Service (httputils2service) Start **
JobDone riga 361
Response from server: <!DOCTYPE html>
<html lang="{ngx.var.captcha_lang or "en"}">
<head>
<meta charset="UTF-8">
<title>Captcha</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7"
crossorigin="anonymous">
<link href="data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAF0lEQVRIx2NgGAWjYBSMglEwCkbBSAcACBAAAeaR9cIAAAAASUVORK5CYII="
rel="icon" type="image/x-icon"/>
<link href="https://fonts.googleapis.com/css?family=Noto+Sans"
rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js?hl={ngx.var.captcha_lang or "en"}"
async defer>
</script>
<style>
html, body {
height: 100%;
}
.wraper {
padding-bottom: 56px;
position: relative;
min-height: 100%;
}
.invisible_mode .wraper {
display: none;
}
.header {
height: 63px;
background-color: white;
}
.middle {
height: 186px;
background-color: rgba(55, 171, 99, 0.75);
}
.bottom {
background-color: #f2f2f2;
position: absolute;
bottom: 0px;
top: 249px;
width: 100%;
}
.captcha_absolute {
margin-top: -153px;
}
.captcha_div {
width: 485px;
margin: 0 auto;
box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.18), 0 0 8px 0 rgba(0, 0, 0, 0.12);
background-color: white;
padding: 47px 48px 18px 48px;
position: relative;
}
.cap_head {
border-bottom: 1px solid #d8d8d8;
padding-bottom: 17px;
margin: 0 10px 20px 10px;
}
.logo_shield {
display: inline-block;
}
.logo_shield img {
width: 54px;
height: 72px;
}
.cap_side {
width: 295px;
}
h4#text {
font-size: 20px;
line-height: 1.38;
color: #000000;
font-weight: bold;
font-family: Noto Sans, sans-serif;
margin: 6px 0 0 0;
}
.cap_text {
font-family: Noto Sans, sans-serif;
font-weight: normal;
font-style: normal;
font-stretch: normal;
line-height: 1.65;
color: #000000;
}
p.cap_note {
font-size: 20px;
margin: 0;
}
.captcha_passed h4#text, .captcha_passed p.cap_note { font-size: 18px }
.cap_mess {
font-size: 13px;
}
.powered_span {
position: absolute;
bottom: 15px;
width: 100%;
text-align: center;
height: 18px;
opacity: 0.45;
font-family: Noto Sans;
font-size: 13px;
font-weight: normal;
font-style: normal;
font-stretch: normal;
color: #1d1d1d;
}
/* A few hacks for re-captcha */
.invisible_mode .re-captcha-wrapper { /* shift reCAPTCHA below our text */
top: 350px !important;
}
.invisible_mode .re-captcha-wrapper > div:first-child { /* hide reCAPTCHA mask */
display: none !important;
}
.visible_mode #re-captcha { /* align to center */
width: 305px;
margin: 0 auto;
}
/* Imunify360 preloader */
.big_loader {
position: absolute;
left: 0;
right: 0;

Message longer than Log limit (4000). Message was truncated.
Error occurred on line: 381 (Main)
java.lang.RuntimeException: JSON Array expected.
at anywheresoftware.b4a.objects.collections.JSONParser.NextArray(JSONParser.java:62)
at org.appmarco.serviceappnew.main._jobdone(main.java:1549)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:351)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
at anywheresoftware.b4a.BA$2.run(BA.java:370)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
 

sirjo66

Well-Known Member
Licensed User
Longtime User
se tutto va bene, dovresti avere la variabile "res" che inizia con un "[", se invece non è andata bene, su "res" ci sarà qualcos'altro.
Basta che aggiungi un IF per verificare che la variabile "res" inizi con "["

Controlla il LOG, ho visto che fai un Log(res) per cui dovresti da lì capire cosa devi controllare
 

MARCO C.

Active Member
Licensed User
se tutto va bene, dovresti avere la variabile "res" che inizia con un "[", se invece non è andata bene, su "res" ci sarà qualcos'altro.
Basta che aggiungi un IF per verificare che la variabile "res" inizi con "["

Controlla il LOG, ho visto che fai un Log(res) per cui dovresti da lì capire cosa devi controllare

Tipo una cosa simile a questo

B4X:
Sub JobDone(Job As HttpJob)
    
    Log(" JobDone riga 361")

    If Job.Success Then
        
        
    Dim res As String
    Dim LenCar As Int
        res = Job.GetString
        Log("Response from server: " & res)
        
        If res.SubString2(0,1) <>"[" Then
            ToastMessageShow("Errore su ricezione dati  ",True)
            
        End If
        
        LenCar =res.Length
        Dim parser As JSONParser
        parser.Initialize(res)
        Select Job.JobName
            
            Case
 

drgottjr

Expert
Licensed User
Longtime User
If res.SubString2(0,1) <>"[" Then
ToastMessageShow("Errore su ricezione dati ",True)
>>>>> return <<<<<<
End If

senza "return", il codice sequente segue come si non ci fosse un errore, no?
 

LucaMs

Expert
Licensed User
Longtime User
If res.SubString2(0,1) <>"[" Then

Giusto perché magari non la conosci (va benissimo anche usare SubString in quel modo, eh)...

If Not(res.StartWith("[")) Then


P.S. anche perché altre volte potresti voler vedere se inizi con una lunga parola o testo e in quel modo non devi contare i caratteri.

If res.StartWith("Pinco") then

senza SubString2(0,6) - senza contare la lunghezza. Inoltre è certamente più leggibile, comprensibile.
 
Last edited:

MARCO C.

Active Member
Licensed User
If res.SubString2(0,1) <>"[" Then
ToastMessageShow("Errore su ricezione dati ",True)
>>>>> return <<<<<<
End If

senza "return", il codice sequente segue come si non ci fosse un errore, no?

ovviamente si ... con il Return . Altrimenti continua , anche se c'è l'evento indesiderato
 

MARCO C.

Active Member
Licensed User
Giusto perché magari non la conosci (va benissimo anche usare SubString in quel modo, eh)...

If Not(res.StartWith("[")) Then


P.S. anche perché altre volte potresti voler vedere se inizi con una lunga parola o testo e in quel modo non devi contare i caratteri.

If res.StartWith("Pinco") then

senza SubString2(0,6) - senza contare la lunghezza. Inoltre è certamente più leggibile, comprensibile.

Fantastico
Non non conosco la funzione STARTWITH
In Visual Basic .. non c'era :)
Grazie
 

drgottjr

Expert
Licensed User
Longtime User
se "job.success" è vero, el messaggio intero è ricevuto. se ci sono problemi di connessione, non vedo come "job.success" sarebbe vero...

nonostante, per "incastrare" gli errori imprevisti (ad es, dati perduti per mala connessione), sirve "try/catch":

B4X:
try
    dim l as list = parser.NextArray
catch
    toastmessageshow("Errore di json",falso)
    return
end try

va bene cercare "[" all'inizio, ma se non si trova "]" al finale (a causa di la connessione, oppure un'altra ragione), si lancia un errore, nonostante il fatto che il server sirve un json array e l'app l'aspettava. try/catch evita un crash
 

MARCO C.

Active Member
Licensed User
se "job.success" è vero, el messaggio intero è ricevuto. se ci sono problemi di connessione, non vedo come "job.success" sarebbe vero...

nonostante, per "incastrare" gli errori imprevisti (ad es, dati perduti per mala connessione), sirve "try/catch":

B4X:
try
    dim l as list = parser.NextArray
catch
    toastmessageshow("Errore di json",falso)
    return
end try

va bene cercare "[" all'inizio, ma se non si trova "]" al finale (a causa di la connessione, oppure un'altra ragione), si lancia un errore, nonostante il fatto che il server sirve un json array e l'app l'aspettava. try/catch evita un crash

In effetti hai ragione : molto spesso non basta controllare la presenza del primo carattere "["..
Spesso mi capita di vedere nel log una sequenza assurda di caratteri che non riesco a gestire come anomalia , per poi riprovare una nuova richiesta di query al server .
Ora prova se con
Try e catch la cosa migliora .
Grazie mille
 

MARCO C.

Active Member
Licensed User
se "job.success" è vero, el messaggio intero è ricevuto. se ci sono problemi di connessione, non vedo come "job.success" sarebbe vero...

nonostante, per "incastrare" gli errori imprevisti (ad es, dati perduti per mala connessione), sirve "try/catch":

B4X:
try
    dim l as list = parser.NextArray
catch
    toastmessageshow("Errore di json",falso)
    return
end try

va bene cercare "[" all'inizio, ma se non si trova "]" al finale (a causa di la connessione, oppure un'altra ragione), si lancia un errore, nonostante il fatto che il server sirve un json array e l'app l'aspettava. try/catch evita un crash

Scusa, nel mio codice ... dove mi consigli di inserire il try e catch ?

B4X:
Sub JobDone(Job As HttpJob)
   
    Log(" JobDone riga 361")

    If Job.Success Then
       
       
    Dim res As String
    Dim LenCar As Int
        res = Job.GetString
        Log("Response from server: " & res)
       
        If res.SubString2(0,1) <>"[" Then
            ToastMessageShow("Errore su ricezione dati  ",True)
           Return
        End If
       
        LenCar =res.Length
        Dim parser As JSONParser
        parser.Initialize(res)
        Select Job.JobName
           
            Case
 

drgottjr

Expert
Licensed User
Longtime User
ad es, così

B4X:
dim l as list
try
    l = parser.NextArray
catch
    toastmessageshow("Errore di json",falso)
Log("Error: " & LastException.Message)
    return
end try

codice...

non c'è motivo di sospettare un problema, ma devi sempre essere al sicuro, no?
supponiamo che la risposta sia corretta. fai ciò che è normale: l = parser.NextArray.
ma lo fai dentro di try/catch. se tutto va bene, el "catch" non si opera, l è valido, e la vita
continua. se parser.NextArray lancia l'errore, lo cattura el "catch". allora puoi fare ciò che
pensi appropriato. (a mio parere, el test per "[" non prova che segue un json array valido...)
B4A te avvisa che tipo di errore con LastException.message. ma, soprattutto, il catch si termina
con return. in caso contrario, el codice segue come se non ci fosse nessun errore
 

MARCO C.

Active Member
Licensed User
ad es, così

B4X:
dim l as list
try
    l = parser.NextArray
catch
    toastmessageshow("Errore di json",falso)
Log("Error: " & LastException.Message)
    return
end try

codice...

non c'è motivo di sospettare un problema, ma devi sempre essere al sicuro, no?
supponiamo che la risposta sia corretta. fai ciò che è normale: l = parser.NextArray.
ma lo fai dentro di try/catch. se tutto va bene, el "catch" non si opera, l è valido, e la vita
continua. se parser.NextArray lancia l'errore, lo cattura el "catch". allora puoi fare ciò che
pensi appropriato. (a mio parere, el test per "[" non prova che segue un json array valido...)
B4A te avvisa che tipo di errore con LastException.message. ma, soprattutto, il catch si termina
con return. in caso contrario, el codice segue come se non ci fosse nessun errore

eccolo modificato . Grazie per la dritta
B4X:
Sub JobDone(Job As HttpJob)
    
    Log(" JobDone riga 361")

    If Job.Success Then
        
        
    Dim res As String
    Dim LenCar As Int
        res = Job.GetString
        Log("Response from server: " & res)
            
        If Not(res.StartsWith("[")) Then
            ToastMessageShow("Errore su ricezione dati  ",True)
            Log("Errore su ricezione dati")
            Return
        End If
        
        LenCar =res.Length
        Dim parser As JSONParser
        parser.Initialize(res)
        Select Job.JobName
            
            Case serviceDevice
                Dim trovato As String
                Dim find As Boolean=False
                
                Dim l As List
                
                Try
                    l = parser.NextArray
                Catch
                    ToastMessageShow("Errore di json",False)
                    Log(LastException)
                    Return
                End Try
                
                If l.Size = 0 Then
                    trovato = "N/A"
                Else
                    
                    Dim m As Map
                    m = l.Get(0)
                    trovato="(" & m.Get("seriale")& ")" & CRLF
                    trovato= trovato & m.Get("utilizzatore")
                    find=True
                End If
 

drgottjr

Expert
Licensed User
Longtime User
la prova per "[" non prova que non ci sono errori piu tardi.
parser.NextArray prova que esiste o non un json array valido.

la prova per "[" sì prova que la riposta non comincia con "[",
ma questo non è per forza un errore. c'è una differenza.
(il server potrebbe aver cambiato qualcosa...)

se vuoi fermarti proprio qui, va bé, ma no è necessariamente per un
errore. se dipendi da quel test per sapere se esiste un errore,
try/catch è meglio. spero di averlo spiegato.

fai come si tutto fosse normale. try/catch ti protegge. il più importante
è evitare un crash. dentro del "catch", puoi fare un'analisi per decidere
come procedere. con "catch" sai que c'era un errore, con il test
per "[" non lo sai sicuro.
 

drgottjr

Expert
Licensed User
Longtime User
mi costa scrivere in italiano con la tastiera americana, ma guarda:
B4X:
 if wjob.success then            ' prima buona notizia
     dim res as string = wjob.getString
     wjob.release
     dim json as jsonParser    ' aspettiamo json, no?  se non, puo metterlo piu in basso

    ' se aspettiamo json, inizialo
    try
       json.initialize( res )
    catch
       log("errore al iniziarsi il json...")   ' non e json oppure no e valido
       return
    end try

    '  allora se si tratta sempre di un server chi manda json array:
    dim l as list
    try
       l = json.NextArray       ' successo!  si salta il catch e l'app continua
    catch  ' problema!
       log("non e json array... o almeno, non e valido")
       ' puoi fare altre cose qui ...
       return     ' non si deve permitire che il codice normale piu basso si esegua
    end try

    codice ...               ' in caso normale di json array

    ------------------------------------------------------------------------------------------------------
    se si tratta di piu di un server oppure un server chi manda json array in certi casi e json object en altri, si fa "case/select"
    
     select wjob.name
        case server_chi_manda json_array
            dim l as list
            try
                l = json.NextArray
            catch
                log("non e json array... o almeno, non e valido")
                ' se puo fare altre cose qui ...
                return
            end try

            codice normale per json array ...

        case oltra_server_chi_manda_json_object
            dim m as map
            try
                m = json.NextObject
            catch
                log("non e json object... o almeno, non e valido")   ' se puo fare altre cose qui ...
                return
            end try

            codice normal per jason object...

        case alto_server_chi_sempre_manda_testo
            ' gia abbiamo catturato il testo nella variabile text (vedere piu in alto)
            codice normale per testo ...
      end select
   else   ' successo falso
      toastmessageshow("Job was not success: " & lastException.message, false)
   end if

certo, se non si aspetta ricevere json del server, non s'inizia il json parser ciecamente. fallo dove si aspetta ricevere json. d'altro canto, se inizi il json parser e non riusce, potrebbe indicare che si tratta di testo, cosa che non e precisamente un errore ma semplicemente una cosa inaspettata. dentro del catch, potresti seguire una linea differente. come ho detto, il piu importante e evitare un crash.
 

MARCO C.

Active Member
Licensed User
mi costa scrivere in italiano con la tastiera americana, ma guarda:
B4X:
 if wjob.success then            ' prima buona notizia
     dim res as string = wjob.getString
     wjob.release
     dim json as jsonParser    ' aspettiamo json, no?  se non, puo metterlo piu in basso

    ' se aspettiamo json, inizialo
    try
       json.initialize( res )
    catch
       log("errore al iniziarsi il json...")   ' non e json oppure no e valido
       return
    end try

    '  allora se si tratta sempre di un server chi manda json array:
    dim l as list
    try
       l = json.NextArray       ' successo!  si salta il catch e l'app continua
    catch  ' problema!
       log("non e json array... o almeno, non e valido")
       ' puoi fare altre cose qui ...
       return     ' non si deve permitire che il codice normale piu basso si esegua
    end try

    codice ...               ' in caso normale di json array

    ------------------------------------------------------------------------------------------------------
    se si tratta di piu di un server oppure un server chi manda json array in certi casi e json object en altri, si fa "case/select"
  
     select wjob.name
        case server_chi_manda json_array
            dim l as list
            try
                l = json.NextArray
            catch
                log("non e json array... o almeno, non e valido")
                ' se puo fare altre cose qui ...
                return
            end try

            codice normale per json array ...

        case oltra_server_chi_manda_json_object
            dim m as map
            try
                m = json.NextObject
            catch
                log("non e json object... o almeno, non e valido")   ' se puo fare altre cose qui ...
                return
            end try

            codice normal per jason object...

        case alto_server_chi_sempre_manda_testo
            ' gia abbiamo catturato il testo nella variabile text (vedere piu in alto)
            codice normale per testo ...
      end select
   else   ' successo falso
      toastmessageshow("Job was not success: " & lastException.message, false)
   end if

certo, se non si aspetta ricevere json del server, non s'inizia il json parser ciecamente. fallo dove si aspetta ricevere json. d'altro canto, se inizi il json parser e non riusce, potrebbe indicare che si tratta di testo, cosa che non e precisamente un errore ma semplicemente una cosa inaspettata. dentro del catch, potresti seguire una linea differente. come ho detto, il piu importante e evitare un crash.

A questo punto disturbo nuovamente drgottjr , per un dubbio che mi è venuto ora :
quale dei 2 codici che mi ha proposto è più idoneo alla ricezione dati dopo che lancio una query ( tipo : select * from clienti where ..... )

Questa con array
B4X:
case server_chi_manda json_array
            dim l as list
            try
                l = json.NextArray
            catch
                log("non e json array... o almeno, non e valido")
                ' se puo fare altre cose qui ...
                return
            end try

            codice normale per json array ...

o questa con MAP ( che non ricordi di aver mai utilizzato )

B4X:
 case oltra_server_chi_manda_json_object
         dim m as map
            try
                m = json.NextObject
            catch
                log("non e json object... o almeno, non e valido")   ' se puo fare altre cose qui ...
                return
            end try

            codice normal per jason object..

vedi anche il mio primo #post con la Sub ExecuteRemoteQuery(Query As String, JobName As String)

Presumo che il mio caso non sia una map ...ma una semplice lista .
Come Map non ho creato nessuna struttura a monte

Grazie per la pazienza dimostrata ;)
 
Last edited:

MARCO C.

Active Member
Licensed User
Last edited:

drgottjr

Expert
Licensed User
Longtime User
è necessario sapere (o conoscere) prima il formato della risposta del server. json? sì o no.
qual è il formato esatto della risposta? no c'è maniera di indovinare. nel tuo caso, invia un json
array (si supone...).

un json array (normalmente) sarebbe composto di una serie di oggetti json.
il formato della risposto te dice dove si trovano questi oggetti (e possibilmente altri array).
metti una rispota intera dentro di uno .zip e lascialo qui nel forum. o dami il "query"
(job.PostString("https://appmacro.netsons.org/app/connessione.php", Query)) lo faro io.

il oggetto json è un tipo di "map", sia, una struttura come un array, ma con un indice string in
vece di un integer, ad es:
un array:
B4X:
dim cosa(2) as string
cosa(0) = "marco", cosa(1) = "corrias" ...

con un map, sarebbe cosa("nome"), cosa("cognome"). ti do un momento da riflessione...

allora, questa struttura non esiste in basic. quindi, è necessario fare così:
B4X:
dim cosa as map
cosa.initialize
cosa.put("name", "marco") 
cosa.put("cognome","corrias")

e doppo (per accedere):
B4X:
dim name as string = cosa.get("nome")    '!!!

un po' come un list, ma un list (è un array) si indica con un integer. il map, no. l'indice
è un string.

un oggetto json si scrive così: {"name": "marco", "cognome": "corrias", "eta", "30"}
allora, un list (oppure json array) di persone sarebbe (possibilmente):

B4X:
[
   {"nome":"marco", "cognome": "corrias", "eta": "30"}, 
   {"nome": "": "cognome":"", "eta":''"}, 
   {"nome": "": "cognome":"", "eta":""},
   ...
]
in questo caso, un json array composto di oggetti json. ci sono altre possibilita.

per leggere questo json:

B4X:
dim l as list
try
   list = json.NextArray
catch
   toastmessageshow("non è array o la risposta è corrotta",true)
   return
end try

dim i as int
for i = 0 to list.size - 1
   dim person as map = l.get(i)
   dim nome as string = person.get("name")
   dim cognome as string = person.get("cognome")

   codice...
next

guarda qui: https://www.b4x.com/android/forum/threads/android-json-tutorial.6923/
 
Top