Why is #Required ignored by Spring? - java

I've read that #Required uses to make sure the property has been set.
But when I try to use it along with Spring Annotation Configuration it doesn't work.
Below you can familiarize with my code base.
#Configuration
#ComponentScan
public class AppConfig {
#Bean(initMethod = "initMethod")
public SimpleClass simpleClass(){
return new SimpleClass();
}
}
public class SimpleClass implements InitializingBean {
private int n;
public SimpleClass() {
System.out.println("constructor");
}
public int getN() {
return n;
}
#Required
public void setN(int n) {
System.out.println("setter");
this.n = n;
}
void initMethod(){
}
#Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet()");
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SimpleClass simpleClass = context.getBean(SimpleClass.class);
}
}
Why does Spring application context create the SimpleClass Bean and don't complain about the absence of injection via setter?
UPD:
When I try to do the same using XML configuration and add then I receive a "Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Property 'n' is required for bean 'simple'"

#Required documentation states (emphasis is mine) :
Marks a method (typically a JavaBean setter method) as being
'required': that is, the setter method must be configured to be
dependency-injected with a value.
With Spring in order to configure a method as dependency injected you have to specify it (#Autowired is the standard way).
But specifying both #Autowired and #Required on a method seems clumsy today :
#Autowired
#Required
public void setN(int n) {
System.out.println("setter");
this.n = n;
}
Instead, to configure the setter to be both dependency-injected and required I advise to use only #Autowired that by default is required as you can notice :
public #interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {#code true}.
*/
boolean required() default true;
}
So it is enough :
#Autowired
public void setN(int n) {
System.out.println("setter");
this.n = n;
}
As a side note, the setter injection will probably fail as the int n will probably not be resolved as a dependency. The #Value annotation on the parameter could probably help you.

You need to use it along with #Autowired (or #Value if you inject simple values) annotation.

Referring to this article:
Without a RequiredAnnotationBeanPostProcessor bean, Spring will not complain.
So ... add another bean of type RequiredAnnotationBeanPostProcessor (using #Autowired) to make it complain.
Also, #Required annotation is to be used for Bean setter. You are trying to do #Required check on a primitive type. As far as I understand, all Spring Beans (or J2EE beans) are to be objects.
For primitive types, you can use a #Value injection.

Related

Spring DI having two constructors at the same time

This is an anti pattern, but I am curious what will actually happen.
If you explicitly define a no-args constructor and a constructor with an autowired parameter, how exactly will spring framework initialize it?
#Service
class Clazz {
private MyBean myBean;
public Clazz(){}
#Autowired
public Clazz(MyBean myBean){
this.myBean = myBean;
}
}
On top of above answers, if there is single constructor declared without #autowire, spring uses same constructor for injection.
If there multiple constructors, then Spring uses constructor which is #autowired.
Mentioned in Spring Doc https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#beans-autowired-annotation
As of Spring Framework 4.3, an #Autowired annotation on such a
constructor is no longer necessary if the target bean only defines one
constructor to begin with. However, if several constructors are
available, at least one must be annotated to teach the container which
one to use
The constructor marked by #Autowired will be used by spring. You can validate this by running the following code.
public class Main {
#Component
static class MyBean {}
#Service
static class Clazz {
private MyBean myBean;
public Clazz(){
System.out.println("empty");
}
#Autowired
public Clazz(MyBean myBean){
this.myBean = myBean;
System.out.println("non-empty");
}
}
#Component
#ComponentScan("my.package")
private static class Configuration {
}
public static void main(String[] args) {
var ctx = new AnnotationConfigApplicationContext();
ctx.register(Configuration.class);
ctx.refresh();
ctx.getBean(Clazz.class);
}
}
The code prints non-empty.
Spring choose constructor first by the largest number of parameters
sortConstructors consider preferring public constructors and ones with a maximum number of arguments.
Meaning Clazz(MyBean myBean)
This is the Comparator used:
(e1, e2) -> {
int result = Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers()));
return result != 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount());

Is there a way to create multiple instances of same class within another class by #Autowired annotation? [duplicate]

By default, spring beans are singletons. I am wondering if there is a way to get multiple instances of same bean for processing.
Here is what I do currently
#Configuration
public class ApplicationMain {
#Value("${service.num: not configured}")
private int num;
//more code
#PostConstruct
public void run(){
for (int i = 0; i < num ; i++) {
MyService ser = new MyService(i);
Future<?> tasks = executor.submit(ser);
}
}
}
Here is the Service class
public class MyService implements Runnable {
private String name;
public Myservice(int i){
name=String.ValueOf(i);
}
}
I have simplified my usecase here.
I want to have MyService as spring bean and get as many as possible based on configuartion (which is num) in the above for-loop? wondering how that is possible.
Thanks
First you'll have to make MyService a Spring bean. You can do this by annotating the class with #Component. Next, as you say, Spring beans are Singletons by default, so this can be changed with one more annotation - #Scope("prototype").
A prototype bean scope means that each time you ask Spring for an instance of the bean, a new instance will be created. This applies to Autowiring, asking the application context for the bean with getBean(), or using a bean factory.
Here is a simple example of how to register a desired number of beans of the same type
#Configuration
public class MultiBeanConfig implements ApplicationContextAware {
#Value("${bean.quantity}")
private int quantity;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
for (int i = 0; i < quantity; i++) {
((ConfigurableApplicationContext)applicationContext).getBeanFactory()
.registerSingleton("my-service-" + i, new MyService());
}
assert(applicationContext.getBeansOfType(MyService.class).size() == quantity);
}
class MyService {
}
}

Inject value from properties in Spring Boot

I have a Rest Controller in which I initialise a service like this :
class Config {
#Value(${"number.of.books"})
private final static String numberOfBooks;
}
class MyController {
private final Service myService = new ServiceImplementation(Config.numberOfBooks)
public ResponseEntity methodA() { ... }
}
The numberOfBooks field has a initialisation value but when it's passed in the ServiceImplementation constructor it comes null.
I'm thinking I'm missing something obvious over here.
What is the mistake and which would be the best practice to inject a value from a property file into a constructor?
I recommend you to directly inject numberOfBooks in your ServiceImplementation, as follows:
public class ServiceImplementation implements Service {
#Value("${number.of.books}")
private String numberOfBooks;
}
Otherwise use setter injection for static variables, as follows:
#Component
class Config {
public static String numberOfBooks;
#Value("${number.of.books}")
public void setNumberOfBooks(String numberOfBooks) {
numberOfBooks = numberOfBooks;
}
}
After studying a little I've found out that the dependency injection happens after the constructor has been called. This being said the approach used was to use Autowired on my services constructor.
class ServiceImplementation implements Service {
private final String numberOfBooks;
#Autowired
private ServiceImplementation(Config config) {
this.numberOfBooks = config.getNumberOfBooks();
}
}
In this way Spring creates the dependency tree and makes sure that Config is not null when injected.

How can I use autowired in a non db access model

I have a model for service to use. But the autowired annotation returns null value. However this autowire works well in service. Is there any to do in the Module class?
public class Module{
private int id;
private String name;
private ArrayList<Function> functions;
#Autowired
private SysModuleLgDao sysModuleLgDao;
public Module() {
sysModuleLgDao.doSth();
}
}
This is my repo class:
#Repository
public interface SysModuleLgDao extends JpaRepository<SysModuleLgEntity, Long> {
public List<SysModuleLgEntity> findByModuleLgIdAndLanguageId(long moduleLgId,long languageId);
}
Object's constructor is called before Spring has a chance to do the wiring, so sysModuleLgDao reference is in its default state (i.e. null). Spring's context loading happens in a later phase, long after the default constructor has been called.
You can work around the problem by performing doSth in a different lifecycle phase, after the Spring bean has been constructed. This can be achieved via the #PostContstruct annotation:
public class Module {
#Autowired
private SysModuleLgDao sysModuleLgDao;
#PostConstruct
public void initialise() {
// at this point sysModuleLgDao is already wired by Spring
sysModuleLgDao.doSth();
}
}
More details here: Why use #PostConstruct?

Can #PostConstruct be used as a substitute of #Bean/#Produces?

I was reading this post when I thought about the possibility of substituting any #Bean (Spring DI) or #Produces (CDI) with a simple #PostConstructor as in the following CDI example:
Replace:
public class MyClassFactory {
#Produces
#RequestScoped
public MyClass createMyClass() {
MyClass myClass = new MyClass();
myClass.setA(1);
return myClass;
}
}
public class MyClass {
private int a;
private void setA(int a) {
this.a = a;
}
}
With:
public class MyClass {
#PostConstruct
public void init() {
this.setA(1);
}
private int a;
private void setA(int a) {
this.a = a;
}
}
Is that correct? What are the differences between those options?
No, #PostConstruct defines an interceptor for the initialization of a bean. It cannot be used to define the instantiation of a bean.
I dont see this as an incorrect question.
#PostConstruct method is invoked after the default constructor invocation and dependency injection (if any) are finished. You can initialize instance variables of a bean using the within a #PostConstruct annotated method. In this case, the difference b/w using #PostConstruct and CDI is that, the instance returned by CDI is a contextual one and since it is #RequestScoped, the lifetime of the 'produced' bean is confined to one HTTP request. A new instance of the bean would be produced once the existing HTTP request is complete. In case of #PostConstruct, its an #Dependent scoped bean (by default) and its life cycle would 'depend' upon the bean which injects it (using CDI #Inject)

Categories

Resources