Jersey: InjectableProvider not picked up - Spring

后端 未结 1 1679
悲哀的现实
悲哀的现实 2021-02-01 10:11

I am currently trying to create an InjectableProvider with Jersey, but I cannot get Jersey to pick it up.

I cannot find any real examples of its usage, or e

1条回答
  •  说谎
    说谎 (楼主)
    2021-02-01 10:40

    How are you initializing Jersey?

    I will assume you are using Jersey using the jersey-spring servlet. In which case Jersey would by default initialize using Spring beans and hence your Provider has to be a Spring bean. Try adding a @Named (or if you do not use atinject @Component or one of the Spring annotaions) to your Provider.

    An example of using Injectable Providers.


    Updated: More clarity on the scope of injection:

    The Provider has to be a Singleton, as for all practical purposes its a factory with scope tied to it and there is no need to construct a factory for every request. The injection itself would happen per request. In other words the getInjectable method would be called for every request. Did you get a chance to try that?

    OTOH, if you extend the SingletonTypeInjectableProvider the same object would be injected into your resource every time.

    I am not sure I completely understand your Provider implementation. I believe something like the following should work.

    public class UserProvider extends PerRequestTypeInjectableProvider{
    
        public UserProvider(){
            super(Users.class);
        }
    
        @Context
        HttpServletRequest request;
    
        @Override
        public Injectable getInjectable(ComponentContext cc, AttributeParam a) {
    
            String attributeValue = AnnotationUtils.getValue(a);
    
            return new Injectable(){
    
                public Users getValue() {
                    System.out.println("Called"); //This should be called for each request
                    return request.getAttribute(attributeValue);
                }
    
            };
    
        }
    
    }
    

    Updated: To provide more information on the injection types and contexts available in Jersey.

    As you probably figured by now, if all you need is access to the HttpServletRequest then just directly injecting it into your Resource or Provider using the @Context annotation will get you that.

    However, to pass those values to the Injectable one has to use a AssistedProvider or use an approach similar to yours. But again you can mitigate that if you inline your Injectable definition in the Provider and inject the HttpServletRequest into the Provider class. In that case the Injectable would be able to access the HttpServletRequest instance (since its there in scope). I just updated my example to show that approach.

    Injection using PerRequestTypeInjectableProvider and SingletonTypeInjectableProvider are not the only two options you have to inject values into your resources. You could also inject using *Param values using a StringReaderProvider. Obviously such an injection is request scoped.

    @Provider
    @Named("userProviderParamInjector")
    public class UserProviderParam implements StringReaderProvider {
    
        @Context
        HttpServletRequest request;
    
        public StringReader getStringReader(Class type, Type type1, Annotation[] antns) {
            if(type.equals(Users.class) {
               return null;
            }
    
            String attributeValue = null;
            for(Annotation a : antns) {
                if((a.getClass().getSimpleName()).equals("AttributeParam")){
                   attributeValue = (String)AnnotationUtils.getValue(a);
                }
            }
    
            return new StringReader(){
                public Users fromString(String string) {
                    // Use the value of the *Param or ignore it and use the attributeValue of our custom annotation.
                    return request.getAttribute(attributeValue);
                }
    
            };
    
        }
    
    }
    

    This Provider would be invoked for any *Param that you have in your resource. So with a Provider like the one above registered and a resource like the one below, the Users value would be injected into your resource method.

    @Path("/user/")
    @Named
    public class UserResource {
    
        @Path("{id}")
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Result get(@AttributeParam("foo") @PathParam("id") Users user) {
        ...
        }
    
    }
    

    But to be honest with you I consider this an abuse of the StringReaderProvider contract whereas the former technique of using Injectable feels cleaner.

    0 讨论(0)
提交回复
热议问题