0

I have a Spring Data Neo4j project which is going to be a data access object consumed by Spring MVC.

I simply wish to have the unit tests run against an in-memory database whilst in production it must connect to a remote server.

Apparently, according to the answer of another question I asked, remote server access is only available in Spring Data Neo4j 4.0.0.M1 but as this is a moving target things keep breaking.

In order to get it to at least compile I am using 4.0.0.BUILD-SNAPSHOT

When running my tests I am now getting the following:

Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:94)
    at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:72)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:200)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:259)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:261)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:219)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accountRepository': Invocation of init method failed; nested exception is java.lang.NullPointerException
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:736)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:109)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:261)
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68)
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86)
    ... 44 more
Caused by: java.lang.NullPointerException
    at org.springframework.data.neo4j.mapping.Neo4jPersistentProperty.<init>(Neo4jPersistentProperty.java:72)
    at org.springframework.data.neo4j.mapping.Neo4jMappingContext.createPersistentProperty(Neo4jMappingContext.java:105)
    at org.springframework.data.neo4j.mapping.Neo4jMappingContext.createPersistentProperty(Neo4jMappingContext.java:41)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:468)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:446)
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:605)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:314)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:489)
    at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:446)
    at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:605)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:314)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:276)
    at org.springframework.data.neo4j.mapping.Neo4jMappingContext.<init>(Neo4jMappingContext.java:64)
    at org.springframework.data.neo4j.repository.support.GraphRepositoryFactoryBean.afterPropertiesSet(GraphRepositoryFactoryBean.java:41)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
    ... 59 more

I have searched and searched and I cannot find a solution to this. The stacktrace is pretty useless in determining why this should be null.

@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan(basePackages = {"co.foo.data"})
@ContextConfiguration(classes={Neo4jTestConfiguration.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class AccountRepositoryTest {
    @Autowired
    AccountRepository accountRepository;

    @Autowired
    UserRepository userRepository;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Test
    public void testCreateAccount() {
        Account account = new Account(new Institution("TestBank"));
        accountRepository.save(account);
        assertNotNull(account.getNodeId());
        assertEquals(account.getInstitution().name, "TestBank");
    }

    @Test
    public void testTransactionsForAccount() {
        Account account = new Account(new Institution("TestBank"));
        accountRepository.save(account);
        assertNotNull(account.getNodeId());
        User user = new User("testuser", "Test", "User", "testpass", null, passwordEncoder, User.Roles.ROLE_USER);
        user.addAccount(account);
        Transaction transaction = new Transaction();
        transaction.Description = "Coffee";
        transaction.Amount = new BigDecimal("3.45");
        transaction.TransactionDate = ZonedDateTime.parse("2015-06-09T16:15:30+01:00[Europe/London]");
        account.addTransaction(transaction);
        userRepository.save(user);

        // Now retrieve
        assertEquals(1, userRepository.count());
        User testuser = userRepository.findOne(user.getNodeId());
        assertEquals(1, testuser.getAccounts().size());
        Account testuser_account = (Account)testuser.getAccounts().toArray()[0];
        assertEquals(1, testuser_account.getTransactions().size());
    }
}

Repositories

public interface AccountRepository extends GraphRepository<Account> {
}

public interface UserRepository extends GraphRepository<User> {
    User findByUsername(String username);
}

build.gradle

group 'co.foo.data'
version '1.0.SNAPSHOT'

def neo4jVersion = "2.1.8"
def springVersion = '4.1.6.RELEASE'
def springSecurityVersion = '4.0.0.RC1'
def springDataNeo4jVersion = '4.0.0.BUILD-SNAPSHOT'

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'maven'
apply plugin: 'ivy-publish'

sourceCompatibility = 1.7
targetCompatibility = 1.7


repositories {
    mavenCentral()
    maven { url "https://m2.neo4j.org/content/repositories/releases" }
    maven { url "https://m2.neo4j.org/content/repositories/snapshots" }
    maven { url "https://repo.spring.io/libs-release" }
    maven { url "https://repo.spring.io/libs-snapshot" }
    maven { url "https://repo.spring.io/snapshot" }
    maven { url "https://repo.spring.io/milestone" }
}

dependencies {
    compile "org.springframework.data:spring-data-neo4j:$springDataNeo4jVersion"

    // Neo4j
    compile "org.neo4j.app:neo4j-server:$neo4jVersion"
    compile "org.springframework.security:spring-security-config:$springSecurityVersion"
    compile "javax.inject:javax.inject:1"

    // Tests
    testCompile group: 'junit', name: 'junit', version: '4.12'
    testCompile "org.springframework:spring-test:$springVersion"
    testCompile group: 'org.neo4j', name: 'neo4j-kernel', version: '$neo4jVersion', classifier: 'tests'
    testCompile group: 'org.neo4j.app', name: 'neo4j-server', version: '$neo4jVersion', classifier: 'tests'

}

I have even tried to follow this project https://github.com/neo4j-examples/neo4j-ogm-university but even that fails to build. Am I going about this the wrong way? Surely something this simple shouldn't be taking me the weeks of effort that I seem to be wasting on this.

Neo4jTestConfiguration

@Configuration
@EnableNeo4jRepositories(basePackages = "co.foo.data.repositories")
@EnableTransactionManagement
@ComponentScan("co.foo.data")
public class Neo4jTestConfiguration extends Neo4jConfiguration {
    @Override
    public SessionFactory getSessionFactory() {
        return new SessionFactory("co.foo.data");
    }

    @Bean
    @Override
    public Neo4jServer neo4jServer() {
        return new RemoteServer("http://localhost:7575");
    }

    @Override
    @Bean
    public Session getSession() throws Exception {
        return super.getSession();
    }
}
Robin Elvin
  • 1,207
  • 12
  • 28
  • What does Neo4jTestConfiguration look like? – Luanne Jul 21 '15 at 15:44
  • 1
    And as you pointed out, the snapshot is a moving target- instead of using M1 please use 4.0.0.RC1 if you need something more stable. – Luanne Jul 21 '15 at 15:47
  • I switched to 4.0.0.RC1 and got a different error injecting userRepository. By commenting out @autowired in my UserDetails class (which is only used by the consuming MVC app) I ended up finding that it was because this class must be named UserRepositoryImpl. Now my tests run but only against a running Neo4j server - InProcessServer doesn't seem available any more? – Robin Elvin Jul 21 '15 at 16:39

1 Answers1

1

The InProcessServer is still available. See SDN 4 - InProcessServer broken in snapshot build which lists the additional dependencies to be added when you're working with RC1 or the snapshot build.

Community
  • 1
  • 1
Luanne
  • 19,145
  • 1
  • 39
  • 51
  • Just to add to this, the NPE you're seeing is due to some bleeding-edge work currently happening to integrate Spring Data REST. You're strongly advised to use RC1 for now. – ATG Jul 22 '15 at 09:25
  • Tried with neo4j-harness 2.2.2 and now getting: Factory method 'neo4jServer' threw exception; nested exception is java.lang.NoClassDefFoundError: org/neo4j/harness/TestServerBuilders – Robin Elvin Jul 22 '15 at 14:35
  • It appears I need to use the non-test neo4j-harness - compile group: 'org.neo4j.test', name: 'neo4j-harness', version: "2.2.3" – Robin Elvin Jul 22 '15 at 15:29