I am using Spring 4.1.1.
I have the following in my spring-dispatcher-servlet.xml
<context:component-scan base-package="com.au.controller,com.au.util" />
<mvc:resources location="/" mapping="/**" />
<mvc:annotation-driven />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/caballocation" />
<property name="username" value="root" />
<property name="password" value="1234" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="AddImplDao" class="com.au.dao.AddressDaoImpl" />
I have the following controller class in package com.au.controller
#Controller
public class ControllerMain {
#Autowired
AddressDao obj;
#RequestMapping(value = "/test")
public #ResponseBody String test(){
//logger.debug("getWelcome is executed!");
obj.select();
return "1";
}
}
In the above code obj.select works as it gets autowired.
But the following class which is in com.au.util package have the value null of the object which is autowired.
public class DistanceCalculator {
#Autowired
AddressDao obj1;
public String calculate(String from, String to) throws IOException, JSONException {
..
Map output = obj1.calc(from, to);
..
}
Obj1 is null while execution. Getting java.lang.NullPointerException at obj1.calc(from,to)
Following is the interface and its implementation.
AddressDao.java
public interface AddressDao {
public void select();
public Map calc(String from,String to);
}
AddressDaoImpl.java
public class AddressDaoImpl implements AddressDao {
#Autowired
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall simpleJdbcCall;
#Autowired
public void setDataSource(DataSource dataSource) {
this.simpleJdbcCall = new SimpleJdbcCall(dataSource).withProcedureName("CheckForValuesInDB");
}
#Override
public void select() {
// TODO Auto-generated method stub
}
#Override
public Map calc(String from, String to) {
// TODO Auto-generated method stub}
What is the reason behind this?
you have to add extra space in com.au.controller,com.au.util so it should look like 'com.au.controller, com.au.util'. As for now only com.au.controller is scanned by your configuration.
//Edit
There should be #Component annotation in DistanceCalculator class
Related
Basically, i have a Sampleapiclass class in which some files are retrieved into a list and the list is looped and for each file performAction is called. if a file fails validation, i want the transaction to roll back. The problem is, i tried annotating with rollback, but even if one file validation fails, transaction is not rolled bak.eg. file 1, succeeds, gets inserted, file 2 fails, but the file 1 is in the database. Any idea what might be wrong ?
As an additonal note, Sampleapiclass is initialied from the main method , may be it has somethin to do that that ?
f.eks: from main class
class MainClass
{
public static void main(String[] args)
{
ApplContext ctx = new ClassPathxmlApplicationContext("application-context.xml");
MainClass app = ctx.getBean(MainClass.class);
app.run(args);
}
void run()
{
Sampleapiclass api = new Sampleapiclass();
DaoClass dao = new Sampleapiclass();
api.apimethod(dao)
}
}
class Sampleapiclass
{
void apimethod(Dao daoclass)
{
serviceClass serviceClass = new ServiceCLass(daoclass);
List<String> files = filesFromSomewhere
for (String file: filesFromSomewhere)
{
try
{
serviceClass.performAction(file);
}
catch(Exception e)
{
}
}
}
}
class serviceClass
{
private final Dao daoclass;
public serviceClass(DaoClass daoclass)
{
this.daoclass = daoclass;
}
#Transactional(rollbackFor=Exception.class)
void performAction(String file) throws CustomException
{
dovalidation(file); // this method can throw CustomExeption if validation fails
daoclass.insert(file)
}
dovalidation(String file) throws CustomExeption
{
if (file.endsWith("somethng") throw new CustomExeption();
}
}
class dao
{
void insert(String file)
{
getNamedParameterJdbcTemplate().update(parameters);
}
}
Contents of app contetxt:
<bean class="Configbean class />
<bean id="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="${main.db.uri}"/>
<property name="username" value="${main.db.username}"/>
<property name="password" value="${main.db.password}"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
The problem is that #Transactional works with AOP. AOP doesn't work on inclass method calls (due to Proxying). Try throwing an exception inside of your #Transactional for it to work or call a method outside of your class also marked with #Transaction(propagation = Propagation.SUPPORTS)
also don't forget #EnableTransactionManagement over your #Configuration class
helpful resource https://javamondays.com/spring-transactions-explained/
I was trying to do generic way of implementation of DAO and I followed as per the Article
Following are my genericDaoImpl class
#SuppressWarnings("unchecked")
#Repository
public abstract class GenericDaoImpl<E, K extends Serializable>
implements GenericDao<E, K> {
#Autowired
private SessionFactory sessionFactory;
protected Class<? extends E> daoType;
/**
* By defining this class as abstract, we prevent Spring from creating
* instance of this class If not defined as abstract,
* getClass().getGenericSuperClass() would return Object. There would be
* exception because Object class does not hava constructor with parameters.
*/
public GenericDaoImpl() {
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
daoType = (Class) pt.getActualTypeArguments()[0];
}
protected Session currentSession() {
return sessionFactory.getCurrentSession();
}
#Override
public void add(E entity) {
currentSession().save(entity);
}
#Override
public void saveOrUpdate(E entity) {
currentSession().saveOrUpdate(entity);
}
#Override
public void update(E entity) {
currentSession().saveOrUpdate(entity);
}
#Override
public void remove(E entity) {
currentSession().delete(entity);
}
#Override
public E find(K key) {
return (E) currentSession().get(daoType, key);
}
#Override
public List<E> getAll() {
return currentSession().createCriteria(daoType).list();
}
}
GENERICDAO
public interface GenericDao<E,K> {
public void add(E entity) ;
public void saveOrUpdate(E entity) ;
public void update(E entity) ;
public void remove(E entity);
public E find(K key);
public List<E> getAll() ;
}
SERVICE CLASS
#Service
public class test {
#Autowired
TestPlanDao testPlanDao;
#Transactional(propagation = Propagation.REQUIRED)
public int saveTestPlan()
{
try
{
TestPlan tp=new TestPlan();
tp.setTestplan_version(1);
testPlanDao.saveTestPlan(tp);
logger.info("testplan saved");
return 1;
}
catch(Exception e)
{
e.printStackTrace();
logger.error(e.getMessage(),e);
return 0;
}
}
This is my daoImpl
#Repository
public class TestPlanDaoImpl extends GenericDaoImpl<TestPlan, Integer> implements TestPlanDao{
#Override
#Transactional
public void saveTestPlan(TestPlan tp) {
// TODO Auto-generated method stub
add(tp);
}
hibernate configuration xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://${mysqlHost}/${mysqldatabase}" />
<property name="username" value="${mysqlUserName}" />
<property name="password" value="${mysqlPassword}" />
<property name="removeAbandoned" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<property name="maxIdle" value="-1" />
<property name ="testOnBorrow" value="true"/>
<property name ="validationQuery" value="SELECT 1"/>
</bean>
<bean id="sessionFactoryConf"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.test.model.TestPlan</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.transaction.auto_close_session">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
I am not able to find the cause of
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:988)
Did you try removing the following property :
<prop key="hibernate.transaction.auto_close_session">true</prop>
I believe that Hibernate will close the session too soon and resulting in your error. Since you use Spring TransactionManager, let it close the session.
you need to add following code in your hibernate configuration xml file
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<!-- property should be wired with a Hibernate SessionFactory in your case it is sessionFactoryConf -->
<property name="sessionFactory" ref="sessionFactoryConf" />
</bean>
You have to remove the #Transactional annotation from the Repository method , use only the #Transactional annotation on the service layer method.
#Repository
public class TestPlanDaoImpl extends GenericDaoImpl<TestPlan, Integer> implements TestPlanDao{
#Override
#Transactional //Remove annotation from here
public void saveTestPlan(TestPlan tp) {
// TODO Auto-generated method stub
add(tp);
}
Remove #Transactional annotation from function and use it on the class level.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryConf" />
</bean>
This happens when you try to save changes on a Business Object after a transaction has already finished.
I think you should take a look to Spring Data JPA ? It has a lot more to offer than a generic DAO.
I'm trying to move from a xml based config to java annotations
I need your help getting this to work:
Obviously I can't set the RemoteJco interface to my SapConnector but what can I do to get this xml-config working?
#Bean
public RmiProxyFactoryBean jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
return jcoPool;
}
#Bean
public SapConnector SapConnector(){
SapConnector sapConnector = new SapConnector();
sapConnector.setJcoPool(jcoPool());
return sapConnector;
}
this in the XML-Config works just fine:
<!-- JCO-Pool RMI Service -->
<bean id="jcoPool" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost/CH"/>
<property name="serviceInterface" value="com.itensis.jco.common.RemoteJco"/>
<property name="refreshStubOnConnectFailure" value="true" />
</bean>
<bean id="SapConnector" class="com.itensis.core.SapConnector">
<property name="jcoPool">
<ref bean="jcoPool" />
</property>
</bean>
this is my SAP-Connector
#Service
public class SapConnector {
#Autowired private RemoteJco jcoPool;
public RemoteJco getJcoPool() {
return jcoPool;
}
public void setJcoPool(RemoteJco jcoPool) {
this.jcoPool = jcoPool;
}
}
You have to make some changes on the jcoPool bean:
#Bean
public RemoteJco jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
jcoPool.afterPropertiesSet();
return (RemoteJco) jcoPool.getObject();
}
Make sure that you return value has the same class as you used as service interface. And you have to call afterPropertiesSet() before calling getObject on the RmiProxyFacotoryBean instance.
applicationContext
<bean id="contentRegisteringBean" parent="abstractRegisteringBean" lazy-init="false">
<property name="processor">
<bean class="com.somepackage.ContentService$Processor"/>
</property>
</bean>
<bean id="abstractRegisteringBean" class="test.spring.MockFactoryBean">
<property name="type" value="com.somepackage.ProcessorRegisteringBeanImpl"/>
</bean>
ProcessorRegisteringBeanImpl
public class ProcessorRegisteringBeanImpl {
private Processor mProcessor;
public Processor getProcessor() {
return mProcessor;
}
public void setProcessor(final Processor processor) {
mProcessor = processor;
}
}
MockFactoryBean.java
public class MockFactoryBean<T> implements FactoryBean<T> {
private Class<T> type;
public void setType(Class<T> type) {
this.type = type;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(type);
}
#Override
public Class<T> getObjectType() {
return type;
}
#Override
public boolean isSingleton() {
return true;
}
}
Exception:
org.springframework.beans.NotWritablePropertyException: Invalid
property 'processor' of bean class
[test.spring.MockFactoryBean]: Bean property 'processor' is
not writable or has an invalid setter method. Does the parameter type
of the setter match the return type of the getter?
When you declare a FactoryBean, Spring expects that you configure properties of the FactoryBean rather than properties of the object it creates.
Try the following instead:
<bean id="contentRegisteringBean" parent="abstractRegisteringBean" lazy-init="false">
<!-- Define concrete class to pass to Mockito.mock() -->
<constructor-arg value = "com.somepackage.ProcessorRegisteringBeanImpl" />
<property name="processor">
<bean class="com.somepackage.ContentService$Processor"/>
</property>
</bean>
<!-- Abstract definition of beans created using Mockito.mock() -->
<bean id="abstractRegisteringBean" abstract = "true"
class="org.mockito.Mockito" factory-method = "mock">
</bean>
So, I read that the best place to put the #Transactional annotation was outside the DAO classes which contains the db access methods, like in a service class which use those methods.
Now, the problem is, once I've already remove this annotations from the DAO classes, I launch the DAO test methods and the aforementioned exception raised. I put back the annotations in the DAO classes and this exception doesn't raises anymore.
Then my question is: how can I clear my DAOs of this annotations and still have my tests working?
Let's add some code:
DAO class
public class UserDAO extends IDAO implements IUserDAO {
#Override
//#Transactional(readOnly=true)
public User get(int idUser) {
return (User) currentSession().get(User.class,idUser);
}}
IDAO Class
public abstract class IDAO {
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Session currentSession()
{
return sessionFactory.getCurrentSession();
}
}
Test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
public class UserDAOTest extends AbstractJUnit4SpringContextTests {
#Autowired
private IUserDAO userDAO;
#Test
public void testGetUser() throws Exception {
User user = userDAO.get(2);
assertNotNull(user);
}
}
app-config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/waldb" />
<property name="username" value="user" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.wal.serverside.persistence.domain.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDAO" class="com.wal.serverside.persistence.DAO.UserDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="com.wal.serverside.persistence" />
</beans>
Gosh, how much stupid can I be?
My test class didn't extend from AbstractTransactionalJUnit4SpringContextTests, so there were nor transaction nor session inside my tests.
This fixed it all:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#Transactional
public class UserDAOTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private IUserDAO userDAO;
public void setUserDAO(IUserDAO userDAO) {
this.userDAO = userDAO;
}
#Test
public void testGetUser() throws Exception {
User user = userDAO.get(2);
assertNotNull(user);
}
}
Try to put not only #Transactional annotaition on your test class but also #TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false). Where you explicitly set the name of the transaction manager that you have defined in xml.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/app-context.xml" })
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#Transactional(propagation=Propagation.REQUIRED, rollbackFor={Exception.class})
public class UserDAOTest {
...
}
Also transaction will not work if you explicitly create the application context in your test method and then get the bean from it:
ApplicationContext appContext = new ClassPathXmlApplicationContext(...);
SomeDAO someDAO = (SomeDAO) appContext.getBean(...);
instad of inhjecting it.
But I see this is not your case.