2012-05-04 11 views
5

Tôi đang phát triển một ứng dụng với Jersey, nơi tôi có nhiều tài nguyên. Mặc dù chức năng chính của các tài nguyên này thay đổi, chúng chia sẻ rất nhiều phương pháp phổ biến (như danh sách, đọc, cập nhật và v.v.). Ứng dụng chạy trên Google App Engine và sử dụng Guice để tiêm phụ thuộc.Cách đúng đắn để tổ chức tài nguyên Jersey bằng cách sử dụng thừa kế và generics là gì?

Cách tiếp cận đầu tiên của tôi là có một AbstactResource chung chứa tất cả các logic chung và nó được mở rộng tương ứng bởi tất cả các tài nguyên khác bổ sung các phương thức tùy chỉnh yêu cầu của chúng.

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 
} 

Và mẫu tài nguyên trông giống như:

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

Tất cả mọi thứ hoạt động tốt trong trường hợp này. Các vấn đề xuất hiện khi tôi thêm một mức trừu tượng khác. Giả sử nếu tôi muốn lưu trữ lịch sử và các thay đổi chỉ cho một số tài nguyên của tôi. Tôi đã tạo ra một lớp trừu tượng mở rộng AbstractResource được gọi là AudiatableResource, bổ sung thêm các chức năng cần thiết.

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

Khi bạn thấy thông số loại trong trường hợp này đã thay đổi (bây giờ nó mở rộng AuditableModel).

nguồn lực bê tông mới sẽ trông giống như:

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

Trong trường hợp này tất cả mọi thứ vẫn hoạt động, nhưng lần này tôi nhận được rất nhiều thông điệp cảnh báo khi khởi động:

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 

Tôi thực sự tự hỏi, nếu cách tiếp cận này là chính xác bằng cách sử dụng Jersey và nếu tôi chỉ có thể bỏ qua thông điệp này. Thật thú vị khi biết các nguồn tài nguyên được tổ chức như thế nào trong các trường hợp khi có số lượng lớn.

Trả lời

4

Một cách cần thực hiện là tách biệt định nghĩa tài nguyên khỏi quá trình triển khai.

  • Có các lớp tài nguyên rất đơn giản, xác định các dịch vụ khác nhau mà bạn muốn cung cấp. Bằng cách này, API bạn tiếp xúc thông qua phần còn lại có thể dễ dàng định vị và được kiểm tra. Các phương pháp khác nhau có thể là đại biểu cho một lớp thực hiện
  • Triển khai logic nghiệp vụ của tài nguyên của bạn trong các triển khai, nơi bạn có thể muốn sử dụng thừa kế cho hành vi chung của nhân tố.

Lý do bạn nhận được các thông báo đó trong thời gian chạy là áo sử dụng thông tin thời gian chạy về các loại trong tài nguyên. Thông tin loại chung được xóa tại thời gian biên dịch, nó không thể nhận được kiểu trả về thực tế của các phương thức lớp chung. Nếu bạn cung cấp một "mặt tiền" REST cho việc triển khai của mình, bạn có thể làm rõ điều này.

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

cảm ơn bạn rất nhiều vì lời khuyên của bạn. Bây giờ tôi hiểu vấn đề tôi đã có với cách tiếp cận của tôi. Tôi sẽ cố gắng tách định nghĩa và cách triển khai theo cách bạn đề xuất – turan