Category: Wicket
In this article I’ll describe how to get started with Spring 3.0.5 and the latest apache-wicket version with Maven. Easiest way is to generate your project skeleton using Maven using with the Wicket archetype. See this page how to generate the project using a maven archetype: http://wicket.apache.org/start/quickstart.html. Or just run the command below:
mvn archetype:create -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.4.15 -DgroupId=my.group -DartifactId=my-artifact -DinteractiveMode=false
Add wicket-spring integration dependencies to the Maven pom, see this guide (is a bit outdated): https://cwiki.apache.org/WICKET/spring.html. When using the latest version make sure that you do not include the wicket-spring-anot dependency because it has been merged into the wicket-spring jar. You do need to add the wicket-ioc jar if you are using annotation-based dependency injection in Wicket.
Below is my Maven pom.xml. It includes the Wicket and Spring dependencies but also Jetty dependencies to run the Wicket application.
...
<properties>
<wicket.version>1.4.15</wicket.version>
<jetty.version>6.1.25</jetty.version>
<slf4j.version>1.5.8</slf4j.version>
<log4j.version>1.2.14</log4j.version>
<wicket.spring.version>1.2.6</wicket.spring.version>
<spring.version>3.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<!-- WICKET DEPENDENCIES -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket</artifactId>
<version>${wicket.version}</version>
</dependency>
<!-- SPRING INTEGRATION -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring</artifactId>
<version>${wicket.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-ioc</artifactId>
<version>${wicket.version}</version>
</dependency>
<!-- SPRING -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- LOGGING DEPENDENCIES - LOG4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
<!-- JUNIT DEPENDENCY FOR TESTING -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<!-- JETTY DEPENDENCIES FOR TESTING -->
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-management</artifactId>
<version>${jetty.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<filtering>false</filtering>
<directory>src/main/resources</directory>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<testResources>
<testResource>
<filtering>false</filtering>
<directory>src/test/java</directory>
<includes>
<include>**</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<optimize>true</optimize>
<debug>true</debug>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>${jetty.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.8</version>
<configuration>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
</plugins>
</build>
...
Modify your web.xml to add the Spring and Wicket integration configuration. Previously you had to configure this using the WicketServlet. The prefered way is to use the WicketFilter as shown below:
... <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>WicketFilter</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> </filter> <filter-mapping> <filter-name>WicketFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ...
That is all, no need to defined the applicationClassName because it will be configured in Spring. Now edit your Spring applicationContext.xml, mine is in the WEB-INF. I prefer loading it from the WEB-INF and not from the classpath to avoid name collisions with other Spring xml files on the classpath.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enable annotation scanning. -->
<context:component-scan base-package="my.package" />
<!-- Wicket WebApplication setup -->
<bean id="wicketApplication" class="my.package.WicketApplication"/>
</beans>
You still need to define that you want to use annotation-based injection of your beans in Wicket specific classes. This can be done by adding the SpringComponentInjector to Wicket in the init method of your WicketApplication.
public class WicketApplication extends WebApplication {
/**
* Constructor
*/
public WicketApplication() {
}
@Override
public void init() {
super.init();
addComponentInstantiationListener(new SpringComponentInjector(this));
}
/**
* @see org.apache.wicket.Application#getHomePage()
*/
public Class<HomePage> getHomePage() {
return HomePage.class;
}
}
Example
An example of leveraging the dependency capabilities of Wicket.
import javax.inject.Named;
@Named("mySpringBean")
public class MySpringBean {
public void foo() {
System.err.println("foo");
}
}
Using the bean in your Wicket WebPage:
public class HomePage extends WebPage {
@SpringBean
private MySpringBean mySpringBean;
public HomePage(final PageParameters parameters) {
mySpringBean.foo();
}
...
}
Launching the application
You can launch the application from the commandline using Maven and Jetty. The pom.xml contains all the required Jetty dependencies. Run the following command:
mvn clean jetty:run
This will compile your application, startup a Jetty instance and deploy the application.
Conclusion
IOC integration in Wicket is getting better and easier to configure, but there is room for improvement though. I would prefer to inject my (Spring) managed beans using @Inject. This allowes for a smooth transition to Java EE6 and standardized annotation usage.
Also the init() section can be improved. Why can the ComponentInstantiationListener not be configured in the Spring configuration? This removes the hard dependency on the SpringComponentInjector in the code.
I created a small utility class which allowes me to configure my Wicket apps using Spring like this:
<!-- Wicket WebApplication setup -->
<bean id="wicketApplication" class="com.oudmaijer.wicket.application.ConfigurableWicketApplication">
<property name="homePage" value="my.HomePage"/>
<property name="componentInstantiationListenerType" value="spring"/>
</bean>
This removes the need for a WicketApplication class for each new application. Here is the code:
public class ConfigurableWicketApplication extends WebApplication {
private Class<WebPage> homePage;
private String type;
/**
* Constructor
*/
public ConfigurableWicketApplication() {
}
@Override
public void init() {
super.init();
if( "spring".equalsIgnoreCase(type) ) {
addComponentInstantiationListener(new SpringComponentInjector(this));
}
}
/**
* @see org.apache.wicket.Application#getHomePage()
*/
public Class<WebPage> getHomePage() {
return homePage;
}
public void setHomePage(Class<WebPage> homePage) {
this.homePage = homePage;
}
public void setComponentInstantiationListenerType(String type) {
this.type = type;
}
}