2012-05-04 15 views
5

Estoy desarrollando una aplicación con Jersey, donde tengo muchos recursos. Aunque la funcionalidad principal de estos recursos varía, comparten muchos métodos comunes (como lista, lectura, actualización, etc.). La aplicación se ejecuta en Google App Engine y usa Guice para la inyección de dependencia.¿Cuál es la forma correcta de organizar los recursos de Jersey utilizando herencia y genéricos?

Mi primer enfoque fue tener un AbstactResource genérico que contiene toda la lógica común, y se extiende respectivamente por todos los demás recursos que agregan los métodos personalizados requeridos.

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 
} 

Y muestra de recursos se ve así:

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

Todo funciona bien en este caso. Los problemas aparecen cuando agrego un nivel más de abstracción. Digamos que si quiero almacenar el historial y los registros de cambios solo para algunos de mis recursos. Creé una clase abstracta más ampliando AbstractResource llamada AudiatableResource que agrega la funcionalidad requerida.

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

Como ve, el parámetro de tipo en este caso ha cambiado (ahora se extiende AuditableModel).

nuevos recursos concretos se verá como:

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

En este caso, todo sigue funcionando, pero esta vez me estoy poniendo un montón de mensajes de advertencia en el arranque:

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 

Realmente Me pregunto si este enfoque es correcto usando Jersey y si puedo ignorar este mensaje. Sería interesante saber cómo se organizan los recursos en los casos en que hay un gran número de ellos.

Respuesta

4

Una forma de hacerlo es separar la definición de los recursos de la implementación.

  • Tienen clases de recursos muy simples que definen los diferentes servicios que desea ofrecer. De esta forma, la API que expone a través del reposo se ubica y audita fácilmente. Los diferentes métodos probablemente sean delegados en una clase de implementación
  • Implemente la lógica comercial de sus recursos en las implementaciones, donde es posible que desee usar la herencia para factorizar el comportamiento común.

La razón por la que recibe esos mensajes en tiempo de ejecución es que jersey usa información de tiempo de ejecución sobre los tipos en el recurso. La información de tipo genérico se borra en tiempo de compilación, no puede obtener el tipo de retorno real de los métodos de clase genéricos. Si proporciona una "fachada" de REST a su implementación, puede hacer que esto sea explícito.

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

muchas gracias por su consejo. Ahora entiendo el problema que tuve con mi enfoque. Trataré de separar la definición y la implementación de la forma en que sugirió – turan

Cuestiones relacionadas