Spring's #Autowired value is null. My application is deployed on weblogic 12c.
I have pasted relevant files below along with explanations.
I tried changing to #Component
DriverServlet.java: Set in web.xml. Called by weblogic. Initializes
application context.
package com.clarksburg.services.configuration;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
public class DriverServlet extends HttpServlet {
public void init() throws ServletException {
// Call the AppConfig class to scan all packages
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("Driver Servlet initialized;");
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void destroy() {
// do nothing.
}
}
AppConfig.java: Does component scanning.
package com.clarksburg.services.configuration;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = { "com.clarksburg.services" })
public class AppConfig {
private static final Logger logger = LogManager.getLogger(AppConfig.class.getName());
public AppConfig() {
logger.debug("App Config called by driver");
// TODO Auto-generated constructor stub
}
// Put Other Application configuration here.
}
The class 'AsynchAQMessageSvcImpl' implements 'AsynchAQMessageSvc' which was generated using WSDL. It's wired to a OSB proxy on weblogic and get's called whenever the proxy gets a JMS message on a AQ queue.
It's annotated with #Service. I tried to autowire ProcessWsPayload in it but when i use it i get a null pointer exception. Printing it's value is also null.
package com.clarksburg.services.messaging;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.clarksburg.services.wsimport.AsynchAQMessageRequestType;
import com.clarksburg.services.wsimport.AsynchAQMessageResponseType;
import com.clarksburg.services.wsimport.AsynchAQMessageSvc;
import com.clarksburg.services.services.ProcessWsPayload;
#Service
#WebService(name = "AsynchAQMessageSvc", targetNamespace = "http://www.clarksburg.com/AsynchAQMessageSvc")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class AsynchAQMessageSvcImpl implements AsynchAQMessageSvc {
#Autowired
ProcessWsPayload processWsPayload;
private static final Logger logger = LogManager.getLogger(AsynchAQMessageSvcImpl.class.getName());
#Override
#WebMethod(operationName = "GetAsynchAQMessage", action = "http://www.clarksburg.com/AsynchAQMessageSvc")
#WebResult(name = "AsynchAQResponse", targetNamespace = "http://www.clarksburg.com/AsynchAQMessageSvc", partName = "response")
public AsynchAQMessageResponseType getAsynchAQMessage(
#WebParam(name = "AsynchAQRequest", targetNamespace = "http://www.clarksburg.com/AsynchAQMessageSvc", partName = "request")
AsynchAQMessageRequestType request) {
logger.debug("processWsPayload is " +processWsPayload);
processWsPayload.processWsPayload(request);
// new ProcessWsPayload().processWsPayload(request);
AsynchAQMessageResponseType response = new AsynchAQMessageResponseType();
response.setServiceResponse("Success");
return response;
}
}
ProcessWsPayload.java: It's called (successfully) by 'AsynchAQMessageSvcImpl'. It's annotated as #Component.
package com.clarksburg.services.services;
import java.math.BigInteger;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.clarksburg.services.configuration.JDBCConfig;
#Component
public class ProcessWsPayload {
private static final Logger logger = LogManager.getLogger(ProcessWsPayload.class.getName());
#Autowired
JDBCConfig jdbcConfig;
/*
* This method is called by a JMS listener. It is being invoked successfully.
* However the value of 'jdbcConfig' is null
*/
public void processWsPayload(wsPayload request) {
BigInteger wsAuditId = request.getAuditId();
system.out.println("The value of JDBCConfig is " +jdbcConfig);
try {
String SQL = "UPDATE AUDIT_TBL SET ws_descriptions = ? WHERE ws_audit_id = ?";
JDBCConfig.jdbcTemplate().update(SQL, "Success with soap send", wsAuditId);
} catch (Exception e) {
logger.debug("Failed to update table with success");
logger.error(e);
}
}
I turned on Spring's TRACE logs and have pasted lines pertaining to Autowiring below.
Spring's relevant autowired logs during deployment:-
InjectionMetadata - Registered injected element on class [com.multiplan.services.messaging.AsynchAQMessageSvcImpl]: AutowiredFieldElement for com.multiplan.services.services.ProcessWsPayload com.multiplan.services.messaging.AsynchAQMessageSvcImpl.processWsPayload
InjectionMetadata - Processing injected element of bean 'AsynchAQMessageSvcImpl': AutowiredFieldElement for com.multiplan.services.services.ProcessWsPayload com.multiplan.services.messaging.AsynchAQMessageSvcImpl.processWsPayload
InjectionMetadata - Registered injected element on class [com.multiplan.services.services.ProcessWsPayload]: AutowiredFieldElement for com.multiplan.services.configuration.JDBCConfig com.multiplan.services.services.ProcessWsPayload.jdbcConfig
InjectionMetadata - Processing injected element of bean 'processWsPayload': AutowiredFieldElement for com.multiplan.services.configuration.JDBCConfig com.multiplan.services.services.ProcessWsPayload.jdbcConfig
AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'processWsPayload' to bean named 'JDBCConfig'
AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'AsynchAQMessageSvcImpl' to bean named 'processWsPayload'
Related
I am getting the below error while starting spring boot application.
The injection point has the following annotations:
#org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type
'java.util.concurrent.atomic.AtomicReference' in your configuration.
Below is the code .
package de.summer.sampleapplayerv1;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#SpringBootApplication(scanBasePackages = {"de.summer.sampleapplayerv1"})
#EnableConfigurationProperties
#EnableJpaRepositories (basePackages ="de.summer.sampleapplayerv1.repository")
#EnableTransactionManagement
public class Sampleapplayerv1Application {
public static void main(String[] args) {
SpringApplication.run(Sampleapplayerv1Application.class, args);
}
}
package de.summer.sampleapplayerv1.service;
import de.summer.sampleapplayerv1.domain.QueueAndPublish;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
#Slf4j
#Service
public class QueueAndPublishServiceImpl implements QueueAndPublishService{
private final AtomicReference<List<QueueAndPublish>> currentJob;
public QueueAndPublishServiceImpl(
#Qualifier("currentJob") AtomicReference<List<QueueAndPublish>> currentJob
){
this.currentJob=currentJob;
}
#Override
public QueueAndPublish getJobStatus(UUID jobId) {
return (QueueAndPublish) currentJob.get().stream()
.filter(j -> j.getJobId()==jobId)
.collect(Collectors.toList());
}
#Override
public List<QueueAndPublish> getAllJobStatus() {
return currentJob.get();
}
#Override
public QueueAndPublish getCategoryDataProcess() {
List<QueueAndPublish> processList=new ArrayList<QueueAndPublish>();
QueueAndPublish process=QueueAndPublish.builder()
.jobId(UUID.randomUUID())
.jobName("Name for Job")
.jobStatus("Not Yet Started")
.build();
Thread t1=new Thread(process.getJobId().toString()){
#Override
public void run(){
log.info("How are you doing");
process.setJobStatus("Completed");
}
};
t1.start();
processList.add(process);
currentJob.set(processList);
return process;
}
#Override
public QueueAndPublish getCatgeoryDataProcessStatus() {
return null;
}
}
package de.summer.sampleapplayerv1.domain;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.UUID;
#Getter
#Setter
#Builder
#Entity
public class QueueAndPublish implements Serializable {
#Id
private UUID jobId;
private String jobName;
private String jobStatus;
}
If I remove the constructor, spring boot application is starting up without any errors. If included , start up is failing with unsatisfied dependency errors.
Can someone please help on what is wrong with config?
You expect Spring to create an instance of class QueueAndPublishServiceImpl for the implementation of QueueAndPublishService. This instance needs a constructor parameter of type AtomicReference<List<QueueAndPublish>> injected.
But you obviously do not define any Spring bean (Bean, Component, Service, ...) of that type.
Edit:
public QueueAndPublishServiceImpl(
#Qualifier("currentJob") AtomicReference<List<QueueAndPublish>> currentJob
){
this.currentJob=currentJob;
}
Here you define a constructor parameter to have a AtomicReference<List<QueueAndPublish>>, and even specify it with a #Qualifier. So you need to provide a Spring bean of this class with this qualifier, otherwise Spring cannot inject it into the constructor call.
Consider defining a bean of type 'java.util.concurrent.atomic.AtomicReference' in your configuration.
Means "something like" adding this to your Sampleapplayerv1Application:
#Bean("currentJob") AtomicReference<List<QueueAndPublish>> currentJob() {
// or a list implementation of your choice.
return new AtomicReference<>(new java.util.ArrayList<>());
}
I have to create multiple beans of same type for different property value which is to be injected using constructor.
Currently I have used Bean scope as Prototype & created multiple methods to read different properties to create new object. How to combine all the different methods into single method and to supply different values at run time to create new bean.
package com.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
#Configuration
public class ConfigClass {
#Bean(name="RC")
public JavaClient getClient(#Autowired Environment env)
{
String sName=env.getProperty("RCSName");
String aUrl=env.getProperty("RCAUrl");
String dUrl=env.getProperty("RCDUrl");
return new JavaClient(sName,aUrl,dUrl);
}
#Bean(name="O")
public JavaClient getOClient(#Autowired Environment env)
{
String sName=env.getProperty("OSName");
String aUrl=env.getProperty("OAUrl");
String dUrl=env.getProperty("ODUrl");
return new JavaClient(sName,aUrl,dUrl);
}
}
Now it is creating 2 beans as per above code. Expectation: How to combine getClient & getOClient into single method, but the property to be supplied in a loop to create multiple beans of same type JavaClient
I have modified my ConfigClass as below & created ApplicationContextAware to inject beans by reading file properties.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.annotation.EnableScheduling;
#Configuration
#EnableScheduling
public class ConfigClass {
#Bean
#Scope("prototype")
public JavaClient getClient(String sName,String aUrl,String dUrl)
{
return new JavaClient(sName,aUrl,dUrl);
}
}
Then Have created ApplicationContextAware to create Beans.
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Iterator;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public ApplicationContext getContext() {
return applicationContext;
}
#PostConstruct
public void init()
{
try {
String fileName = "Url.txt";
Resource resource = new ClassPathResource(fileName);
File file = resource.getFile();
List<String> lines = Files.readAllLines(file.toPath());
for (Iterator<String> iterator = lines.iterator(); iterator.hasNext();) {
String line = (String) iterator.next();
String[] s = line.split(",");
applicationContext.getBean(JavaClient.class,s[0], s[1], s[2]);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have one spring component bean which contains a method methodA defined by #HystrixCommand with fallbackMethod. The bean has another method methodB invokes methodA by CompletableFuture.supplyAsync(...). I expect Hystrix javanica will weave the aspect on methodA, but when I debug it, I didn't see hystrix aspect is weaved.
Here are some of the main sudo code,
TestApplication:
package com.my.own.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackages = "com.my.own.test")
public class TestApplication {
public static void main(final String[] args) throws Exception {
SpringApplication.run(TestApplication.class, args);
}
}
ApplicationConfiguration:
package com.my.own.test;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy(exposeProxy = true)
#EnableConfigurationProperties
#EnableCircuitBreaker
public class ApplicationConfig {
}
AsyncConfig:
package com.my.own.test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
#Configuration
#EnableAsync
public class AsyncConfig {
#Value("${spring.threadpool.executor.core:10}")
private int corePoolSize;
#Value("${spring.threadpool.executor.max:20}")
private int maxPoolSize;
#Value("${spring.threadpool.executor.queue:1000}")
private int queueCapacity;
#Value("${spring.threadpool.executor.timeout:true}")
private boolean coreThreadTimeOut;
#Value("${spring.threadpool.executor.keepalive:30000}")
private int keepAlive;
#Value("${spring.threadpool.executor.prefix:ThreadPoolTaskExecutor}")
private String threadNamePrefix;
#Bean("taskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setAllowCoreThreadTimeOut(coreThreadTimeOut);
executor.setKeepAliveSeconds(keepAlive);
executor.setThreadNamePrefix(threadNamePrefix + "-");
executor.initialize();
return executor;
}
}
TestController:
package com.my.own.test.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.my.own.test.core.TestProcessor;
#RestController
public class TestController {
private static Logger logger = LoggerFactory.getLogger(TestController.class);
#Autowired
TestProcessor tester;
#RequestMapping(value = "/test", method = { RequestMethod.POST })
public void test() {
tester.methodB();
}
}
TestProcessor:
package com.my.own.test.core;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
#Component
public class TestProcessor {
#Autowired
private ThreadPoolTaskExecutor executor;
public void methodB() {
final List<CompletableFuture<String>> a = new ArrayList<>();
a.add(CompletableFuture.supplyAsync(() -> methodA(), executor));
CompletableFuture.allOf(a.toArray(new CompletableFuture[a.size()])).join();
}
#HystrixCommand(fallbackMethod = "deferPushdown")
public String methodA() {
if (true) {
throw new RuntimeException();
} else {
return "methodA";
}
}
public String deferMethodA() {
return "deferMethodA";
}
}
Run output
Jan 03, 2018 2:55:55 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.util.concurrent.CompletionException: java.lang.RuntimeException] with root cause
java.lang.RuntimeException
at com.my.own.test.core.TestProcessor.methodA(TestProcessor.java:40)
at com.my.own.test.core.TestProcessor.lambda$0(TestProcessor.java:33)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
P.S.
From the output, methodA is not invoked from hystrix aspect, but by lambda directly. Is this an issue on Hystrix or javanica? Please share if you know a solution. I appreciate it.
Unless you’re using aspectj weaving (which requires special handling of compile steps, I think), spring defaults to using interface/cglib weaving, which only applies to the first method called from outside the class, as described in https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-understanding-aop-proxies.
In summary, if you call methodB, no aspect applies and the call from methodB to methodA is not eligible for aspect interception.
To activate the aspect you have to call methodB directly from outside the TestProcessor class.
By mean of Spring libraries I have to develope a DAL (Data Access Layer) in the form of a jar library which will be imported into the main application.
I want to use Hibernate to access a MySQL DB and DBCP for the management of the connections pool.
I have written the config file DALConfig.java which contains the configuration of the DAL beans:
package my.dal.config;
import java.util.Properties;
import javax.annotation.Resource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
// Needed by Spring to add this class to the ApplicationContext's configuration
#Configuration
#ComponentScan(basePackages = { "my.dal.config" })
// Property file in which are written the MySQL connection properties
#PropertySource("classpath:dbconnection.properties")
public class DALConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_POOL_INITIAL_SIZE = "pool.initialsize";
private static final String PROPERTY_NAME_POOL_MAX_IDLE = "pool.maxidle";
// Needed to access property file
#Resource
private Environment environment;
// The bean which defines the BasicDataSource (DBCP)
#Bean
public BasicDataSource dataSource() throws Exception
{
Properties props = new Properties();
props.put("driverClassName", environment.getProperty(PROPERTY_NAME_DATABASE_DRIVER));
props.put("url", environment.getProperty(PROPERTY_NAME_DATABASE_URL));
props.put("username", environment.getProperty(PROPERTY_NAME_DATABASE_USERNAME));
props.put("password", environment.getProperty(PROPERTY_NAME_DATABASE_PASSWORD));
props.put("initialSize", environment.getProperty(PROPERTY_NAME_POOL_INITIAL_SIZE));
props.put("maxIdle", environment.getProperty(PROPERTY_NAME_POOL_MAX_IDLE));
BasicDataSource bds = BasicDataSourceFactory.createDataSource(props);
return bds;
}
// Bean used to translate Hibernate's exceptions into Spring's ones
#Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor()
{
PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
return b;
}
}
Then I wrote the HibernateConfig.java config file which contains the Hibernate configuration stuff
package my.dal.hibernateconfig;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
#Configuration
#ComponentScan(basePackages = { "my.dal.hibernatesessionfactory" })
#PropertySource("classpath:dbconnection.properties")
public class HibernateConfig {
private static final String PROPERTY_NAME_DAL_CLASSES_PACKAGE = "hibernate.dal.package";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
#Resource
private Environment environment;
#Autowired
DataSource dataSource;
// Bean which defines the FactoryBean for the SessionBean
#Bean
public LocalSessionFactoryBean sessionFactory()
{
LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
lsfb.setPackagesToScan(PROPERTY_NAME_DAL_CLASSES_PACKAGE);
Properties hibernateProperties = new Properties();
hibernateProperties.put("dialect", PROPERTY_NAME_HIBERNATE_DIALECT);
lsfb.setHibernateProperties(hibernateProperties);
lsfb.setDataSource(dataSource);
return lsfb;
}
#Bean
public HibernateTransactionManager transactionManager()
{
// THE EXCEPTION IS THROWN AT THIS LINE
HibernateTransactionManager htm = new HibernateTransactionManager((SessionFactory) sessionFactory());
return htm;
}
}
Next I wrote the UserDAO.java class which is a DAO for the User class which models the DB's User table.
package my.dal.dao;
import my.models.User;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Component
#Repository
#Transactional
public class UserDAO
{
private SessionFactory sessionFactory;
#Autowired
public UserDAO(SessionFactory sessionFactory) {
this.sessionFactory=sessionFactory;
}
public int insert(User user) {
return (Integer) sessionFactory.getCurrentSession().save(user);
}
public User getByUsername(String username) {
return (User) sessionFactory.getCurrentSession().get(User.class, username);
}
public void update(User user) {
sessionFactory.getCurrentSession().merge(user); // .update(user);
}
public void delete(String username) {
User u = getByUsername(username);
sessionFactory.getCurrentSession().delete(u);
}
}
The mapping class User.java (generated using the Eclipse's Hibernate tools) is
package my.models;
public class User implements java.io.Serializable {
private String username;
private String idUserKeystone;
private String firstName;
private String lastName;
private String password;
private String email;
private String emailRef;
private String employer;
private boolean confirmed;
// Getters, setters and full constructor
}
Now I want to test the DAL. The testing class is DALTest.java
package my.dal.tests;
import static org.junit.Assert.assertTrue;
import my.dal.config.DALConfig;
import my.dal.dao.UserDAO;
import my.dal.hibernateconfig.HibernateConfig;
import my.models.User;
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#ContextConfiguration(classes = { DALConfig.class, HibernateConfig.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class DALTest {
#Autowired
UserDAO userDAO;
#Test
public void testGetUser() {
User user = null;
// Let's see if the user "myuser" is into the database
user = userDAO.getByUsername("myuser");
assertTrue(null != user);
}
}
When I run the test it throws the following exceptions
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class my.dal.hibernateconfig.HibernateConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.orm.hibernate4.HibernateTransactionManager my.dal.hibernateconfig.HibernateConfig.transactionManager()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.orm.hibernate4.LocalSessionFactoryBean$$EnhancerBySpringCGLIB$$d866ed45 cannot be cast to org.hibernate.SessionFactory
...
Caused by: java.lang.ClassCastException: org.springframework.orm.hibernate4.LocalSessionFactoryBean$$EnhancerBySpringCGLIB$$d866ed45 cannot be cast to org.hibernate.SessionFactory
at my.dal.hibernateconfig.HibernateConfig.transactionManager(HibernateConfig.java:55)
at my.dal.hibernateconfig.HibernateConfig$$EnhancerBySpringCGLIB$$bd53a036.CGLIB$transactionManager$1(<generated>)
at my.dal.hibernateconfig.HibernateConfig$$EnhancerBySpringCGLIB$$bd53a036$$FastClassBySpringCGLIB$$119f2c5b.invoke(<generated>)
...
It seems like the problem is the cast at the line
HibernateTransactionManager htm = new HibernateTransactionManager((SessionFactory) sessionFactory())
On the contrary, the Internet is full of example writing that line that way.
What could be the problem?
Thank you in advance
A FactoryBean<Foo> is a bean that creates objects of type Foo. It's not, itself, of type Foo (as the javadoc would show you). To get the Foo it creates, you simply call getObject() on the factory bean:
HibernateTransactionManager htm =
new HibernateTransactionManager(sessionFactory().getObject());
Use case: I have my container configured via classpath scanning #ComponentScan. For my test configuration I need the ability to mock specific beans.
Due to the order of loading, beans loaded via classpath scan are not overriding properly when using #Configuration. The following code samples demonstrate the problem. BaseExample.java shows how it is possible to override beans via configuration. ScanExample.java shows that overriding a bean that was loaded via #ComponentScan is skipped (see final note).
A demo project is available on bitbucket.
// BaseExample.java
package com.glassworks.mock;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Joiner;
public class BaseExample {
private static final Logger log = LoggerFactory.getLogger(BaseExample.class);
private static AnnotationConfigApplicationContext ctx;
public static void main(String args[]) {
ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);
String beans[] = ctx.getBeanDefinitionNames();
log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));
for(String bean : beans) {
log.info("{}: {}", bean, ctx.getBean(bean));
}
}
#Configuration
public static class Config {
#Bean
public AccountDao accountDao() {
log.debug("Creating accountDao [Config]");
return new AccountDao();
}
}
#Configuration
public static class OverrideConfig {
#Bean
public Object accountDao() {
log.debug("Creating accountDao [OverrideConfig]");
return Mockito.mock(AccountDao.class);
}
}
}
Output:
21:05 INFO | com.glassworks.mock.BaseExample | accountDao: Mock for AccountDao, hashCode: 666537607
[// ScanExample.java
package com.glassworks.mock;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Joiner;
public class ScanExample {
private static final Logger log = LoggerFactory.getLogger(ScanExample.class);
private static AnnotationConfigApplicationContext ctx;
public static void main(String args[]) {
ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);
String beans[] = ctx.getBeanDefinitionNames();
log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));
for(String bean : beans) {
log.info("{}: {}", bean, ctx.getBean(bean));
}
}
#Configuration
#ComponentScan("com.glassworks.services")
public static class Config {
}
#Configuration
public static class OverrideConfig {
#Bean
public AccountDao accountDao() {
log.debug("Creating accountDao [OverrideConfig]");
return Mockito.mock(AccountDao.class);
}
}
}
Output:
21:08 INFO | com.glassworks.mock.ScanExample | accountDao: com.glassworks.services.AccountDao#48805ebb
// AccountDao.java
package com.glassworks.services;
import org.springframework.stereotype.Repository;
#Repository
public class AccountDao {
}
Note
Its worth noting on that with logging set to debug, Spring indicates that it is skipping over the definition. This appears to be a bug.
21:09 DEBUG | o.s.c.a.ConfigurationClassBeanDefinitionReader | Skipping loading bean definition for [BeanMethod:name=accountDao,declaringClass=com.glassworks.mock.ScanExample$OverrideConfig]: a definition for bean 'accountDao' already exists. This is likely due to an override in XML.