2016-04-21 12 views
2

Ich habe eine JAX-RS-REST-API mit mehreren Unterressourcen, z.Wie mit mehreren Subressourcen in JAX-RS umzugehen?

users/{user_id}/posts/{post_id}/comments/{comment_id}. Die Ressourcen sind in einzelne Klassen (UsersResource, UserResource, PostsResource usw.) unterteilt und werden über Sub-Resource-Locators angesprochen. Jede Ressource verwendet einen Korrelationsdienst (UserService, PostService, CommentService), um auf die Datenbank zuzugreifen.

Wie würde ich das realisieren? Ich habe versucht, nach einem Beispiel zu suchen, konnte aber nur sehr einfache finden.

Ich habe bereits mehrere Ansätze implementiert, aber alle "fühlen" sich falsch.

Eine war, alle Dienste in die Wurzelressource zu injizieren und sie weiterzugeben. Es scheint jedoch verschwenderisch, alle Dienste zu instanziieren, obwohl nur die erste benötigt wird.

Eine andere war, alle Ressourcen @RequestScoped zu machen und die nachfolgende Ressource zu injizieren, damit der richtige Dienst an der richtigen Stelle injiziert werden kann. Aber ich müsste die Unterressource im Voraus injizieren, selbst wenn ich sie nicht brauchte und ich wäre nicht in der Lage, Parameter weiterzugeben.

Mein aktueller Ansatz schlägt fehl, den Dienst nicht in meine Unterressource zu injizieren. (Siehe unten)

root resource (resources/users)

@RequestScoped 
@Path("users") 
public class UsersResource() { 

    @Inject 
    private UserService service; 

    @Path("{user_id}") 
    public UserResource getUserResource(@Context ResourceContext context, @PathParam("user_id") Long id) { 
     User entity = this.service.find(id); 

     if (entity == null) 
      throw new WebApplicationException(Response.status(Status.NOT_FOUND).build()); 

     return context.initResource(new UserResource(entity, this.service)); 
    } 
} 

user sub resource (resources/users/{user_id})

public class UserResource() { 

    private User entity; 
    private UserService service; 

    public UserResource(User entity, UserService service) { 
     this.entity = entity; 
     this.service = service; 
    } 

    @GET 
    public Response doGet() { 
     return Response.ok(entity).build(); 
    } 

    @Path("posts") 
    public TodosResource getPostsResource(@Context ResourceContext context) { 
     return context.initResource(new PostsResource(entity)); 
    } 
} 

posts sub resource (resources/users/{user_id}/posts)

public class PostsResource() { 

    @Inject // can't inject here 
    private PostService service; 

    private User user; 

    public PostsResource(User user) { 
     this.user = user; 
    } 

    @POST 
    public Response doPost(@Context UriInfo info, Post post) { 
     post.setUser(this.user); 
     Post entity = this.service.persist(post); 
     URI uri = info.getAbsolutePathBuilder().path("/" + entity.getId()).build(); 

     return Response.created(uri).entity(entity).build(); 
    } 

    @Path("{post_id}") 
    public PostResource getpostResource(@Context ResourceContext context, @PathParam("post_id") Long id) { 
     Post entity = this.service.find(id); 

     if (entity == null) 
      throw new WebApplicationException(Response.status(Status.NOT_FOUND).build()); 

     return context.initResource(new PostResource(entity)); 
    } 

Service Beispiel

@Stateless 
public class UserService { 

    @PersistenceContext 
    private EntityManager em; 

    (...) 
} 
+0

wird Betrachtet man, wie Sie es eingerichtet haben, kann ich nicht helfen, aber das Gefühl, dass Sie das Set-up selbst zu kompliziert haben. Ich hätte eine gesamte "API" -Ressource auf der Ebene von UsersResource erstellt und alle Dienste auf dieser Ebene injiziert und dann den Inhalt der Unterressourcen auch auf dieser Ebene zugeordnet. – Compass

+0

Mein Grund war nur, dass ich sie nicht instanziieren wollte, wenn ich nicht müsste. Die Wurzelressource müsste eine Instanz für jeden möglichen Dienst erstellen, selbst wenn die Anforderung für den Stamm selbst gedacht ist. – aaeeiioouu

+1

Die Idee hinter der Verwendung mehrerer Dienste in einer Ressource ist nicht, dass Sie sie alle jetzt brauchen werden, aber Sie werden sie auf jeden Fall irgendwann brauchen, damit sie bereit sind zu gehen, wenn sie gebraucht werden.Ihr Server wird eine einzelne Instanz Ihrer UsersResource für alle Benutzer ausführen, aber im Moment schlagen Sie vor, UserResource und PostResource von kurzer Dauer auf Abruf bereitzustellen, was nach dem Abschluss nicht mehr möglich ist , die erheblich teurer ist als eine einzelne Ressource. – Compass

Antwort

0

Vielleicht ein bisschen spät, aber die Antwort darauf ist immer noch schwer zu finden.

Um EJBs direkt in Unterressourcen zu injizieren, die Unterressourcen mit @Provider annotieren, könnte es auch eine gute Idee sein, @Products anzuhängen.

So Ihre

public class PostsResource() { 

@Provider 
@Produces(MediaType.APPLICATION_JSON) 
public class PostsResource() {