final Util Class Static vs Singleton Class - java

Currently I'm trying to Implement a utility Class that generates an invoice in a PDF Format and I predict that I'll need spring beans to be injected in my Utility Class Afterwards.
But I don't need the class to be instanciated, I only need the methods. So for me it's a dilemma
So I did some research and I still haven't made my mind If I want a spring singleton bean or .
Spring Singleton : Source
#Service
public class Singleton {
private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
public Singleton() {
final Singleton previous = INSTANCE.getAndSet(this);
if(previous != null)
throw new IllegalStateException("Second singleton " + this + " created after " + previous);
}
public static Singleton getInstance() {
return INSTANCE.get();
}
}
Or A final Class :
public final InvoiceUtil {
private InvoiceUtil() {}
public static String convertToPDF (Template template) {
//Do the work
}
}
but with the second approach, my class isn't managed by Spring so I can not inject beans to it.
Make me undrestand !! :p

If you use a Spring bean, do not implement Spring Service as a Singleton with getInstance(). Just add #Service and Spring will only instantiate it once.
You can use static methods, and later pass any dependency also to these methods (if those are few dependencies):
public static String convertToPDF (Template template, NeededHelper helper) {
...
}

Related

Call singleton class in spring boot rest api controller

I am new to spring framework. I have to use spring boot and have a rest controller as below :-
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
and I have a class which needs to be singleton :-
#Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
I want to know the correct way to call this singleton class in my rest controller. I know that by default the scope of a bean in spring is singleton. Is this the correct way to call the singleton class in rest controller?
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
or
We need to call it using the getInstance() method? Also do we need to explicitly have the getInstance method in the TransactionStatisticsCacheImpl class?
One of the major advantages of container injection is that you can get the benefits of singleton semantics without all the serious problems of "hard" singletons (such as difficulty testing). Get rid of the getInstance manual business and let Spring take care of ensuring that a single instance is created and used for the context.
Just for clarification: By default, the spring IOC container will create only one instance per bean definition, unless if you specified otherwise using the #Scope stereotype. But if you create an instance using getInstance() the bean pre-processors and post-processors will not work correctly on that bean definition. And also you can use the #Autowired stereotype to inject a bean definition as needed and if you have different implementations for the same definition you can use the #Qualifier stereotype to specify the implementation that you need to inject, alternatively, you can use the constructor injection to inject your bean definition as needed without auto wiring as mentioned here Spring #Autowire on Properties vs Constructor
I would stick to the answers above. However, if you want to preserve further instantiation of the class in your code (or you want to keep your specific implementation of singleton), you can do it with getInstance().
Firstly, get rid of #Component annotation in your class:
// #Component
public class TransactionStatisticsCacheImpl implements TransactionCache {
private static TransactionStatisticsCacheImpl instance;
public static TransactionStatisticsCacheImpl getInstance(){
if(Objects.isNull(instance)){
synchronized (TransactionStatisticsCacheImpl.class) {
if(Objects.isNull(instance)){
instance = new TransactionStatisticsCacheImpl();
}
}
}
return instance;
}
private TransactionStatisticsCacheImpl() {}
}
Then, you may instantiate your singleton #Bean by defining #Configuration class - this way your bean would get managed by spring container.
#Configuration
public class SingletonConfiguration {
#Bean
public TransactionCache transactionCache() {
return TransactionCacheImpl.getInstance();
}
}
Eventually, you can have your singleton injected in your RestController using #Autowired.
#RestController
public class StatisticsController {
private TransactionCache transactionCache;
#Autowired
public StatisticsController(TransactionCache transactionCache) {
this.transactionCache = transactionCache;
}
#PostMapping("/tick")
public ResponseEntity<Object> addInstrumentTransaction(#Valid #RequestBody InstrumentTransaction instrumentTransaction) {
transactionCache.addTransaction(instrumentTransaction);
return new ResponseEntity<>(HttpStatus.CREATED);
}
}

Using an autowired singleton bean in a non spring managed java class

Alright, this might seem pretty stupid to all the veterans out there, but bear with me here, as I'm only finding my way around Spring & Spring Boot.
I've got a Controller class here,
#RestController
public class Controller {
private static final Logger logger = LogManager.getLogger(Controller.class);
private static Controller controller = null;
#Autowired
private ApplicationParameters applicationParameters;
public static Controller getInstance() {
if (controller == null) {
synchronized (Controller.class) {
if (controller == null) {
controller = new Controller();
}
}
}
return controller;
}
public Controller() {}
public ApplicationParameters getApplicationParameters() {
return applicationParameters;
}
#RequestMapping("/")
public void init() {
try {
for (Entry<String, String> prop : applicationParameters.getProperties().entrySet())
logger.info("Loaded System Property: " + prop.getKey() + " -> " + prop.getValue());
Utils.concatenate("key1", "key2");
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
which autowires the ApplicationParameters bean with properties from a Property file.
Utils Class
public class Utils {
protected static final Logger logger = LogManager.getLogger(Utils.class);
//Need to get the value of the property keys propKey1 & propKey2 and concat them.
public static String concatenate(String propKey1, String propKey2) throws Exception {
if(StringUtils.isNoneEmpty(propKey2) && StringUtils.isNoneEmpty(propKey1)) {
return Controller.getInstance().getApplicationParameters().getProperties().get(propKey1) + Controller.getInstance().getApplicationParameters().getProperties().get(propKey2)
} else {
logger.error("System Property is undefined." );
return null;
}
}
So, I'd like use this autowired ApplicationParameters bean as a singleton instance throughout the lifecycle of my project.
For instance, I'd like to use it in the Utils class. Clearly Utils class is not spring managed, its just a regular old java class.
So I'd like to know how to use fully initialized applicationParameters in my Utils class.
This is what I've tried so far:
Autowiring the ApplicationParameters again in the Utils class, like this,
public class Utils {
#Autowired
private ApplicationParameters applicationParameters;
protected static final Logger logger = LogManager.getLogger(Utils.class);
But applicationParameters will be null here as, I'm presuming, this is because, Utils is not a spring managed bean.
Make Controller class singleton. (Not sure how to go about doing this as init() needs to get invoked when web server starts, then where to call getInstance()?)
Hence, would someone be so kind as to assist a novice here.
P.S. The Utils class is shown only as a sample to bring home the fact that, a spring managed autowired bean has to be used in a regular java class.
You could make the spring context accessible from outside with a helper class like this one:
public class SpringContextUtil implements ApplicationContextAware {
static ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
Then, you could do something like this: SpringContextUtil.getApplicationContext.getBean("applicationParameters")
As a first rule, don't. A second don't either. Only if you really must, as there is no garantuee that this will work reliable as there is no way that everything has been properly initialized when this method is called. Instead try re-working your util to be a spring managed class as well.
If you really want, ditch most of your code as you are trying to be too smart in your code. Use this hack (yes it is a hack imho and should be avoided if necessary!).
public class SpringUtil {
private static final ApplicationContext ctx;
SpringUtil(ApplicationContext ctx) {
SpringUtil.ctx=ctx;
}
public static Controller getController() {
return this.ctx.getBean(Controller.class);
}
public static ApplicationParameters getApplicationParameters() {
return ctx.getBean(ApplicationParameters.class);
}
}
Then cleanup your controller
#RestController
public class Controller {
private static final Logger logger = LogManager.getLogger(Controller.class);
#Autowired
private ApplicationParameters applicationParameters;
#GetMapping("/")
public void init() {
try {
for (Entry<String, String> prop : applicationParameters.getProperties().entrySet())
logger.info("Loaded System Property: " + prop.getKey() + " -> " + prop.getValue());
Utils.concatenate("key1", "key2");
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
THen use the SpringUtil to obtain the ApplicationParameters instead of the controller
public class Utils {
protected static final Logger logger = LogManager.getLogger(Utils.class);
//Need to get the value of the property keys propKey1 & propKey2 and concat them.
public static String concatenate(String propKey1, String propKey2) throws Exception {
if(StringUtils.isNoneEmpty(propKey2) && StringUtils.isNoneEmpty(propKey1)) {
return SpringUtils.getApplicationParameters().getProperties().get(propKey1) + SpringUtils.getApplicationParameters().getProperties().get(propKey2)
} else {
logger.error("System Property is undefined." );
return null;
}
}
However this is quite a hack and might work in 90% of the cases. Also there is quite a design flaw/smell as you are doing a lot of getter chaining in your class. So all in all you are probably better of refactoring the Utils to make use of regular method calls and proper design techniques.

Loading static properties file class

Currently I am using a singleton class to read and load the propertied file. I get an instance of this in any class where I want to use a property value.
Would not it be better to use a static class instead which can be loaded once (when server started or something .. ) instead of using a singleton ? Why and why not ?
Moreover how can we load a static class OnServerStart or when war gets deployed.
PS: Project is web application
Singleton is better for dependency injection and unit testing than statics.
You may inject an instance of singleton class or a Mock of that type to any other class under test.
public class PropertiesHolder {
private static final PropertiesHolder INSTANCE = new PropertiesHolder();
private final Properties props;
private PropertiesHolder() {
props = load();
}
public static PropertiesHolder getInstance() {
return INSTANCE;
}
public String getProperty(String key) {
return props.getProperty(key);
}
private Properties load() {
...
}
}
Then you may mock PropertiesHolder in your test:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock private PropertiesHolder holder;
#Test
public void testSomething() {
SomeService service = new SomeService(holder);
when(holder.getProperty("foo")).thenReturn("bar");
String result = service.doSomething();
assertEquals(...)
}
}
For production code you may use:
new SomeService(PropertiesHolder.getInstance());
Or even better, use DI framework, e.g. Spring, for wiring a beans. PropertiesHolder would be a generic bean with factory method getInstance() and the scope 'singleton'.
If you're using Spring in your web application I'd suggest using with it's PropertyPlaceholderConfigurer.
If you don't want to use Spring for that and need to do some actions (e.g. loading property file) on servlet when webapp is started then use ServletContextListener as Bhesh Gurung has suggested.

Builder Pattern Using Spring Injected Resources

I have a Builder that uses several resources that are injected via Spring. It looks similar to this:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class SandBoxBuilder {
private final SandUtil sandUtil;
private Sand sand;
private Box box;
#Autowired
public SandBoxBuilder(SandUtil sandUtil) {
this.sandUtil = sandUtil;
}
public SandBoxBuilder setSand(Sand sand) {
this.sand = sand;
return this;
}
public SandBoxBuilder setBox(Box box) {
this.box = box;
return this;
}
public SandBox build() {
SandBox sandBox = new SandBox(sand);
sandUtil.changeBox(sandBox, box);
return sandBox;
}
}
The problem I have with this is that it is not thread safe. I know that this builder should not be a singleton, but I am not sure how to use the spring injected resources (SandUtil) without wiring the builder up and injecting it where I use it.
How can I implement a thread safe builder that utilizes singletons injected by spring?
Solution
Because of some architectural constraints I could not inject the utilities into my calling classes. I ended up implementing a factory builder bean that returns new instances of a builder that has references to the spring resources.
Solution Implementation
#Component
public class SandBoxBuilderFactory {
private final SandUtil sandUtil;
#Autowired
public SandBoxBuilderFactory(SandUtil sandUtil) {
this.sandUtil = sandUtil;
}
public Builder newBuilder(){
return new Builder(sandUtil);
}
public static class Builder {
private final SandUtil sandUtil;
private Sand sand;
private Box box;
private Builder(SandUtil sandUtil) {
this.sandUtil = sandUtil;
}
public Builder setSand(Sand sand) {
this.sand = sand;
return this;
}
public Builder setBox(Box box) {
this.box = box;
return this;
}
public SandBox build() {
SandBox sandBox = new SandBox(sand);
sandUtil.changeBox(sandBox, box);
return sandBox;
}
}
}
Usage
newBuilder().setBox(box).setSand(sand).build();
You are using your SandBoxBuilder as a bean because of #Component. Wherever you need it, you must have access to the ApplicationContext. I would propose, instead of injecting the SandBoxBuilder bean, inject the SandUtil bean and use it to create SandBoxBuilder instances
#Service
public class MyService {
private final SandUtil sandUtil;
#Autowired
public MyService (SandUtil sandUtil) {
this.sandUtil = sandUtil;
}
public void someMethod() {
SandBoxBuilder builder = new SandBoxBuilder(sandUtil);
... // use it
}
}
Does SandUtil need to be a bean? It might fit as a static utility class.
I do not know much about the Spring IOC lately. I use the Tapestry IOC alot which should provide similar inner working.
First of all a singleton should be thread-safe per definition. So if you create the builder every time you use it, the builder does not need to be thread-safe. The SandUtil must be in itself threadsafe.
It's like a contract: If you are a singleton service you are injected in multiple threads. Therefore a singleton service has to be threadsafe (synchronized methods, shared lock, synchronized objects and so on). If your service is PerThread meaning the same service is only used within a single thread, it has not to be thread safe.
So ensure SandUtil is threadsafe and you are fine if Sandbox is PerThread or PerOccurence (new instance is created every time it is injected).
If you want to make the builder threadsafe since you can not be sure a single instance of it is only used within a thread - and you do not care much about performance - you can just add synchronized keyword to every non-private method of the builder class. This is the poor-mans concurrency control otherwise check out some tutorials about concurrency control like the original Java lesson
I'm guessing the non-thread-safe part of this has to do with the sandUtil field?
You can use external locking on the changeBox method to ensure synchronized access to it.
Otherwise, perhaps the 'prototype' bean scope would help you out?
http://docs.spring.io/spring/docs/3.0.x/reference/beans.html#beans-factory-scopes
http://docs.spring.io/spring/docs/3.0.x/reference/beans.html#beans-factory-scopes-prototype

Is it possible and how to do Assisted Injection in Spring?

In Guice 2 or 3, exists so called Assisted/Partial Inject described here. With this, Guice synthesizes factory implementation (implementing my interface) for my object and some of the constructor arguments are injected by Guice, and some are provided from the context.
Is it possible and how to do the same thing with Spring?
The following does exactly what i asked for. Though, it does not synthesize the implementation of the factory, it is good enough as the factory has access to the injection context so that can use other beans (injectable artifacts) during construction. It uses java based #Configuration instead of XML, but it will work with XML too.
The factory interface:
public interface Robot {
}
// Implementation of this is to be injected by the IoC in the Robot instances
public interface Brain {
String think();
}
public class RobotImpl implements Robot {
private final String name_;
private final Brain brain_;
#Inject
public RobotImpl(String name, Brain brain) {
name_ = name;
brain_ = brain;
}
public String toString() {
return "RobotImpl [name_=" + name_ + "] thinks about " + brain_.think();
}
}
public class RobotBrain implements Brain {
public String think() {
return "an idea";
}
}
// The assisted factory type
public interface RobotFactory {
Robot newRobot(String name);
}
// this is the Spring configuration showing how to do the assisted injection
#Configuration
class RobotConfig {
#Bean #Scope(SCOPE_PROTOTYPE)
public RobotFactory robotFactory() {
return new RobotFactory() {
#Override
public Robot newRobot(String name) {
return new RobotImpl(name, r2dxBrain());
}
};
}
#Bean #Scope(SCOPE_PROTOTYPE)
public Brain r2dxBrain() {
return new RobotBrain();
}
}
The test code:
public class RobotTest {
#Test
public void t1() throws Exception {
ApplicationContext ctx = new
AnnotationConfigApplicationContext(RobotConfig.class);
RobotFactory rf = ctx.getBean(RobotFactory.class);
assertThat(rf.newRobot("R2D2").toString(),
equalTo("RobotImpl [name_=R2D2] thins about an idea"));
}
}
This achieves exactly what Guice does. The tricky difference is the Scope. Spring's default scope is Singleton and Guice's is not (it is prototype).
AFAIK you can't. In Spring you can have Instantiation using a static factory method or Instantiation using an instance factory method. With the second option you can define a bean myFactoryBean working as a factory for another bean. You can also pass construction arguments to myFactoryBean by using constructor-arg (see for example the section Using An Instance Factory Method on this blog), which gives you the equivalent of Guice-injected arguments. However, I don't know of any way to provide further arguments from context when invoking the factory method.
I finally ported Guice AsssitedInject to Spring (or maybe any jakarta.inject container if you're lucky)
https://gitlab.com/wholesail-oss/assisted-inject
Check it out and let me know if it helps you :)

Categories