Jersey 3 - Configuring binding with bindFactory

793 Views Asked by At

Using Jersey 3.0.1, I am struggling to get binding working.

I have this binding module with the factories below:

public static class MyBinder extends AbstractBinder {
    @Override
    protected void configure() {
      LOG.info("Attempting to configure binder");
      bindFactory(DataSourceFactory.class).to(HikariDataSource.class).in(Singleton.class);
      bindFactory(JooqConfigFactory.class).to(Configuration.class).in(Singleton.class);
      bindFactory(DSLContextFactory.class).to(DSLContext.class).in(Singleton.class);
      LOG.info("Configured binder");
    }
}

public static class DataSourceFactory implements Supplier<HikariDataSource> {
    @Override
    public HikariDataSource get() {
      ...
      return new HikariDataSource(config);
    }
}

public static class JooqConfigFactory implements Supplier<Configuration> {
    @Inject
    HikariDataSource dataSource;

    @Override
    public Configuration get() {
      ...   
      return conf;
    }

}

public static class DSLContextFactory implements Supplier<DSLContext> {
    @Inject
    Configuration config;

    @Override
    public DSLContext get() {
      return DSL.using(config);
    }
}

Then I have the setup for my Servlet using embedded Jetty:

public void start() throws Exception {
    int port = appConfig.getProperty("http.port", 9998);
    Server server = new Server(port);

    ServletContextHandler ctx =
        new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
    ctx.setContextPath("/");
    server.setHandler(ctx);
    ResourceConfig config = new JerseyConfig();
    ServletHolder servlet = new ServletHolder(new ServletContainer(config));
    servlet.setInitOrder(1);
    ctx.addServlet(servlet, "/*");

    server.start();
    server.join();
}

public static class JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
      packages("com.sodonnell.jersey", "jersey.config.server.provider.packages");
      register(new MyBinder());
    }
}

And in my Rest service I simply try to inject a private instance variable:

public MyClass {

  @Inject  // javax.inject.Inject
  private DSLContext dslContext;

}

However this dslContext is always null. I can see from the logs, that it prints the LOG.info("Configured binder"); message. However putting similar logs in my factory classes show they never get called.

Has anyone got any idea what I am missing?

EDIT

To make things simpler, I created this class:

public class SimpleClass {

  private static Logger LOG = LoggerFactory.getLogger(SimpleClass.class);

  public SimpleClass() {
    LOG.info("Call the simple class constructor");
  }

Changed my binder module:

import com.google.inject.Injector;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.util.Properties;
import java.util.function.Supplier;
...


 // This is a nested class 
 public static class MyBinder extends AbstractBinder {
    @Override
    protected void configure() {
      LOG.info("Attempting to configure binder");
      bind(new SimpleClass()).to(SimpleClass.class); 
    }
  }

Then attempted to inject just SimpleClass:

package com.sodonnell.hdfs3.rest;

import com.sodonnell.hdfs3.SimpleClass;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.HEAD;
import jakarta.ws.rs.core.HttpHeaders;

import jakarta.ws.rs.Path;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import org.jooq.DSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;

  @Inject
  private SimpleClass simpleClass;
...

But its still null, although I see both the log messages. There must be some fundamental setup I am missing.

Full cut down code with the SimpleClass example at:

github.com/sodonnel/jerseyBind

1

There are 1 best solutions below

1
On BEST ANSWER

The answer is quite simple. You are using Jersey 3.0 which has switched to the new Jakarta naming. javax is thrown out the window - this includes javax.inject. All the javax package names have now been changed to jakarta. So to get the inject to work, the @Inject import should be

import jakarta.inject.Inject;

This change is part of the change of Java EE to Jakarta EE Starting from Jakarta EE 8 to Jakarta EE 9, all the namespacing has changed from javax to jakarta. So things like javax.servlet will now be jakarta.servlet. Weird, yes a huge breaking change with no backward compatibility.

In your case you have all the correct components to work with Jakarta (i.e. Jersey 3.0 and Jett 11), but you just need to make use of the new namespacing. Notice all the JAX-RS imports are now jakarta also.