@BeanParam annotation in GUICE + JERSEY Bridge

410 Views Asked by At
    @GET
    @Path("/book")
    public Response getBook(@BeanParam Filter filter) {

    }

Filter paramater is getting initialized but nothing is set in the bean

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

I do have setter and getter for all properties present in Filter object.

F.Y.I. I am using the HK2 guice-bridge.

2

There are 2 best solutions below

0
Lukas S. On

I was able to reproduce the problem with guice-bridge. It seems that when the bridge is initialized (via guiceBridge.bridgeGuiceInjector(...)), only the BeanParam's default constructor is being called instead of also setting the properties (or calling the constructor with parameters).

If it's possible in your project, you could try to provide a constructor with parameters.

This is a simple app:

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;
   }

}

The used service:

@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();
  }
}

And here's a simple 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;
  }

}

Using Guice version 4.1.0, guice-bridge version 2.4.0, Jersey version 2.25.1 and Javax servlet version 3.1.0.

0
sasa On

You can try to use Guice-Jersey without bridge. There is a project called "Guice Webserver Module" which integrates Guice with Jersey 2, Jetty and Jackson where this approach is implemented.

What you need to do is to bind your resource in Guice context, e.g.

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

There is a Jersey's feature which will scan for all binding annotated with @Path, and will register instance in Jersey's context after instantiation:

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;
  }

There is also a example (written as part of integration test) for BeanParams - BeanParamsIntegrationTest