0

Looking for any type of solution here, but I'll propose my thought process along the way.
Working with Spring-Mybatis (over a MySql database) and running it through the Maven embedded jetty plugin.

So it's a pretty simple issue I'm running into and easy to re-create. Basically, Mybatis-Spring requires one to define a Spring bean for the SqlSessionFactoryBean class. This class implements Spring's FactoryBean interface. To wire it up properly, one should supply it, among other things, a DataSource. I reference the JDBC connection details elsewhere in code (for Mybatis-Generator purposes) and would like to keep those details consolidated to one place: property file or something else.

For now, I have a property file, and everything built pretty standard from a Spring point-of-view. I start seeing issues when trying to boot up the Jetty server though, Mybatis-Spring seems to catch itself in a circular dependency.

I cannot say I quite know exactly what causes this circular reference, but I do know the point of failure: I set the JDBC driver to null when trying to call (from an autowired Environment env.getRequiredProperty("jdbc.driver"). It's an NPE (on the env object); the property later gets initialized as I print it out in a PostConstructor.

My understanding of this issue is that since the SqlSessionFactoryBean is a Spring factory bean (does this make it of BFPP type?), that normal autowiring and bean instantiation cannot be assumed to be available. What further solidifies this point is that if I hard-code the JDBC details (or otherwise make the SqlSessionFactoryBean method static), then Jetty is able to start-up just fine and the application works as expected. Obviously hard-coding in the JDBC details is not desired here -- I reference these details in one other spot.

tl;dr
How can I statically access Spring's environment property values, say, in a Factory Bean method? I have tried an @autowired+postconstruct route and a implement-application-context-aware approach; both to no avail.

code samples

public abstract class AbstractMybatisConfig {
    @Autowired
    Environment env;

    String jdbcDriver;
    String jdbcUrl;
    String jdbcUsername;
    String jdbcPassword;

    // if I try the below statement, the env object throws an NPE
    // jdbcDriver = env.getRequiredProperty( "jdbc.driver" );

    @PostConstruct
    protected void postConstruct() {
        jdbcDriver = env.getRequiredProperty( "jdbc.driver" );
        // this statement prints out "com.mysql.jdbc.Driver" as expected
        System.out.println( jdbcDriver );
        jdbcUrl = env.getRequiredProperty( "jdbc.url" );
        jdbcUsername = env.getRequiredProperty( "jdbc.username" );
        jdbcPassword = env.getRequiredProperty( "jdbc.password" );
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName( jdbcDriver );
        // this statement prints out null
        System.out.println( jdbcDriver );
        dataSource.setUrl( jdbcUrl );
        dataSource.setUsername( jdbcUsername );
        dataSource.setPassword( jdbcPassword );
        return dataSource;
    }

    @Bean  // circular reference happens here b/c dataSource() sets null properties
    public SqlSessionFactoryBean sqlSessionFactory() {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource( dataSource() );
        // ...other (unrelated) configuration goes here...
        return sqlSessionFactory;
    }

    private static getJdbcProperties() {
        Properties jdbcProps = new Properties();
        // when this method is invoked, Spring complains the resource does not exist
        // (and it is the same String used to identify this property file in my PropertySources annotation found in another config)
        jdbcProps.load( new ClassPathResource( "classpath:META-INF/properties/mybatis.properties" ).getInputStream() );
        // ...code to grab property values omitted for brevity...
        return jdbcProps
    }
npm622
  • 66
  • 6
  • It'll be hard to help you without you showing us some code. It's hard to picture what you describe and provide an answer or ideas. – Edwin Dalorzo Mar 10 '15 at 14:13
  • Added context: I found [this](http://stackoverflow.com/questions/17512596/contextproperty-placeholder-doesnt-resolve-references) SO question which seems nearly identical to mine. I've tried following the setup and resolution found here (mainly, creating a MapperScannerConfigurer instead of relying on the @MapperScan annotation Mybatis-Spring gives you), but to no avail. My issue lies with SqlSessionFactory being a FactoryBean, and DataSource bean not having access to Properties when its called to be instantiated. – npm622 Mar 11 '15 at 21:37
  • Right on @Edwin-Dalorzo, thanks for the pointer and for looking. I included the main problem file above. Let me know if anything else is unclear. – npm622 Mar 11 '15 at 21:38
  • I used Configuration annotation to load the properties and then Autowired the properties to the class, if you think you will like to take a look at a solution like this, let me know – Ian Lim Apr 03 '15 at 02:42

0 Answers0