2012-05-04 8 views
5

Sto sviluppando un'applicazione con Jersey dove ho molte risorse. Sebbene la funzionalità principale di queste risorse sia variabile, condividono molti metodi comuni (come elenco, lettura, aggiornamento ed ecc.). L'app viene eseguita su Google App Engine e utilizza Guice per l'integrazione delle dipendenze.Qual è il modo giusto per organizzare le risorse di Jersey usando ereditarietà e generici?

Il mio primo approccio era di avere un AbstactResource generico che contenga tutta la logica comune, ed è esteso rispettivamente da tutte le altre risorse che aggiungono i loro metodi personalizzati richiesti.

public class AbstractResource<T> { 

@GET 
public ListPage<T> list(@QueryParam("limit") Integer limit, 
    @QueryParam("start") Integer start) { 
    // ... implementation 
} 

@GET 
@Path("/{id}") 
public T get(@PathParam("id") Long id) { 
    // ... implementation 
} 

E campione risorsa assomiglia:

public class TenantResource extends AbstractResource<Tenant> { 
    // custom resource related methods here 
} 

Tutto funziona bene in questo caso. I problemi appaiono quando aggiungo un altro livello di astrazione. Diciamo se voglio memorizzare la cronologia e i log delle modifiche solo per alcune delle mie risorse. Ho creato un'altra classe astratta che estende AbstractResource chiamato AudiatableResource che aggiunge la funzionalità richiesta.

public abstract class AuditableResource<T extends AuditableModel> 
    extends AbstractResource { 
     // here I override update and create methods to save changelogs 
} 

Come vedi il parametro di tipo in questo caso è cambiata (ora si estende AuditableModel).

Nuove risorse in calcestruzzo sarà simile:

public class PropertyResource extends AuditableResource<Tenant> { 
    // custom resource related methods here 
} 

In questo caso tutto funziona ancora, ma questa volta sto ricevendo un sacco di messaggi di avviso in fase di start-up:

WARNING: Return type T of method public T com.pkg.AbstractResource.get(java.lang.Long) is not resolvable to a concrete type 
WARNING: Return type T of method public T com.pkg.AbstractResource.getNew() is not resolvable to a concrete type 
WARNING: Return type com.pkg.data.ListPage<T> of method public com.pkg.ListPage<T> com.pkg.AbstractResource.list(java.lang.Integer,java.lang.Integer) is not resolvable to a concrete type 

davvero Mi chiedo se questo approccio sia corretto usando Jersey e se posso semplicemente ignorare questi messaggi. Sarebbe interessante sapere come sono organizzate le risorse nei casi in cui vi è un gran numero di esse.

risposta

4

Un modo per andare è separare la definizione delle risorse dall'implementazione.

  • Sono classi di risorse molto semplici, che definiscono i diversi servizi che si desidera offrire. In questo modo, l'API che esponi attraverso il resto è facilmente individuabile e verificabile. I diversi metodi sono probabilmente delegati a una classe di implementazione
  • Implementare la logica di business delle risorse nelle implementazioni, in cui si potrebbe voler utilizzare l'ereditarietà per valutare il comportamento comune.

Il motivo per cui si ottengono quei messaggi in fase di esecuzione è che la jersey utilizza le informazioni di runtime sui tipi nella risorsa. Informazioni di tipo generico cancellate in fase di compilazione, non possono ottenere il tipo di ritorno effettivo dei metodi di classe generici. Se fornisci una "facciata" REST alla tua implementazione, puoi renderla esplicita.

public class Facade { 
    private final PropertyResource propertyResource; 
    public Facade() { 
    propertyResource = new PropertyResource(); 
    } 
    @GET 
    @Path("somepath") 
    public Tenant something() { 
    return propertyResource.something(); 
    } 
} 
+0

grazie mille per il vostro consiglio. Ora capisco il problema che ho avuto con il mio approccio. Proverò a separare la definizione e l'implementazione nel modo in cui hai suggerito – turan

Problemi correlati