在Jersey 2.29中使用自定义注释注入方法参数

时间:2019-08-06 15:16:31

标签: java dependency-injection jersey

我将旧项目从Jersey 2.22升级到最新版本,并且在迁移依赖项注入时遇到一些问题。

我们使用自定义注释将用户/令牌注入方法参数中:

@GET
public Response getAll(@SdnBasicAuth final UserManagement.User user) { 
    // ... Check user rights return Response.accepted().build();
}

现在我无法通过新泽西州解耦依赖注入获得有效的解决方案。

系统行为如下:

  1. 在应用程序启动时,我的虚拟用户两次调用getAll方法(这不是预期的行为,我们只需要此调用来响应请求)。

在启动时会同时调用供应商和解析器,但在我发出“真实”请求时不会调用。

注意:在解析器中,参数final ServiceHandle<?> root为空。

我该如何重现Jersey 2.22的行为(请参见文章底部的代码)

感谢您的帮助。


带有jersey 2.29的新代码版本:

依赖项列表:

    <dependency>
        <groupId>org.glassfish.hk2</groupId>
        <artifactId>hk2-core</artifactId>
        <version>${hk2.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.hk2</groupId>
        <artifactId>hk2-api</artifactId>
        <version>${hk2.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.hk2</groupId>
        <artifactId>hk2-locator</artifactId>
        <version>${hk2.version}</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
        <version>${jersey.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>${jersey.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-bean-validation</artifactId>
        <version>${jersey.version}</version>
        <scope>provided</scope>
    </dependency>

活页夹:

    import org.glassfish.hk2.api.InjectionResolver;
    import org.glassfish.jersey.internal.inject.AbstractBinder;
    import org.glassfish.jersey.process.internal.RequestScoped;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import javax.inject.Singleton;
    import javax.ws.rs.core.GenericType;

    public class BasicAuthBinder extends AbstractBinder {

        // SLF4J Logger
        private static final Logger LOG = LoggerFactory.getLogger(BasicAuthBinder.class);

        @Override
        protected void configure() {
            bindFactory(BasicAuthSupplier.class)
                .to(UserManagement.User.class)
                .proxyForSameScope(false)
                .in(Singleton.class);

    // I have try to change to this : 
    // .in(RequestScoped.class);
    // But after that I have the following exception at startup.
    // org.glassfish.hk2.api.MultiException: A MultiException has 1 exceptions.  
    // They are:
    // java.lang.IllegalStateException: Not inside a request scope.

            bind(BasicAuthResolver.class)
                .to(new GenericType<InjectionResolver<SdnBasicAuth>>() {})
                .in(Singleton.class);
        }
    }

解析器

    import org.glassfish.hk2.api.Injectee;
    import org.glassfish.hk2.api.InjectionResolver;
    import org.glassfish.hk2.api.ServiceHandle;

    import javax.inject.Inject;
    import javax.inject.Named;

    public class BasicAuthResolver implements org.glassfish.hk2.api.InjectionResolver<SdnBasicAuth> {

        @Inject
        @Named (InjectionResolver.SYSTEM_RESOLVER_NAME)
        org.glassfish.hk2.api.InjectionResolver<Inject> systemInjectionResolver;

        @Override
        public Object resolve(final Injectee injectee, final ServiceHandle<?> root) {
            if (UserManagement.User.class == injectee.getRequiredType()) {
                return systemInjectionResolver.resolve(injectee, root);
            }

            return null;
        }

        @Override
        public boolean isConstructorParameterIndicator() {
            return false;
        }

        @Override
        public boolean isMethodParameterIndicator() {
            return true;
        }
    }

供应商:

    import java.util.function.Supplier;

    public class BasicAuthSupplier implements Supplier<UserManagement.User> {

        // SLF4J Logger
        private static final Logger LOG = LoggerFactory.getLogger(BasicAuthSupplier.class);



        public BasicAuthSupplier() {
        }

        @Override
        public UserManagement.User get() {
            // Dummy code to create the user.
            return UserManagement.User.newUser().build();
        }
    }

和API:

    @Path ("/my-path")
    @Consumes (APPLICATION_JSON)
    @Produces (APPLICATION_JSON)
    public class  {

       @GET
        public Response getAll(@SdnBasicAuth final UserManagement.User user) {
            // ... Check user rights
            return Response.accepted().build();
        }
    }

以下是球衣2.22上的工作代码

注释:

    @Target ({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
    @Retention (RetentionPolicy.RUNTIME)
    @Documented
    public @interface SdnBasicAuth {
    }

活页夹:

    import org.glassfish.hk2.api.InjectionResolver;
    import org.glassfish.hk2.api.TypeLiteral;
    import org.glassfish.hk2.utilities.binding.AbstractBinder;
    import org.glassfish.jersey.server.spi.internal.ValueFactoryProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import javax.inject.Singleton;

    public class BasicAuthBinder extends AbstractBinder {

        // SLF4J Logger
        private static final Logger LOG = LoggerFactory.getLogger(BasicAuthBinder.class);

        private final UserManagement userManagement;

        public BasicAuthBinder(final UserManagement userManagement) {
            this.userManagement = userManagement;
        }

        @Override
        protected void configure() {
            bind(userManagement).to(UserManagement.class);

            bind(BasicAuthFactory.class)
                .to(ValueFactoryProvider.class)
                .in(Singleton.class);

            bind(BasicAuthResolver.class)
                .to(new TypeLiteral<InjectionResolver<SdnBasicAuth>>() {
                })
                .in(Singleton.class);
        }
    }

工厂:

    import org.glassfish.hk2.api.Factory;
    import org.glassfish.hk2.api.ServiceLocator;
    import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
    import org.glassfish.jersey.server.internal.inject.AbstractValueFactoryProvider;
    import org.glassfish.jersey.server.internal.inject.MultivaluedParameterExtractorProvider;
    import org.glassfish.jersey.server.model.Parameter;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    import javax.inject.Inject;
    import javax.inject.Singleton;
    import javax.servlet.http.HttpServletRequest;
    import javax.ws.rs.container.ResourceContext;
    import javax.ws.rs.core.Context;

    @Singleton
    public class BasicAuthFactory extends AbstractValueFactoryProvider {

        // SLF4J Logger
        private static final Logger LOG = LoggerFactory.getLogger(BasicAuthFactory.class);

        @Inject
        private UserManagement userManagement;

        @Inject
        public BasicAuthFactory(MultivaluedParameterExtractorProvider mpep, ServiceLocator injector) {
            super(mpep, injector, Parameter.Source.UNKNOWN);
        }

        @Override
        protected Factory<?> createValueFactory(Parameter parameter) {
            Class<?> classType = parameter.getRawType();
            if (parameter.getAnnotation(SdnBasicAuth.class) == null) {
                LOG.debug("Not injecting user management provider.");
                return null;
            }
            if (classType == null || (!classType.equals(UserManagement.User.class))) {
                LOG.warn("IdentityParam annotation was not placed on correct object type; Injection might not work correctly!");
                return null;
            }
            return new IdentityParamValueFactory(userManagement);
        }

        private static final class IdentityParamValueFactory extends AbstractContainerRequestValueFactory<UserManagement.User> {

            private final UserManagement userManagement;
            @Context
            private ResourceContext context;

            public IdentityParamValueFactory(final UserManagement userManagement) {
                this.userManagement = userManagement;
            }

            public UserManagement.User provide() {
                final HttpServletRequest request = context.getResource(HttpServletRequest.class);

                // Dumb code to do the authorization stuff not related of our problem.
                return UserManagement.User.newUser().build();
            }
        }
    }

解析器:

    import org.glassfish.jersey.server.internal.inject.ParamInjectionResolver;

    import javax.inject.Singleton;

    @Singleton
    public class BasicAuthResolver extends ParamInjectionResolver<SdnBasicAuth> {

        public BasicAuthResolver() {
            super(BasicAuthFactory.class);
        }
    }

0 个答案:

没有答案