Jersey: how to access the global application object?

1k Views Asked by At

I'm creating a REST web application with Java, Tomcat and Jersey. I'm using annotations (no web.xml!) I ended up using this application configuration:

package com.my_own.server;

import java.util.Properties;
import javax.ws.rs.ApplicationPath;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.my_own.db.PostgreSQLDb;

@ApplicationPath("/api")
public class Application extends javax.ws.rs.core.Application {
    private static Logger logger = LogManager.getLogger(Application.class);
    public static Application application = null;

    public final Properties properties;
    public final PostgreSQLDb adminDb;

    public Application() throws Exception {
        logger.debug("Loading properties from ",
                    getClass().getClassLoader().getResource("config.properties"));
        properties = new Properties();
        properties.load(getClass().getClassLoader().getResourceAsStream("config.properties"));
        adminDb = new PostgreSQLDb(properties, "admin");
        application = this; // Setting the global application object here
    }

}

Here is my problem. There is a single global application objects for the web container. I'm saving it into a static field, from the application constructor. I need to access it from other classes later (it holds the global configuration, a global database connection factory, and probably other things.)

Am I doing this right? I suspect that there must be a better way: save a reference to the application when annotations are processed. But I'm not sure how. Can I be sure that the Application's constructor will be called exactly once, and the Application.application reference can be accessed later, from any REST call?

2

There are 2 best solutions below

4
On BEST ANSWER

Let me share my opinion: you can use of course a well-known Singleton pattern to store a "global" static object, however, it's really an antipattern these days.

If it's not a homework or something then storing global "static" objects is always a bad idea design-wise. If you want to know why there are many sources that answer this question, like this discussion for example

So I suggest considering using a Dependency Injection container instead, There are many really good containers out there: Spring, Guice to name a few.

These containers can store these objects as beans and if your "pieces" of functionality are also managed by these containers, you'll be able to "inject" application beans right into the controller.

It effectively solves all the issues introduced by singleton pattern.

4
On

Use dependency injection in jersey, bind your application when initializing:

public class MyApplication extends ResourceConfig {
    public MyApplication() {
        super(MyApplication.class);

        register(new MyBinder());
        packages(true, "location.of.my.jersey.classes");
    }

    /* Bind is used to let jersey know what can be injected */
    private static class MyBinder extends AbstractBinder {
        @Override
        protected void configure() {
            bind(MyApplication.class).to(MyApplication.class);
        }
    }
}

Then in your code:

@Path("myapi")
@Produces(MediaType.APPLICATION_JSON)
public class ServerRoutes {
    @Inject
    MyApplication application;

//... your rest code here
}

Now you can access MyApplication from within your code without needing any statics or singletons, jersey handles it.