【问题标题】:@BeanParam annotation in GUICE + JERSEY BridgeGUICE + JERSEY Bridge 中的 @BeanParam 注释
【发布时间】:2017-04-30 03:02:23
【问题描述】:
    @GET
    @Path("/book")
    public Response getBook(@BeanParam Filter filter) {

    }

过滤器参数正在初始化,但 bean 中没有设置任何内容

class Filter {@QueryParam("author")String author}

我确实为 Filter 对象中存在的所有属性设置了 setter 和 getter。

仅供参考。我正在使用 HK2 guice-bridge

【问题讨论】:

  • author 应该代表什么? @FormParam@QueryParam@HeaderParam 等?您是否添加了相应的注释?
  • 是的,我确实添加了注释,这是 QueryParam 更新了问题。
  • 那么你是说这没有 guice 可以工作,而那个guice 就是问题所在?你能证实这一点。只是想弄清楚你为什么提到 guice。
  • 检查一下github.com/medvedev/beanparam-jersey-guice 有人有示例项目来显示 Jersey @BeanParam 和 Guice DI 框架的问题..
  • 我不使用您正在使用的库 (dropwizard-guice),但看起来是 open issue

标签: guice jersey-2.0 hk2 guice-servlet


【解决方案1】:

我能够重现 guice-bridge 的问题。似乎当 bridge 已初始化(通过 guiceBridge.bridgeGuiceInjector(...)),仅调用 BeanParam 的默认构造函数,而不是设置属性(或使用参数调用构造函数)。

如果在您的项目中可能,您可以尝试提供带参数的构造函数。

这是一个简单的应用程序:

public class App extends ResourceConfig {

   @Inject
   public App(final ServiceLocator serviceLocator) {
     register(Service.class);

     final Injector injector = initializeInjector(serviceLocator);
   }

   private Injector initializeInjector(final ServiceLocator serviceLocator) {
     GuiceBridge.getGuiceBridge()
         .initializeGuiceBridge(serviceLocator);

     final Injector injector = Guice.createInjector(
         new ApplicationModule(serviceLocator));
     final GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
     guiceBridge.bridgeGuiceInjector(injector);
     return injector;
   }

}

使用的服务:

@Path("service")
public class Service {

  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Response save(@Valid @BeanParam final SimpleBean bean) {
    System.out.println(bean.getProperty());
    return Response.status(Status.CREATED)
        .build();
  }
}

这是一个简单的 bean:

public class SimpleBean {

  // Avoid this constructor!
  // public SimpleBean() {
  //  System.out.println("constructor called");
  // }

  public SimpleBean(@FormParam("property") final String property) {
    this.property = property;
    System.out.println("constructor with params called: " + property);
  }

  @Length(max = 100)
  @NotBlank
  private String property;

  public String getProperty() {
    System.out.println("getter called");
    return property;
  }

  public void setProperty(final String property) {
    System.out.println("setter called with " + property);
    this.property = property;
  }

}

使用 Guice 4.1.0 版、guice-bridge 2.4.0 版、Jersey 2.25.1 版和 Javax servlet 3.1.0 版。

【讨论】:

    【解决方案2】:

    您可以尝试在没有桥的情况下使用 Guice-Jersey。有一个名为"Guice Webserver Module" 的项目将Guice 与Jersey 2、Jetty 和Jackson 集成在一起,实现了这种方法。

    你需要做的是在 Guice 上下文中绑定你的资源,例如

    public class MyModule extends AbstractModule() {
        public void configure() {
                bind(BooksResource.class);
        }
    

    Jersey 有一个功能,它会扫描所有带有 @Path 注释的绑定,并在实例化后在 Jersey 的上下文中注册实例:

    public boolean configure(FeatureContext context) {
        injector.getBindings().entrySet()
            .stream()
            .filter(entry -> entry.getKey().getTypeLiteral().getRawType().getAnnotation(Path.class) != null)
            .map(entry -> injector.getInstance(entry.getKey()))
            .forEach(context::register);
    
        return true;
      }
    

    还有一个用于 BeanParams 的示例(作为集成测试的一部分编写)-BeanParamsIntegrationTest

    【讨论】: