Announcement Announcement Module
Collapse
No announcement yet.
How to store sample data Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to store sample data

    In RubyOnRails when doing development one could store basic data in a boot script (so when ever an application booted it would have some thing to ply with)

    What is a good way to populate a database with dummy entries in spring roo? Assuming that one is using persistence technologies provided by Spring Roo only (which seems to me is hibernate most of the time)

  • #2
    Not an "official" technique, but my normal approach is to write a DataSeeder.java class that has a method annotated with @PostConstruct (http://java.sun.com/javaee/5/docs/ap...Construct.html). Spring detects this and invokes the method at startup time. In the body of the method I use an approach of "if (Person.countPersons() > 0) { /* do stuff */ }". It's simple and it works.

    Comment


    • #3
      Of course your data seeder class also needs to be a Spring bean, e.g. have the @Component annotation on it, or be explicitly created by a <bean> element in the Spring config file, etc.

      Comment


      • #4
        dbunit maven plugin

        Other option could be integrate org.codehaus.mojo:dbunit-maven-plugin.

        This Maven plugin allow both default (initial production values) and sample (initial test values) data defined on XML format. You can define between a lot of insertion modes:

        * insert if not exists and fails if exists
        * insert if not exists or update if exists
        * ...

        This approach is database independent by persistence systems as Hibernate.

        Comment


        • #5
          Good idea. I guess in a production environment, when Maven is not an option, you could use the DBUnit API direct from within your app in order to load the desired production data.

          Comment


          • #6
            Hi, I am just trying this method, however I can't get it to work. No error or whatsoever, it just silently doesn't do anything

            Here's the class

            Code:
            @Component
            public class DataSeeder {
            
            	@PostConstruct
            	public void seedData() {
            		if (0 == Entity1.countEntity1() && 0 == Entity2.countEntity2()) {
            			Entity1 e = new Entity1();
            			e1.setName("E1 Name");
            			
            			Entity2 e2 = new Entity2();
            			e2.setName("E2 Name");
            			e2.setEntity1(e1);
            			e2.setCreatedOn(new Date());
            			e2.persist();
            		}
            	}
            }
            On debugging mode I can see the method is executed, and I've activated hibernate.show_sql which shows the queries for the counts at the beggining, but no inserts.

            After that, the server starts fine, just no initial data is loaded...

            Is there anything I'm missing?

            Comment


            • #7
              Trying marking it @Transactional.

              Comment


              • #8
                Hi, thanks for your help.
                Unfortunately it didn't work out, and it's still not persisting the objects into the database :/

                Comment


                • #9
                  Make a public no-arg constructor in your class and console output that it is even being loaded. Also check the <context:component-scan base-package="some.package">bean definition in src/main/resources/META-INF/spring/applicationContext.xml and verify your class is under the base-package specified. If necessary move your startup logic to the constructor (once you can see it is executing) instead of @PostConstructor. It should work; we do it all the time....

                  Comment


                  • #10
                    Me too

                    I'm having the same problem as jeduan. Here's my script:

                    Code:
                    // Spring Roo 1.0.1.RELEASE [rev 601] log opened at 2010-02-21 10:14:07
                    project --topLevelPackage load
                    persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY 
                    entity --class ~.Thing
                    controller all --package ~.web
                    Here's the SQL logging in persistence.xml:
                    Code:
                    ...
                    <persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
                        <provider>org.hibernate.ejb.HibernatePersistence</provider>
                        <properties>
                            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
                                <property name="hibernate.hbm2ddl.auto" value="create"/>
                            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
                            <property name="hibernate.show_sql" value="true"/>
                        </properties>
                    </persistence-unit>
                    And here's my loader:
                    Code:
                    import javax.annotation.PostConstruct;
                    
                    import org.springframework.stereotype.Component;
                    import org.springframework.transaction.annotation.Transactional;
                    
                    @Component
                    @Transactional
                    public class Loader {
                        
                        public Loader() {
                            System.out.println("Constructing...");
                            new Thing().persist();
                        }
                    
                        @PostConstruct
                        private void load() {
                            System.out.println("Loading...");
                            new Thing().persist();
                        }
                    }
                    Here's the console output during mvn jetty:run (leaving out irrelevant stuff about Jetty, Log4J, URL rewriting, etc):

                    Code:
                    ...
                    [INFO] Starting jetty 6.1.10 ...
                    ...
                    2010-02-21 10:27:58.665:/load:INFO:  Initializing Spring root WebApplicationContext
                    ...
                    Constructing...
                    Loading...
                    ...
                    [INFO] Started Jetty Server
                    In other words, there are no inserts happening. If you go to the home page and submit the "Create new Thing" form, the console outputs this:

                    Code:
                    Hibernate: insert into thing (id, version) values (null, ?)
                    Hibernate: call identity()
                    Hibernate: select thing0_.id as id0_0_, thing0_.version as version0_0_ from thing thing0_ where thing0_.id=?
                    So the inserting and logging is working when it's not the Loader doing the inserting.

                    What are we doing wrong?

                    P.S. Seems like other people are having the same problem; is there anything to their claim that @PostConstruct can't be used in a transactional context?
                    Last edited by Andrew Swan; Feb 20th, 2010, 06:48 PM. Reason: Added blog link

                    Comment


                    • #11
                      I can confirm @Transactional does not work with @PostConstruct. I must confess I haven't tried this technique for some time and was unaware it no longer worked. Debug messages confirm the reason it fails:

                      Code:
                      [main] DEBUG org.springframework.transaction.aspectj.AnnotationTransactionAspect - Skipping transactional joinpoint [load.Loader.afterPropertiesSet] because no transaction manager has been configured
                      No amount of setting depends-on and injecting the PlatformTransactionManager in would assist. Not to worry, there's another way.

                      My new advice is to implement ApplicationListener<ContextLoadedEvent> and do the logic there. A sample (and fully tested!) class is below:

                      Code:
                      package load;
                      
                      import org.springframework.context.ApplicationListener;
                      import org.springframework.context.event.ContextRefreshedEvent;
                      import org.springframework.stereotype.Component;
                      import org.springframework.transaction.annotation.Transactional;
                      
                      @Component
                      public class Loader implements ApplicationListener<ContextRefreshedEvent>{
                      
                              @Override
                              @Transactional
                              public void onApplicationEvent(ContextRefreshedEvent event) {
                                  System.out.println("before: " + Thing.countThings());
                                  new Thing().persist();
                                  System.out.println("after: " + Thing.countThings());
                              }
                      }
                      HTH
                      Ben

                      Comment


                      • #12
                        I can confirm that this method solves all the prior issues we had. Thanks a lot.

                        Comment


                        • #13
                          OK, this is weird

                          Ben, I tried what you suggested, but the ContextRefreshedEvent gets fired twice; once when the app starts up:

                          Code:
                          2010-02-23 12:41:14,208 [main] DEBUG blah.DataSeeder - Loading system data...
                          2010-02-23 12:41:14,520 [main] DEBUG blah.DataSeeder - Loading test data...
                          2010-02-23 12:41:14.254:/amgr:INFO:  org.tuckey.web.filters.urlrewrite.UrlRewriteFilter INFO: loaded (conf ok)
                          2010-02-23 12:41:14.301::INFO:  Started [email protected]:8080
                          2010-02-23 12:41:14.348::INFO:  Started [email protected]:8443
                          [INFO] Started Jetty Server
                          [INFO] Starting scanner at interval of 5 seconds.
                          ... and once when the first request comes in (some 19 seconds later):
                          Code:
                          2010-02-23 12:41:33.855:/amgr:INFO:  Initializing Spring FrameworkServlet 'amgr'
                          2010-02-23 12:41:34,223 [btpool0-2] WARN  org.apache.tiles.context.ChainedTilesRequestContextFactory - Cannot find TilesRequestContextFactory class or
                          g.apache.tiles.portlet.context.PortletTilesRequestContextFactory
                          2010-02-23 12:41:34,348 [btpool0-2] DEBUG blah.DataSeeder - Loading system data...
                          2010-02-23 12:41:34,364 [btpool0-2] DEBUG blah.DataSeeder - Loading test data...
                          I tried listening for the ContextStartedEvent instead, but that never fires! I see that someone else has observed both these phenomena. There's no open JIRA issues relating to the ContextStartedEvent. What are we doing wrong?

                          I guess I can work around it with a static boolean "loaded" flag in my DataSeeder class, but that seems like an ugly hack.

                          Comment


                          • #14
                            We had the same issue, ultimately we are using maven dbunit plugin to get the data loaded. This plugin is used in Appfuse.

                            -Irshad
                            Last edited by Andrew Swan; Oct 16th, 2011, 05:23 PM. Reason: Fixed autocorrect error

                            Comment


                            • #15
                              I came across this issue in a project recently and ended up using the @PostInitializer mentioned here

                              Comment

                              Working...
                              X