在Jersey 2.27中注册自定义ValueParamProvider

dav*_*vid 2 java jersey jersey-2.0

我意识到这些是内部API,但是如果内部可以使用它们,为什么不让特权较低的人群使用它们,它们也非常有用。即使这些API在Jersey 2.25中是内部的,也可以使用,并且我想在不破坏自定义Jersey扩展的情况下升级Jersey版本。

当然可以ValueParamProvider在Jersey 2.27中进行扩展,但是我再也看不到一种注册该Provider及其触发注释的方法。查看Jersey如何针对自己的实现执行此操作,现在使用BoostrapConfigurator,它似乎已被内部化,以至于外部实现无法使用相同的方法。

也许我对此有误,如果有人对方法有清晰的描述,那就太好了。否则,有人知道做相同事情的方法吗?

曾经工作...

ResourceConfig resourcceConfig = ...

resourceConfig.register(new AbstractBinder() {

    @Override
    protected void configure (){ 
      bind(MyParamValueFactoryProvider.class).to(ValueFactoryProvider.class).in(Singleton.class);
      bind(MyParamInjectionResolver.class).to(new TypeLiteral<InjectionResolver<EntityParam>>() {

      }).in(Singleton.class);
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

有了适当的实现AbstractValueFactoryProviderParamInjectionResolver

现在看来您需要实现ValueParamProvider,这很容易,但是我不确定如何再使用Jersey框架正确进行注册。任何帮助表示赞赏。

Pau*_*tha 5

您无需使用任何BootstrapConfigurator。您需要做的就是将服务添加到注射器中,稍后将添加它们到值提供者列表中。

要配置它,您仍然可以使用AbstractBinder,但可以使用Jersey 1代替HK2 。将ValueParamProvider仍然可以绑定同样的方式,但对于InjectionResolver,你应该确保实现不HK2解析器,但新泽西州一个。然后,而不是结合TypeLiteral结合GenericType

我只是想补充一点,人们在尝试实现参数注入时存在一个误解,就是我们还需要InjectResolver为方法参数使用自定义注释。不是这种情况。方法参数注释只是我们应在ValueParamProvider#getValueProvider()方法内部检查的标记注释。InjectResolver仅对于非方法参数注入(例如,字段和构造函数注入)才需要An 。如果不需要,则不需要InjectionResolver

以下是使用Jersey测试框架的完整示例。我没有使用InjectionResolver,只是为了表明它不是必需的。

import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.model.Parameter;
import org.glassfish.jersey.server.spi.internal.ValueParamProvider;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.core.Response;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Function;

import static org.assertj.core.api.Assertions.assertThat;


public class ParamInjectTest extends JerseyTest {

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

    private static class User {
        private String username;
        public User(String username) {
            this.username = username;
        }
        public String getUsername() {
            return this.username;
        }
    }

    public static class AuthValueParamProvider implements ValueParamProvider {

        @Override
        public Function<ContainerRequest, ?> getValueProvider(Parameter parameter) {
            if (parameter.getRawType().equals(User.class)
                    && parameter.isAnnotationPresent(Auth.class)) {
                return new UserParamProvider();
            }
            return null;
        }

        private class UserParamProvider implements Function<ContainerRequest, User> {
            @Override
            public User apply(ContainerRequest containerRequest) {
                return new User("Peeskillet");
            }
        }

        @Override
        public PriorityType getPriority() {
            return Priority.HIGH;
        }
    }

    public static class AuthFeature implements Feature {

        @Override
        public boolean configure(FeatureContext context) {
            context.register(new AbstractBinder() {
                @Override
                protected void configure() {
                    bind(AuthValueParamProvider.class)
                            .to(ValueParamProvider.class)
                            .in(Singleton.class);
                }
            });

            return true;
        }
    }

    @Path("test")
    @Consumes("text/plain")
    public static class TestResource {
        @POST
        @Produces("text/plain")
        public Response post(String text, @Auth User user) {
            return Response.ok(user.getUsername() + ":" + text).build();
        }
    }


    @Override
    public ResourceConfig configure() {
        return new ResourceConfig()
                .register(TestResource.class)
                .register(AuthFeature.class);
    }

    @Test
    public void testIt() {
        final Response response  = target("test")
                .request()
                .post(Entity.text("Test"));

        assertThat(response.getStatus()).isEqualTo(200);
        assertThat(response.readEntity(String.class)).isEqualTo("Peeskillet:Test");
    }
}
Run Code Online (Sandbox Code Playgroud)

我还要提到的另一件事是,在以前的版本中,您扩展AbstractValueFactoryProvider并实现了a ParamInjectionResolver,大多数人这样做是为了遵循Jersey如何实现参数注入,同时仍然允许其他注入点(字段和构造函数)。如果您仍想使用此模式,则可以。

下面是AuthFeature从以上测试重构而成的

public static class AuthFeature implements Feature {

    @Override
    public boolean configure(FeatureContext context) {
        InjectionManager im = InjectionManagerProvider.getInjectionManager(context);

        AuthValueParamProvider authProvider = new AuthValueParamProvider();

        im.register(Bindings.service(authProvider).to(ValueParamProvider.class));

        Provider<ContainerRequest> request = () -> {
            RequestProcessingContextReference reference = im.getInstance(RequestProcessingContextReference.class);
            return reference.get().request();
        };

        im.register(Bindings.injectionResolver(new ParamInjectionResolver<>(authProvider, Auth.class, request)));

        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我只是从源头中找出这些东西。我在中看到的所有这些配置ValueParamProviderConfigurator。您无需实现自己的ParamInjectionResolver。正如上面的功能所做的那样,Jersey已经有一个我们可以使用的具体类。

如果您TestResource将字段更改为注入,它现在应该可以使用

@Path("test")
@Consumes("text/plain")
public static class TestResource {

    @Auth User user;

    @POST
    @Produces("text/plain")
    public Response post(String text) {
        return Response.ok(user.getUsername() + ":" + text).build();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @pjanssen 是的,应该可以通过将其绑定到“InjectionResolver”来进行注册。我只是选择使用 Bindings.injectionResolver() 快捷方法,因为 Jersey 在他们的源代码中就是这样做的。不过,您应该使用 Jersey AbstractBinder,而不是 HK2。 (2认同)