I am new to Spring & Hibernate and I have spent a couple of weeks trying to get to grips with it. Most of my experience is with Oracle development so this is a departure for me. Hibernate is working but Spring is giving me a headache.
I tried following this tutorial but using an Oracle db and my Address table.
http://www.codejava.net/frameworks/spring/spring-4-and-hibernate-4-integration-tutorial-part-1-xml-configuration
The web page wasn't working so I tried a test case on the HomeController.java That didn't work so but I believe I have narrowed it down to a null pointer in addressDao and so I wrote a test case for that to try to pin it down.
java.lang.NullPointerException: null
springexp.unittest.AddressDaoTest.testListAddr(AddressDaoTest.java:29)
package springexp.unittest;
import bussys.model.Address;
import springexp.dao.AddressDao;
import java.util.List;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
public class AddressDaoTest
{
#Autowired
private AddressDao addressDao;
#RequestMapping(value="/")
/**
* #see springexp.dao.AddressDao#listAddr()
*/
#Test
public void testListAddr()
{
List<Address> listAddresses = addressDao.listAddr(); << error thrown here
System.out.println(listAddresses.get(1).getFirstname());
fail("Unimplemented");
}
}
I have also spent a long time reading stackoverflow and others to try to fix the null pointer issue but there seems to be lots of ways of writing this and it has changed in various versions.
In servlet-context.xml I have this:
<!-- Hibernate Session Factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>springexp.dao.AddressDao</value>
</list>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="addressDao" class="springexp.dao.AddressDaoImpl">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
<!-- added this recently based on one suggestion -->
<bean id="addressDaoTest" class="springexp.unittest.AddressDaoTest">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
AddressDaoImpl.java
package springexp.dao;
import bussys.model.Address;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
public class AddressDaoImpl
implements AddressDao
{
private SessionFactory sessionFactory;
public AddressDaoImpl(SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
#Override
#Transactional
public List<Address> listAddr()
{
#SuppressWarnings("unchecked")
List<Address> listAddress = (List<Address>)
sessionFactory.getCurrentSession().createCriteria(Address.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
return listAddress;
}
}
I hope this is enough to give a clue to my mistake(s).
Related
I have been working on various issues to get this Spring-Hibernate app to work. I have probably made a basic error.
This seems to be a recurring question with many answers covering older versions of Hibernate. I am using Spring 4.3.9 and Hibernate 4.0.5
The UT gets a SessionFactory but getCurrentSession() is returning null and in debug I can see that currentSessionContext is null.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="data.xml"/>
</beans>
data.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
>
<!-- Enable autowiring -->
<tx:annotation-driven/>
<!-- context:annotation-config/-->
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="packagesToScan" value="com.my"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.connection.pool-size">1</prop>
<prop key="hibernate.cache.provider_cache">org.hibernate.cache.NoCacheProvider</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>
</beans>
SpringConfig.java
package utils.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
#Configuration
#Import
(
{SpringRepositoryConfig.class
}
)
#ImportResource("classpath:configuration/applicationContext.xml")
public class SpringConfig
{
}
SpringRepositoryConfig.java
package utils.config;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import utils.persistence.ItemRepository;
import utils.persistence.HibernateItemRepositoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
// Declare as a configuration class
#Configuration
public class SpringRepositoryConfig
{
#Autowired
SessionFactory sessionFactory;
// Define repository bean
#Bean
public ItemRepository itemRepository()
{
ItemRepository rep = new HibernateItemRepositoryImpl();
rep.setSessionFactory(sessionFactory);
return rep;
}
}
SpringServicesConfig.java
package utils.config;
import javax.inject.Inject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import bussysutils.persistence.ItemRepository;
import bussysutils.repository.DecoderLoadRepository;
import bussysutils.repository.DecoderLoadRepositoryImpl;
#Configuration
public class SpringServicesConfig
{
#Inject
ItemRepository repository;
#Bean
public DecoderLoadRepository decoderLoadRepository()
{
DecoderLoadRepositoryImpl decoderLoad = new DecoderLoadRepositoryImpl(repository);
return decoderLoad;
}
}
SessionConfig.java
package utils;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class SessionConfig
{
public static SessionFactory buildFactory(String url
,String user
,String password)
{
ServiceRegistry sr;
SessionFactory sfactory;
Configuration config = new Configuration();
config.setProperty("hibernate.connection.url", url);
config.setProperty("hibernate.connection.username", user);
config.setProperty("hibernate.connection.password", password);
StandardServiceRegistryBuilder ssrb
= new StandardServiceRegistryBuilder().applySettings(config.getProperties());
sr = ssrb.build();
try
{
sfactory = config.buildSessionFactory(sr);
}
catch (Throwable ex)
{
throw new ExceptionInInitializerError(ex);
}
return sfactory;
}
}
UT_DecoderLoad.java
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import utils.DecoderLoad;
import utils.SessionConfig;
import utils.config.SpringConfig;
import utils.persistence.HibernateItemRepositoryImpl;
import utils.persistence.ItemRepository;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
#ContextConfiguration(classes = SpringConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class UT_DecoderLoad
{
#Autowired
SessionFactory sessionFactory;
#Test
public void decoderLoadTest()
{
try
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
sessionFactory = SessionConfig.buildFactory("jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=my-host-name.my.com)(PORT=1521))(CONNECT_DATA=(SERVER=dedicated)(SERVICE_NAME=dev)))"
,"myuser"
,"mypassword");
}
catch (SQLException e)
{
System.err.println("uploadServlet ERROR - " + e.getMessage());
System.out.print("uploadServlet logon ERROR - SQLException: " + e.getMessage());
e.printStackTrace();
}
Session s = sessionFactory.getCurrentSession(); /// <<<<<<<<
s.beginTransaction();
DecoderLoad decoderLd = new DecoderLoad();
decoderLd.setSiteRefNo("123456");
System.out.println(decoderLd.getSiteRefNo());
// update the database
ItemRepository itemRepo = new HibernateItemRepositoryImpl();
// itemRepo.create(decoderLd);
s.save(decoderLd);
s.getTransaction().commit();
}
}
You are making things very complicated for yourself, first you are mixing XML and Java based configuration and you have a configuration class for single beans. Either use Java or XML but don't mix them, especially if you aren't sure what those things do.
Your DataSource setup is also flawed as it is a partially setup DataSource.
Next your SessionFactory configuration is basically useless due to the use of the SessionConfig (which basically renders your Spring configuration useless). You shouldn't be using the SessionConfig, so drop it. Your SessionFactory configuration in the XML is also flawed, the hibernate.connection properties don't do anything, due the the injected DataSource and you shouldn't be messing around with the hibernate.current_session_context property unless you are using JTA. Spring will manage it for you.
Your unit test is also flawed, you should be injecting the repository not creating a new instance yourself.
That being said and moving everything to xml your data.xml should look something like this.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context">
<tx:annotation-driven/>
<context:property-placeholder location="jdbc.properties" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.my"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.cache.provider_cache">org.hibernate.cache.NoCacheProvider</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernatTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="itemRepository" class="utils.config.HibernateItemRepositoryImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="decoderLoadRepository" class="utils.config.DecoderLoadRepositoryImpl">
<constructor-arg ref="itemRepository" />
</bean>
</beans>
The jdbc.properties would contain the following
jdbc.url=jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=my-host-name.my.com)(PORT=1521))(CONNECT_DATA=(SERVER=dedicated)(SERVICE_NAME=dev)))
jdbc.username=myuser
jdbc.password=mypassword
You can now drop your SessionConfig, SpringServicesConfig and SpringRepositoryConfig classes as the first you shouldn't have in the first place the config class are obsolete due to adding the context to the xml file.
Now your test is also flawed as it should be #Transactional and should load the XML file instead of the java config.
#ContextConfiguration("classpath:configuration/applicationContext.xml")
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class UT_DecoderLoad {
#Autowired
SessionFactory sessionFactory;
#Test
public void decoderLoadTest() {
Session s = sessionFactory.getCurrentSession(); /// <<<<<<<<
DecoderLoad decoderLd = new DecoderLoad();
decoderLd.setSiteRefNo("123456");
System.out.println(decoderLd.getSiteRefNo());
s.save(decoderLd);
s.flush(); // "simulate a commit"
}
}
Although not sure what you are testing here, you should probably be testing the HibernateItemRepositoryImpl.
#ContextConfiguration("classpath:configuration/applicationContext.xml")
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class UT_DecoderLoad {
#Autowired
SessionFactory sessionFactory;
#Autowired
ItemRepository repository
#Test
public void decoderLoadTest() {
DecoderLoad decoderLd = new DecoderLoad();
decoderLd.setSiteRefNo("123456");
repository.create(decoderLd);
sessionFactory.getCurrentSession().flush(); // "simulate a commit"
// Validate the existence in the database
}
}
This is my current version, it runs but does not update the db table.
data.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
>
<!-- Enable autowiring -->
<tx:annotation-driven/>
<context:property-placeholder location="resources/jdbc.properties"/>
<bean id="DataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="DataSource"/>
<property name="packagesToScan" value="utils"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.cache.provider_cache">org.hibernate.cache.NoCacheProvider</prop>
<prop key="show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="itemRepository" class="utils.persistence.HibernateItemRepositoryImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="decoderLoadRepository" class="utils.repository.DecoderLoadRepositoryImpl">
<constructor-arg ref="itemRepository" />
</bean>
</beans>
UT_DecoderLoad.java
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import utils.DecoderLoad;
import utils.persistence.ItemRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
#ContextConfiguration("classpath:configuration/applicationContext.xml")
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class UT_DecoderLoad
{
#Autowired
SessionFactory sessionFactory;
#Autowired
ItemRepository itemRepo;
#Test
public void decoderLoadTest()
{
DecoderLoad decoderLd = new DecoderLoad();
decoderLd.setSiteRefNo("123456");
decoderLd.setDecoderNo("999");
System.out.println(decoderLd.getSiteRefNo());
itemRepo.create(decoderLd);
sessionFactory.getCurrentSession().flush();
}
}
I added a primary key column into the db table so that I could add the required #Id
DecoderLoad.java
package utils;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#Entity
#Table(name = "Decoder_Load")
public class DecoderLoad
{
public DecoderLoad()
{
}
// pojo with annotations
#Id
#Column(name = "decoder_no")
private String decoderNo;
...
I also added javassist to the pom.
Maven compile complains:
package org.springframework.test.context does not exist
package org.springframework.test.context.junit4 does not exist
This simple test runs but it is not inserting a record without forcing it and causing other issues.
EDIT: just learned that a test does a rollback so it will not commit.
I get a NoSuchBeanDefinitionException when trying to run my program (: No bean named 'org.springframework.orm.hibernate4.LocalSessionFactoryBean' is defined) Yet the bean has been defined in the Beans2.xml file. The classes are listed below. Thanks.
PieceHibernateDAO.java
package sample.spring.chapter01;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.hibernate.SessionFactory;
import org.springframework.core.io.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.TransactionStatus;
//import org.springframework.transaction.TransactionCallback;
//import org.springframework.transaction.TransactionTemplate;
#Repository(value="PieceHibernateDAO")
public class PieceHibernateDAO {
#Autowired
private SessionFactory sessionFactory;
public int createPieceHibernate(final Piece piece) {
sessionFactory.getCurrentSession().save(piece);
return piece.getpieceid();
}
//public Piece getPiece
public void fill(Resource resource) throws FileNotFoundException, IOException{
InputStream is=resource.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
CSVParser parser = CSVFormat.DEFAULT.withHeader().parse(br);
for (CSVRecord record:parser) {
String ref=record.get("référence ascensoriste").trim();
String asc=record.get("ascensoriste").trim();
//String desc=record.get("Description article").trim();
String prix=record.get("Pv");
String category=record.get("Familie").trim();
//System.out.println(category);
Piece lift_comp=new Piece();
lift_comp.setasc(asc);
//lift_comp.setdesc(desc);
lift_comp.setref(ref);
lift_comp.setprice(prix);
lift_comp.settype(category);
lift_comp.setinfo();
//listp.add(lift_comp);
int cpid=lift_comp.getcompanyid(asc);
lift_comp.setcompanyid(cpid);
//sessionFactory.getCurrentSession().save(lift_comp);
createPieceHibernate(lift_comp);
}
}
}
Beans2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="sample.spring" />
</bean>
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/liftcomp_db" />
<property name="username" value="root" />
<property name="password" value="8K887h))00" />
</bean>
<bean id="PieceHibernateDAO"
class="sample.spring.chapter01.PieceHibernateDAO">
<property name="sessionFactory" ref="org.springframework.orm.hibernate4.LocalSessionFactoryBean"/>
</bean>
<bean id="PieceDAO" class="sample.spring.chapter01.PieceDAO">
<property name="listp" ref="Piece"></property>
</bean>
<bean id = "Company" class = "sample.spring.chapter01.Company"/>
<bean id = "Family" class = "sample.spring.chapter01.Family"/>
<bean id = "Piece" class = "sample.spring.chapter01.Piece"/>
</beans>
You create a bean with id sessionFeactory. this must be the value in the ref Attribute:
<property name="sessionFactory" ref="sessionFactory"/>
because this is the id of the bean.
I am new to the world of spring jms , prior to this i have used the core java program without spring where we have manually create the connection factories but rite now i am learning spring jms , rite now i have configured the xml but plesae advise how can i design corresponding java classes by which i can send the text message to the queue
<bean id="tibcoEMSJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">com.tibco.tibjms.naming.TibjmsInitialContextFactory</prop>
<prop key="java.naming.provider.url">tcp://abcnet:707</prop>
<prop key="java.naming.security.principal">abc</prop>
<prop key="java.naming.security.credentials">abc</prop>
</props>
</property>
</bean>
<bean id="tibcoEMSConnFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="tibcoEMSJndiTemplate" />
</property>
<property name="jndiName">
<value>GenericConnectionFactory</value>
</property>
</bean>
<bean id="tibcosendJMSTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref local="tibcoEMSConnFactory" />
</property>
<property name="defaultDestinationName">
<value>test.data</value>
</property>
<property name="pubSubDomain">
<value>false</value>
</property>
<property name ="receiveTimeout">
<value>120000</value>
</property>
</bean>
folks as advise i have designthe java class below but my question is that there should be another class which consists of main methid and which load my xml , i have design the below java class but still i know it is not correct if you do not mind pls can you please show how to design the java classes so that i can grasp and in which the depenmdencies are injected by my above xml pls..
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.Session;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jndi.JndiTemplate;
public class JmsQueueSender {
private JmsTemplate jmsTemplate;
private Queue queue;
public void setConnectionFactory(ConnectionFactory cf) {
this.jmsTemplate = new JmsTemplate(cf);
}
public void setQueue(Queue queue) {
this.queue = queue;
}
public void simpleSend() {
this.jmsTemplate.send(this.queue, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("hello queue world");
}
});
}
}
Read the documentation.
The simplest use of your JmsTemplate would be...
tibcoJmsTemplate.convertAndSend("foo");
...which will convert foo to a TextMessage and send it to your default destination (test.data).
The JmsTemplate has these high level methods as well as providing more advanced features if you need access to the session, or to post process the message after conversion.
I have spent three days trying to find the solution to this problem to no avail. I am desperate to figure this out. I have a simple spring app, running in servlet 2.5 with jstl tags 1.2, running in tomcat with spring 3.1, using hibernate and the hibernate jpa implementation.
I can list data from a page, but I cannot complete an insert. The record goes back, it appears to fire through with no problems. Yet no insert takes place. I know there are other posts similar but I have looked through them all and have not been able to find a solution anywhere.
If I run the exact same code via a MAIN class, the insert works fine. It just does not work when running as a web-app in tomcat.
I have tried running this via the main which works, inside the controller I have skipped calling the service layer, trying to go directly to the interface, when that didnt work, I tried going directly to the implementing DAO class, and that didnt work. It appears via the spring logs, that the entity manager is getting created, and shut down before a transaction takes place.
Please help me.
Here is my App-context
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName">
<context:component-scan base-package="com.naturalbornliar.site"/>
<tx:annotation-driven />
<!-- Bean declarations go here-->
<bean id="duke" class="com.naturalbornliar.site.entity.Admin">
<constructor-arg name="admin_id" type="Long" value="15" />
<constructor-arg name="admin_login" type="String" value="testUser" />
<constructor-arg name="admin_pwd" type="String" value="testPwd" />
<constructor-arg name="email_id" type="int" value="15" />
<constructor-arg name="quote" type="String" value="Something to say here" />
</bean>
<!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> -->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"/> -->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/nbl_db"/> -->
<!-- <property name="username" value="web_user"/> -->
<!-- <property name="password" value="web_pwd"/> -->
<!-- <property name="initialSize" value="5"/> -->
<!-- <property name="maxActive" value="10"/> -->
<!-- </bean> -->
<bean id="simpledataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/nbl_db"/>
<property name="username" value="web_user"/>
<property name="password" value="web_pwd"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="simpledataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="nblPersistenceUnit"/>
<property name="dataSource" ref="simpledataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
</bean>
<!-- <bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> -->
<!-- <property name="persistenceUnitName" value="nblPersistenceUnit"/> -->
<!-- <property name="dataSource" ref="simpledataSource"/>-->
<!-- <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> -->
<!-- </bean> -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL"/>
<property name="showSql" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* *..CategoryDaoImpl.*(..))" advice-ref="txAdvice"/>
</aop:config>
</beans>
Here is my controller:
package com.naturalbornliar.site.mvc;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.naturalbornliar.site.entity.Category;
import com.naturalbornliar.site.entity.Link;
import com.naturalbornliar.site.service.CategoryService;
#Controller
#RequestMapping("/categories")
public class CategoryController {
protected final Logger logger = Logger.getLogger(CategoryController.class);
private final CategoryService categoryService;
#Inject
public CategoryController(CategoryService categoryService){
this.categoryService = categoryService;
}
#RequestMapping(value="/listCategories")
public String listLinks(Model model){
model.addAttribute("categories", categoryService.getAllCategories());
return "categories";
}
#RequestMapping(method=RequestMethod.GET, params="new")
public String showCreateCategoryForm(Model model){
model.addAttribute(new Category());
return "addcategory";
}
#RequestMapping(method=RequestMethod.POST)
public String addCategoryFromForm(Category category, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return"addcategory";
}
categoryService.addCategory(category);
return "redirect:/categories/listCategories";
}
}
Here is my service called from the controller:
package com.naturalbornliar.site.service;
import java.util.Collection;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import com.naturalbornliar.site.entity.Category;
import com.naturalbornliar.site.i.ICategoryDao;
#Service
public class CategoryService {
private ICategoryDao iCategoryDao;
#Inject
public CategoryService(ICategoryDao iCategoryDao){
this.iCategoryDao = iCategoryDao;
}
public Collection<Category> getAllCategories(){
return iCategoryDao.getAllCategories();
}
public Collection<Category> getCategoriesByType(String type) {
return iCategoryDao.getCategoriesByType(type);
}
public Category getCategoryById(Long id) {
throw new UnsupportedOperationException();
}
public void deleteCategory(Category category) {
throw new UnsupportedOperationException();
}
public void updateCategory(Category category) {
throw new UnsupportedOperationException();
}
public void inactivateCategory(Category category){
throw new UnsupportedOperationException();
}
public void addCategory(Category category){
iCategoryDao.addCategory(category);
}
}
Here is my implementing DAO:
package com.naturalbornliar.site.dao;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.naturalbornliar.site.entity.Content;
import com.naturalbornliar.site.i.IContentDao;
#Transactional
#Repository
public class ContentDaoImpl implements IContentDao {
protected final Logger logger = Logger.getLogger(ContentDaoImpl.class);
#PersistenceContext
private EntityManager em;
public EntityManager getEm() {
return em;
}
public void setEm(EntityManager em) {
this.em = em;
}
#Override
public void addContent(Content content) {
// TODO Auto-generated method stub
em.persist(content);
}
#Override
public void deleteContent(Content content) {
// TODO Auto-generated method stub
em.remove(content);
}
#Override
public void inactivateContent(Content content) {
// TODO Auto-generated method stub
}
#Override
public Content getContentById(Long id) {
// TODO Auto-generated method stub
return null;
}
#Override
public Content getContentByName(String name) {
// TODO Auto-generated method stub
return null;
}
#Override
public Collection<Content> getAllObjects() {
List<Content> resultList = em.createQuery("FROM Content", Content.class).getResultList();
return resultList;
}
}
Here is the interface (just in case)
package com.naturalbornliar.site.i;
import java.util.Collection;
import com.naturalbornliar.site.entity.Content;
public interface IContentDao {
public void addContent(Content content);
public void deleteContent(Content content);
public void inactivateContent(Content content);
public Content getContentById(Long id);
public Content getContentByName(String name);
public Collection<Content> getAllObjects();
}
Jeremy, thay may be many problems with that and I had similar problem.
In my case I used tomcat and I needed to add spring weaver to tomcat (this problem is described here: http://asrijaffar.blogspot.com/2007/02/spring-jpa-tomcat.html).
In my case I needed to have:
<tx:annotation-driven proxy-target-class="true" />
In DispatcherServlet config.
Additionally in db-context config:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="jpatest" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Well I actually solved the problem. Here is the solution, there was another stackoverflow issue that solved it:
Spring #Transaction not starting transactions
Basically all that was needed for transactions to fire correctly was for me to add:
<tx:annotation-driven proxy-target-class="true"/>
to my servlet xml. I guess if you just have it in the application config.xml it only works when running under the main class (like in a standalone) if you need to run it in a container you have to declare transaction annotations in the servlet as well.
I also spent several hours trying to figure out where the problem is although my previous application with the same stack is working fine and I wasn't able to understand the difference.
And.... the error was in tag in spring-servlet.xml - it was defined to scan the root package with all the web controller, repository classes, etc.
After changing it to make scanning of the package with web controllers only, the problem was gone..
Just for you (and for me) in case you might meet the same problem, just an additional hint
I also had this same problem, spent couple nights searching - alex solutions saved me - in servlet xml I changed context:component-scan to scan only package with web controller.
Example from this page should look like
<context:component-scan base-package="com.naturalbornliar.site.mvc"/>
I'm brand spanking new at Spring and have gotten a majority of the knowledge I do have from the Spring Recipes book from Apress.
I've got LDAP authentication working with Spring Security within one webapp. I would like to rip out my application context beans and properties files from this one webapp, however, and somehow externalize them so that all of our webapps can reference the same beans. So when we need to change something (like the ldapuser or the ldap urls), we change it in one place and the rest of the apps just know.
UPDATE
I've implemented Reloadable Spring Properties which is reloading properties when the files they come from are touched. I am using encrypted properties, however, so below is class I created on top of the Reloadable Spring Properties ones.
ReloadingEncryptablePropertyPlaceholderConfigurer.java
package;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.util.text.TextEncryptor;
import org.jasypt.properties.PropertyValueEncryptionUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
public class ReloadingEncryptablePropertyPlaceholderConfigurer extends ReloadingPropertyPlaceholderConfigurer {
protected final Log logger = LogFactory.getLog(getClass());
private final StringEncryptor stringEncryptor;
private final TextEncryptor textEncryptor;
public ReloadingEncryptablePropertyPlaceholderConfigurer(TextEncryptor textEncryptor) {
super();
logger.info("Creating configurer with TextEncryptor");
Validate.notNull(textEncryptor, "Encryptor cannot be null");
this.stringEncryptor = null;
this.textEncryptor = textEncryptor;
}
public ReloadingEncryptablePropertyPlaceholderConfigurer(StringEncryptor stringEncryptor) {
super();
logger.info("Creating configurer with StringEncryptor");
Validate.notNull(stringEncryptor, "Encryptor cannot be null");
this.stringEncryptor = stringEncryptor;
this.textEncryptor = null;
}
#Override
protected String convertPropertyValue(String originalValue) {
if (!PropertyValueEncryptionUtils.isEncryptedValue(originalValue)) {
return originalValue;
}
if (this.stringEncryptor != null) {
return PropertyValueEncryptionUtils.decrypt(originalValue, this.stringEncryptor);
}
return PropertyValueEncryptionUtils.decrypt(originalValue, this.textEncryptor);
}
#Override
protected String parseStringValue(String strVal, Properties props, Set visitedPlaceholders) throws BeanDefinitionStoreException {
return convertPropertyValue(super.parseStringValue(strVal, props, visitedPlaceholders));
}
}
And here's how I use it in my securityContext.xml:
<bean id="securityContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldaps://ldapserver" />
<property name="urls" value="#{ldap.urls}" />
</bean>
<bean id="timer" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<bean id="reloadProperties" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="period" value="1000"/>
<property name="runnable">
<bean class="ReloadConfiguration">
<property name="reconfigurableBeans">
<list>
<ref bean="configproperties"/>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
<bean id="configproperties" class="ReloadablePropertiesFactoryBean">
<property name="location" value="classpath:ldap.properties"/>
</bean>
<bean id="ldapPropertyConfigurer" class="ReloadingEncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="properties" ref="configproperties"/>
</bean>
<bean id="jasyptConfig" class="org.jasypt.encryption.pbe.config.SimpleStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndTripleDES" />
<property name="password" value="########" />
</bean>
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="jasyptConfig" />
</bean>
How about:
Writing a method that returns a list
of LDAP servers - reading from a
database table or property files
expose this wethod via jndi and use it to inject a list of the servers into your spring config
If you need the ldap servers to be refreshed dynamically you could have a job poll for changes periodically or else have an admin webpage or jmx bean to trigger the update. Be careful of concurrency isses for both these methods (something reading the list while you are updating)
Wouldn't that be Spring Security? It can deal with LDAPs. And if you make it one security service that everyone uses, wouldn't that be the way to manage it?