I have a very strange problem and looking for the solution here. I spent significant amount of time by reading articles and other questions on SO however no luck.
I am using #Transactional annotation in my sample application of Spring 3 and hibernate 3 as shown below. In the last line of method I am explicitly throwing NullPointerException as shown below.
package com.mkyong.common;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mkyong.stock.bo.StockBo;
import com.mkyong.stock.model.Stock;
#Service("stockService")
public class StockServiceImpl {
final static Logger logger = Logger.getLogger(StockServiceImpl.class);
#Transactional(rollbackFor ={ NullPointerException.class} )
public void createNewStock(StockBo stockBo) {
/** insert **/
Stock stock = new Stock();
String code = "xee";
stock.setStockCode(code);
stock.setStockName(code);
stockBo.save(stock);
logger.debug("#################### After Save ##########################");
throw new NullPointerException();
}
}
However this transaction is not rolling back and always commiting to database even though NullPointerException is thrown.
Below is my application context file
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- Database Configuration -->
<import resource="../database/DataSource.xml" />
<import resource="../database/Hibernate.xml" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Auto scan the components -->
<context:component-scan base-package="com.mkyong.stock" />
<bean
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
Judging from your configuration you are using Hibernate, however you are using the transaction manager that is solely for plain JDBC usage.
To have proper transaction management you must use the PlatformTransactionManager which belongs to your persistence technology. In your case you should use the HibernateTransactionManager instead of the DataSourceTransactionManager.
<bean id="transactionManager" class="org.springframework.hibernate5.HibernateTransactionManager>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Note: This is for Hibernate5 (see the package name) use the one that fits your version of hibernate.
Make sure that the class that contains the method is in the application context not in the web application context (simple: the parent class of the method should be a service, repository etc. not a controller).
Also check that you import the #Transactional annotation from the right spring package.
Using only #Transactional annotation is enough. You dont require rollbackFor attribute to rollback on NullPointerException. Transactions with #Transactional annotation are defaulted to RuntimeException.
You should add rollbackFor only if you want to rollback on Checked Exceptions.
Related
There are several posts on this question but still not getting the solution.
This the parent class Userr.
In a #OneToMany relationship I want to remove a particular child Account.
Now When I do this by "DELETE" query I am getting following exception.
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
#RooJavaBean
#RooToString
#RooJpaEntity
#RooJpaActiveRecord(finders = { "findUserrsByUserName"})
public class Userr {
#NotNull
#Column(unique = true)
private String userName;
#NotNull
private int userType;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Account> accounts = new ArrayList<Account>();
}
Child class
#RooJavaBean
#RooToString
#RooJpaActiveRecord
#RooJpaEntity
public class Account {
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
List<Message> messages = new ArrayList<Message>();
/*#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
List<PremiumPlayPositionCombination> premiumPlayPosition = new ArrayList<PremiumPlayPositionCombination>();*/
#OneToMany(mappedBy="account", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
List<PositionCombinationArc> allPositionsArc = new ArrayList<PositionCombinationArc>();
#ManyToOne
#JoinColumn(name="user_id")
private Userr user;
}
Here is my delete query
#Transactional
public static void deleteClientByClientId(Long clientId) {
System.out.println("Delete query findUsersClientsByUser" + clientId);
int deleteCount= entityManager().createQuery("DELETE FROM Account where id =:clientId").setParameter("clientId", clientId).executeUpdate();
System.out.println("Delete query findUsersClientsByUser" + deleteCount);
}
I have added in ApplicationContext-security.xml like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 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/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!--
This will automatically locate any and all property files you have
within your classpath, provided they fall under the META-INF/spring
directory. The located property files are parsed and their values can
then be used within application context files in the form of
${propertyKey}.
-->
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
<!--
Turn on AspectJ #Configurable support. As a result, any time you
instantiate an object, Spring will attempt to perform dependency
injection on that object. This occurs for instantiation via the "new"
keyword, as well as via reflection. This is possible because AspectJ
is used to "weave" Roo-based applications at compile time. In effect
this feature allows dependency injection of any object at all in your
system, which is a very useful feature (without #Configurable you'd
only be able to dependency inject objects acquired from Spring or
subsequently presented to a specific Spring dependency injection
method). Roo applications use this useful feature in a number of
areas, such as #PersistenceContext injection into entities.
-->
<context:spring-configured/>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com"/>
<property name="port" value="587"/>
<property name="username" value="noreply#uforic.in"/>
<property name="password" value="noreply#123"/>
<property name="javaMailProperties">
<props>
<prop key="mail.transport.protocol">smtp</prop>
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.debug">true</prop>
</props>
</property>
</bean>
<!--
This declaration will cause Spring to locate every #Component,
#Repository and #Service in your application. In practical terms this
allows you to write a POJO and then simply annotate the new POJO as an
#Service and Spring will automatically detect, instantiate and
dependency inject your service at startup time. Importantly, you can
then also have your new service injected into any other class that
requires it simply by declaring a field for your service inside the
relying class and Spring will inject it. Note that two exclude filters
are declared. The first ensures that Spring doesn't spend time
introspecting Roo-specific ITD aspects. The second ensures Roo doesn't
instantiate your #Controller classes, as these should be instantiated
by a web tier application context. Refer to web.xml for more details
about the web tier application context setup services.
Furthermore, this turns on #Autowired, #PostConstruct etc support. These
annotations allow you to use common Spring and Java Enterprise Edition
annotations in your classes without needing to do any special configuration.
The most commonly used annotation is #Autowired, which instructs Spring to
dependency inject an object into your class.
-->
<context:component-scan base-package="com.uforic.optionstrader">
<context:exclude-filter expression=".*_Roo_.*" type="regex"/>
<!--context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/-->
</context:component-scan>
You can check following things in your code:
If you are using spring based transaction then make sure you import org.springframework.transaction.annotation.Transactional class for #Transactional annotation
In your case it might be javax.transaction.Transactional
I see deleteClientByClientId method in your code as static. #Transactional in spring does not have support for static methods. Make your method non static which is annotated as transactional.
You can refer #Transactional with static method
Let me know, which option works for you.
In Spring context file you need to add below code:
<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:p="http://www.springframework.org/schema/p"
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.xsd">
<tx:annotation-driven />
Also, add your spring security bean configuration.
When trying to update/delete using Hibernate, it is mendatory to surround the query by a transaction Begin() and Commit() example :
EntityTransaction tr=em.getTransaction();
tr.begin();
Query query = (Query) em.createQuery( "update etudiant set email= :em, adresse= :adr,telephone= :tele,password= :pwd"
+ " where email= :mail");
query.setParameter("em", email)
.setParameter("adr", adresse)
.setParameter("tele", tele)
.setParameter("pwd", pass)
.setParameter("mail", ancienEmail);
int a= query.executeUpdate();
tr.commit();
I am implementing the hazelcast map store for persistence. But could not autowired spring beans(DataSource below) into the hazelcast mapstore object (meaning hazelcast not getting the map store object from spring beans). I read that hazelcast supports spring DI. What am i missing ? Below is my partial map store code
If I get the bean from context using get bean like below
MySQLStore store = (MySQLStore)context.getBean(MySQLStore.class);
I get mysql store with the datasource dependency injected. So this should be an issue with Hazelcast not getting beans from spring. Am I missing any configuration in hazelcast map store.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Component;
import com.hazelcast.core.MapStore;
#Component
public class MySQLStore implements MapStore<String, ScripDetails> {
#Autowired
private DataSource dataSource;
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public ScripDetails load(String arg0) {
System.out.println("loading data from store");
String sql = "SELECT * FROM DATA";
Connection conn = null;
Below is the spring-beans xml with has the datasource and component scan which includes the MySQLStore package.
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.tlab"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://host:port/DB" />
<property name="username" value="username" />
<property name="password" value="password" />
</bean>
</beans>
Hazelcast xml below
<?xml version="1.0" encoding="UTF-8"?>
<hazelcast
xsi:schemaLocation="http://www.hazelcast.com/schema/config
http://www.hazelcast.com/schema/config/hazelcast-config-3.0.xsd"
xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<network>
<join><multicast enabled="true"/></join>
</network>
<map name="scrips">
<backup-count>1</backup-count>
<time-to-live-seconds>0</time-to-live-seconds>
<max-idle-seconds>0</max-idle-seconds>
<eviction-policy>LRU</eviction-policy>
<eviction-percentage>25</eviction-percentage>
<merge-policy>hz.ADD_NEW_ENTRY</merge-policy>
<map-store enabled="true">
<class-name>com.tlab.MySQLStore</class-name>
</map-store>
</map>
</hazelcast>
In your example, Hazelcast instance is not a Spring bean. You need to configure Hazelcast instance using Spring. You can find documentation here and examples
I hope that it helps.
Thank you
I am trying to incorporate Spring transactions into my project, and it seems that they are not working. I went through some tutorials nad Spring docs, and for me everything seems OK.
What I have:
1) context file:
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="jdbcTemplate" class="webapp.dataaccess.commons.JdbcTemplateProvider">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- dao section -->
<bean id="modesDao" class="webapp.dataaccess.opcalc.basicdao.CalcModesData">
<property name="jdbc" ref="jdbcTemplate" />
</bean>
<!-- lots of DAO beans defined same way -->
2) data source defined on server:
<Resource name="jdbc/calc_webapp" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="user" password="password" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/service" defaultAutoCommit = "true" />
3) and finally in one of the DAO beans I have this method:
#Transactional(propagation=Propagation.REQUIRED)
public Boolean saveFullOrganization(OrganizationLevel org) throws Exception{
Boolean out = true;
try{
Integer adminPermKey = permDao.saveAdminPermissions(org.getPermissions().getAdminPermission());
org.getPermissions().setAdminPermissionKey(adminPermKey);
Integer sellPermKey = permDao.saveSellingPermissions(org.getPermissions().getSellingPermission());
org.getPermissions().setSellingPermissionKey(sellPermKey);
Integer dszPermKey = permDao.saveDszPermissions(org.getPermissions().getDszPermission());
org.getPermissions().setDszPermissionKey(dszPermKey);
Integer reportPermKey = permDao.saveReportingPermissions(org.getPermissions().getReportingPermission());
org.getPermissions().setReportingPermissionKey(reportPermKey);
if(org.getPermissions().getKey()==null){
Integer permissions = permDao.savePermissionsSet(org.getPermissions(), null);
org.setPermissionsKey(permissions);
}
saveOrganizationUnit(org, org.getKey());
}catch(Exception e){
e.printStackTrace();
throw e;
}
return out;
}
Flow is rather intuitive - first part of method prepares permission entries for organization unit (each operation in bean permDao is also transactional), then finally calls "saveOrganizationUnit" to finalize adding new entry. I assumed that with transaction management if any exception occure in the middle of that procedure, then no data from it will go to DB. But my tests proved that if I trigger artificial exception before "saveOrganizationUnit" operation (which interrupts whole process nad jumps out of the method) the permission part lands in DB anyway. So, as I understand, transactions are not working in my solution.
I am not sure what should I check and what can be wrong (I am kind of Spring noob, so please, don't kick if its something obvious).
Default behavour of #Transactional is defined as follows:
Any RuntimeException triggers rollback, and any checked Exception does not.
So, I guess you are throwing a checked exception. If you want to trigger rollback in this case, you need to configure #Transactional accordingly:
#Transactional(propagation=Propagation.REQUIRED, rollbackFor = Exception.class) ...
I testing my DAO, but it didn't work. The following error occurs:
Tests in error:
testAccountOperations(com.tsekhan.rssreader.dao.HibernateControllerTest): Error creating bean with name 'com.tsekhan.rssreader.dao.HibernateControllerTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.tsekhan.rssreader.dao.HibernateController com.tsekhan.rssreader.dao.HibernateControllerTest.hibernateController; nested exception is java.lang.IllegalArgumentException: Can not set com.tsekhan.rssreader.dao.HibernateController field com.tsekhan.rssreader.dao.HibernateControllerTest.hibernateController to $Proxy25
My DAO:
#Service
#Scope("singleton")
public class HibernateController extends HibernateDaoSupport {
#Autowired
public SessionFactory sessionFactory;
#Transactional
public void addAcount(Account account) {
sessionFactory.getCurrentSession().saveOrUpdate(account);
}
}
My test for this DAO:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:/applicationContext.xml")
public class HibernateControllerTest {
#Autowired
HibernateController hibernateController;
private Set<Channel> getTestChannelList(String channelLink) {
Channel testChannel = new Channel();
testChannel.setSourceLink(channelLink);
Set<Channel> testChannelList = new HashSet<Channel>();
testChannelList.add(testChannel);
return testChannelList;
}
private Account getTestAccount(String accountLogin, String channelLink) {
Account testAccount = new Account();
testAccount.setAccountLogin(accountLogin);
testAccount.setChannelList(getTestChannelList(channelLink));
return testAccount;
}
#Test
public void testAccountOperations() {
hibernateController
.addAcount(getTestAccount("test_login", "test_link"));
}
}
My 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"
xmlns:context="http://www.springframework.org/schema/context"
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.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"
default-autowire="byName">
<!-- Enabling spring-transaction annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Enabling annotation-driven configurating -->
<context:annotation-config />
<!-- Creation of transaction manager -->
<bean id="transactionManager" scope="singleton"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory" scope="singleton"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:/hibernate.cfg.xml"/>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
</bean>
<!--
A Spring interceptor that takes care of Hibernate session lifecycle.
-->
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean name="employeeDAO" scope="prototype"
class="com.tsekhan.rssreader.dao.HibernateController" />
<!-- Searching for hibernate POJO files in package com.tsekhan.rssreader.web -->
<context:component-scan base-package="com.tsekhan.rssreader.web" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
</beans>
I note, that if you comment #Transactional in DAO, bean is created correctly. What happens?
First of all its realy bad to give name ending in Controller to a DAO its very confusing, Controller and DAO have all together different purpose.
When you add #Transactional to a service or dao class, for spring to make it work in a transaction needs to create a proxy of that class, its a kind of wrapper where in before the execution of proxied class(class in consideration which is proxied) method spring starts the transaction and after the execution in case no exceptions completes the transaction, this can be done in spring via AOP and Annotations. To describe in code.
public class OriginalDaoImpl implements OriginalDao extends DaoSupport {
public void save(Object o){
manager.save(o);
}
}
public class ProxyDaoImpl implements OriginalDao {
private OriginalDao originalDaoImpl; //instance of OriginalDaoImpl
public void save(Object o){
try{
transaction.start();
originalDaoImpl.save(o);
transaction.commit();
}catch(Exception e){
transaction.rollback();
}finally{
//clean up code
}
}
}
As you see this is not an exact implementation but a foundation code, how transaction magically works for you. The key point is there interface OriginalDao which makes this injection easy as OriginalDaoImpl and ProxyDaoImpl both implement same interface. Hence they can be swapped i.e. proxy taking place of original. This dynamic proxy can be created in java by Java dynamic proxy. Now, the question what if your class is not implementing an interface, it gets harder for the replacement to happen.
One of the libraries CGLIB as far as I know, helps in such a scenario, whereby it generates a dynamic subclass for the class in consideration and in overriden method performs the magic as described above, by calling super.save(o) to delegate to original code.
Now to the problem of injection.
Create interface and make your dao implement that and spring will default to JDK proxy as it is behaving now.
Add proxy-target-class="true" attribute to <tx:annotation-driven transaction-manager="transactionManager"/>
As far as exception is concerned it is throwing as it is expecting injected bean to be of type 'HibernateController' but its not.
For you reference you can refer links below.
10.5.6 Using #Transactional
Spring AOP Doc
Hope this helps !!!!!.
If your are using Spring MVC make sure to scan specific controller classes alone in servlet context file. Otherwise it will scan 2 times and transaction is not available on the application context.
The Google Code site of Morphia says it "works great with Guice, Spring, and other DI frameworks."
I'm learning Spring at the moment, so i'm just experimenting with connecting these two tools.
I've created a User POJO to store user objects with Morphia in MongoDB. I've also created a UserDAO class extending BasicDAO from Morphia to access objects.
My Spring application context configuration XML looks like this:
<?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-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
xmlns:aop="http://www.springframework.org/schema/aop">
<bean class="java.lang.String" id="mongoDb">
<constructor-arg value="test"/>
</bean>
<bean class="com.google.code.morphia.Morphia" id="morphia" />
<bean class="com.mongodb.Mongo" id="mongo"/>
<bean class="hu.inagy.testspring.daos.UserDAO" id="userDao">
<constructor-arg ref="morphia" index="0" />
<constructor-arg ref="mongo" index="1" />
<constructor-arg ref="mongoDb" index="2" />
</bean>
</beans>
I have a simple main class to test functionality:
public class App
{
public static void main( String[] args )
{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/app-context.xml");
UserDAO userDao = (UserDAO) applicationContext.getBean("userDao");
userDao.deleteByQuery(userDao.createQuery());
User user = new User();
user.setName("Test");
userDao.save(user);
User ret = userDao.find().get();
System.out.println("Saved user is: "+ret);
}
}
This works fine, however i don't know if i did everything as it should be. For example i haven't called ensureIndexes() and ensureCaps() on the datastore. My code also doesn't have an explicit mapping call for the POJOs on the Morphia object.
Are these done for me automatically or should i do other things to use Morphia correctly with Spring?
I don't use spring but this articles seems to talk about exactly what you need, a hook to do things when you app starts: http://leshazlewood.com/2007/07/30/spring-application-bootstrap-data/
You can do the Datastore.ensureIndexes/Caps() there.
You can also read this thread about using #Autowire and annotations instead of the xml, if you like that stuff.
http://groups.google.com/group/morphia/browse_thread/thread/1013b17963f29468