You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

Table of contents

List of major changes from 1.2 to 2.0 (under development)

See the changelist for minor changes and bug fixes.

IMPORTANT - SILENT FAILURES

Application.get() and Session.get() will return null when threadlocals are not set instead of throwing an NPE

JSE 5

Wicket 2.0 requires Java 5. The main reason behind making this change is that we felt Wicket 1.2 is good enough to last a long time, and we didn't want to miss out any longer on parameterized types (generics).

Generics/ Parameterized types

Wicket re-implemented models and components to take advantage of generics.
for instance:

ListView numbers = new ListView<String>(group, "numbers", NUMBERS)
{
	@Override
	protected void populateItem(ListItem<String> item)
	{
		new Radio<String>(item, "radio", item.getModel());
		new Label(item, "number", item.getModelObject());
	};
};

list views will now only accept models that produce lists. The above example it is a list with Strings (declared like <List<String>>). Also, item.getModelObject produces a string directly.

The increased type safety allows you make your client code more robust, and it also allows you to develop components that have a 'tighter' interface to the outside world. E.g. you can now specify that a component only works with models that produce Person objects.

There are a couple of minor enhancements we did or plan to do, like using enums instead of wicket.util.lang.EnumeratedType (which theoretically might have serialization issues) and enhanced for loops etc.

Constructor change

Component#add is removed in favor of passing in the parent using the component's constructor. So instead of using Component#add to build the component hierarchy, you need to pass in the proper parents to reflect the hierarchy. This change is usually referred to as the 'constructor change' in discussions on the mailing lists and the IRC channel.

Instead of:

MyLink link = new MyLink("link");
add(link);
link.add(new Label("myLabel", "myText"));

you now do:

MyLink link = new MyLink(this, "link");
new Label(link, "myLabel", "myText");

The greatest advantage of passing in parents in the constructor instead of having method add, is that the full component hierarchy is known at construction time. This allows Wicket to know the exact coupling of the component to markup elements. It is very convenient for 'rich' components (you typically need to know the path/ unique id of a component when you work with javascript) but also allows you to do things like directly manipulating the tag's attributes (attribute modifiers won't be needed as much) and allows Wicket to fail early and with better information if the component hierarchy does not match the hierarchy as declared in the markup file(s).

Replacing components

Before the constructor change, you would call Component#replace to replace a component with another one. This method does not exist anymore. Instead, you either create a new component with the same parent and id (so the hierarchy will match; the new component is then the current), or you call Component#reAttach to set it as the current one.

If you look at

wicket.examples.template.TemplatePage

, in 1.2, the code to replace a banner looked like this:

add(new Link("changeAdLink")
{

{panel}
  public void onClick()
  {
    if (currentBanner.getClass() == Banner1.class)
    {
      TemplatePage.this.replace(currentBanner = new Banner2("ad"));
    }
    else
    {
      TemplatePage.this.replace(currentBanner = new Banner1("ad"));
    }
  }
{panel}
});

After the constructor change, the code with the same effect, looks like this:

new Link(this, "changeAdLink")
{
{panel}
  public void onClick()
  {
    if (currentBanner.getClass() == Banner1.class)
    {
      new Banner2(TemplatePage.this, "ad");
    }
    else
    {
      new Banner1(TemplatePage.this, "ad");
    }
  }
{panel}
};

Alternatively, this could be rewritten like:

new Link(this, &quot;changeAdLink&quot;)
{
{panel}
  public void onClick()
  {
    if (currentBanner == banner1)
    {
      currentBanner = banner2;
    }
    else
    {
      currentBanner = banner1;
    }
    currentBanner.reAttach();
  }
{panel}
};

Where we would hold references to banner1 and banner2 in the page after we created them:

banner2 = new Banner2(this, &quot;ad&quot;);
currentBanner = banner1 = new Banner1(this, &quot;ad&quot;);

Note that as we created banner1 after banner2 here, banner1 will be the current one.

Replaced EnumeratedType by JSE 5's enum

The enums that were previously instances of EnumeratedType are accessed slightly different. That is because the enum elements are part of the enum definition; they are not declared outside of it like was the case with the EnumeratedTypes. For instance, instead of:

IRequestCycleSettings.ONE_PASS_RENDER

you now have to access that same element as:

IRequestCycleSettings.RenderStrategy.ONE_PASS_RENDER

or

import wicket.settings.IRequestCycleSettings.RenderStrategy;
...
RenderStrategy.ONE_PASS_RENDER

Opened up for covariance

Covariance, which comes with JDK 5, triggered us to remove final from some methods where covariance typically is nice to use, like Component.getSession and Component.getApplication. Thus, you can now define

@Override
public LibrarySession getSession()
{
{panel}
  return (LibrarySession)super.getSession();
{panel}
}

in a base class and then use

LibrarySession libSession = getSession();

Or - probably even more useful:

public final class LibrarySession extends WebSession
{
	public static LibrarySession get()
	{
		return (LibrarySession)Session.get();
	}
...

and

LibrarySession.get().isSignedIn();

Filter instead of a Servlet

Wicket no longer uses a Servlet as it's main option. In fact, using a servlet filter (WicketFilter) will be
the recommended pattern. Replace code like (in subclasses of WebApplication):

ServletContext sc = getWicketServlet().getServletContext();

with

ServletContext sc = getServletContext();

and

wicket.protocol.http.IWebApplicationFactory#createApplication(wicket.protocol.http.WicketServlet)

is replaced by

wicket.protocol.http.IWebApplicationFactory#createApplication(wicket.protocol.http.WicketFilter)

You can get the servlet context from a filter like this:

filter.getFilterConfig().getServletContext()

The main advantage of working with a filter instead of a servlet is that it is easier to pass through resources, and map your application to the root.

Wicket-Spring

@SpringBean.name has been deprecated and replaced with @SpringBean.id which aligns much better with spring.

Validation Changes

Form component level validation has been decoupled from FormComponent so that validators can be reused outside wicket. The new API can be found in <b>wicket.validation</b> package, with the validator implementations in <b>wicket.validation.validator</b>. From the point of view of validator development not much has changed if you extended the <b>AbstractValidator</b>; if you however implemented the IValidator interface directly you will need to use the new API, namely error reporting via <b>ValidationError</b> instead of <b>FormComponent.error(List,Map)</b>. Errors with messages fully constructed inside the validator can still be reported using <b>FormComponent.error(String)</b>.

  • No labels