2012-05-10 5 views
12

in Java quando uso l'annotazioneJAX-RS JSON abbastanza uscita

@Produces("application/json") 

l'uscita non è formattato in formato leggibile. Come posso farlo?

+0

cosa JSON-serializzatore stai usando? –

+0

Basta usare lo standard netbeans. Creato con la procedura guidata "nuovi servizi Web RESTful dalle classi di entità" Sono nuovo, ma penso che sia Jackson? – niklas

+1

Sì, è Jackson – DaTroop

risposta

13

Crea questa classe ovunque nel tuo progetto. Sarà caricato sulla distribuzione. Si noti lo .configure(SerializationConfig.Feature.INDENT_OUTPUT, true); che configura il mapper per formattare l'output.

Per Jackson 2.0 e versioni successive, sostituire le due linee .configure() con questi: .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false) .configure(SerializationFeature.INDENT_OUTPUT, true);

e modificare le importazioni di conseguenza.

package com.secret; 

import javax.ws.rs.Produces; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.ext.ContextResolver; 
import javax.ws.rs.ext.Provider; 
import org.codehaus.jackson.map.DeserializationConfig; 
import org.codehaus.jackson.map.ObjectMapper; 
import org.codehaus.jackson.map.SerializationConfig; 

/** 
* 
* @author secret 
*/ 
@Provider 
@Produces(MediaType.APPLICATION_JSON) 
public class JacksonContextResolver implements ContextResolver<ObjectMapper> { 
    private ObjectMapper objectMapper; 

    public JacksonContextResolver() throws Exception { 
     this.objectMapper = new ObjectMapper(); 
    this.objectMapper 
     .configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false) 
     .configure(SerializationConfig.Feature.INDENT_OUTPUT, true); 
    } 

    @Override 
    public ObjectMapper getContext(Class<?> objectType) { 
     return objectMapper; 
    } 
} 

Tenere presente che la formattazione ha un effetto negativo sulle prestazioni.

+2

Come sa Jersey utilizzare questo risolutore di contesto, piuttosto che il provider JAXRS integrato in Jackson? – Cheeso

+0

con l'annotazione @Provider – DaTroop

+1

Presumibilmente entrambi sono annotati in questo modo ... – Cheeso

17

Solo per la cronologia, se si desidera abilitare l'output grazioso solo per alcune risorse, è possibile utilizzare the @JacksonFeatures annotation in un metodo di risorsa.

Ecco esempio:

@Produces(MediaType.APPLICATION_JSON) 
@JacksonFeatures(serializationEnable = { SerializationFeature.INDENT_OUTPUT }) 
public Bean resource() { 
    return new Bean(); 
} 
+1

'@ JacksonFeatures' è disponibile solo su un metodo, non su una classe. – NomeN

1

Sulla utile risposta di DaTroop, qui è un'altra versione che permette di scegliere tra JSON ottimizzata e JSON formattato in base alla presenza o meno di un parametro "bella":

package test; 


import javax.ws.rs.Produces; 
import javax.ws.rs.core.Context; 
import javax.ws.rs.core.MediaType; 
import javax.ws.rs.core.MultivaluedMap; 
import javax.ws.rs.core.UriInfo; 
import javax.ws.rs.ext.ContextResolver; 
import javax.ws.rs.ext.Provider; 

import org.codehaus.jackson.map.ObjectMapper; 
import org.codehaus.jackson.map.SerializationConfig; 

@Provider 
@Produces(MediaType.APPLICATION_JSON) 
public class JacksonContextResolver implements ContextResolver<ObjectMapper> { 

    private ObjectMapper prettyPrintObjectMapper; 
    private UriInfo uriInfoContext; 

    public JacksonContextResolver(@Context UriInfo uriInfoContext) throws Exception { 
     this.uriInfoContext = uriInfoContext; 

     this.prettyPrintObjectMapper = new ObjectMapper(); 
     this.prettyPrintObjectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); 
    } 

    @Override 
    public ObjectMapper getContext(Class<?> objectType) { 

     try { 
      MultivaluedMap<String, String> queryParameters = uriInfoContext.getQueryParameters(); 
      if(queryParameters.containsKey("pretty")) { 
       return prettyPrintObjectMapper; 
      } 

     } catch(Exception e) { 
      // protect from invalid access to uriInfoContext.getQueryParameters() 
     } 

     return null; // use default mapper 
    } 
} 
+0

Sebbene questa sia una buona soluzione, funziona * solo la prima volta che viene chiamata una risorsa. Dopodiché, il provider è stato registrato e sei bloccato con una bella stampa (o meno). Per una reale flessibilità, scegli una soluzione di filtro. – mvreijn

12

Ecco come eseguire correttamente l'output condizionale pretty/non-pretty json in base alla presenza di "pretty" nella stringa di query.

Creare un PrettyFilter che implementa ContainerResponseFilter, che sarà eseguito su ogni richiesta:

@Provider 
public class PrettyFilter implements ContainerResponseFilter { 

    @Override 
    public void filter(ContainerRequestContext reqCtx, ContainerResponseContext respCtx) throws IOException { 

     UriInfo uriInfo = reqCtx.getUriInfo(); 
     //log.info("prettyFilter: "+uriInfo.getPath()); 

     MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters(); 
     if(queryParameters.containsKey("pretty")) { 
      ObjectWriterInjector.set(new IndentingModifier(true)); 
     } 

    } 

    public static class IndentingModifier extends ObjectWriterModifier { 

     private final boolean indent; 

     public IndentingModifier(boolean indent) { 
      this.indent = indent; 
     } 


     @Override 
     public ObjectWriter modify(EndpointConfigBase<?> endpointConfigBase, MultivaluedMap<String, Object> multivaluedMap, Object o, ObjectWriter objectWriter, JsonGenerator jsonGenerator) throws IOException { 
      if(indent) jsonGenerator.useDefaultPrettyPrinter(); 
      return objectWriter; 
     } 
    } 
} 

e praticamente il gioco è fatto!

È necessario assicurarsi che questa classe venga utilizzata da Jersey mediante scansione automatica dei pacchetti o registrata manualmente.

Passate poche ore a cercare di raggiungere questo obiettivo e scoprendo che nessuno ha mai pubblicato una soluzione pronta all'uso.

+0

Questa è la soluzione migliore di gran lunga, vorrei poter upvote due volte. Non dimenticare di usare 'register (PrettyFilter.class)' nel tuo 'ResourceConfig'. – mvreijn