Understanding how nested Spring #Transactional works - spring

I'm porting an EJB application to Spring and I'm facing some issues.
The application is running in standalone (that's why we choose spring) with eclipselink.
In this application I need to create an Order, for which I first need to create a Customer, the OrderLines and then add a Payment for this Order.
The problem is that I want to do all the insertion in a single Transaction so that if the payment fails to be persisted nothing must be persisted. I tried to achieve this but it looks like I'm spanning multiple independent transaction because in case of failure data are persisted to th DB (ex: payment fails, customer is created anyway).
Here is the entry point :
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
BeanFactory beanFactory = (BeanFactory) context;
MyService service = beanFactory.getBean(MyService.class);
service.getNewOrders(true);
}
Here is the bean I'm resolving (using beanFactory.getBean) :
#Component
#Scope("prototype")
public class MyService {
#Autowired
private CustomerService customerService;
#Autowired
private OrderService orderService;
#Autowired
private PaymentService paymentService;
#Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public void getNewOrders(boolean formattedOutput) {
try {
List<RawData> rawData = // Acquire data from a remote web service (http rest based)
for (RawData data : rawData) {
try {
this.handleOrder(data);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
private Order handleOrder(RawData rawData) throws Exception {
Customer customer = new Customer();
// Fill customer with rawData
this.customerService.create(customer);
Order order = new Order();
order.setCustomer(customer);
// Fill order with rawData
this.orderService.create(order);
Payment payment = new Payment();
payment.setOrder(order);
// Fill payment with rawData
this.paymentService.create(payment);
return order;
}
}
Each service looks like the following :
#Service
#Transactional
public class CustomerService {
#Autowired
private CustomerDao customerDao;
public void create(Customer customer) {
// some works on customer fields (checking values etc)
this.customerDao.create(customer);
}
}
Which are all backed by a Dao :
#Repository
public class CustomerDao {
#PersistenceContext
protected EntityManager em;
public void create(Customer customer) {
this.em.persist(customer);
}
}
Here are a few dependencies from maven pom.xml :
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.jolbox</groupId>
<artifactId>bonecp</artifactId>
<version>0.8.0-rc1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
<version>2.3.2</version>
</dependency>
Here is the persistence.xml :
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/db" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="" />
</properties>
</persistence-unit>
</persistence>
The spring configuration is the following :
<?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:p="http://www.springframework.org/schema/p"
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.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="myDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="jpaPropertyMap">
<map>
<entry key="eclipselink.weaving" value="false" />
</map>
</property>
</bean>
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="myTxManager" />
<context:component-scan base-package="com.application" />
</beans>
EDIT
Added the creation of the ApplicationContext from the main, and an omitted method from MyService.java

How can you call the service method since it's private? It should be public. Private methods can't be intercepted by the Spring transactional interceptor, and can't be overridden by the CGLib dynamic proxy.
EDIT: OK, it's the usual problem. You're calling, from the main method, the method getNewOrders(), which is public and transactional. The Spring interceptor intercepts this method call. Since there is no transaction and the method is marked as SUPPORTS, Spring doesn't start any transaction.
Then this method calls the private handleOrder() method. Note that not only the method is private, which makes it impossible for Spring to intercept the method call, but the call is from a method in a component to a method in the same component. So even is the method was public, Spring could not intercept this method call. The transactional handling is proxy-based:
method --> transactional proxy --> Spring bean 1 --> transactional proxy --> Spring bean2
In this case, since you're not calling a method of another component, there is no proxy interception, and no transaction is started.
method --> transactional proxy --> Spring bean 1 --> transactional proxy --> Spring bean2
^ |
|___|
So, what you have to do is
create another Spring bean 'OrderHandler, for example)
move the handleOrder() method to this Spring bean, make it public
inject OrderHandler in MyService
And it will work fine.
This is explained in details in the Spring documentation.

Related

Invocation of init method failed; nested exception is javax.persistence.PersistenceException

Guys i've came across a problem which i googled a lot and tried to find solutions in stackflow,however it failed and there seems no body have met with the same problem .What's more , i've got exhausted.Below is my code and configuration files.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.robot</groupId>
<artifactId>springdata</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<dependencies>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-
data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/hibernate/hibernate-entitymanager --
>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.6.Final</version>
</dependency>
</dependencies>
</project>
in my dependency xml,i add spring data and hibernate.
<?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:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--1 配置数据源-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="url" value="jdbc:mysql:///spring_data"></property>
</bean>
<!--2 配置EntityManagerFactory-->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="packagesToScan" value="com.robot"/>
<property name="jpaProperties">
<props>
<prop
key="hibernate.ejb.naming_strategy">
org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop
key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!--<!–3 配置事务管理器–>-->
<!--<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">-->
<!--<property name="entityManagerFactory" ref="entityManagerFactory"/>--
>
<!--</bean>-->
<!--<!–4 配置支持注解的事务–>-->
<!--<tx:annotation-driven transaction-manager="transactionManager"/>-->
<!--<!–5 配置spring data–>-->
<!--<jpa:repositories base-package="com.robot" entity-manager-factory-
ref="entityManagerFactory"/>-->
<!--<context:component-scan base-package="com.robot"/>-->
</beans>
below is my entity class, it is very simple,so i don't think any thing will go wrong.
package com.robot.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class Employee {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
#GeneratedValue
#Id
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
below is my test class
package com.robot.dao;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StudentSpringDataTest {
private ApplicationContext ctx=null;
#Before
public void setUp(){
System.out.println("Set Up");
ctx= new ClassPathXmlApplicationContext("beans_new.xml");
}
#After
public void tearDown(){
System.out.println("Tear Down");
ctx =null;
}
#Test
public void initializationTest(){
}
}
when i run the initializationTest method it show error like the picture described.
log info
For your next questions do not include your stack traces as image.
The error is clear: "No identifier specified for entity: ....", and that is because you have your #Id annotation on a set method, and you can not use annotation on settters. You need to use it either on the field or on the getter method.
Hibernate mapping annotations - Access type
Try:
#Entity
public class Employee {
#GeneratedValue
#Id
private int id;
...
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
...
}

Error creating bean 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1'

I'm trying to create a web-app, using Maven and Intellij Idea. Tests work fine as installing in .war-file. But when I try to refer to my rest with jetty, I have lots of error cases:
Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1' defined in ServletContext resource [/WEB-INF/rest-spring.xml]: Initialization of bean failed;
nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonProcessingException
Here are rest module files:
Web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>restDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--the location of the spring context configuration file-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/rest-spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
rest-spring.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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:model.properties</value>
<value>classpath:database.properties</value>
<value>classpath:automobile.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath*:create-tables-model.sql"/>
<jdbc:script location="classpath*:create-tables-automobile.sql"/>
<jdbc:script location="classpath*:data-script.sql"/>
</jdbc:initialize-database>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter"/>
</list>
</property>
</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
<property name="prettyPrint" value="true" />
</bean>
<bean id="modelDao" class="com.dao.ModelDaoImpl">
<constructor-arg ref="dataSource" />
</bean>
<bean id="automobileDao" class="com.dao.AutomobileDaoImpl">
<constructor-arg ref="dataSource" />
</bean>
<bean id="modelService" class="com.service.ModelServiceImpl">
<property name = "modelDao" ref = "modelDao"/>
</bean>
<bean id="automobileService" class="com.service.AutomobileServiceImpl">
<property name = "automobileDao" ref = "automobileDao"/>
</bean>
<context:component-scan base-package="com.rest"/>
</beans>
ModelRestController
package com.rest;
import com.dto.ModelDto;
import com.general.Model;
import com.service.ModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
/**
* Created by kohtpojiep on 23.01.16.
*/
#RestController
public class ModelRestController
{
private static final Logger LOGGER = LogManager.getLogger();
#Autowired
private ModelService modelService;
#RequestMapping(value="/models", method = RequestMethod.GET)
public #ResponseBody List<Model> getAllModels()
{
LOGGER.debug("Getting all models");
return modelService.getAllModels();
}
#RequestMapping(value="/model", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.CREATED)
public #ResponseBody Integer addModel(#RequestBody Model model)
{
LOGGER.debug("Adding model modelName = {}", model.getModelName());
return modelService.addModel(model);
}
#RequestMapping (value="/model/{modelId}/{modelName}", method=RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody void updateModel(#PathVariable(value="modelId") Integer modelId,
#PathVariable(value="modelName") String modelName)
{
LOGGER.debug("Updating model modelId = {}", modelId);
modelService.updateModel(new Model(modelId,modelName));
}
#RequestMapping (value="/model/{modelName}", method = RequestMethod.DELETE)
#ResponseStatus(value = HttpStatus.NO_CONTENT)
public #ResponseBody void deleteModelByName(#PathVariable(value = "modelName") String modelName)
{
LOGGER.debug("Deleting model modelName= {}",modelName);
modelService.deleteModelByName(modelName);
}
#RequestMapping (value="/modelsdto", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody
ModelDto getModelsDto()
{
LOGGER.debug("Getting models Dto");
return modelService.getModelDto();
}
}
AutomobileRestController
package com.rest;
import com.dto.AutomobileDto;
import com.general.Automobile;
import com.service.AutomobileService;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
/**
* Created by kohtpojiep on 02.02.16.
*/
#RestController
public class AutomobileRestController
{
private static final Logger LOGGER = LogManager.getLogger();
#Autowired
AutomobileService automobileService;
private static LocalDate convertToLocalDate(String date)
{
DateTimeFormatter formattedDate = DateTimeFormat.forPattern("dd/MM/yyyy");
return formattedDate.parseLocalDate(date);
}
#RequestMapping(value = "/automobiles", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody List<Automobile> getAllAutomobiles()
{
LOGGER.debug("Getting all automobiles");
return automobileService.getAllAutomobiles();
}
#RequestMapping(value = "/automobile", method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.CREATED)
public #ResponseBody Integer addAutomobile (#RequestBody Automobile automobile)
{
LOGGER.debug("Adding automobile modelName = {}",automobile.getModelName());
return automobileService.addAutomobile(automobile);
}
#RequestMapping(value = "/automobile/update", method = RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody void updateAutomobile (#RequestBody Automobile automobile)
{
LOGGER.debug("Updating automobile automobileId = {}", automobile.getAutomobileId());
automobileService.updateAutomobile(automobile);
}
#RequestMapping(value = "/automobile/{automobileId}", method = RequestMethod.DELETE)
#ResponseStatus(value = HttpStatus.NO_CONTENT)
public #ResponseBody void depeteAutomobile (#PathVariable (value="automobileId")
Integer automobileId)
{
LOGGER.debug("Deleting automobile automobileId = {}",automobileId);
automobileService.deleteAutomobileById(automobileId);
}
#RequestMapping(value = "/automobiles/date-sort", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.ACCEPTED)
public #ResponseBody List<Automobile> getAutomobilesSortedByDate (#RequestParam(value="firstDate")
String firstDate, #RequestParam (value="lastDate") String lastDate)
{
LOGGER.debug("Getting automobiles sorted by date:\n");
return automobileService.getAutomobilesSortedByDate(
convertToLocalDate(firstDate),convertToLocalDate(lastDate));
}
#RequestMapping(value = "/automobilesdto", method = RequestMethod.GET)
#ResponseStatus(value = HttpStatus.OK)
public #ResponseBody
AutomobileDto getAutomobileDto()
{
LOGGER.debug("Getting automobile DTO");
return automobileService.getAutomobileDto();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>usermanagement</artifactId>
<groupId>com.epam.brest.course2015</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-rest</artifactId>
<name>${project.artifactId}</name>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.epam.brest.course2015</groupId>
<artifactId>app-service</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.16.v20140903</version>
<configuration>
<stopPort>9091</stopPort>
<stopKey>STOP</stopKey>
<webAppConfig>
<contextPath>/rest</contextPath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webAppConfig>
<scanIntervalSeconds>10</scanIntervalSeconds>
<connectors>
<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
<port>8081</port>
</connector>
</connectors>
</configuration>
</plugin>
</plugins>
</build>
</project>
I saw solutions for similar situations: people offer to change versions of used frameworks and up the search level of component scan, but it doesn't work for me.
Add dependency to your POM:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
As you use dependency management in parent POM, there is no need to specify version.
Solved! The problem was I use not only jackson-core dependency, but also jackson databind, datatype and annotations and these dependencies had different versions: 2.7.1 for "core" and 2.4.3 for other ones. Now I use the same version for all of them and thus adding dependency had an affect. Thx for your help!)
I had the same problem. I used spring version 5.0.5.RELEASE and Jackson Core version 2.4.3.
I upgraded Jackson core up to 2.9.5 and it works now : exception "Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter' " dissapeared and my rest service works.
Before in my pom.xml :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
After :
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
I hope it will help.
Yes. Using version 2.9.5 works:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
I'm using spring-webmvc: 5.0.12.RELEASE, if that helps.

Caching of default Spring Data JPA Methods

Task: make basic methods of spring jpa data cacheable (using hibernate/jpa), like
Page<T> findAll(Pageable pageable)
List<T> findAll();
etc
and do it on some kind of top generic interface level, without custom dao implementations.
This is continuation of original topic
How to add QueryHints on Default Spring Data JPA Methods?
I haven't still found the solution, but tried to solve it with different ways, including adding annotations like
#javax.persistence.Cacheable and #org.hibernate.annotations.Cache
on data model class.
Here are some excerpts of my config:
pom.xml (taken from here):
...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.1.9.Final</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.7.0</version>
</dependency>
...
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
...
applicationContext.xml:
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
persistence.xml:
...
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
...
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true" />
</properties>
...
Apart from all above I have configured spring 3.2 cache, but eventually I want to have a solution not based on spring cache, so at the moment I don't use spring cache config.
My model looks like:
#Entity
#Table(name = "ABC")
#Cacheable(true)
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ABC {
...
My parent generic DAO looks like:
public interface CacheableGenericDao<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
List<T> findAll();
Page<T> findAll(Pageable pageable);
<S extends T> S save(S entity);
...
P.S. Here is one more useful link concerning the topic, but I do want use basic method names.
So what am I missing conceptually? Is there any approach at all or do I want too much?
this is how the things seem to go: jira.springsource.org/browse/DATAJPA-173

MongoTemplate instance is not created inside spring

I want to try spring integration with MongoDB, For this purpose I did following things. but its not working Some how MongoTemplate instance is not created and throws java.lang.NullPointerException.
here is my application-context.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"
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">
<!-- Activate annotation configured components -->
<context:annotation-config/>
<!-- Scan components for annotations within the configured package -->
<context:component-scan base-package="com.jeroenreijn.mongodb.example">
<context:exclude-filter type="annotation" expression="org.springframework.context.annotation.Configuration"/>
</context:component-scan>
<!-- Factory bean that creates the Mongo instance -->
<bean id="mongo" class="com.mongodb.Mongo">
<constructor-arg name="host" value="127.0.0.1" />
<constructor-arg name="port" value="27017" />
</bean>
<!-- Define the MongoTemplate which handles connectivity with MongoDB -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate" depends-on="mongo">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="firstMongoDB"/>
</bean>
<!-- Use this post processor to translate any MongoExceptions thrown in #Repository annotated classes -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
here is my main method :
public class MainApplication {
/**
* This is a variable used for Logging purpose, I have used slf4j.
*/
final Logger LOGGER = LoggerFactory.getLogger(MainApplication.class);
#Autowired
MongoTemplate mongoTemplate;
public void savePerson(Person p) {
mongoTemplate.save(p);
}
public static void main(String[] args) {
Person p = new PersonImpl("1", "Ayushya", "Devmurari");
MainApplication ma = new MainApplication();
ma.savePerson(p);
ma.LOGGER.info("Person named : " + p.getName() + " with id : "
+ p.getId() + " is saved.");
}
}
Here is my model class :
#Document(collection = "AnotherPersonCollection")
public class PersonImpl implements Person {
private String id;
private String name;
private String surname;
// Constructor
public PersonImpl() {
}
public PersonImpl(String id, String name, String surname) {
this.id = id;
this.name = name;
this.surname = surname;
}
#Override
public String getId() {
return id;
}
#Override
public void setId(String id) {
this.id = id;
}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
#Override
public String getSurname() {
return surname;
}
#Override
public void setSurname(String surname) {
this.surname = surname;
}
#Override
public String toString() {
return "Person has name " + "Id :" + id + "\n" + name + " \n"
+ "surname :" + surname;
}
}
Need assistance I have tried several tutorials, like mkyong and many others and I have faced NoBeanDefinitionFound for "mongoTemplate" error: so I tried this.
UPDATE: here is my pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.discusit</groupId>
<artifactId>MongoDBAppTrail4</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Trying to create MongoDBApp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- Log4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<!-- mongodb java driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>2.11.0</version>
</dependency>
<!-- Spring data mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Here is my stacktrace :
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'mongoTemplate' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:568)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1102)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117)
at com.discusit.main.MainApplication.main(MainApplication.java:39)
I have look #Aayush solution. I have found two errors:
You don't call correctly your xml file configuration.
Before:
ApplicationContext ctx = new GenericXmlApplicationContext("classpath*:application-context.xml");
After:
ApplicationContext ctx = new GenericXmlApplicationContext("classpath:META-INF/applicationContext.xml");
You call an ExceptionTranslationPostProcessor. Why ? This call causes an error. I removed it.
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
So finally, i have tested your application with small changes and all it's working. Dont forget to start mongodb server and create your database "firstMongoDB". For more information read here: http://docs.mongodb.org/manual/tutorial/getting-started/
I have published your project in github: https://github.com/m-reka/spring-data-mongoTemplate
Tell me when i can remove it :)
As mentioned, you have to create application context in your main class. To use autowire you can define your main class as spring bean.
<?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"
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">
<!-- your mongodb bean befinitions -->
<bean class="fullpackage.MainApplication"/>
</beans>
And then just get the instance in your main class
public class MainApplication {
/**
* This is a variable used for Logging purpose, I have used slf4j.
*/
final Logger LOGGER = LoggerFactory.getLogger(MainApplication.class);
#Autowired
MongoTemplate mongoTemplate;
public void savePerson(Person p) {
mongoTemplate.save(p);
}
public static void main(String[] args) {
ApplicationContext ctx = new GenericXmlApplicationContext("application-context.xml");
MainApplication ma = ctx.getBean(MainApplication.class);
Person p = new PersonImpl("1", "Ayushya", "Devmurari");
ma.savePerson(p);
ma.LOGGER.info("Person named : " + p.getName() + " with id : " + p.getId() + " is saved.");
}
}
in your main method add :
ApplicationContext context =
new ClassPathXmlApplicationContext("application-context.xml"); //change xml path as you need.
MMongoTemplate mongoTemplate=context.getBean(MMongoTemplate.class);
As you use main method, which is skipping loading the beans in spring context , so the autowire will not work.
use this way to configure mongodb
AppMongoConfig.class
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import com.mongodb.Mongo;
#Configuration
public class AppMongoConfig {
public #Bean
MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new Mongo(), "testing");
}
public #Bean
MongoTemplate mongoTemplate() throws Exception {
//remove _class
MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);
return mongoTemplate;
}
}
/-------------------------------------------------------------------------------------------------/
testing-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<mongo:mongo host="testing" port="27017">
<mongo:options connections-per-host="100"
threads-allowed-to-block-for-connection-multiplier="5"
max-wait-time="120000000"
connect-timeout="10000000"
socket-keep-alive="true"
socket-timeout="15000000"
auto-connect-retry="true"/>
</mongo:mongo>
<mongo:db-factory dbname="testing"
mongo-ref="mongo" />
<bean id="mongoTypeMapper"
class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey">
<null />
</constructor-arg>
</bean>
<bean id="mongoMappingContext"
class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="mongoConverter"
class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mongoMappingContext" />
<property name="typeMapper" ref="mongoTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mongoConverter" ref="mongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" />
</bean>
</beans>
/---------------------------------------------------------------------------/
#Autowired
private MongoTemplate mongoTemplate ;
#Override
public String methodTesting(classname object) { //classname change to your class name
String response="failer";
try {
if (!mongoTemplate.collectionExists(classname.class)) {
mongoTemplate.createCollection(classname.class);
}
mongoTemplate.save(object);
`response="success";`
} catch (Exception e) {
System.out.println("inside catch");
e.printStackTrace(); // TODO: handle exception
}
return response;
}

Spring-data cross store entity management

I want to use Postgres, MongoDB and Neo4j together in my application. I was able to configure them all, however now each of my POJOs is backed my graphNode as well as document by aspectJ.
Is there any way to filter out which POJOs are backed by graphNodes only and which by document only?
I have a problem with saving POJOs when I do it more than twice [sic!] in a single request and I can see in the log that mongo and neo4j are both trying to create lots of instances which cause some king of deadlock.
So long story short:
Is there a way to filter data mappings to configure pojo "A" to be mapped by RDBMS and graph (no document) and pojo B by document and graph (no RDBMS)
Is there any sample for cross-store spring-data based application which more or less covers my problem?
Why can I save two instances of pojo class in my controller one by one but when third instance is created I can notice a deadlock?
[EDIT]
What I've noticed:
Mongo aspectj builder backs #Entity annotated POJOs an I don't know how to use #Entity to map POJO for Hibernate and not in MongoDB
Neo4j related freeze occurs only when connected via REST and happens sometimes on 3rd sometimes on 4th and sometimes doesnt happen at all. See the controller initiation how it is done.I've tried all commented lines with no success.
Transaction manager configuration must be placed in correct place, otherwise Neo4J configuration validator service fails.
[/EDIT]
I use:
Spring 3.0.5
SpringRoo 1.4
Spring-data 1.0
Postgres 9.0 + Hibernate 3.5.5
Neo4j 1.3 remotely
MongoDB 1.8.2 remotely
All DBs are on single remote machine and works fine
[EDIT]
POM slices:
<properties>
<roo.version>1.1.4.RELEASE</roo.version>
<spring.version>3.0.5.RELEASE</spring.version>
<aspectj.version>1.6.11</aspectj.version>
<slf4j.version>1.6.1</slf4j.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-security.version>3.0.5.RELEASE</spring-security.version>
<jackson.version>1.8.0</jackson.version>
<spring.data.mongodb.version>1.0.0.M2</spring.data.mongodb.version>
<spring.data.graph.version>1.0.0.RELEASE</spring.data.graph.version>
<spring.data.commons.version>1.0.0.RELEASE</spring.data.commons.version>
</properties>
...
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>${spring.data.graph.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-cross-store</artifactId>
<version>${spring.data.mongodb.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>${spring.data.mongodb.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-rest</artifactId>
<version>${spring.data.graph.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons-core</artifactId>
<version>${spring.data.commons.version}</version>
<scope>compile</scope>
</dependency>
....
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.0</version>
<dependencies>
<!-- NB: You must use Maven 2.0.9 or above or these are ignored (see
MNG-2972) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
<aspectLibrary>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
</aspectLibrary>
<aspectLibrary>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-cross-store</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
POJO:
#NodeEntity
#RooToString
#RooJavaBean
public class DElement {
#Indexed
private Long id;
#RelatedTo(direction=Direction.BOTH, elementClass=DRegion.class, type="SUBELEMENT_OF")
private Set<DElement> childElements = new HashSet<DElement>();
#Indexed(indexName = "delement-name", fulltext=true)
private String name;
#Transactional
public void addChild(DElementchild child)
{
this.childElements.add(child);
}
}
Controller (with loading):
#Controller
#RequestMapping(value="/DElements")
public class DElementsController {
DElementRepository DElementRepository;
GraphDatabaseContext gdbc;
#Autowired
public DElementsController(DElementRepository DElementRepository, GraphDatabaseContext gdbc)
{
this.DElementRepository = DElementRepository;
this.gdbc = gdbc;
this.initElements();
}
#Transactional
private void initElements()
{
try
{
DElementRepository.deleteAll();
}
catch (Exception e) {} finally{}
//Transaction txn = gdbc.beginTx();
referenceNode.createRelationshipTo(allElements.getPersistentState(), myRelation);
DElement naElements = new DElement().persist();
naElements.setName("1");
allElements.addChild(naElements);
DElement saElements = new DElement().persist();
saElements.setName("2");
allElements.addChild(saElements);
DElement euElements = new DElement().persist();
euElements.setName("3");
allElements.addChild(euElements);
DElement afElements = new DElement().persist();
afElements.setName("4");
allElements.addChild(afElements);
DElement asElements = new DElement().persist();
asElements.setName("5");
allElements.addChild(asElements);
DElement auElements = new DElement().persist();
auElements.setName("6");
allElements.addChild(auElements);
//txn.success();
//txn.finish();
}
}
applicationContext.xml
<?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"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:graph="http://www.springframework.org/schema/data/graph"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/data/graph http://www.springframework.org/schema/data/graph/datagraph-1.0.xsd
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">
<context:property-placeholder location="classpath*:META-INF/spring/*.properties" />
<context:spring-configured />
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<context:component-scan base-package="com.foobar">
<context:exclude-filter expression=".*_Roo_.*"
type="regex" />
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/foobar" />
<mongo:mongo host="${foobar.mongodb.addr}" port="27017" />
<mongo:mapping-converter base-package="com.foobar.lib.model.mongo"/>
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg name="mongo" ref="mongo" />
<constructor-arg name="databaseName" value="foobar" />
<constructor-arg name="defaultCollectionName" value="basecoll" />
</bean>
<bean class="org.springframework.data.document.mongodb.MongoExceptionTranslator" />
<!-- Mongo cross-store aspect config -->
<bean
class="org.springframework.data.persistence.document.mongo.MongoDocumentBacking"
factory-method="aspectOf">
<property name="changeSetPersister" ref="mongoChangeSetPersister" />
</bean>
<bean id="mongoChangeSetPersister"
class="org.springframework.data.persistence.document.mongo.MongoChangeSetPersister">
<property name="mongoTemplate" ref="mongoTemplate" />
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean
id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
destroy-method="shutdown" >
<constructor-arg index="0" value="c:/neo4j/data/foobar" />
</bean>
<!-- REST DOESNT WORK FOR THE MOMENT
<bean id="graphDatabaseService" class="org.springframework.data.graph.neo4j.rest.support.RestGraphDatabase">
<constructor-arg value="${foobar.neo4j.reststore}"/>
</bean> -->
<!-- <bean id="graphDatabaseContext" class="org.springframework.data.graph.neo4j.support.GraphDatabaseContext">
<property name="graphDatabaseService" ref="graphDatabaseService"/>
</bean> -->
<graph:repositories base-package="com.foobar.data.repositories.neo4j" graph-database-context-ref="graphDatabaseContext"/>
<graph:config graphDatabaseService="graphDatabaseService" entityManagerFactory="entityManagerFactory" />
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
[/EDIT]
Some general remarks.
You only need to pass in the entityManagerFactory to Spring Data Graph when you want to use Graph-JPA cross store persistence. An example can be found here. If you do so then you should also enable the partial=true flag on your POJOs that you want to participate in the cross store setting.
Spring Data Graph Cross store and Spring Data MongoDB cross store work differently in how they interact with JPA, SDG works from the Graph POJO side when persisting or loading entities they are (re-)connected to their JPA entity (via the #Id field).
On the other hand Spring Data MongoDB uses AspectJ to augment some of the Methods of the EntityManager to kick in lifecycle events for the document database.
Right now there is no story for integrating MongoDB and Neo4j. But as we, the project leads of both projects live in the same city and work closely together I think that should be doable.
It would be great if you could share your complete project code somewhere with us, either on github (could also be a private repo [my github id is "jexp", or per mail or dropbox).
So that we could dig directly into it.
To your questions:
graph + rdmbs are all Entities that have partial = true and you have to have #Entity annotations on your POJO
I'm not sure how mongo-cross-store persistence is configured correctly
normally that should be configured via persistence.xml to which stores an entity is mapped?
i.e. perhaps we should devise an mechanism that says that configures a persistence.xml per store that wants to interact with the EntityManager/JPA/RDMBS
probably that also works by defining two entity managers one for the graph and the other one for mongo?
you should probably get it running in embedded mode of neo4j first, and look into remote server (REST) later
you should probably update Spring Data Graph to 1.1.M2, Neo4j to 1.4 and AspectJ to 1.6.12.M1
Please connect personally,so that we can work out all the issues and arrive at a good solution.

Resources