PDA

View Full Version : [JSON + JAVA] esempio


agosteeno
17-02-2011, 11:26
Salve a tutti, siccome nn riesco a trovare nessun esempio che mi sia realmente d'aiuto, provo a fare una domanda direttamente qua, sperando che qualcuno possa darmi una mano. Sostanzialmente dovro' fare un'applicazione che girera' su Android, dovra' fare alcune richieste ad un server in Java (c'e' una servlet in ascolto del client) e poi ricevere dei dati in risposta. Questi dati dovranno essere serializzati in JSON e spediti con un paradigma REST (quindi usando GET e POST HTTP. Il punto e' che nn degli esempi pratici dal quale trarre spunto e le varie guide e tutorial nn mi sono d'aiuto. Quindi per cercare di capire ho formulato un esempio:
Ho un client (generico in Java) che dovra' fare una richiesta al server, mandando un oggetto dato:

public class dati {
/**
* classe che serve per incapsulare alcuni dati a caso che verranno scambiati tra client e server
*/

int numero;
String stringa;

public dati() {
numero = 0;
stringa = "";
}
}


Il client dovrebbe inviarlo tramite una httpPost con un valore numero particolare e la stringa vuota e il server dovrebbe rispondergli con il valore della stringa corrispondente a quel valore di numero (un esempio stupidissimo giusto per fargli spedire qualcosa).
Vorrei serializzare il tutto con JSON, recuperarlo sul server fare l'operazione e poi rispedirlo al client.
Se qualcuno mi da' una mano gli saro' eternamente grato!

PGI-Bis
17-02-2011, 15:41
In verità tutto si riduce nel mandare una stringa al server.

Lato servlet, nel processRequest potresti avere una cosa del genere:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
BufferedReader input = request.getReader();
JSONObject object = (JSONObject) JSONValue.parse(input);
Number numero = (Number) object.get("numero");
if(numero.intValue() == 0) {
object.put("stringa", "ciau pep'");
} else {
object.put("stringa", "not understood");
}
System.out.println("Incoming request: " + object.toJSONString());
PrintWriter out = response.getWriter();
try {
out.print(object.toJSONString());
} finally {
out.close();
}
}

Qui uso le API json-simple.

Lato android-client, pigli il dato e lo impacchetti in un JSONObject:

JSONObject o = new JSONObject();
o.put("numero", dato.getNumero());
o.put("stringa", dato.getStringa());

Ottieni quindi la stringa json:

String json = o.toString();

Poi apri una connessione http alla servlet, mandi come corpo del messaggio la stringa json e leggi il corpo della risposta come una stringa JSON:

String jsonString = stringa letta dal corpo della risposta http...
o = new JSONObject(jsonString);
dato.setNumero(o.getInt("numero"));
dato.setStringa(o.getString("stringa"));

Sfortunatamente le api http di android sono mutuate da apache e come tutte le api di apache per dire "ciao" sembra di dover spaccare l'atomo ma, turandosi il naso, non dovrebbe essere così complicato.

agosteeno
17-02-2011, 15:52
Grazie mille, veramente molto gentile. Ora sto' cercando di cavarci fuori qualcosa, ma mi sembra abbastanza incasinato per fare cose che dovrebbero essere semplici... Le api poi sono introvabili e nn spiegano quasi nulla. Sopratutto poi faccio fatica a trovare esempi!

PGI-Bis
17-02-2011, 16:01
Io sto scaricando per curiosità adesso l'sdk di android (tra un venti-venticinque giorni dovrei aver finito, grazie telecomitalia), magari poi saprò essere più specifico sulla parte client.

Comunque la documentazione delle api la trovi qui:

http://developer.android.com/reference/packages.html

Per lo sviluppo io ti consiglierei netbeans per la parte server che è un gioiellino, installi il plug-in JavaEE con glassfish 3 e vai via liscio come l'olio. Per la parte client invece vai di Eclipse + Android Development Toolkit.

agosteeno
17-02-2011, 16:08
No, ma su android in generale non ho problemi, si trova parecchio materiale in giro. Il problema e JSON... Doveva essere semplicissimo e invece non ci sto' capendo nulla!

PGI-Bis
17-02-2011, 18:25
Santi numi, ogni avvio dell'emulatore è un parto :D.

Comunque, il json di android sembra funzionare allo stesso modo degli altri, a parte l'essere un pelo più scomodo per via delle eccezioni.

Il JSONObject è una mappa chiave valore, tale e quale ad un hashmap. In più ha la particolarità di poter essere serializzato-deserializzato da una stringa, che è appunto in formato json. La serializzazione avviene con il metodo toString.

JSONObject o = new JSONObject();
o.put("chiave", "valore");//valore può anche essere un primitivo
o.put("chiave2", "valore2");
String datiInFormatoJSon = o.toString();

La stringa è poi fatta di un tot di { " : } eccetera ma a noi non interessa, usiamo questi JSONObject apposta per potercene fregare.

Quindi alla fine tu spari attraverso il socket o l'httphandler o quel che è la stringa che ottieni dal metodo toString del tuo/dei tuoi JSONObject.

Quando ricevi, fai l'inverso: ricevi una stringa che supponi essere un testo json e la converti:

String rispostaDelServer = corpo della risposta o un attributo
JSONObject o = new JSONObject(rispostaDelServer);

A quel punto, se tutto va come deve, "o" ha i suoi campi, accessibili tramite le chiavi omonime e i metodi get.

C'è una certa farraginosità nel fatto che le api lato android sono proprio il minimo sindacale (un po' come json-simple). Sarebbe stato un pelo più utile poter avere una conversione diretta javabean-json ma, volendo, non è difficile da scrivere.

En passant, per chi fosse interessato, anche il plug-in per netbeans pare funzionare:

http://kenai.com/projects/nbandroid/pages/Intro

agosteeno
21-02-2011, 10:48
Giusto una cosa per vedere se ho capito: in pratica la "definizione" diciamo dell'oggetto JSON la faccio quando inserisco i campi. Mi spiego, quando creo un oggetto JSON (lato client per es) e inseriesco i campi numero e stringa, questo oggetto diventa:
{
numero:valN,
stringa:valS,
}

Poi nel server, quando arriva la stringa creo un JSONObject, estraggo i campi numero e stringa (come se mi arrivasse un oggetto che so' avere quei campi). Correggimi se sbaglio: praticamente non c'e' quindi una definizione vera e propria, e' solo una specie di "accordo" tra client e server che l'oggetto che arriva avra' quei campi.

PGI-Bis
21-02-2011, 11:38
La sensazione è, a grandi linee, corretta.

A grandi linee perchè comunque parliamo di definizioni in senso proprio: stabilisci che esistono delle collezioni nominali di attributi in grado di ripartire un'universalità di cose in due sottoinsiemi. Non hai una controparte tipizzata per quelle definizioni (tipicamente un javabean), anche perchè le api android quanto a javabean mi sembrano scarsine. Puoi comunque creare una classe di supporto per la conversione lato client di una stringa json in un javabean. A a quel punto arriveresti idealmente a dire una cosa del tipo:

//lato client
Dati dati = new Dati();
dati.setNumero(x);
dati.setStringa(y);
invia(dati.toJSONString());

//lato server
JSONBean messaggio = JSONBeans.read(input);
if(messaggio instanceof Dati) {
Dati d = (Dati) messaggio;
if(d.getNumero() == 0) d.setStringa("pippo");
writer.write(d.toJSONString());
}

Ma è un meccanismo ipotetico che dovresti creare usando le api di android (lato java credo che ci siano già dei convertitori json-javabean)

agosteeno
22-02-2011, 09:39
Questo sarebbe una cosa che mi piacerebbe di piu'. Io dovrei fare alcune operazioni: la prima sarebbe di inviare un numero identificativo per avere indietro alcuni dati associati a questo (che potrebbe essere il primo il valore di un campo di un oggetto e i dati associati sono il resto dei campi di questo oggetto), per es:

class dato{
int id;
string val1;
double val2;
objX val3;
}


Io invierei una nuova istanza di dato parsato con JSON dove c'e' solo il valore di id, il server legge questo valore e legge dei dati associati e risponde con un'oggetto dato che ha i dati relativi ad id.
Siccome io, per vari motivi, ancora nn ho tutti i dati che mi interessano e cmq dovrei fare delle aggiunte in seguito, vorrei poter fare il parsing solo dell'oggetto e non dei campi, in modo che l'aggiunta dei nuovi dati la farei solo nella classe oggetto (o cmq solo nella logica che tratta questi dati). Non so' se ho reso l'idea...
In pratica nel modulo che invia e riceve questi dati al/dal dispositivo non vorrei occuparmi dei campi particolari, ma solo dell'oggetto... Non so' se una cosa del genere sia possibile...

PGI-Bis
22-02-2011, 12:30
Tutto si può fare, al limite bisogna vedere se c'è qualcosa di già fatto per evitare di perdere tempo. Per la piattaforma SE/EE ci sono sicuramente dei "trasformatori" javabean-json, per android non lo ma si può scrivere se manca.