2016-05-20 33 views
8

Sto utilizzando Jersey per implementare il servizio web RESTful. Ora il MediaType in cui restituisco i dati è JSON.Personalizza il serializzatore Json invece del valore predefinito di Jersey?

@GET 
@Produces({MediaType.APPLICATION_JSON }) 
public Response service() { 
    return Response 
      .ok(entity) 
      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) 
      .build(); 
} 

Qui ho impostato CONTENT_TYPE a JSON e la mia entità verrà convertito in JSON dal framework Jersey.

Ora voglio personalizzare la mia risposta JSON.

Es: Voglio rimuovere gli elementi vuoti o cambiare il nome della chiave del mio oggetto Json. predefinito di conversione JSON di Jersey:

{ 
    "cinter" : { 
    "state" : 1, 
    "checks" : 10, 
    } 
} 

Quello che voglio:

{ 
    "cin" : { 
    "st" : 1, 
    "cs" : 10, 
    } 
} 

So che posso usare di Jackson libreria mia ObjectMapper personalizzare il mio JSON in base alle mie esigenze.

Ma è questo il modo standard per farlo se voglio la conversione JSON in modo diverso rispetto alla conversione predefinita di Jersey ??

Oppure posso modificare i parametri in ObjectMapper di Jersey ??

Devo usare il mio ObjectMapper?

+0

Che aspetto hai POJO? Perché può essere facilmente risolto con @JsonProperty (name = "cit") e così via sopra i nomi dei campi.Se non riesci a cambiare il tuo pojo, allora sì, devi usare Mixin personalizzato o serializzatore su 'ObjectMapper' – varren

+0

@My POJO ha annotazioni JAXB (@XmlRootElement) e sì, non posso cambiarle. Quindi per ogni diversa risposta dovrei configurare 'ObjectMapper' in modo diverso? Qualche idea su 'ContextResolver'? –

+0

Non puoi _cambiarli, ma puoi _add_ annotazioni? Se possibile, '@ JsonProperty' sulle proprietà e' @ JsonRootName' sulla classe con risolvere il tuo problema –

risposta

3

Ecco le mie opinioni sulle opzioni. Prima di tutto

Quindi per ogni risposta diversa dovrei configurare ObjectMapper in modo diverso?

Se si desidera utilizzare entrambe le versioni JSON in luoghi diversi come questo

public Response getObject()   // returns {"cinter" : {"state" : 1,"checks" : 10}} 
public Response getShortNamesObject() // returns {"cin" : {"st" : 1,"cs" : 10}} 

Than sì, è necessario utilizzare più ObjectMappers.

Ma se si desidera utilizzare solo 1 rappresentazione ovunque, probabilmente sarà possibile impostare Jackson una volta con un mix personalizzato per le lezioni. In ogni caso ecco come si può fare entrambe le opzioni: E consente di guardare al caso semplice con la versione appena 1 JSON necessario

public class TestBean { 
    private String name; 
    private int id; 
    //getters and setters 
} 

public interface TestBeanMixin { 
    @JsonProperty("short_field_name") 
    String getName(); 
    @JsonProperty("short_field_id") 
    int getId(); 
} 

@Provider 
@Priority(1) 
public class MixInJacksonJsonProvider extends JacksonJaxbJsonProvider { 
    private static final ObjectMapper mapper = createMapper(); 

    public MixInJacksonJsonProvider() { 
     setMapper(mapper); 
    } 

    private static ObjectMapper createMapper() { 
     final ObjectMapper result = new ObjectMapper(); 
     result.addMixIn(TestBean.class, TestBeanMixin.class); 
     return result; 
    } 
} 

Questo codice produrrà nomi brevi per voi POJO campi in tutto il mondo. e di attuare un comportamento diverso per la richiesta differente dobbiamo aggiungere nuova annotazione personalizzato come questo:

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.METHOD, ElementType.TYPE}) 
public @interface MixIn {} 

controller sarà simile a questa:

@Path("test") 
public class MyResource { 

    @GET 
    @MixIn // <== Here is important part 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response getShortName() { 
     return Response.ok(demoObj()).build(); 
    } 

    @POST 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response postLongName() { 
     return Response.ok(demoObj()).build(); 
    } 
} 

E la nostra MixInJacksonJsonProvider avranno 2 più @Override:

//.. same as before 

    @Override 
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     return super.isReadable(type, genericType, annotations, mediaType) && hasMixInAnnotation(annotations); 
    } 

    @Override 
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 
     return super.isWriteable(type, genericType, annotations, mediaType) && hasMixInAnnotation(annotations); 
    } 
    public static boolean hasMixInAnnotation(Annotation[] annotations){ 
     for(Annotation annotation: annotations){ 
      if (annotation instanceof MixIn){ 
       return true; 
      } 
     } 
     return false; 
    } 
} 

Ecco il codice demo per giocare: https://github.com/varren/jersey2-jacksonsetup/tree/master/src/main/java/ru/varren

+0

Insieme ai nomi brevi, mi piacerebbe anche avere altre configurazioni come 'objectMapper.WRAP_ROOT_VALUE' in alcuni Pojos e forse non in altri. Quindi tutte le configurazioni fornite in 'ObjectMapper' saranno disponibili attraverso le annotazioni nelle classi MixIn? –

+0

@SiddharthTrikha dipende davvero da quello che vuoi. Se vuoi che 1 pojo abbia sempre la stessa rappresentazione con WRAP_ROOT per esempio e con altro pojo senza, puoi farlo con solo 1 objectmapper. È possibile modificare il serializzatore di classe o aggiungere annotazioni alla classe o utilizzare MixIn. Non importa davvero. Ma se hai bisogno di avere più versioni json dello stesso POJO, devi creare più mappatori di oggetti e usare diversi mixin/serializzatori per loro + usare annotazioni personalizzate nel tuo controller per specificare quale deve essere usata la versione personalizzata. – varren

Problemi correlati