Piotrowy Piotrowy - 26 days ago 16
Java Question

Injecting objects into singleton class with spring annotations

How to inject object into singleton class with spring annotations?

I have some code like in this following snippet and I want to inject object of class B into it.

public class A {
private B b;
private static A instance;

private A () {
set some timer tasks
...
}

public A getInstance() {
if (instance == null) { instance = new A(); }
return instance;
}


When I use @Inject above the b object, I have NullPointerException.

public final class SessionHolder {

private static SessionHolder instance;
@Inject
@Getter
@Setter
private PdbIdContainer pdbIdContainer;

private Map<UUID, SessionData> sessionMap;

private SessionHolder() {
this.sessionMap = new ConcurrentHashMap<>();
pdbIdContainer.update();
TimerTask timerTask1 = new TimerTask() {
@Override
public void run() {
Date d = new Date();
sessionMap.entrySet().stream().filter(map -> TimeUnit.MILLISECONDS.toMinutes(
d.getTime() - map.getValue().getLastUseTime().getTime()) >= Integer.parseInt(
AppController.getConfig().getSessionInterval())).forEach(map -> sessionMap.remove(map.getKey()));
}
};
TimerTask timerTask2 = new TimerTask() {
@Override
public void run() {
pdbIdContainer.update();
}
};
Timer timer = new Timer();
timer.scheduleAtFixedRate(timerTask1,
Integer.parseInt(AppController.getConfig().getSessionMapDelay()),
Integer.parseInt(AppController.getConfig().getSessionMapInterval()));
timer.scheduleAtFixedRate(timerTask2,
Integer.parseInt(AppController.getConfig().getPdbIdsSetDelay()),
Integer.parseInt(AppController.getConfig().getPdbIdsSetInterval()));
}


public static SessionHolder getInstance() {
if (instance == null) {
instance = new SessionHolder();
}
return SessionHolder.instance;
}

public static SessionData getSession(UUID id) {
return getInstance().sessionMap.get(id);
}

public static UUID createSession(StructureContainer structure) {
UUID id = UUID.randomUUID();
getInstance().sessionMap.put(id, new SessionData(structure, new Date()));
return id;
}
}

Answer

In Spring application, you do not need to and you should not create singleton classes. Spring will make sure that only single instance of this class exists in the context when you create a singleton bean (singleton is a default bean scope).

Your class should look like:

@Component
public class SessionHolder {

    private PdbIdContainer pdbIdContainer;

    private Map<UUID, SessionData> sessionMap;

    @Autowired // you can omit @Autowired if you use Spring 4.3 or higher
    SessionHolder(PdbIdContainer pdbIdContainer) {
        this.pdbIdContainer = pdbIdContainer;
        this.sessionMap = new ConcurrentHashMap<>();
        pdbIdContainer.update();
        TimerTask timerTask1 = new TimerTask() {
            @Override
            public void run() {
                Date d = new Date();
                sessionMap.entrySet().stream().filter(map -> TimeUnit.MILLISECONDS.toMinutes(
                        d.getTime() - map.getValue().getLastUseTime().getTime()) >= Integer.parseInt(
                        AppController.getConfig().getSessionInterval())).forEach(map -> sessionMap.remove(map.getKey()));
            }
        };
        TimerTask timerTask2 = new TimerTask() {
            @Override
            public void run() {
                pdbIdContainer.update();
            }
        };
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(timerTask1,
                                  Integer.parseInt(AppController.getConfig().getSessionMapDelay()),
                                  Integer.parseInt(AppController.getConfig().getSessionMapInterval()));
        timer.scheduleAtFixedRate(timerTask2,
                                  Integer.parseInt(AppController.getConfig().getPdbIdsSetDelay()),
                                  Integer.parseInt(AppController.getConfig().getPdbIdsSetInterval()));
    }

    public SessionData getSession(UUID id) {
        return sessionMap.get(id);
    }

    public UUID createSession(StructureContainer structure) {
        UUID id = UUID.randomUUID();
        sessionMap.put(id, new SessionData(structure, new Date()));
        return id;
    }
}
Comments