SORU
3 Mayıs 2011, Salı


Kalan JAX-RS ile KURU

Aynı yol ve sorgu parametreleri bir kaç gerektiren tüm JAX-RS kaynak işleyicileri, tekrarlanan kod en aza indirmek için çalışıyorum. Temel url her kaynak için şablonu bu gibi görünüyor:

/{id}/resourceName

ve her bir kaynak birden çok subresources vardır:

/{id}/resourceName/subresourceName

Bu yüzden, kaynak/subresource yolları (dahil. sorgu parametreleri) gibi görünebilir

/12345/foo/bar?xyz=0
/12345/foo/baz?xyz=0
/12345/quux/abc?xyz=0
/12345/quux/def?xyz=0

Kaynaklar foo quux arasında ortak parçaları @PathParam("id") @QueryParam("xyz"). Benolabilirbu gibi sınıflar: kaynak uygulamak

// FooService.java
@Path("/{id}/foo")
public class FooService
{
    @PathParam("id") String id;
    @QueryParam("xyz") String xyz;

    @GET @Path("bar")
    public Response getBar() { /* snip */ }

    @GET @Path("baz")
    public Response getBaz() { /* snip */ }
}

// QuuxService.java
@Path("/{id}/quux")
public class QuxxService
{
    @PathParam("id") String id;
    @QueryParam("xyz") String xyz;

    @GET @Path("abc")
    public Response getAbc() { /* snip */ }

    @GET @Path("def")
    public Response getDef() { /* snip */ }
}

get* Her bir yönteme parametre enjeksiyon tekrar etmekten hep kaçındım.1Bu iyi bir başlangıç, ama kaynak sınıflar arasında tekrarlanmasını önlemek için mümkün olmak istiyorum. CDI ben de ihtiyacı olan) ile çalışan bir yaklaşım FooService QuuxService 26 ** olabilir abstract temel sınıf kullanmak için:

// BaseService.java
public abstract class BaseService
{
    // JAX-RS injected fields
    @PathParam("id") protected String id;
    @QueryParam("xyz") protected String xyz;

    // CDI injected fields
    @Inject protected SomeUtility util;
}

// FooService.java
@Path("/{id}/foo")
public class FooService extends BaseService
{
    @GET @Path("bar")
    public Response getBar() { /* snip */ }

    @GET @Path("baz")
    public Response getBaz() { /* snip */ }
}

// QuuxService.java
@Path("/{id}/quux")
public class QuxxService extends BaseService
{   
    @GET @Path("abc")
    public Response getAbc() { /* snip */ }

    @GET @Path("def")
    public Response getDef() { /* snip */ }
}

Düzgün çalışır get* yöntemleri, içinde: util Bu alan boş değil. Ne yazık ki, JAX-RS enjeksiyon yapardeğil; id xyz FooService get* yöntemleri null QuuxService.

Bu sorun için düzeltme veya geçici çözüm var mı?

Bunu yapmak istediğiniz gibi CDI çalıştığı göz önüne alındığında, @PathParams (vb.) enjekte etmek için başarısızlık diye merak ediyorum alt sınıfların içine bir böcek veya JAX-RS spec sadece bir parçası.


Zaten denedim başka bir yaklaşım gerektiği gibi FooService QuuxService delegeler için tek bir giriş noktası olarak BaseService kullanıyor. Bu RESTful Java with JAX-RS subresource belirleyicileri kullanarak açıklandığı gibi temelde.

// BaseService.java
@Path("{id}")
public class BaseService
{
    @PathParam("id") protected String id;
    @QueryParam("xyz") protected String xyz;
    @Inject protected SomeUtility util;

    public BaseService () {} // default ctor for JAX-RS

    // ctor for manual "injection"
    public BaseService(String id, String xyz, SomeUtility util)
    {
        this.id = id;
        this.xyz = xyz;
        this.util = util;
    }

    @Path("foo")
    public FooService foo()
    {
        return new FooService(id, xyz, util); // manual DI is ugly
    }

    @Path("quux")
    public QuuxService quux()
    {
        return new QuuxService(id, xyz, util); // yep, still ugly
    }
}

// FooService.java
public class FooService extends BaseService
{
    public FooService(String id, String xyz, SomeUtility util)
    {
        super(id, xyz, util); // the manual DI ugliness continues
    }

    @GET @Path("bar")
    public Response getBar() { /* snip */ }

    @GET @Path("baz")
    public Response getBaz() { /* snip */ }
}

// QuuxService.java
public class QuuzService extends BaseService
{
    public FooService(String id, String xyz, SomeUtility util)
    {
        super(id, xyz, util); // the manual DI ugliness continues
    }

    @GET @Path("abc")
    public Response getAbc() { /* snip */ }

    @GET @Path("def")
    public Response getDef() { /* snip */ }
}

Bu yaklaşımın dezavantajı CDI enjeksiyon ne de JAX-RS enjeksiyon ne subresource sınıfları çalışır. Bunun nedeni oldukça açık2bu ne amademektirel ile alt sınıflar' dağınık ve yapıcı, çirkin ve kolayca beni daha fazla enjeksiyon özelleştirmek izin vermez. içine yeniden enjekte alanlar değil." Örnek: 45 ** bir örnek FooService ama QuuxService. içine istediğimi söyle Açıkça BaseService, CDI enjeksiyon sınıfları başlatmasını olduğum için işe yaramaz, çirkinlik devam etti.


tl;dr sürekli JAX-RS işleyici sınıfları kaynak alanları arasında enjekte önlemek için doğru yolu Nedir?

Ve neden CDI bu ile hiçbir sorunları varken alanları JAX-RS ile enjekte miras, değil mi?


1 düzenleyin

@Tarlog, yönü biraz sorularımın cevabını buldum sanırım

Neden miras alanları JAX-RS ile enjekte değil mi?

JSR-311 §3.6:

Eğer alt veya uygulama yöntemi olan, herhangi bir JAX-RS ek açıklamalar o zamantümsüper sınıfın metodu açıklama yok sayılır.

Bu karar için gerçek bir sebebi var eminim, ama ne yazık ki bu gerçeği, bu özel kullanım durumda bana karşı çalışıyor. Hala herhangi bir olası geçici çözümler ilgileniyorum.


1Alan düzeyi enjeksiyon şimdi her istek için kaynak sınıfı için bağlı olduğum kullanarak uyarı örnekleme, ama bununla yaşayabilirim.
2Bir new FooService() çok kapsayıcı/JAX-RS uygulaması arıyorum çünkü.

CEVAP
9 EYLÜL 2013, PAZARTESİ


İşte kullandığım bir çözüm

İle BaseService için bir kurucu tanımlamak 've' xyz kullanımı'. ıd

// BaseService.java
public abstract class BaseService
{
    // JAX-RS injected fields
    protected String id;
    protected String xyz;

    public BaseService (String id, String xyz) {
        this.id = id;
        this.xyz = zyx;
    }
}

Enjekte ile: tüm alt sınıflar üzerinde yapıcı tekrarlayın

// FooService.java
@Path("/{id}/foo")
public class FooService extends BaseService
{
    public FooService (@PathParam("id") String id, @QueryParam("xyz") String xyz) {
        super(id, xyz);
    }

    @GET @Path("bar")
    public Response getBar() { /* snip */ }

    @GET @Path("baz")
    public Response getBaz() { /* snip */ }
}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • AmazonWireless

    AmazonWirele

    8 EYLÜL 2010
  • UsherVEVO

    UsherVEVO

    15 EKİM 2009
  • Wild Academy

    Wild Academy

    8 Aralık 2009