6

neo4jDatabase() is fine but environment is always null in graphDatabaseService()... how/why?

@Configuration
@PropertySource("classpath:/neo4j.properties")
@EnableNeo4jRepositories("reservation.repository.neo4j")
public class Neo4jConfig extends Neo4jConfiguration {

    @Inject
    Environment environment;

    @Bean(initMethod = "setupDb")
    public Neo4jDatabase neo4jDatabase() {
        // Environment fine here...
        return new Neo4jDatabase(this.environment.getProperty("data.file.path"));
    }

    @Bean(destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {
        if (environment == null) {
            // Always gets here for some reason...why?
            return new EmbeddedGraphDatabase("/Temp/neo4j/database");
        } else {
            return new EmbeddedGraphDatabase(this.environment.getProperty("database.path"));
        }
    }
}

Versions: Spring 3.2.0.RELEASE, spring-data-neo4j 2.1.0.RELEASE.

chrisjleu
  • 4,329
  • 7
  • 42
  • 55
  • Hi, have you tried to use 'this' in your null check? "if (this.environment == null)". By doing this, you'll match the other uses of that object in your class. Once sync'd, you can start unraveling the problem (i.e. using Spring 3.1). – Tony R Feb 08 '13 at 04:09
  • Is this code being used in a web app? Are you sure its not a case of having two application contexts, one with the environment configured and one not? – BenG Mar 01 '13 at 13:50

2 Answers2

1

In case anyone else is having the same issue - the following worked for me:

@Configuration
@PropertySource("classpath:neo4j.properties")
@EnableNeo4jRepositories(basePackages = "com.mydomain.neo4j.repo")
public class Neo4jConfig 
{
    @Autowired
    Environment environment;

    @Bean(name="graphDatabaseService", destroyMethod = "shutdown")
    public GraphDatabaseService getGraphDatabaseService() 
    {
        // any custom graph db initialization
        return new EmbeddedGraphDatabase(this.environment.getProperty("database.path"));
    }
}

NOTE: I am NOT extending Neo4jConfiguration. It just tuns into a spaghetti of Autowired dependencies with the Environment member variable never set by the time it's needed for the initialization of the graphDatabaseService. You can get it to work using a @PostConstruct but you end up with a bunch of NotInTransactionException's. I didn't have time to dig into why - instead, in your main AppConfig class, you simply import your custom Neo4j configuration AS WELL AS the base abstract Neo4j configuration class. Essentially, you're doing in code what the XML configuration would do.

@Configuration
@Import({Neo4jConfig.class, Neo4jConfiguration.class})
@ComponentScan(basePackages = {"com.mydomain"}, excludeFilters = @Filter({Controller.class, Configuration.class}))
public class MainConfig
{
    // any other configuration you have
}
Matt Wielbut
  • 2,584
  • 25
  • 29
0

The answer from mwielbut is partly correct but it's not 100% sufficient because one would've to specify the base package for domain classes as well.

Check the following source code for complete working implementation

The property file load

package com.example.analytics.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
@ConfigurationProperties(locations = "classpath:application.yml", ignoreUnknownFields = false, prefix = "neo4j")
public class DatabaseConnectionProperties {

    private static final Logger LOG = LoggerFactory.getLogger(DatabaseConnectionProperties.class);

    private String uri;
    private String username;
    private String password;

    public String getUri() {
        return uri;
    }

    public void setUri(final String uri) {
        this.uri = uri;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(final String password) {
        this.password = password;
    }

    @PostConstruct
    public void uponConstruction(){
        LOG.debug("Construction of the class {} has been completed!", this.getClass().getName());
        LOG.debug("Database connection properties have been loaded from application.yml in the classpath");
        LOG.debug("Initialised URI: {} , username: {}, password: {}", uri, username, password);
    }
}

Database connection configuration

package com.example.analytics.config;


import org.neo4j.graphdb.GraphDatabaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.rest.SpringCypherRestGraphDatabase;

@Configuration
@ComponentScan(basePackages = "com.example.analytics.config")
@EnableConfigurationProperties(DatabaseConnectionProperties.class)
public class DatabaseConnectionConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(DatabaseConnectionConfiguration.class);

    @Autowired
    private DatabaseConnectionProperties databaseConnectionProperties;

    /**
     * Connect to the remote instance of Neo4j through its REST interface
     * @return
     */
    @Bean(name="graphDatabaseService", destroyMethod = "shutdown")
    public GraphDatabaseService graphDatabaseService() {

        LOG.debug("Creating the graph database service with credentials");

        final String uri = databaseConnectionProperties.getUri();
        final String username = databaseConnectionProperties.getUsername();
        final String password = databaseConnectionProperties.getPassword();

        LOG.debug("URI: {}", uri);
        LOG.debug("Username: {}", username);
        LOG.debug("Password: {}", password);
        final SpringCypherRestGraphDatabase graphDatabase = new SpringCypherRestGraphDatabase(uri, username, password);
        LOG.debug("Graph database instance has been successfully created!");
        return graphDatabase;
    }

}

Main configuration

package com.example.analytics.config;

import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableNeo4jRepositories(basePackages = "com.example.analytics.repository")
@EnableTransactionManagement(mode = AdviceMode.PROXY)
@Import({DatabaseConnectionConfiguration.class})
public class MainConfiguration extends Neo4jConfiguration {

    public MainConfiguration() {
        setBasePackage("com.example.analytics.model");
    }
}

Main application

package com.example.analytics;

import com.example.analytics.config.DatabaseConnectionConfiguration;
import com.example.analytics.config.MainConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import javax.annotation.PostConstruct;

@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.example.analytics"})
@Import(MainConfiguration.class)
public class AnalyticsApplication {

    private static final Logger LOG = LoggerFactory.getLogger(DatabaseConnectionConfiguration.class);

    public static void main(final String[] args) {

        SpringApplication.run(AnalyticsApplication.class, args);
    }

    @PostConstruct
    public void uponConstruction() {
        LOG.debug("Construction of the class {} has been completed!", this.getClass().getName());
    }
}
Community
  • 1
  • 1
Viswanath
  • 1,413
  • 13
  • 25