Wicket and Spring

Installing Spring Framework on top of Wicket. Here are a few things to remember...

Wicket and Spring

The Spring Framework offers a couple of things Wicket doesn't. In order to use the Spring Framework in my Wicket web application, I hit a few bumps: shared dependencies, configuration (like Property-> Deployment Assembly, applicationcontext.xml, web.xml and pom.xml), and missing Spring jars, that were not clearly reported as missing in the (eclipse) Console. In this article, I will address all of them individually.


Spring library

The first thing to do is download (and/or copy the maven dependencies) all (yes ALL) spring jars from the maven repository. (You can always throw them away later, but for now, you do not want to be harrassed by missing objects or functions). To help you a little on your way, here is the part of xml for your pom.xml:

<!--  SPRING DEPENDENCIES -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-core</artifactId>
	<version>${spring.version}</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>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>${spring.version}</version>
</dependency>

Make sure to add your Spring version to the pom.xml properties. In this example that would be:

<spring.version>4.3.6.RELEASE</spring.version>


Wicket Libraries

When everything seems to compile properly, it is time to add (at least) two more libraries to make Spring and Wicket play nice together: wicket-spring and wicket-ioc. Here are the dependencies for your pom.xml:


<!-- Wicket & Spring -->
<dependency>
	<groupId>org.apache.wicket</groupId>
	<artifactId>wicket-spring</artifactId>
	<version>${wicket.version}</version>
</dependency>

<dependency>
	<groupId>org.apache.wicket</groupId>
	<artifactId>wicket-ioc</artifactId>
	<version>${wicket.version}</version>
</dependency>

Make sure to add your Spring version to the pom.xml properties. In this example that would be:

<wicket.version.version>6.16.0</wicket.version>


Eclipse: Property -> Deployment Assembly

One thing easily forgotten, when trying to run from eclipse directly, is adding the files that need to be deployed to your project deployment assembly. Since I normally use a Maven pom.xml to compile and copy my code to the necessary locations, this is one of those things I often forget.

Context Listener

Make sure to add the following piece of code to your web.xml

<listener>
<listener-class>
	org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>  

The web.xml is usually located in your src/main/webapp/WEB-INF folder (at least, if you are using Eclipse with the standard folder hierarchy). When this is missing, your Spring Components (Beans) will not be found and instantiated by the Spring framework.

Spring Application Context

You can use one (yes, just one) XML to manage your beans. To save you the trouble of specifying each bean singlehandedly, you can use something called "component-scan", that will do the dirty work for you. The applicationcontext.xml, usually in the same folder as your web.xml. The content looks more or less like:

<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-3.0.xsd
			    http://www.springframework.org/schema/context
			    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
		  
	<context:component-scan base-package="com.youproject.beans" />
</beans>

Obviously, you would replace the base-package with your own beans package(s).

If you don't like using the component-scan at applicationcontext level, you can also decide to create seperate context xmls to manage your component-scanned beans. This can be done, for instance, by adding

@ContextConfiguration(locations={ "/aSeperateContext.xml" })"

to your class files. As you can see, you use an array of xml files as value for locations, so you can add as many as you want. Then there is also a way to fully specify each seperate bean, but why go through all the trouble?

For each bean that you want to autoscan, the only thing you have to add to the class is @Component. Yes, it is that simple. Now Spring recognizes the bean in the component-scan. But what if it is a service, or a repository, or a controller. Should I specify all of them as @Component? Well, yes and no. It is possible, but it is not considered good coding practice to specify all of them as @Component. It is like referring to all your classes as "Object", instead of there specialty. So if you add a service, controller or repository, be sure to instead tag them as @Service, @Controller or @Repository. When you do specify it like this, you do not have to add @Component, because @Service, @Controller and @Repository are all recognized as @Components.
That is a lot of theoretical mumbo-jumbo. So lets put it in practice. Suppose we have a class called Figure we want to have Spring manage for us:

package com.yourproject.beans;

public class Figure{ 
    @Component
    public Figure(){ 
        ... 
        public draw(){
            // do something 
        }
        ... 
}


Next we use this bean in another class, where we leave the creation (and management) of the Figure object to Spring


public class Runner{
    ...
    @Autowire
    Figure figure;
    ...
    public static void main(String[] arguments){
        figure.draw();
    }
    ... 
}


So what did we just do?

  • We defined a Pojo (Plain old java object) called Figure, and added @Component, for the component-scan to find it.

  • Next we added an object, named figure, of class Figure, but did not instantiate it (using new Figure(...)).

  • Then in the execution of class Runner we ask the figure to draw itself using figure.draw().

If we wouldn't be using the Spring framework, you would now get a nullpointer exception, because the variable figure was not assigned a pointer to a Figure object. However, because we used @Autowire, the Spring Framework created it, and will manage it, for us. This is what is also called "inversion of control", specifically "dependency injection".


Final Words


Why is it so important to have Spring do things for you, like creating the objects? You could as easily create it yourself by using new Figure(), right?

Yes, you could.

But that would also mean you have to manage it yourself, creating massive amounts of code only to track and trace the object in case your application is scaled, decide to keep it cached in memory and for how long, and deal with all kinds of security issues that come with creating large enterprise applications / websites. By using the Spring Framework, this is all done for you. It saves you time and hassle over the little (but extremely important) details, and that is what frameworks are all about.

This article was not about explaining Spring to you, but making Spring and Wicket work out a peace treaty and coexist within the same project. If you want to learn more about Spring, you can visit all kinds of websites (including the original website) for exammples and application of the Spring Framework. It covers all kinds of Spring related concepts, like AOP (Aspect Oriented Programming), Web, ORM, and so on and so forth.

But why would you keep on using Wicket, if you can instead use the Spring Framework? The easiest and best answer I can give you is:

Why not?

If you believe in golden hammers, silver bullets, and ponies that crap rainbows, then just one framework will be enough for you. But in practice, have you ever encountered such a pony? I am sure that your pony is currently looking like a hybrid pony-cow-dragon, because that one pony just wasn't good enough for you. Well, good luck rewriting all your code when you try to upgrade to the next version of that framework. A framework is not meant for you to mess around with whenever you feel something is missing. Just accept that you will have to take a different approach. Either code it from scratch, and by that I do not mean abuse features in the framework to mold your own monster of Frankenstein, or try using multiple frameworks, which in the end allows you to use best of both worlds. True, there are downside (and that is what this article is all about), but that is not a valid reason for simply not trying.




The following tools and frameworks were used:
Eclipse Mars, Tomcat 7.0, Java EE 7, Hibernate 5.0.1, Wicket 6.16.0, Spring Framework 4.3.6