2014-09-03 18 views
6

Ho una cinquantina di controller che utilizzano l'annotazione @ResponseBody.Spring Ajax @ResponseBody con valori restituiti nulli

Ti piace questa:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) 
public @ResponseBody Object getObject(@RequestParam("id") Long id) { 
    Object object = provider.getObject(id); 
    return object; 
} 

Alcune volte getObject metodo di ritorno null. Il problema è che sul lato client ottengo la risposta vuota anziché null.

Nell'implementazione iniziale abbiamo l'oggetto personalizzato JsonView che funziona come wrapper senza l'annotazione @ResponseBody.

Ti piace questa:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) 
public JsonView<Object> getObject(@RequestParam("id") Long id) { 
    Object object = provider.getObject(id); 
    return new JsonView(object); 
} 

Quindi stava funzionando benissimo.

Ho trovato qualche soluzione a How do you override the null serializer in Jackson 2.0? ma sfortunatamente funziona solo per i campi nei POJO.

Avete qualche idea su come può essere gestito?

Grazie in anticipo!

+0

Puoi dirci in quale libreria è presente la generica classe 'JsonView'? –

risposta

6

Questo non è un problema da risolvere.

Spring ha uno schema comune in cui, se un metodo di gestione restituisce null, significa indicare che il gestore ha già trattato la produzione e la scrittura del contenuto di risposta appropriato e che non sono necessarie ulteriori azioni in primo piano.

Spring ha applicato questo modello nella sua RequestResponseBodyMethodProcesser (l'implementazione HandlerMethodReturnValueHandler per @ResponseBody). Controlla se il valore restituito è null. Imposta la richiesta come gestita. Se il valore restituito non è null, tenta di serializzarlo con uno HttpMessageConverter appropriato.

Un'opzione è creare la propria annotazione @ResponseBodyNull e un corrispondente HandlerMethodReturnValueHandler che fa lo stesso ad eccezione anche di handle null. Si noti che non è possibile riutilizzare il codice necessariamente da RequestResponseBodyMethodProcess perché alcuni HttpMessageConverters non riescono a provare a utilizzare null.

Un'altra opzione simile è quella di ignorare RequestResponseBodyMethodProcessor ad accettare null (con le limitazioni sopra citate) e registrarlo in modo esplicito con il tuo RequestMappingHandlerMapping, sovrascrivendo il default HandlerMethodReturnValueHandler s. Devi farlo con attenzione (cioè registrare gli stessi), a meno che tu non voglia perdere la funzionalità.

La soluzione migliore, IMO, sarebbe quella di non occuparsi di null nel corpo della risposta. Se getObject non restituisce nulla, mi sembra un 404. Imposta il codice di risposta appropriato e voilà!

È sempre possibile iniettare il HttpServletResponse nel vostro metodo di gestore e fare qualcosa di simile

Object object = getObject(..); 
if (object == null) { 
    response.getWriter().print("null"); 
    // also set the content type to application/json 
} 
return object; 

Supponendo che si sapeva che questo doveva essere serializzato per JSON.

2

è possibile restituire un ResponseEntity e specificare lo stato HTTP di un errore quando l'oggetto è nullo:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) 
public ResponseEntity<Object> getObject(@RequestParam("id") Long id) { 
    Object object = provider.getObject(id); 
    if (object == null) { 
     return new ResponseEntity<Object> (HttpStatus.BAD_REQUEST); // Or any other error status 
    } else { 
     return new ResponseEntity<Object> (object, HttpStatus.OK); 
    } 
} 

In questo modo il vostro cliente sarà in grado di sapere quando l'oggetto è nullo controllare lo stato della risposta.

Se è effettivamente necessario il valore NULL restituito è possibile configurare Jackson per serializzare esso (codice da tkuty):

<mvc:annotation-driven> 
    <mvc:message-converters register-defaults="true"> 
     <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
      <property name="objectMapper"> 
       <bean class="com.fasterxml.jackson.databind.ObjectMapper"> 
        <property name="serializationInclusion"> 
         <value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value> 
        </property> 
       </bean> 
      </property> 
     </bean> 
    </mvc:message-converters> 
</mvc:annotation-driven> 

Spero che questo aiuto.

+0

Sfortunatamente qualsiasi approccio non funziona nel mio caso: 1) Il primo continua restituisce risposta vuota in quanto il seguente codice è presente in: \t \t Oggetto body = responseEntity.getBody(); \t \t if (corpo! = Null) { \t \t \t writeWithMessageConverters (corpo, returnType, inputMessage, outputMessage); \t \t} \t \t else { \t \t \t // intestazioni a filo del HttpServletResponse \t \t \t outputMessage.getBody(); \t \t}. Quindi è solo preint null come priviues ed evitare il metodo writeWithMessageConverters. – fashuser

+0

Il tuo secondo suggerimento non funzionerà, perché "null" non raggiungerà mai il "MappingJackson2HttpMessageConverter", si fermerà al "RequestResponseBodyMethodProcessor". –

-3

In primo luogo, io consiglio di non si dovrebbe scrivere in questo modo:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) 
public @ResponseBody Object getObject(@RequestParam("id") Long id) { 
    /* 
    */ 
} 

farlo come codice standard. prova questo:

@RequestMapping(value = "/someUrl.controller", method = RequestMethod.GET) 
@ResponseBody 
public Object getObject(@RequestParam("id") Long id) { 
    Object object = provider.getObject(id); 
    return object; 
} 

Ho esperienza con scanner di qualità, in questo modo è possibile evitare errori rilevati dallo scanner. Per quanto riguarda il tuo problema, puoi provare Transformer o addScala() per restituire un POJO. Ho affrontato questo problema e ho fatto un patto! In bocca al lupo.

+0

Vuoi dire specificare l'annotazione sotto la firma del metodo, perché questo provoca un errore di compilazione "Duplicate annotation @ResponseBody"? Grazie! – fashuser

+0

No Voglio dire, non si dovrebbe mettere annotazione dopo accessor e prima datatype di un metodo. Usa la mia strada. Scanner di qualità (come SonarQube) realizzerà che si tratta di un errore grave e deve essere un refactoring! Ho affrontato e ottenere esperienze. Non è un errore di compilazione "annotazione duplicata". Si compilerà correttamente, ma dovresti standardizzare il tuo codice. –

+0

Come è un errore? Potrebbe essere l'opinione dello stile del codice, ma sicuramente non è un errore. E la tua risposta non risponde alla domanda. –