In Spring project I can use #Autowired annotation.
#Service
public class DefaultUserService implements UserService {
...
#Autowired
private UserDao userDao;
But I don't understand how do it in JavaEE project. I found:
#Inject
private AvayaDao avayaDao;
But my avayaDao is NULL. I tried add annotation
#Default
public class AvayaService {
...
#Inject
private AvayaDao avayaDao;
but not helped. It id my Dao:
public interface AvayaDao extends BaseDao<AvayaSdr> {
List<AvayaSdr> getAll();
void insertCdr(AvayaSdr avayaSdr);
}
It is My Service:
#Default
public class AvayaService {
private static AvayaService instance;
#Inject
private AvayaDao avayaDao;
public synchronized static AvayaService me() {
if (instance == null) {
instance = new AvayaService();
}
return instance;
}
public Set<String> selectAllLoadedAVAYAcmCDRFiles() {
Set<String> result = new HashSet<>();
List<AvayaSdr> resultList = avayaDao.getAll();
for (AvayaSdr avayaSdr : resultList) {
result.add(avayaSdr.getHashValue());
}
return result;
}
public void insertCdr(String fileHash) {
AvayaSdr avayaCmCdr = new AvayaSdr("", fileHash, 0);
avayaDao.insertCdr(avayaCmCdr);
}
java.lang.NullPointerException
Either the AvayaDao must be an EJB and annotated with #Stateless or #Singleton or you use CDI injection and an empty beans.xml file is needed (http://docs.oracle.com/javaee/6/tutorial/doc/gjbnz.html) if you are using Java EE 6. In Java EE 7 the attribute bean-discovery-mode="all" must be set (https://docs.oracle.com/javaee/7/tutorial/cdi-adv001.htm).
UPDATE 1:
Enterprise Java Beans are POJOS annotated with #Stateless, #Statefull or #Singleton, that are managed by the EJB container inside the application server. They are able to access container specific services like the TimerService, the security context and aspects like transaction support and monitoring. Stateless enterprise java beans are also pooled by the application server.
UPDATE 2:
#Tiny Your right, but if AvayaDao is no EJB and your application contains a beans.xml file, where interceptors or other CDI specific POJOS are registered the default bean-discovery-mode is 'annotated' and the injection will not work with not annotated POJOS and explicitly setting the 'all' value is needed (http://www.adam-bien.com/roller/abien/entry/when_your_di_breaks_bean). Another option would be using no beans.xml if you explicitly know, that your application is only deployed in JAVA EE 7 environments.
Related
I am new at spring MVC framework and i am currently working in a web application that uses a session scoped bean to control some data flow.
I can access these beans in my application context using #Autowired annotation without any problem in the controllers. The problem comes when I use a class in service layer that does not have any request mapping (#RequestMapping, #GetMapping nor #PostMapping) annotation.
When I try to access the application context directly or using #Autowired or even the #Resource annotation the bean has a null value.
I have a configuration class as follow:
#Configuration
#EnableAspectJAutoProxy
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class, basePackages = "com.quantumx.nitididea.NITIDideaweb.repository")
public class AppConfig implements WebMvcConfigurer {
#Bean (name = "lastTemplate")
#SessionScope
public LastTemplate getlastTemplate() {
return new LastTemplate();
}
//Some extra code
}
The POJO class is defined as :
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I have a Test class that is annotated as service and does not have any request mapping annotated method:
//#Controller
#Service
public class Test {
// #Autowired
// private ApplicationContext context;
// #Autowired
#Resource(name = "lastTemplate")
public LastTemplate lastTemplate;
// #Autowired
// public void setLastTemplate(LastTemplate lastTemplate) {
// this.lastTemplate = lastTemplate;
// }
public Test() {
}
// #RequestMapping("/test")
public String testing() {
// TemplateForma last = (TemplateForma) context.getBean("lastInsertedTemplate");
// System.out.println(last);
System.out.println(lastTemplate);
// System.out.println(context.containsBean("lastTemplate"));
// System.out.println(context.getBean("lastTemplate"));
System.out.println("Testing complete");
return "Exit from testing method";
// return "/Messages/Success";
}
}
As you can see, there is a lot of commented code to show all the ways i have been trying to access my application context, using an Application context dependency, autowiring, declaring a resource and trying with a request mapping. The bean is null if no controller annotation and request mapping method is used and throws a java null pointer exception when I use the context getBean() methods.
Finally I just test my class in a controller that i have in my app:
#RequestMapping("/all")
public String showAll(Model model) {
Test test = new Test();
test.testing();
return "/Administrator/test";
}
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked. How can access my application context in a service class without mapping a request via controller?
Worth to mention that I also tried to change the scope of the bean to a Application scope and singleton, but it not worked
It should have worked in this case.
How can access my application context in a service class without mapping a request via controller?
Try one of these :-
#Autowired private ApplicationContext appContext;
OR
Implement ApplicationContextAware interface in the class where you want to access it.
Edit:
If you still want to access ApplicationContext from non spring managed class. Here is the link to article which shows how it can be achieved.
This page gives an example to get spring application context object with in non spring managed classes as well
What worked for me is that session scoped bean had to be removed in the application configuration declaration and moved to the POJO definition as follows:
#Component
#SessionScope
public class LastTemplate {
private Integer lastId;
public LastTemplate(){
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}
The I just call the bean using #Autowired annotation.
I am trying to Inject a class into my entity listener created by my jpa provider. The following code throws a PersistenceException - unable to build hibernate SessionFactory (which I expected). From my research it seems like jpa 2.1 supports dependency injection. I am missing some type of binding/provides for guice to know about this class. My guess is it has to be some type of run time binding.
public class EntityListener {
private SomeService service;
#Inject
public EntityListener(SomeService service) {
this.service = service;
}
#PostLoad
public void load(Object o){
//use service here
}
}
I have different types of Provider (interface) classes say ProviderA, ProviderB and so on. In a normal world, I would create a class called ProviderFactory such that
public class ProviderFactory{
public Provider getProviderByName(String providerName){
for (Provider provider : availableProviders){
if (provider.getName.equalIgnoreCase(providerName)){
return provider;
}
}
return null;
}
}
Now, What I want to know that are there any provided annotations to help me use this factory classes in singleton way ? These factories are static in nature and they can be configured at application runtime. So i am looking for singleton implementation here.
#Component/#Service/#Repository/#Controller/#RestController are using singleton scope by default.
You can implement a factory pattern in Spring as shown below:
#Component
public class ProviderFactory {
#Autowired
private ProviderA providerA;
#Autowired
private ProviderB providerB;
public static Provider getProviderByName(String providerName) {
if (providerName.equalsIgnoreCase("providerA")) {
return providerA;
} else if (providerName.equalsIgnoreCase("providerB")) {
return providerB;
}
}
}
If you annotate each Provider class with one of the stereotype annotations (#Component, #Service, #Repository, #Controller or #RestController), then you can #Autowire them into your factory:
#Component
public class ProviderFactory {
#Autowired
private List<Provider> availableProviders;
public Provider getProviderByName(String providerName) {
for (Provider provider : availableProviders) {
if (provider.getName.equalIgnoreCase(providerName)){
return provider;
}
}
return null;
}
}
However, if you intend to use your Provider instances in other Spring beans, I would recommend to use #Qualifier in conjunction with #Autowire to let Spring solve which instance to use, e.g.
#Component
public class ClassThatDependsOnSpecificProvider {
#Autowired
#Qualifier("providerA")
private Provider providerA;
}
More info about #Qualifier can be found in the Fine-tuning annotation-based autowiring with qualifiers chapter in the Spring reference docs.
I stuck with a simple refactoring from plain Java to Spring. Application has a "Container" object which instantiates its parts at runtime. Let me explain with the code:
public class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
public void load() {
// repeated several times depending on external data/environment
RuntimeBean beanRuntime = createRuntimeBean();
runtimeBeans.add(beanRuntime);
}
public RuntimeBean createRuntimeBean() {
// should create bean which internally can have some
// spring annotations or in other words
// should be managed by spring
}
}
Basically, during load container asks some external system to provide him information about number and configuration of each RuntimeBean and then it create beans according to given spec.
The problem is: usually when we do in Spring
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
Container container = (Container) context.getBean("container");
our object is fully configured and have all dependencies injected. But in my case I have to instantiate some objects which also needs dependency injection after I execute load() method.
How can I achieve that?
I am using a Java-based config. I already tried making a factory for RuntimeBeans:
public class BeanRuntimeFactory {
#Bean
public RuntimeBean createRuntimeBean() {
return new RuntimeBean();
}
}
Expecting #Bean to work in so called 'lite' mode. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html Unfortunately, I found no difference with simply doing new RuntimeBean();
Here is a post with a similar issue: How to get beans created by FactoryBean spring managed?
There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Configurable.html but it looks like a hammer in my case.
I also tried ApplicationContext.getBean("runtimeBean", args) where runtimeBean has a "Prototype" scope, but getBean is an awful solution.
Update 1
To be more concrete I am trying to refactor this class:
https://github.com/apache/lucene-solr/blob/trunk/solr/core/src/java/org/apache/solr/core/CoreContainer.java
#see #load() method and find "return create(cd, false);"
Update 2
I found quite interesting thing called "lookup method injection" in spring documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection
And also an interesting jira ticket https://jira.spring.io/browse/SPR-5192 where Phil Webb says https://jira.spring.io/browse/SPR-5192?focusedCommentId=86051&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-86051 that javax.inject.Provider should be used here (it reminds me Guice).
Update 3
There is also http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.html
Update 4
The issue with all these 'lookup' methods is they don't support passing any arguments.. I also need to pass arguments as I would do with applicationContext.getBean("runtimeBean", arg1, arg2). Looks like it was fixed at some point with https://jira.spring.io/browse/SPR-7431
Update 5
Google Guice have a neat feature for it called AssistedInject. https://github.com/google/guice/wiki/AssistedInject
Looks like I found a solution. As I am using java based configuration it is even simpler than you can imagine. Alternative way in xml would be lookup-method, however only from spring version 4.1.X as it supports passing arguments to the method.
Here is a complete working example:
public class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
private RuntimeBeanFactory runtimeBeanFactory;
public void load() {
// repeated several times depending on external data/environment
runtimeBeans.add(createRuntimeBean("Some external info1"));
runtimeBeans.add(createRuntimeBean("Some external info2"));
}
public RuntimeBean createRuntimeBean(String info) {
// should create bean which internally can have some
// spring annotations or in other words
// should be managed by spring
return runtimeBeanFactory.createRuntimeBean(info);
}
public void setRuntimeBeanFactory(RuntimeBeanFactory runtimeBeanFactory) {
this.runtimeBeanFactory = runtimeBeanFactory;
}
}
public interface RuntimeBeanFactory {
RuntimeBean createRuntimeBean(String info);
}
//and finally
#Configuration
public class ApplicationConfiguration {
#Bean
Container container() {
Container container = new Container(beanToInject());
container.setBeanRuntimeFactory(runtimeBeanFactory());
return container;
}
// LOOK HOW IT IS SIMPLE IN THE JAVA CONFIGURATION
#Bean
public BeanRuntimeFactory runtimeBeanFactory() {
return new BeanRuntimeFactory() {
public RuntimeBean createRuntimeBean(String beanName) {
return runtimeBean(beanName);
}
};
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
RuntimeBean runtimeBean(String beanName) {
return new RuntimeBean(beanName);
}
}
class RuntimeBean {
#Autowired
Container container;
}
That's it.
Thanks everyone.
i think that your concept is wrong by using
RuntimeBean beanRuntime = createRuntimeBean();
you are bypassing Spring container and resorting to using regular java constructor therefore any annotations on factory method are ignored and this bean is never managed by Spring
here is the solution to create multiple prototype beans in one method, not pretty looking but should work, I autowired container in RuntimeBean as proof of autowiring shown in log also you can see in log that every bean is new instance of prototype when you run this .
'
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
Container container = (Container) context.getBean("container");
container.load();
}
}
#Component
class Container {
private List<RuntimeBean> runtimeBeans = new ArrayList<RuntimeBean>();
#Autowired
ApplicationContext context;
#Autowired
private ObjectFactory<RuntimeBean> myBeanFactory;
public void load() {
// repeated several times depending on external data/environment
for (int i = 0; i < 10; i++) {
// **************************************
// COMENTED OUT THE WRONG STUFFF
// RuntimeBean beanRuntime = context.getBean(RuntimeBean.class);
// createRuntimeBean();
//
// **************************************
RuntimeBean beanRuntime = myBeanFactory.getObject();
runtimeBeans.add(beanRuntime);
System.out.println(beanRuntime + " " + beanRuntime.container);
}
}
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public RuntimeBean createRuntimeBean() {
return new RuntimeBean();
}
}
// #Component
class RuntimeBean {
#Autowired
Container container;
} '
A simple approach:
#Component
public class RuntimeBeanBuilder {
#Autowired
private ApplicationContext applicationContext;
public MyObject load(String beanName, MyObject myObject) {
ConfigurableApplicationContext configContext = (ConfigurableApplicationContext) applicationContext;
SingletonBeanRegistry beanRegistry = configContext.getBeanFactory();
if (beanRegistry.containsSingleton(beanName)) {
return beanRegistry.getSingleton(beanName);
} else {
beanRegistry.registerSingleton(beanName, myObject);
return beanRegistry.getSingleton(beanName);
}
}
}
#Service
public MyService{
//inject your builder and create or load beans
#Autowired
private RuntimeBeanBuilder builder;
//do something
}
Instead of using SingletonBeanRegistry you can use this:
BeanFactory beanFactory = configContext.getBeanFactory();
Anyway SingletonBeanBuilder extends HierarchicalBeanFactory and HierarchicalBeanFactory extends BeanFactory
You don't need the Container because all of the runtime objects should be created, held and managed by ApplicationContext. Think about a web application, they are much the same. Each request contains external data/environment info as you mentioned above. What you need is a prototype/request scoped bean like ExternalData or EnvironmentInfo which can read and hold runtime data through a static way, let's say a static factory method.
<bean id="externalData" class="ExternalData"
factory-method="read" scope="prototype"></bean>
<bean id="environmentInfo" class="EnvironmentInfo"
factory-method="read" scope="prototype/singleton"></bean>
<bean class="RuntimeBean" scope="prototype">
<property name="externalData" ref="externalData">
<property name="environmentInfo" ref="environmentInfo">
</bean>
If you do need a container to save the runtime objects, code should be
class Container {
List list;
ApplicationContext context;//injected by spring if Container is not a prototype bean
public void load() {// no loop inside, each time call load() will load a runtime object
RuntimeBean bean = context.getBean(RuntimeBean.class); // see official doc
list.add(bean);// do whatever
}
}
Official doc Singleton beans with prototype-bean dependencies.
It is possible to register beans dynamically by using BeanFactoryPostProcesor. Here you can do that while the application is booting (spring's application context has been initialized). You can not register beans latest, but on the other hand, you can make use of dependency injection for your beans, as they become "true" Spring beans.
public class DynamicBeansRegistar implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (! (beanFactory instanceof BeanDefinitionRegistry)) {
throw new RuntimeException("BeanFactory is not instance of BeanDefinitionRegistry");
}
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// here you can fire your logic to get definition for your beans at runtime and
// then register all beans you need (possibly inside a loop)
BeanDefinition dynamicBean = BeanDefinitionBuilder.
.rootBeanDefinition(TheClassOfYourDynamicBean.class) // here you define the class
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addDependsOn("someOtherBean") // make sure all other needed beans are initialized
// you can set factory method, constructor args using other methods of this builder
.getBeanDefinition();
registry.registerBeanDefinition("your.bean.name", dynamicBean);
}
#Component
class SomeOtherClass {
// NOTE: it is possible to autowire the bean
#Autowired
private TheClassOfYourDynamicBean myDynamicBean;
}
As presented above, you can still utilize Spring's Dependency Injection, because the post processor works on the actual Application Context.
I have some issues with DI in Spring Framework (version 4.1.1). I wrote a small library that creates its own application context and uses DI to configure its components. It consists of the following classes. First the config file for the application context.
#Configuration
#ComponentScan(basePackages = { "package.containing.services" })
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"package.containing.repositories"})
#PropertySource({"classpath:config-file.properties"})
public class ConnectorConfig {
#Resource
private Environment env;
#Bean
public DataSource dataSource() { /* DataSource config here */ }
#Bean
public EntityManagerFactory entityManagerFactory() { /* EntityManagerFactory config here */ }
#Bean
public PlatformTransactionManager transactionManager() { /* TransactionManager config here */ }
}
The JPA Repository:
#Repository
#Transactional(readOnly = true)
public interface LogEntryJpaRepository extends JpaRepository<LogEntryEntity, Long> {
#Query("SELECT l FROM LogEntryEntity l WHERE logentry_time >= :fromDate AND logentry_time <= :toDate AND logentry_data NOT LIKE 'EXTERNAL COMMAND:%' ORDER BY logentry_time ASC, logentry_id ASC")
public List<LogEntryEntity> findInTimeframe(#Param("fromDate") Timestamp fromDate, #Param("toDate") Timestamp toDate);
#Query("SELECT COUNT(l) FROM LogEntryEntity l WHERE logentry_time >= :fromDate AND logentry_time <= :toDate AND logentry_data NOT LIKE 'EXTERNAL COMMAND:%'")
public long countInTimeframe(#Param("fromDate") Timestamp fromDate, #Param("toDate") Timestamp toDate);
}
A simple service that forwards calls to the repository:
#Service
public class Connector {
#Autowired
private LogEntryJpaRepository logEntryRepo;
public LogEntryEntity getLogEntryById(long id) {
return logEntryRepo.findOne(id);
}
public List<LogEntryEntity> getLogEntriesInTimeframe(LocalDateTime fromDate, LocalDateTime toDate) {
return logEntryRepo.findInTimeframe(Timestamp.valueOf(fromDate), Timestamp.valueOf(toDate));
}
public long countLogEntriesInTimeframe(LocalDateTime fromDate, LocalDateTime toDate) {
return logEntryRepo.countInTimeframe(Timestamp.valueOf(fromDate), Timestamp.valueOf(toDate));
}
}
And finally a factory that provides the singleton instance of the service to external consumers:
public class ConnectorFactory {
private static ApplicationContext ctx;
public static Connector getInstance() {
if(ctx == null) {
ctx = new AnnotationConfigApplicationContext(ConnectorConfig.class);
}
return ctx.getBean(Connector.class);
}
private ConnectorFactory() {};
}
I wrote some unit tests to test the factory and repository and it is all working fine. I get a bean returned from the factory.
But when I include this library in a larger project the DI does no longer work properly. The larger project consists of several services that consume connectors like the above to fetch data from external services. They are injected using the #Autowired annotation It is a maven project so I added the above library to the dependencies, compiling works fine. I added a bean definition to a config class in my larger project to gain access to the connector's service:
#Configuration
#EnableTransactionManagement(proxyTargetClass = true)
#ComponentScan({"de.decoit.imonitor.gui.dao"})
#PropertySource({"classpath:imonitor-gui.properties"})
public class PersistenceConfig {
#Resource
private Environment env;
#Bean
public Connector connector() {
return ConnectorFactory.getInstance();
}
}
And this is where the problem occurs: When injecting the Connector bean into a service in my larger project, the DI inside the library fails. It says that he cannot find a suitable bean for the LogEntryJpaRepository dependency.
Why does the DI work fine when run inside a unit test but does fail when used inside another application context? In my understanding the context of the larger project does not need to know the repository bean, the configuration is done by the context inside the library. That context just exposes the service bean to external consumers, no configuration needs to be done by the context of the larger project.
Is there some mistake in my configuration or even design flaws for the library itself? This is my first library that uses DI to configure itself so maybe I just did something completely wrong?
[EDIT] Removed #Import statement from configuration class, that was a remains of testing, not there in real code. Sorry!