Colleagues, hello! Is is possible to inject beans inside of class which is created via 'new' operator?
For example:
public class TestClass implements Callback {
#Inject
TestClassRepository repository;
//just only methods...
}
And 'TestClass' is created from another class:
Flyway.configure().collbacks(new TestClass()).load();
I have an issue with this,because 'repository.anyMethods()' inside of TestClass creates 'NullPointer' exception.
'TestClassRepository' is marked with the '#ApplicationScoped' and '#Startup' annotations.
#Singleton
public class TestConfig {
#javax.enterprise.inject.Produces
public TestClass testClass() {
return new TestClass();
}
}
another class annotated with the #ApplicationsScoped or #Singleton:
#Inject
public void method(TestClass testClass) {
Flyway.configure().collbacks(testClass).load();
// your code
}
If you create an object by yourself calling a constructor (new TestClass()) then quarkus doesn't manipulate that object, and doesn't inject a repository.
No you cannot inject beans inside a class that is instanciate with the new keyword.
But you can still find a way around like so :
#Dependent
public class BeanFactory {
#Inject
TestClassRepository repository
#Produces
public TestClass createTestClass() {
return new TestClass(this.repository);
}
You can find more details here : Quarkus Contexts and dependency Injection
Also you can define multiple beans for different profiles as mentionned few lines bellow Here
This means you can create a repository for your tests and one for prod or whatever is best for your case.
Also I do not think the annotation "#Startup" would add anything to your TestClassRepository bean.
Related
I have a requirement where I want to call a parameterised constructor of a class annotated with #Component inside another class which is annotated with #Service
feel free if you didn't get my question.
#Service
Class ServiceClass{
//here I want to create ComponentClass instance by Spring.
Result result=new ComponentClass(sending data to get result);
}
#Component
Class ComponentClass {
Component(received data){
}
}
I think you should try "Autowired" keyword. It says "Hey Spring Framework try to initialize the variable for me".
#Autowired
Result result=new ComponentClass(sending data to get result);
Whenever you define a #Servive or a #Component a bean of that type will be created (keep in mind that all beans are singletons).
A bean can be injected into any other spring managed bean by making use of this annotation:
#Service
Class ServiceClass{
#Autowired
Result result;
}
Using beans (components, services etc.) is not always needed and especially in the case, you need an non-singleton class, things can get tricky because of two reasons:
You won't be able to use annotations on that class
A non-annotated (spring managed bean) class do not support injection.
To inject a bean inside a class that is not annotated you will need to define a spring context:
#Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context
public static <T extends Object> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.context = context;
}
}
and then into any class:
Class ServiceClass{
Result result = SpringContext.getBean(Result.class);
}
where result is a either component or service.
I am trying to autowire a bean inside of a Singleton class, I know that it always a best idea to avoid manual autowiring, but this class is being used in so many places so I do not want to change the caller of this class.
Runner.java
#Component
public class RunnerClass {
#Autowired
public ConfigService configService;
}
ConfigService.java
#Service
public class ConfigService {
private ConfigServiceDAO = ConfigServiceDAO.getInstance();
}
ConfigServiceDAO.java
public class ConfigServiceDAO {
//Bean I want to autowire here....
#Autowired
ConfigServiceDAOBuilder DAOBuilder
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE = new ConfigServiceDAO();
private SingletonHolder() {}
}
}
DAOBuilder inside ConfigServiceDAO is always null, which makes sense because my understanding is when the class is instantiated manually, spring injection doesn't happen.
What could be the solution here if I want to keep ConfigServiceDAO as non spring component?
====EDIT====
I know it is possible to make ConfigServiceDAO as a spring component and autowire all dependencies.
But a lot of classes from different packages already call
ConfigServiceDAO.getInstance().someMethod()
So I guess the the right question is, what would be the best way to autowire a spring component to the class that is instantiated manually.
I don't know your use case but you cannot use #Autowired annotation outside a Spring bean.
However if you really need to access a Spring bean from a non Spring piece of code you can do it like below. However this is a very non Spring way of designing your dependencies.
import org.springframework.context.ApplicationContext;
public enum ApplicationContextHolder {
INSTANCE;
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
Then you have a configuration class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
#Configuration
public class SomeConfig {
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void init() {
ApplicationContextHolder.INSTANCE.setApplicationContext(applicationContext);
}
}
Then in your DAO class you get a reference to the builder bean you are interested. Something like this:
public class ConfigServiceDAO {
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE =
ApplicationContextHolder.INSTANCE.getApplicationContext().getBean(ConfigServiceDAOBuilder.class).buildConfigServiceDAO()
private SingletonHolder() {}
}
}
Again this is a very non Spring way of doing things.
Spring processed #Autowired only in beans that it manages by itself.
So you have two choices:
Get Rid Of singleton - if you're using spring, its already a singleton in the application context. This is by far the best approach in general (assuming other parts of application that call your singleton are also spring driven). I don't think you should fear to change ConfigServiceDAO.getInstance.method() - refactoring tools in IDE will do the job.
If you can't do 1, Don't use autowired annotation in the singleton - its useless anyway, instead, when you have an application context configured (in listener that spring emits when the application started for example), get the access to the ConfigServiceDAOBuilder bean by calling appCtx.getBean(ConfigServiceDAOBuilder.class) and "inject it" manually by reflection, this is what Spring does with spring managed beans anyway:
#EventListener
public void onApplicationReadyEvent(ApplicationReadyEvent event) {
ConfigServiceDAOBuilder builder =
event.getApplicationContext().getBean(ConfigServiceDAOBuilder.class);
ConfigServiceDao dao = ConfigServiceDAO.getInstance();
dao.setDaoBuilder(builder); // or alternatively by reflection
}
As a side note, consider using method setDaoBuilder to be a package private to protect the singleton from some accidentally calling a setter
As far as I understand what you want: Create by Spring ConfigServiceDAOBuilder. After that inject it into non-managed object of class ConfigServiceDAO. You can do it after the Spring application context is instantiated. For example with CommanLineRunner:
#Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
#Autowired
ConfigServiceDAOBuilder DAOBuilder
#Override
public void run(String...args) throws Exception {
ConfigServiceDAO.getInstance().init(DAOBuilder);
}
}
In ConfigServiceDAO has to be method init that helps to register all needed beans.
I'm confused after reading your comments, hence let me put in this way. What you are referring to manual autowiring is the Spring dependency injection way.
Whenever you are using any of the Spring Stereotype annotations with default scope instance is always Singleton.
Your ConfigService class has the problem.
Your are mixing up things, you should create a separate config class with #configuration and create Bean for the class ConfigServiceDAO, something like below
#Configuration
Class Config{
#Bean
public ConfigServiceDAO configServiceDAO( ){
return ConfigServiceDAO.getInstance();
}
}
then autowire the ConfigServiceDAO in the ConfigService class. With this Spring will resolve all of the dependency in correct order and DAOBuilder shouldn't be null.
I have a project structure similar to the one linked here: https://stackoverflow.com/a/29583882/1243462 . I have a util library containing a Service class in one JAR, meant to be consumed from another Java library/Maven project. However, my Service class itself uses Constructor Injection. So, where the original question had:
#Service
public class PermissionsService { ... }
I have
#Service
public class PermissionsService {
public PermissionsService(#Autowired PermissionsDao dao) {
//assign private dao field to autowired dao
}
}
And, like the original post, I want to create an instance of PermissionsService and inject it into my client/consumer application. I'm not sure of how to create a Configuration class.
#Configuration
public class PersistenceConfig {
public PermissionsService getPermissionsServiceBean() {
//What goes here?
}
}
For now, I have a workaround where I replaced the #Autowired PermissionsDao constructor argument with a field injection, and having a no-args constructor. This allows me to:
#Configuration
public class PersistenceConfig {
public PermissionsService getPermissionsServiceBean() {
return new PermissionsService();
}
}
But, since Field injection is discouraged, what is the right way to structure this code?
In your main module
#Configuration
#Import(PersistenceConfig.class)
public class ServiceConfig() {
}
In your utils module
#Configuration
#ComponentScan(basePackages = {"path-to-persistence-service-and-any-dependencies"})
public class PersistenceConfig {
}
The fact that you use constructor injection for PermissionsDao should not matter if you get the configuration right.
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{
I am attempting to use mocks in my integration test and am not having much luck. I am using Spring 3.1.1 and Mockito 1.9.0, and the situation is as follows:
#Component
public class ClassToTest {
#Resource
private Dependency dependency;
}
and
#Component
public class Dependency {
#Resource
private NestedDependency nestedDependency;
}
Now, I want to do an integration test of ClassToTest using Spring's JavaConfig. This is what I have attempted, and it doesn't work:
#Test
#ContextConfiguration
public class ClassToTestIntegrationTest {
#Resource
private ClassToTest classToTest;
#Resource
private Dependency mockDependency;
#Test
public void someTest() {
verify(mockDependency).doStuff();
// other Mockito magic...
}
#Configuration
static class Config {
#Bean
public ClassToTest classToTest() {
return new ClassToTest();
}
#Bean
public Dependency dependency() {
return Mockito.mock(Dependency.class);
}
}
}
I have simplified my setup to make the question easier to understand. In reality I have more dependencies and only want to mock some of them - the others are real, based on config imported from my prod #Configuration classes.
What ends up happening is I get a NoSuchBeanDefinitionException saying that there are no beans of type NestedDependency in the application context. I don't understand this - I thought Spring would receive Mockito's mocked instance of Dependency and not even look at autowiring it. Since this isn't working I end up having to mock my entire object graph - which completely defeats the point of mocking!
Thanks in advance for any help!
I had the same problem and I found another solution.
When Spring instantiate all your beans, it will check if it's a Mockito Mock and in this case, I return false for injection property. To use it, just inject it in a Spring context
Code below:
public class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
private static final MockUtil mockUtil = new MockUtil();
public MockBeanFactory() {
super();
}
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockUtil.isMock(bean);
}
}
What Mockito does when mocking classes is it creates a subclass using cglib having some fancy name like: Dependency$EnhancerByMockito (IIRC). As you probably know, subclasses inherit fields from their parent:
#Component
public class Dependency {
#Resource
private NestedDependency nestedDependency;
}
public class Dependency$EnhancerByMockito extends Dependency{
//...
}
This means Spring still sees the field in base class when presented with mock. What you can do:
Use interfaces, which will cause Mockito to employ dynamic proxies rather than CGLIB-generated classes
Mock NestedDependency - I know it will just cascade the problem one level further
Disable #Resource annotation scanning for tests