2013-05-09 16 views
6

miei dati JSON in arrivo request().body().asFormUrlEncoded().get("records")Bind dati (JSON) forma complessa automaticamente

[{"string":"foo","termId":"793340"},{"string":"bar","termId":"460288"}] 

La mia definizione del modulo:

public static class MyForm { 
    @Constraints.Required 
    public List<Map<String,String>> records; 
    public String someField; 
} 

Essa non vincola la records automaticamente. Poi ho provato con un POJO invece:

public static class Record { 
    public String string; 
    public String termId; 
    public void setString(String string) { 
     this.string = string; 
    } 
    public void setTermId(String termId) { 
     this.termId = termId; 
    } 
} 

e adattato forma:

public static class MyForm { 
    @Constraints.Required 
    public List<Record> records; 
    public String someField; 
} 

non vincola i dati in automatico. Ho davvero bisogno di utilizzare API di basso livello come Jackson per questo semplice caso d'uso? Qualche puntatore? Impossibile trovare un esempio di copia/incolla, e da Jackson ho org.codehaus.jackson e com.fasterxml.jackson sul mio classpath.

AGGIORNAMENTO 2013-05-10: aggiunto un campo secondario someField per chiarire che lo records è solo un campo, non l'intera struttura dati. La risposta che segue (non riesco a vedere le risposte su questo schermo di modifica, quindi non importa, ce n'è solo una) funziona, ma solo con i record. Ecco un esempio:

private List<Record> recordsFromRequest() { 
    String[] jsonData = request().body().asFormUrlEncoded().get("records"); 
    Form<Record> recordDummyForm = Form.form(Record.class); 
    Iterator<JsonNode> it = Json.parse(jsonData[0]).iterator(); 
    List<Record> records = new ArrayList<>(); 
    while (it.hasNext()) { 
     records.add(recordDummyForm.bind(it.next()).get()); 
    } 
    return records; 
} 

Per gli altri campi del modulo che faccio, come al solito:

Form<MyForm> form = play.data.Form.form(MyForm.class).bindFromRequest(); 

Così adesso riesco a tutti i dati del modulo distaccati, e il mio problema è risolto in questo modo (grazie !). Tuttavia, è un po 'brutto. Quello che non riesco ancora a capire è come avere tutti i dati dei post in un oggetto. Se qualcuno risponde a questo, aggiornerò la domanda e rimuoverò questa parte. Altrimenti accetterò l'unica risposta tra un paio di giorni.

risposta

2

A mio parere, è necessario utilizzare le API jackson come descritto nella documentazione ufficiale here.

Presumo che si ottiene il JSON con request().body().asFormUrlEncoded().get(), quindi restituisce String[] contenente la stringa JSON. Si può fare qualcosa di simile (Forse un po 'complicato e perdere Exception movimentazione):

String[] jsonData = request().body().asFormUrlEncoded().get("records") 
MyForm myForm = new MyForm(); 
// Record should act as form, because each JSON string data contain this type 
Form<Record> form = Form.form(Record.class); 
// parse the JSON string and assign iterator 
Iterator<JsonNode> it = Json.parse(jsonData[0]).iterator(); 
// assign to the MyForm instance 
while (it.hasNext()) { 
    formData.records.add(form.bind(it.next()).get()); // bind the JSON and add 
} 

Così, alla fine del codice di cui sopra, dovrebbe ((MyForm) formData).records contiene List<Record> oggetto dalla JSON.

+1

Come scritto nella domanda: questo funziona. Non mi consente di combinare i miei "record" con altri valori di forma. E spero ancora che il gioco abbia o avrà in futuro una soluzione molto più semplice. –

1

Stavo cercando di riprodurre il tuo errore. Così ho creato un modello come segue:

public class EasyContact { 

public String someField; 

@Required 
public List<Record> records; 

public static class Record { 
    public String string; 
    public String termId; 
    @Override 
    public String toString() { 
     return "Record [string=" + string + ", termId=" + termId + "]"; 
    } 
} 

@Override 
public String toString() { 
    return "EasyContact [someField=" + someField + ", records=" + records+ "]"; 
} 
} 

Poi un controller semplice come questo:

public static Result submit() { 
    Form<EasyContact> filledForm = form(EasyContact.class).bindFromRequest(); 
    Logger.info("Posted binding: " + filledForm.get().toString()); 
    return ok(); 
} 

Ora è il momento di prova:

curl -X POST -H 'Content-Type: application/json' -d '{"someField":"didac", "records": [{"string": "string1", "termId": "111"},{"string": "string2", "termId": "222"}]}' localhost:9000/contacts 

Nella riga di comando del gioco posso vedere l'output corretto:

[info] application - Posted binding: EasyContact [someField=didac, records=[Record [string=string1, termId=111], Record [string=string2, termId=222]]] 

L'unico errore che ho trovato è quando Content-Type non è impostato nella richiesta (-H ...).In tal caso, il framework genera un'eccezione IllegalState.

+0

Il '@ Required' funziona per te? Ho realizzato questo tipo di architettura ma non controllo '@ Requiered' in oggetto figlio (Record nel nostro caso) –

+1

Aggiungi anche l'anotazione @Valid. Potrebbe funzionare –

+0

Ho il mio dio Mi hai salvato! Se vuoi rispondere alla mia domanda qui: http://stackoverflow.com/questions/31165273/form-validation-in-play-framework La contrassegnerò come risolta. –

Problemi correlati