Search code examples
spring-data-neo4j-4neo4j-ogm

SDN4 Java configuration and indexes.auto=assert


I'm moved my Neo4j configuration from ogm.properties to Java config.

This is my current config:

@Configuration
@EnableNeo4jRepositories(basePackages = "com.example.domain.repository.neo4j")
@EnableTransactionManagement
public class Neo4jTestConfig {

    @Value("${neo4j.embedded.database.path}")
    private String storeDir;

    @Bean
    public Neo4jTransactionManager transactionManager() throws Exception {
        return new Neo4jTransactionManager(sessionFactory());
    }

    @Bean
    public SessionFactory sessionFactory() {

        Components.setDriver(new EmbeddedDriver(graphDatabaseService()));

        return new SessionFactory("com.example");
    }

    @Bean(destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {

        // @formatter:off
        GraphDatabaseService graphDatabaseService = new GraphDatabaseFactory()
                .newEmbeddedDatabaseBuilder(new File(storeDir))
                .loadPropertiesFromFile(this.getClass().getClassLoader().getResource("neo4j.properties").getPath())
                .newGraphDatabase();
        // @formatter:on

        return graphDatabaseService;
    }

}

Right now I don't know how to properly add OGM property indexes.auto=assert to this configuration.

UPDATED

I have updated my configuration as following:

@Profile("test")
@Configuration
@EnableNeo4jRepositories(basePackages = "com.example.domain.repository.neo4j")
@EnableTransactionManagement
public class Neo4jTestConfig {

    @Value("${neo4j.embedded.database.path}")
    private String storeDir;

    @Bean
    public Neo4jTransactionManager transactionManager() throws Exception {
        return new Neo4jTransactionManager(sessionFactory());
    }

    @Bean
    public SessionFactory sessionFactory() {

        Components.setDriver(new EmbeddedDriver(graphDatabaseService()));

        return new SessionFactory(configuration(), "com.example.domain.model");
    }

    @Bean(destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {

        // @formatter:off
        GraphDatabaseService graphDatabaseService = new GraphDatabaseFactory()
                .newEmbeddedDatabaseBuilder(new File(storeDir))
                .loadPropertiesFromFile(this.getClass().getClassLoader().getResource("neo4j.properties").getPath())
                .newGraphDatabase();
        // @formatter:on

        return graphDatabaseService;
    }

    @Bean
    public org.neo4j.ogm.config.Configuration configuration() {
        org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
        config.autoIndexConfiguration().setAutoIndex("assert");
        return config;
    }

}

but it fails right now with a following exception:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.neo4j.ogm.session.SessionFactory]: Factory method 'sessionFactory' threw exception; nested exception is org.neo4j.ogm.exception.ServiceNotFoundException: Could not load driver: null.
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 80 common frames omitted
Caused by: org.neo4j.ogm.exception.ServiceNotFoundException: Could not load driver: null.
    at org.neo4j.ogm.service.DriverService.load(DriverService.java:57)
    at org.neo4j.ogm.service.DriverService.load(DriverService.java:69)
    at org.neo4j.ogm.service.Components.loadDriver(Components.java:158)
    at org.neo4j.ogm.service.Components.driver(Components.java:104)
    at org.neo4j.ogm.session.SessionFactory.<init>(SessionFactory.java:44)
    at org.neo4j.ogm.session.SessionFactory.<init>(SessionFactory.java:93)
    at com.example.domain.configuration.Neo4jTestConfig.sessionFactory(Neo4jTestConfig.java:37)
    at com.example.domain.configuration.Neo4jTestConfig$$EnhancerBySpringCGLIB$$bde0f39a.CGLIB$sessionFactory$1(<generated>)
    at com.example.domain.configuration.Neo4jTestConfig$$EnhancerBySpringCGLIB$$bde0f39a$$FastClassBySpringCGLIB$$b12a6805.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358)
    at com.example.domain.configuration.Neo4jTestConfig$$EnhancerBySpringCGLIB$$bde0f39a.sessionFactory(<generated>)
    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:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 81 common frames omitted

UPDATED

This is my production configuration based on Bolt Driver:

@Profile("production")
@Configuration
@EnableNeo4jRepositories(basePackages = "com.example.domain.repository.neo4j")
@EnableTransactionManagement
public class Neo4jConfig {

    @Value("${neo4j.server.database.uri}")
    private String serverDatabaseUri;

    @Value("${neo4j.username}")
    private String username;

    @Value("${neo4j.password}")
    private String password;

    @Bean
    public Neo4jTransactionManager transactionManager() throws Exception {
        return new Neo4jTransactionManager(sessionFactory());
    }

    @Bean
    public SessionFactory sessionFactory() {
        Components.setDriver(new BoltDriver());

        return new SessionFactory(configuration(), "com.example.domain.model");
    }

    @Bean
    public org.neo4j.ogm.config.Configuration configuration() {
        org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration();

        // @formatter:off
        configuration
            .autoIndexConfiguration()
                .setAutoIndex("assert");
        configuration
            .driverConfiguration()
                .setCredentials(username, password)
                .setURI(serverDatabaseUri);
        // @formatter:on

        return configuration;
    }

}

This configuration is working fine but I still have issue with Embedded based Java configuration.


Solution

  • This seems to be a blind spot in OGM configuration, so some jumping through hoops is needed.

    There are 2 issues:

    • driver class name must be set, otherwise you will get NPE
    • even when you do that the driver you set by Components.setDriver will get destroyed in new SessionFactory (OGM thinks you are reconfiguring it)

    For embedded db with custom config your sessionFactory() should look as follows:

    org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration();
    // Register your configuration here, this will confuse OGM so the driver you set below won't be destroyed
    Components.configure(configuration);
    
    // Register your driver
    EmbeddedDriver driver = new EmbeddedDriver(graphDatabaseService());
    Components.setDriver(driver);
    
    // Set driver class name so you won't get NPE
    configuration.driverConfiguration().setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver");
    
    // Configure auto index
    configuration.autoIndexConfiguration().setAutoIndex("assert");
    
    return new SessionFactory(configuration, "com.example");
    

    It works, but beware it is a hack. Should be fine for tests though.