2013-05-07 34 views
5

Tôi có một thời gian khó hiểu cơ chế tiêm của Jersey. Đặc tả JAX-RS (http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-520005) nói rằng việc tiêm thông qua @Context có thể có trong các lớp con ứng dụng, các lớp tài nguyên gốc và các nhà cung cấp.Jersey @ Phạm vi tiếp theo

Tôi hiện có một lớp được khởi tạo ngay khi khởi động và có phương thức được gọi theo mọi yêu cầu. Bên trong phương thức tôi cần truy cập đối tượng UriInfo hiện tại. Vấn đề là, phương pháp này không được gọi từ mã của tôi. Vì vậy, tôi không thể vượt qua UriInfo trực tiếp đến phương pháp.

Tôi thực sự muốn làm một cái gì đó như thế này:

public class MyClass implements ThirdPartyInterface { 

    // not possible because class is no Application subclass, root resource class or provider 
    @Context 
    private UriInfo uriInfo; 

    public void methodCallebByThirdPartyCode() { 
     Uri requestUri = uriInfo.getRequestUri(); 

     // do something 
    } 
} 

Tôi cố gắng này. Rõ ràng là không thành công:

public class MyClass implements ThirdPartyInterface { 

    private UriInfo uriInfo; 

    public MyClass(UriInfo uriInfo) { 
     this.uriInfo = uriInfo; 
    } 

    public void methodCallebByThirdPartyCode() { 
     Uri requestUri = uriInfo.getRequestUri(); 

     // do something 
    } 
} 

@Provider 
@Produces(MediaType.WILDCARD) 
public class MyBodyWriter implements MessageBodyWriter<MyView> { 

    @Context 
    private UriInfo uriInfo; 

    private MyClass myClass; 

    private ThirdPartyClass thirdPartyClass; 

    public MyBodyWriter() { 
     // uriInfo is null at this time :(
     myClass = new MyClass(uriInfo); 

     thirdPartyClass = new ThirdPartyClass(); 
     thirdPartyClass.register(myClass); 
    } 

    public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException { 
     // execute() calls MyClass#methodCallebByThirdPartyCode() 
     thirdPartyClass.execute(); 
    } 
} 

Cách giải quyết duy nhất tôi có thể nghĩ là đây. Tôi không nghĩ rằng nó rất sạch sẽ:

public class MyClass implements ThirdPartyInterface { 

    private UriInfo uriInfo; 

    public void setUriInfo(final UriInfo uriInfo) { 
     this.uriInfo = uriInfo; 
    } 

    public void methodCallebByThirdPartyCode() { 
     Uri requestUri = uriInfo.getRequestUri(); 

     // do something 
    } 
} 

@Provider 
@Produces(MediaType.WILDCARD) 
public class MyBodyWriter implements MessageBodyWriter<MyView> { 

    @Context 
    private UriInfo uriInfo; 

    private MyClass myClass; 

    private ThirdPartyClass thirdPartyClass; 

    public MyBodyWriter() { 
     myClass = new MyClass(); 

     thirdPartyClass = new ThirdPartyClass(); 
     thirdPartyClass.register(myClass); 
    } 

    public void writeTo(final MyView view, final Class<?> type, /* and so on */) throws IOException, WebApplicationException { 
     myClass.setUriInfo(uriInfo); 

     // execute() calls MyClass#methodCallebByThirdPartyCode() 
     thirdPartyClass.execute(); 

     myClass.setUriInfo(null); 
    } 
} 

Tôi hy vọng có giải pháp tốt hơn, nhưng có lẽ tôi hoàn toàn đi sai hướng.

Cảm ơn!

+0

Có thể bạn chỉ cần 'ContainerRequestFilter'? – Willy

+0

Tôi không biết nếu điều này làm việc trong tình huống của tôi. Đặc điểm kỹ thuật nói rằng "Các lớp nhà cung cấp được khởi tạo bởi thời gian chạy JAX-RS". Nhưng tôi cần một tham chiếu đến đối tượng tại thời điểm xây dựng, để chuyển nó tới dịch vụ của bên thứ ba. –

Trả lời

3

câu trả lời muộn, nhưng một câu hỏi hay ... do đó, cho phép đi:

Bạn có thể sử dụng một org.glassfish.hk2.api.Factoryjavax.inject.Provider cho tiêm. Tôi không biết kể từ phiên bản này có sẵn, vì vậy có thể bạn phải nâng cấp phiên bản jersery của bạn. Đối với các mẫu sau tôi đã sử dụng jersey 2.12.

Trước tiên, bạn phải thực hiện và đăng ký/ràng buộc một nhà máy cho bạn MyClass:

MyClassFactory:

import javax.inject.Inject; 
import javax.ws.rs.core.UriInfo; 
import org.glassfish.hk2.api.Factory; 
// ... 

public class MyClassFactory implements Factory<MyClass> { 

    private final UriInfo uriInfo; 

    // we will bind MyClassFactory per lookup later, so 
    // the constructor will be called everytime we need the factory 
    // meaning, uriInfo is also per lookup 

    @Inject 
    public MyClassFactory(final UriInfo uriInfo) { 
     this.uriInfo = uriInfo; 
    } 

    @Override 
    public MyClass provide() { 
     return new MyClass(uriInfo) 
    } 

    @Override 
    public void dispose(UriInfo uriInfo) { 
     // ignore 
    } 

} 

Đăng ký doanh nghiệp qua ResourceConfig:

import org.glassfish.hk2.api.PerLookup; 
import org.glassfish.hk2.utilities.binding.AbstractBinder; 
import org.glassfish.jersey.server.ResourceConfig; 
// ... 

public class MyResourceConfig extends ResourceConfig { 

    public MyResourceConfig() { 
     register(new AbstractBinder() { 
      @Override 
      protected void configure() { 
       bindFactory(MyClassFactory.class).to(MyClass.class).in(PerLookup.class); 
       // ... bind additional factories here 
      } 
     }); 
     // ... 
    } 

} 

Bây giờ bạn có thể tiêm MyClass mỗi lần tìm kiếm nhà cung cấp, tài nguyên, v.v.
Nhưng chú ý: Afaig có hai cách tiếp cận es và chỉ một người sẽ làm việc như sau cùng được mong đợi cho các nhà cung cấp ...

import javax.inject.Inject; 
import javax.ws.rs.Produces; 
import javax.ws.rs.ext.MessageBodyWriter; 
import javax.ws.rs.ext.Provider; 
// ... 

@Provider 
@Produces("application/foo-bar") 
public class MyBodyWriter implements MessageBodyWriter<MyView> { 

    // first approache - don't do it! 
    // will only injected once, cause MyBodyWriter is only instantiated once 
    @Inject 
    private MyClass myClass; 

    // second approache - works fine! 
    private final javax.inject.Provider<MyClass> provider; 

    // MyBodyWriter instantiate once 
    // get an inject provider here 
    @Inject 
    public MyBodyWriter(javax.inject.Provider<MyClass> myClassProvider) { 
     this.provider = myClassProvider; 
    } 

    @Override 
    public boolean isWriteable(Class<?> t, Type g, Annotation[] a, MediaType m) { 
     return t == MyView.class; 
    } 

    @Override 
    public long getSize(MyView t, Class<?> c, Type g, Annotation[] a, MediaType m) { 
     // deprecated by JAX-RS 2.0 and ignored by Jersey runtime 
     return 0; 
    } 

    @Override 
    public void writeTo(MyView v, Class<?> c, Type t, Annotation[] a, MediaType m, MultivaluedMap<String, Object> s, OutputStream o) throws IOException, WebApplicationException { 

     // attention: its not per lookup !!! 
     MyClass myClassDirectInjected = myClass; 
     System.out.println(myClassDirectInjected); // same instance everytime 

     // but this is ;) 
     MyClass myClassFromProvider = provider.get(); 
     System.out.println(myClassFromProvider); // it's a new instance everytime 

     // ... 
    } 

} 

Hy vọng điều này sẽ hữu ích hơn.