Announcement Announcement Module
Collapse
No announcement yet.
Java Config Support for Repository Configuration? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Java Config Support for Repository Configuration?

    I'm just curious if there is a Java-based config alternative to using the following SDG XML config?

    Code:
    <datagraph:repositories base-package="org.mycompany.graph" />
    I'm already getting around the <datagraph:config /> XML by importing the Neo4jConfiguration class into one of my @Configuration class:

    Code:
    @Configuration
    @Import({ Neo4jConfiguration.class })
    @ImportResource("META-INF/spring/graphRepository-config.xml")
    public class AppConfig
    {
        ...
    }
    As you can see, I'm forced to carry around "META-INF/spring/graphRepository-config.xml" just for the one line of repository configuration.

    **NOTE: I'm not opposed to XML config, just am curious if there is an alternative.**

  • #2
    Just from the top of my head, it should be enough to declare per domain repository

    @Bean
    public MyDomainObjectRepository myDomainObjectRepository(GraphDatabaseContext ctx) {
    GraphRepositoryFactoryBean factoryBean=new GraphRepositoryFactoryBean();
    factoryBean.setGraphDatabaseContext(ctx);
    factoryBean.setRepositoryInterface(MyDomainObjectR epository.class);
    // if needed
    // factoryBean.setCustomImplementation(new CustomImplementation()); // or bean thereof
    return factoryBean.getObject();
    }

    don't know how to do the package scan in the java config

    with spring 3.1 we can use namespace config in the JavaConfig as well, it certainly gets easier then.

    Cheers

    Michael

    Comment


    • #3
      I can't speak for the DataGraph team particularly, but we are currently at work on providing a consistent approach for java-based equivalents for Spring XML namespace elements in Spring 3.1 M2. Stay tuned to the blog for news on that, and in the meantime, I would suggest raising an issue against SDG to this effect. "Provide @Configuration alternatives for <datagraph:*/> elements" would do as a subject line.

      With regard to Michael's suggestion on using a FactoryBean within a @Bean method, this is generally discouraged - it is awkward having to call the getObject() method, and means that the FactoryBean instance itself will not go through the normal container lifecycle. For example, if the FactoryBean implements InitializingBean, you'll need to call afterPropertiesSet() yourself - more awkwardness. It is acknowledged that this may be the only way to get it done in certain cases, but just furthers the need for SDG to provide @Configuration-friendly alternatives.

      For one example of a 'more friendly' approach, take a look at what we've done with Spring's support for Hibernate in the forthcoming M2 release. As you may be familiar, Spring has always shipped FactoryBeans for Hibernate SessionFactory configuration - LocalSessionFactoryBean and AnnotationSessionFactoryBean, particularly.

      In 3.1 M2, we've refactored these types to extend from more fundamental "SessionFactoryBuilder" types that are easy to use within @Bean methods. The FactoryBean types remain, but only for use within XML-based configuration.

      Take a look at the JavaDoc on these two types for details:

      https://github.com/cbeams/spring-fra...ryBuilder.java

      https://github.com/cbeams/spring-fra...ctoryBean.java

      Comment


      • #4
        Chris,

        thanks so much for the pointers, I think we'll wait for the 3.1 support for that.

        Michael

        Comment


        • #5
          Now that Spring 3.1 is coming into it's own at milestone 2, has the SDG team investigated adding these facilities in 1.1.0?

          Comment


          • #6
            We discussed that and are not so sure about pulling everyone who uses Spring Data projects to 3.1.M2, but an idea was to use profiles and have some support classes in there that are built against 3.1.M2.

            Cheers

            Michael

            Comment


            • #7
              I've tried registering the FactoryBean within a @Bean method, but I'm finding that my @Autowired property within my @Configuration class is still null at the time when the FactoryBean is being registered within the @Bean method. My understanding was the @Autowired properties would be injected right after the construction of my @Configuration class, but the FactoryBean must be throwing off that sequence in the ApplicationContext lifecycle.

              Here's the debug from application startup:

              Code:
              2011-07-04 08:12:34,636 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating shared instance of singleton bean 'repositoryConfig'
              2011-07-04 08:12:34,636 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating instance of bean 'repositoryConfig'
              2011-07-04 08:12:34,637 DEBUG [org.springframework.beans.factory.annotation.InjectionMetadata] - Found injected element on class [org.mycompany.note.config.RepositoryConfig$$EnhancerByCGLIB$$c1c65d77]: AutowiredFieldElement for private org.springframework.data.graph.neo4j.support.GraphDatabaseContext org.mycompany.note.config.RepositoryConfig.graphDatabaseContext
              2011-07-04 08:12:34,637 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Eagerly caching bean 'repositoryConfig' to allow for resolving potential circular references
              2011-07-04 08:12:34,642 DEBUG [org.springframework.beans.factory.annotation.InjectionMetadata] - Processing injected method of bean 'repositoryConfig': AutowiredFieldElement for private org.springframework.data.graph.neo4j.support.GraphDatabaseContext org.mycompany.note.config.RepositoryConfig.graphDatabaseContext
              2011-07-04 08:12:34,644 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating shared instance of singleton bean 'aclRepoFactoryBean'
              2011-07-04 08:12:34,645 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Ignoring bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'aclRepoFactoryBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
              2011-07-04 08:12:34,645 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning eagerly cached instance of singleton bean 'repositoryConfig' that is not fully initialized yet - a consequence of a circular reference
              2011-07-04 08:12:34,673 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating shared instance of singleton bean 'graphDatabaseContext'
              2011-07-04 08:12:34,674 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Creating instance of bean 'graphDatabaseContext'
              ...
              2011-07-04 08:12:36,347 DEBUG [org.springframework.beans.factory.support.DisposableBeanAdapter] - Invoking destroy() on bean with name 'localAppConfig'
              2011-07-04 08:12:36,349 ERROR [org.springframework.test.context.TestContextManager] - Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@24c4a3] to prepare test instance [org.mycompany.note.common.AclRepositoryTests@13f3045]
              java.lang.IllegalStateException: Failed to load ApplicationContext
              	at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:181)
              	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
              	at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
              	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
              	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:220)
              	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:301)
              	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
              	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:303)
              	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
              	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
              	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
              	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
              	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
              	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
              	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
              	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
              	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
              	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
              	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
              	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
              	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
              	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
              	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
              	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
              	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
              Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name aclRepoFactoryBean' defined in class org.mycompany.note.config.RepositoryConfig: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: "GraphDatabaseContext must not be null!"
              	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
              	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
              	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
              	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
              	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
              	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
              	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
              	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:563)
              	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
              	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
              	at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:73)
              	at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:128)
              	at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:172)
              	... 24 more
              Caused by: java.lang.IllegalArgumentException: GraphDatabaseContext must not be null!
              	at org.springframework.util.Assert.notNull(Assert.java:112)
              	at org.springframework.data.graph.neo4j.repository.GraphRepositoryFactoryBean.afterPropertiesSet(GraphRepositoryFactoryBean.java:54)
              	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1479)
              	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
              	... 36 more
              Can anyone offer any suggestions on how to register a FactoryBean as a @Bean within a @Configuration class?
              Last edited by jzcfk9; Jul 4th, 2011, 07:34 AM.

              Comment


              • #8
                @jzcfk9,

                I'll need to see some code to address this properly. Please paste the relevant @Configuration bits here, or feel free to submit a project that reproduces the issue by following these instructions: https://github.com/SpringSource/spri...-issues#readme

                Comment


                • #9
                  Rather than posting my entire project, I hope this small contrived example will be sufficient to simulate what I'm refering to.

                  Comment


                  • #10
                    @jzcfk9,

                    Thanks for the project. I've confirmed that this is in fact an issue, but need to investigate further as to a solution. I've created https://jira.springsource.org/browse/SPR-8514 to track the issue; please put a watch on it, as I won't update this forum thread further.

                    As a workaround in the meantime, consider changing the signature of your FactoryBean-returning @Bean method to be the actual target object type and calling factoryBean.getObject() to return it directly. You may need to call afterPropertiesSet() and other lifecycle methods.

                    Comment


                    • #11
                      Oliver Gierke and I also discussed adding support for @Configuration based repository factories but this means that we have to do some larger changes to the build as we want the spring data projects not to depend on Spring 3.1. but rather be usable with 3.0 too. So that will be about adding 3.1. support classes and building + testing everything against 3.1. and then against 3.0.5 and packaging and deploying with 3.0 dependencies.

                      It might take a while for that to get done though (we're also looking into converting the maven builds into gradle builds anyway).

                      Cheers

                      Michael

                      Comment


                      • #12
                        BTW for anyone who may be interested in this, I was able to register a BeanPostProcessor that is BeanFactoryAware in the application context; and this allowed me to auto detect all repositories (through ClassPathScanning) and register them in the ApplicationContext. This is all without any XML. This will work for the short term until DATACMNS-47 is resolved.

                        Comment

                        Working...
                        X