The test with transactionrequiredexception failed: when loading JPA and neo4j configurations, no transaction is in progress
I have a JPA web application that contains some integration tests for the JPA repository At present, there is no integration test for the neo4j repository
Now, I have added some neo4j features to this existing JPA web application
I am now using the neo4j repository and the JPA repository My entity and repository have different names and are located in different packages
My tests all extend the following classes:
@WebAppConfiguration @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { ApplicationConfiguration.class,WebSecurityTestConfiguration.class,WebConfiguration.class }) @Transactional public abstract class AbstractControllerTest { ... }
When the application configuration does not have any tests, the tests run normally
Neo4J configuration: @Configuration @ComponentScan(basePackages = { "it.robot.rest.config" }) @Import({ DatabaseConfiguration.class,Log4jWeb.class }) public class ApplicationConfiguration { }
However, when adding the neo4j configuration, they will make an error in the exception:
@Configuration @ComponentScan(basePackages = { "it.robot.rest.config" }) @Import({ DatabaseConfiguration.class,Neo4JRepositoryConfiguration.class,Log4jWeb.class }) public class ApplicationConfiguration { }
The exceptions are:
javax.persistence.TransactionrequiredException: no transaction is in progress
This is the neo4j configuration (I tried the neo4jconfiguration and crossstoreneo4jconfiguration classes, and I got the same exception):
@Configuration @EnableNeo4jRepositories(basePackages = { "it.robot.data.neo4j.repository" } ) @EnableTransactionManagement @ComponentScan(basePackages = { "it.robot.data.neo4j.service" }) public class Neo4JRepositoryConfiguration extends Neo4jConfiguration { public static final String URL = "http://localhost:7474/db/data/"; public static final String LOGIN = "neo4j"; public static final String PASSWORD = "mypassword"; Neo4JRepositoryConfiguration() { setBasePackage("it.robot.data.neo4j.domain"); } @Bean GraphDatabaseService graphDatabaseService() { return new SpringCypherRestGraphDatabase(URL,LOGIN,PASSWORD); } }
This is the JPA configuration:
@Configuration @Import({ JpaService.class,Log4j.class }) @EnableTransactionManagement @ComponentScan(basePackages = { "it.robot.data.config" }) @EnableJpaRepositories(basePackages = { "it.robot.data.jpa" },repositoryfactorybeanClass = it.robot.data.jpa.repository.GenericRepositoryfactorybean.class) public class DatabaseConfiguration { ... }
It seems that the neo4jconfiguration class transaction manager has the same name as the JPA transaction manager ("transaction manager") and overrides it
I will use the JPA transaction manager provided by spring to satisfy Neo 4J, but I wonder if it is feasible
Some additional information
I am using spring-data-neo4j and spring-data-neo4j-rest version 3.3 2.RELEASE
I am using the neo4j database instead of the embedded server. Of course, the neo4j server has been started
I disabled authentication on the database because it blocked my curl request and did not seem to update the password:
curl -H "Accept:application/json" -H "Content-Type: application/json" "http://localhost:7474/user/neo4j/password" -X POST -d "{ \"password\" : \"myownpassword\" }"
The only user I know doesn't seem to have a strong voice:
stephane@stephane-ThinkPad-X301:~> curl -H "Accept:application/json" -H "Content-Type: application/json" "http://localhost:7474/user/neo4j" stephane@stephane-ThinkPad-X301:~> stephane@stephane-ThinkPad-X301:~>
I didn't create any "architecture / structure" in the diagram, and I'm not sure if I should
Neo4j entity:
@NodeEntity @SequenceGenerator(name = "id_generator",sequenceName = "sq_id_part") public class Neo4JPart extends BaseEntity { @Column(nullable = false) private String name; @Column(nullable = false,unique = true) private String serialNumber; private Integer weight; @ManyToOne @JoinColumn(name = "manufacturer_id",nullable = false) private Neo4JManufacturer manufacturer; @Fetch @RelatedTo(type = "part",direction = Direction.BOTH) public Set<Neo4JPart> parts; public Neo4JPart() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSerialNumber() { return serialNumber; } public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } public Neo4JManufacturer getManufacturer() { return manufacturer; } public void setManufacturer(Neo4JManufacturer manufacturer) { this.manufacturer = manufacturer; } public Set<Neo4JPart> getParts() { return parts; } public void setParts(Set<Neo4JPart> parts) { this.parts = parts; } public String toString() { String results = name + "'s compatible parts include\n"; if (parts != null) { for (Neo4JPart part : parts) { results += "\t- " + part.name + "\n"; } } return results; } } @MappedSuperclass public class BaseEntity { @GraphId @GeneratedValue(strategy = GenerationType.AUTO,generator = "id_generator") @Column(name = "id") private Long id; @Version @Column(nullable = false) private int version; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public int getVersion() { return this.version; } public void setVersion(int version) { this.version = version; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) { return false; } BaseEntity that = (BaseEntity) obj; return this.id.equals(that.getId()); } @Override public int hashCode() { return id == null ? 0 : id.hashCode(); } }
And neo4j repositories:
public interface Neo4JPartRepository extends GraphRepository<Neo4JPart> { public Neo4JPart findByName(String name); public Neo4JPart findBySerialNumber(String serialNumber); public Page<Neo4JPart> findByManufacturer(@Param("manufacturer") Neo4JManufacturer manufacturer,Pageable page); public List<Neo4JPart> findByManufacturer(@Param("manufacturer") Neo4JManufacturer manufacturer); public Page<Neo4JPart> findByPartsName(String name,Pageable page); } public interface Neo4JManufacturerRepository extends GraphRepository<Neo4JManufacturer> { Neo4JManufacturer findByName(String name); }
Maven dependencies are:
<org.springframework.version>4.1.2.RELEASE</org.springframework.version> <hibernate.version>4.3.6.Final</hibernate.version> <dependencies> <dependency> <groupId>com.thalasoft</groupId> <artifactId>tool@R_332_2419@</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.2.1</version> </dependency> <dependency> <groupId>MysqL</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.3.172</version> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.1-api</artifactId> <version>1.0.0.Final</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-core</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-jpa</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> <version>1.10.2.RELEASE</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.4</version> </dependency> <dependency> <groupId>org.lazyluke</groupId> <artifactId>log4jdbc-remix</artifactId> <version>0.2.7</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.jadira.usertype</groupId> <artifactId>usertype.jodatime</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.jasypt</groupId> <artifactId>jasypt</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>1.6.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-neo4j</artifactId> <version>3.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-neo4j-rest</artifactId> <version>3.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-neo4j-cross-store</artifactId> <version>3.3.2.RELEASE</version> </dependency> </dependencies>
I tried to upgrade to search maven. Org Version 0, but the build now provides the following exceptions:
AnnotationFormatError: Invalid default: public abstract java.lang.Class org.springframework.data.neo4j.config.EnableNeo4jRepositories.repositoryBaseClass()
I'm referring to the documentation http://docs.spring.io/spring-data/neo4j/docs/3.4.0.RELEASE/reference/pdf/spring-data-neo4j-reference.pdf You don't see any information about repository baseClass in
The source code Javadoc only says:
Configure the repository base class to be used to create repository proxies for this particular configuration.
This gives me a headache and wants to know what a repository agent is if I need one in my case
Solution
I can use the solution provided by the chain transaction manager in implementing spring chainedtransactionmanager according to the "best forces 1pc" pattern to solve the problem, following Simon's how do I properly set up cross store persistence using spring data JPA + neo4j? Tips for
I just need to change my neo4j configuration I don't even need to touch anything in another JPA transaction manager
This is my neo4j configuration:
@EnableNeo4jRepositories(basePackages = { "it.robot.data.neo4j.repository" }) @EnableTransactionManagement @ComponentScan(basePackages = { "it.robot.data.neo4j.service" }) public class Neo4JRepositoryConfiguration extends Neo4jConfiguration { private static Logger logger = LoggerFactory.getLogger(Neo4JRepositoryConfiguration.class); public static final String URL = "http://localhost:7474/db/data/"; public static final String LOGIN = "neo4j"; public static final String PASSWORD = "xxxxx"; Neo4JRepositoryConfiguration() { setBasePackage("it.robot.data.neo4j.domain"); } @Bean GraphDatabaseService graphDatabaseService() { return new SpringCypherRestGraphDatabase(URL,PASSWORD); } @Autowired LocalContainerEntityManagerfactorybean entityManagerFactory; @Override public PlatformTransactionManager neo4jTransactionManager( GraphDatabaseService graphDatabaseService) { return new ChainedTransactionManager( new JpaTransactionManager(entityManagerFactory.getObject()),new JtaTransactionManagerfactorybean(graphDatabaseService).getObject()); } }