Spring Autowiring is not working - java

Can someone explain why Autowiring is not working in the following context ?
I have the following class that I would love to Autowire:
#Component
public class UserFormatter {
...
}
Now I want to Autowire the UserFormatter in this class:
If I declare the UserFormatter as static it works fine but why does it work only this way?
#Data
#Component
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class ScenarioInfo {
#Transient
private static UserFormatter userFormatter;
#Autowired
public void generateUserFormatter(UserFormatter userFormatter) {
this.userFormatter = userFormatter;
}
Why can't I just write
#Data
#Component
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class ScenarioInfo {
#Transient
#Autowire
private UserFormatter userFormatter;
And why do I have to use a Function in order to Autowire the userFormatter ?
I'd be happy if someone could help me.:)

It depends on how you are initializing your ScenarioInfo class. JB Nizet is right about the use of new keyword stopping all the subsequent hierarchical Autowiring. If you want to create the ScenarioInfo object straight from the main method where #Autowire is not possible, then annotate the calling class(which is App here) with #Configuration and use
Annotationconfigapplicationcontext ctx = new Annotationconfigapplicationcontext(App.class);
ScenarioInfo scenarioInfo = ctx.getBean(ScenarioInfo.class);
where the App is the class with the main method in it. You could also use BeanFactory interface and its implementations but ApplicationContext is more feature rich. Plus I have never used the BeanFactory` myself, so you'd have to ask someone else on how to configure it for your project.

Related

#AllArgsConstructor not working with spring bean

I am having the class like below
#Controller
#RequestMapping(value = "/test")
#AllArgsConstructor
public class TestController {
#Qualifier("userDAO")
private final Test testDAO;
}
Below is my bean registration
<bean id="userDAO" class="com.test.dao.TestImpl"
p:sqlSessionFactory-ref="testSqlSessionFactory" />
when I run my app got error like below
No default constructor found; nested exception is java.lang.NoSuchMethodException bean configuration
Also I tried to add the lombok.config file in root and copied the Qualifier annotation, that's also not helped.
spring version is 3.2.15. lombok version 1.18.16
It's working fine with below
#Autowired
public TestController(#Qualifier("userDAO") final Test testDAO) {
this.testDAO = testDAO;
}
How to resolve this?
Adding only an #AllArgsConstructor isn't enough, as it will add the constructor but it doesn't add #Autowired. Because that is missing Spring will look for the default constructor.
To fix you can do 1 of 3 things
Upgrade to Spring 4.3 or higher, as that will automatically use the single constructor and autowire it
Instruct lombok to add #Autowired to the constructor.
Ditch lombok and just provide the constructor yourself.
The first should be pretty easy (include a newer version of Spring in your dependencies). The second requires some additional code.
#Controller
#RequestMapping(value = "/test")
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class TestController {
private final Test testDAO;
}
The #Qualifier won't work (and should be removed) as it should be on the constructor argument.
I would just ditch Lombok for this case and just add the constructor (option 3).
#Controller
#RequestMapping(value = "/test")
public class TestController {
private final Test testDAO;
#Autowired
public TestController(#Qualifier("userDAO") Test testDao) {
this.testDao=testDao;
}
}

How to ask for Prototype bean in Spring service class without applicationContext

I have a component defined with prototype scope. I want to use that component in my service class. I want spring to provide me a new instance of that Bean everytime I call for it.
Component Class:
#Getter
#Setter
#Component
#Scope("prototype")
public class ProtoTypeBean {
//.. Field variables
}
Service Class:
#AllArgsConstructor
#Service
public class ServiceClass {
ProtoTypeBean prototypeBean;
ArrayList<ProtoTypeBean> prototypeBeans;
public void demoMethod(ArrayList<String> someArrayList) {
for(var singleString: someArrayList) {
prototypeBean.setFieldValue(singleString);
prototypeBeans.add(prototypeBean);
}
System.out.println(prototypeBeans.toString());
}
}
By using this configuration, I am getting the same instance of ProtoTypeBean in my prototypeBeans ArrayList. The question is, how would I make Spring understand to give me a new instance of prototypeBean every time I am calling it into the foreach loop?
I found I can use ApplicationContext.getBean() to get a new instance of the Bean in foreach loop but I also heard that it's a bad practice. So kindly help me with the best practice.
Use an ObjectProvider to lazily get the result you want. However the first prototype scoped bean will not be represented in the list of beans as, well they are prototype scoped.
#AllArgsConstructor
#Service
public class ServiceClass {
private final ObjectProvider<ProtoTypeBean> provider;
public void demoMethod(ArrayList<String> someArrayList) {
PrototypeBean pb = provider.getIfUnique();
for(var singleString: someArrayList) {
pb.setFieldValue(singleString);
pb.add(prototypeBean);
}
System.out.println(prototypeBean.toString());
}
}
Also if you don't need all the dependency injection, proxy creation etc. for your object then why bother. There is nothing wrong with just the new keyword in a Spring application. Not everything has to be managed by Spring.
Set up your prototype bean similar to this:
#Getter
#Setter
#Component
#Scope("prototype")
public class ProtoTypeBean {
final private String param;
public ProtoTypeBean(final String p) {
this.param = p;
}
}
Now, in your service class use a BeanFactory to create the beans for you:
#Service
#AllArgsConstructor
public class ServiceClass {
private final BeanFactory factory;
private List<ProtoTypeBean> prototypeBeans;
#Autowired
public ServiceClass(final BeanFactory f) {
this.factory = f;
}
public void demoMethod(List<String> someArrayList) {
this.prototypeBeans = someArrayList
.stream()
.map(param -> factory.getBean(ProtoTypeBean.class, param))
.collect(Collectors.toList());
}
}
I came across this issue recently. I am sure there must be a better way than mine, but this is how I did it:
public class ServiceClass {
ArrayList<ProtoTypeBean> prototypeBeans = new ArrayList<>();
#Autowired
ApplicationContext ctx;
public void demoMethod(ArrayList<String> someArrayList) {
for(var singleString: someArrayList) {
//magic is in below line.. getting a bean from ApplicatioContext.
ProtoTypeBean prototypeBean= ctx.getBean("protoTypeBean"); //Or ctx.getBean(ProtoTypeBean.class);
prototypeBean.setFieldValue(qBean.getFieldValue());
prototypeBeans.add(prototypeBean);
}
System.out.println(prototypeBeans.toString());
}
This way, Spring container always give you a new instance. And it is totally managed by Spring container.
The way you tried it, I tried that as well, but it would always inject one instance at the time of autowiring, hence defeating the purpose of prototyping.
You could have gone the route of using new Keyword. But then that is just regular Java instantiation and I think that new instance is not managed by Spring because it is annotated with #Component instead of #Configuration. I could be wrong here though.

How to create a factory-method with arguments?

Could you please help me to get rid of ApplicationContext?
I have a factory so that all book instances are spring-beans.
I think it's a good decision to make all beans spring-beans.
#Component
public class BookFactoryImpl implements BookFactory {
private final ApplicationContext applicationContext;
#Autowired
public BookFactoryImpl(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public Book createBook(String name) {
return applicationContext.getBean(Book.class, name);
}
}
Here is a configuration class with a #Beanmethod that is used to instantiate a new instance of Book class:
#Configuration
#ComponentScan({"factory"})
public class AppConfig {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
#Lazy
public Book book(String name) {
return Book.builder().name(name).build();
}
}
Here is my Book entity class:
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#EqualsAndHashCode
#ToString
#Builder
public class Book {
#Id
#GeneratedValue
private int id;
#Basic(fetch = FetchType.LAZY)
private String name;
}
I have more one idea - to annotate BookFactoryImpl with #Configuration and move #Bean method in it but in this case, my factory will be turned into #Configuration class with the broken lifecycle.
What do you think, what is the best way to implement a factory and how to reduce external dependencies like ApplicationContext?
Or maybe it's nice to make all factories as #Configuration classes with #Bean methods, how do you think?
No, it is not a good idea to make every single class in your application managed by Spring.
JPA entities usually should be instantiated by your code inside Spring managed beans.
I usually use the following approach:
Define the singleton bean that will contain a dependency on factory:
public class MyService {
private final Provider<Book> bookFactory;
public MyService(Provider<Book> bookFactory) {
this.bookFactory = bookFactory;
}
public void doSomething() {
Book book = bookFactory.get();
book.setNumberOfReaders(numOfReaders); // this is a drawback, book is mutable, if we want to set runtime params (like numberOfReaders)
....
}
}
Now Define a prototype for book bean:
#Configuration
public class MyConfiguration {
#Bean
#Scope("prototype")
public Book book(...) {
return new Book(...);
}
#Bean // scope singleton by default
public MyService myService(Provider<Book> bookFactory) {
return new MyService(bookFactory);
}
}
Notice, Provider is of type "javax.inject.Provider", in order to use id, import (for example in maven):
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
Spring can handle this since 4.x ( I guess 4.1) without any additional configuration
Of course, this approach eliminates that need to inject application context to the factory and in general to maintain a factory
One drawback is that it doesn't allow building the object with arguments, these arguments have to be specified in runtime.
There is also another approach, a runtime generation of sub-class in conjunction with #Lookup annotation, its described Here but IMO Provider approach is better.

Spring boot: Consider defining a bean of type 'com.repository.services.interfacename' in your configuration

I've deployed an spring boot application, where i created an interface and implement it with two classes.
public interface interfacename {
LinkedHashSet<String> names(String path);
}
And implemented classes are
#Component
public class class1 implements interfacename {
......
}
#Component
public class class2 implements interfacename {
......
}
Now i try to create an instance for both the classes using interface name,
#Autowired
#Qualifier("class1")
interfacename imp1;
#Autowired
#Qualifier("class2")
interfacename imp2;
It is the configuration class,
#Configuration
public class interfacenameConfig {
#Bean
#ConditionalOnProperty(name = "class1", matchIfMissing = true)
public interfacename class1Service() {
return new class1();
}
#Bean
#ConditionalOnProperty(name = "stanfordname")
public interfacename class2Service() {
return new class2();
}
}
My Project structure is,
com.repository
application.java(#SpringApplcation)
com.repository.controller
applicationcontroller.java(#RestController)
com.repository.services
interfacename.java
interfacenameconfig.java(#configuration)
class1.java(#component)
class2.java(#component)
It throws the following error
Action:
Consider defining a bean of type 'com.repository.services.interfacename' in your configuration.
please someone guide me to solve this.
Thanks in advance
In you're usage you're saying that you want beans with the ids / names class1 and class2respectively:
#Autowired
#Qualifier("class1")
interfacename imp1;
#Autowired
#Qualifier("class2")
interfacename imp2;
But in the configuration you gave them different names:
#Configuration
public class interfacenameConfig {
#Bean
#ConditionalOnProperty(name = "class1", matchIfMissing = true)
public interfacename class1Service() {
return new class1();
}
#Bean
#ConditionalOnProperty(name = "stanfordname")
public interfacename class2Service() {
return new class2();
}
}
Namely: class1Service and class2Service. Those Ids are derived from the name of the function instantiating the beans
Two possible fixes:
Give them the names you want with #Bean("class1") and #Bean("class2").
OR
Use the names they have in the qualifier, that is: #Qualifier("class1Service") and #Qualifier("class2Service")
In your configuration class you should have an annotation to prompt for component scanning to the package that your interface interfacename belongs.
E.g.:
#ComponentScan({"com.repository.services"})
In Spring-boot you usually have this annotation in the Spring boot application class
e.g.
#SpringBootApplication
#ComponentScan({"com.repository.services"})
public class MyApplication {
}
UPDATE
If you have multiple classes implementing an interface you can use the value attribute when annotating them as #Component
#Component(value="class1")
public class class1 implements interfacename
#Component(value="class2")
public class class2 implements interfacename
and then #Autowire them with #Qualifier as you already do.
Based on your last update, since the #SpringBootApplication is in the parent directory of your spring-managed beans I think you can omit the #ComponentScan annotation. Spring will scan by default all the sub-packages below com.repository.
However I still believe that the interfacenameconfig class is redundant. Why are you declaring the same beans as the ones you have annotated as #Component? Either #Component or #Bean, there is no reason having both for the same beans as far as I know and it could probably be the source of your problem.
You need to add #Service annotation above interface implementation.
e.g. #Component
public interface interfacename {
LinkedHashSet<String> names(String path);
}
#Service
public class interfaceDefinition implements interfacename{
LinkedHashSet<String> names(String path){
// write code here
}
}
I have add the qualifier annotation along with #Component annotation. Then i ensure the application it is working fine.
#Component
#Qualifier("class1")
public class class1 implements interfacename {
......
}
Thanks for the reply

NullPointerException when autowiring into non-spring managed class (POJO) - Spring Boot

I'm relatively new to Spring Boot and dependency injection overall, so please forgive any noob things going on here. I'm building an API and am having trouble when injecting dependencies into a POJO resource (DTO).
When I call the method in the POJO this.numComments = commentSvc.getAllForPhoto(this.getId()); I am getting a NullPointerException. However, when I do this from another spring-managed bean and pass the values into the constructor, it works fine.
After reading around, it looks like I need to do something with aspectJ and Load Time Weaving, but I'm not sure what that would look like in my code.
In essence, my approach looks something like this:
PhotoResource.java (POJO)
public class PhotoResource extends BaseRepresentable {
#Autowired
CommentService commentSvc;
private Long id;
private Integer numComments;
PhotoResource(PhotoEntity entity){
super(entity);
this.setId(entity.getId);
this.numComments = commentSvc.getAllForPhoto(this.getId());
}
}
CommentService.java
#Service
public class CommentService{
public List<CommentResource> getAllForPhoto(Long photoId) {
// code to get all comments for photo
}
}
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
Spring won't inject the dependency unless you ask the Spring container to manage the bean. In order for commentSvc to be injected into PhotoResource class, you need to annotate it with #Component or #Bean or #Service, e.g.:
#Component
public class PhotoResource extends BaseRepresentable {
#Autowired
CommentService commentSvc;
}
And make sure the package of this class is included into #ComponentScan packages.
Also, the following won't compile:
#Service
public class CommentService(){
You don't need paranthesis to declare a class, it should be:
#Service
public class CommentService{

Categories

Resources