I like annotations and loathe oodles of XML. To get Spring and Hibernate work with those nice @Transactional, @Service and @Entity annotations by scanning your classpath, the following Spring configuration files should do the trick for your default Wicket Quickstart project (provided you add the necessary Spring and Hibernate dependencies to your setup). Figuring this out took me an evening (especially getting the scanners and @Transactional support up and running), so here’s my setup such that you don’t have to spend the evening yourself:
<?xml version="1.0" encoding="UTF-8"?> <beans default-autowire="autodetect" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean id="wicketApplication" class="com.mycompany.WicketApplication" /> <bean id="placeholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="ignoreUnresolvablePlaceholders" value="false" /> <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> <property name="ignoreResourceNotFound" value="false" /> <property name="locations"> <list> <value>classpath*:/application.properties</value> </list> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>${jdbc.driver}</value> </property> <property name="url"> <value>${jdbc.url}</value> </property> <property name="username"> <value>${jdbc.username}</value> </property> <property name="password"> <value>${jdbc.password}</value> </property> </bean> <tx:annotation-driven transaction-manager="txManager" /> <!-- setup transaction manager --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="sessionFactory" /> </property> </bean> <bean id="interceptor" class="com.mycompany.hibernate.HibernateInterceptor"> </bean> <!-- hibernate session factory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.hbm2ddl.auto">create</prop> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.connection.pool_size">5</prop> <prop key="hibernate.current_session_context_class">thread</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cglib.use_reflection_optimizer">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.hibernate.cache.use_query_cache">true</prop> </props> </property> <property name="entityInterceptor"> <ref bean="interceptor" /> </property> <property name="packagesToScan"> <list> <value>com.mycompany.entities</value> </list> </property> </bean> <context:component-scan base-package="com.mycompany" /> </beans>
This setup requires one additional file—application.properties:
jdbc.driver=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:mem:phonebook jdbc.username=sa jdbc.password= hibernate.dialect=org.hibernate.dialect.HSQLDialect
This will configure Spring and Hibernate to use an in memory HSQLDB database. You’ll need to download the HSQLDB jar for this as well. Or you can configure this to use mysql, oracle, sqlserver or postgresql. Put these files in src/main/resources.
I have to add the following dependencies to my quickstart pom to get HSQLDB, Hibernate and Spring working:
<dependency> <groupId>org.apache.wicket</groupId> <artifactId>wicket-spring-annot</artifactId> <version>${wicket.version}</version> </dependency> <!-- HIBERNATE DEPENDENCIES --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.2.6.ga</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>ejb3-persistence</artifactId> <version>3.3.2.Beta1</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.4.0.GA</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.6</version> <scope>compile</scope> </dependency> <!-- DATABASE DEPENDENCIES - HSQLDB --> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency>
You’ll also have to configure the web.xml file to enable Spring and Spring’s OpenSessionInView filter.:
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <display-name>wicket-spring-hibernate</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>opensessioninview</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter> <filter-name>wicket-spring-hibernate</filter-name> <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> <init-param> <param-name>applicationFactoryClassName</param-name> <param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value> </init-param> <init-param> <param-name>applicationClassName</param-name> <param-value>com.mycompany.WicketApplication</param-value> </init-param> </filter> <filter-mapping> <filter-name>opensessioninview</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>wicket-spring-hibernate</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
The world is your oister!
Cool stuff, bookmarked! This will certainly come in handy some day ;)
Could somebody make this to a maven archetype? That would be awesome!
Cheers, Stefan
Comment by Stefan F — June 5, 2009 @ 10:54 am
is the
applicationClassName
com.mycompany.WicketApplication
really necessary ? in my configuration it works without it
im still working with wicket 1.4, is http://cwiki.apache.org/WICKET/spring.html#Spring-AnnotationbasedApproach still the way to use spring beans inside page (and other) wicket classes ?
Comment by Michael Lange — June 5, 2009 @ 4:13 pm
Nice, haven’t got your example working yet using 1.4-rc6;
- for wicket-spring-annot version doesn’t work, seems like there are only versions for the 1.3 branch, so setting the version to 1.3.6 instead of ${wicket.version} should do the trick
- something seems to have gone wrong with the interceptor bean:
replacing the com.mycompany by org.springframework.orm.hibernate3 does not seem to be enough so guess something else went missing
finally, it is not mentioned the first file is applicationContext.xml
Comment by Antoine — July 13, 2009 @ 11:47 pm
Hello Antoine, I am having similar problems. Did you ever get this to working?
Comment by David — August 5, 2009 @ 12:53 am
what is the name and path of the first file you created? it’s very difficult for a newbie to figure it out.
Comment by buddy — August 19, 2009 @ 12:03 am
Great setup tutorial, tobad it doesn’t work! :-(
Comment by Simon — October 18, 2009 @ 9:30 pm
For those of you that want to work with Wicket 1.4.6:
There dependency on “wicket-spring-annot” is no longer required. Simply remove it. This package was used only in Wicket 1.3.
Its purpose was to add annotation support due to the fact that Wicket 1.3 could run on JDK 1.4, which did not have annotations. Starting with Wicket 1.4, JDK 5 (or later) is required and therefore the annotation support is not needed.
Remove the on that and it should work with Wicket 1.4 as well.
Comment by Alexandros Karypidis — February 10, 2010 @ 4:41 pm
I have been trying this for a while now but I can’t get it to work. I removed hibernate3-maven-plugin from the pom and copied the above code (with corrections). The sessionFactory and the interceptor have a cyclic dependency:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ’sessionFactory’ defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean ‘interceptor’ while setting bean property ‘entityInterceptor’; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘interceptor’ defined in class path resource [applicationContext.xml]: Unsatisfied dependency expressed through bean property ’sessionFactory’: : Error creating bean with name ’sessionFactory’: FactoryBean which is currently in creation returned null from getObject; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ’sessionFactory’: FactoryBean which is currently in creation returned null from getObject
I have searched a lot on the Spring forum and seen some advice on cyclic dependencies, like BeanPostProcessor, but I can’t get it to work. Does anyone here have the same experience and have solved the problem?
Comment by Erik — March 26, 2010 @ 3:02 pm
@Erik: Do not use an interceptor. Simple as that; you’ll be much better off using event listeners. If you really have to use the interceptor (which quickly becomes a god-like class) then you can always implement ApplicationContextAware interface and manually fetch beans from that.
Btw, sounds a bit strange that your interceptor would have to have a sessionFactory reference. Perhaps its there by mistake?
Comment by Joonas — April 6, 2010 @ 2:09 pm