Migrating to Wicket 1.3Page edited by Martijn DashorstChanges (0)
Full Content1.3 is the current stable release. Migrating to Wicket 1.3
Table of contents
Package renameDue to Wicket incubating at Apache, we applied a package rename for all core projects. Instead of wicket.* we now use org.apache.wicket.*. The http://wicket.sourceforge.net namescape declarations should be changed to http://wicket.apache.org. Filter instead of a ServletThe recommended set-up for Wicket now uses a servlet-api Filter, not a servlet-api Servlet (although a Servlet is still provided for use in environments that do not support a Filter). Replace code like this (in subclasses of WebApplication): Unknown macro: {code}
ServletContext sc = getWicketServlet().getServletContext(); with Unknown macro: {code}
ServletContext sc = getServletContext(); and Unknown macro: {code}
wicket.protocol.http.IWebApplicationFactory#createApplication(wicket.protocol.http.WicketServlet) is replaced by Unknown macro: {code}
wicket.protocol.http.IWebApplicationFactory#createApplication(wicket.protocol.http.WicketFilter) You can get the servlet context from a filter like this: Unknown macro: {code}
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. Here's an example of how to configure your application now with a filter in web.xml: Unknown macro: {code}
<?xml version="1.0" encoding="UTF-8"?> <web-app> <filter-mapping> API changesIModel changeIModel#getObject(Component) is replaced by IModel#getObject() and Here are some regex replacement that are helpful: Unknown macro: {code}
s/public\s+Object\s+getObject\s*(\s*(final)\s(wicket.)?Component\s+\w+\s*)/public Object getObject() and Unknown macro: {code}
s/public\s+void\s+setObject\s*(\s*(final)\s(wicket.)?Component\s+\w+,\s*(final)\s*Object\s+(\w+)\s)/public void setObject(Object \2) You're probably best off doing the calls to get/setObject you did on models yourself manually. Some miscellaneous abstract model classes have been removed as they did not provide much value. Here is a simple migration mapping if you extended one of the removed classes in your code: Unknown macro: {code}
AbstractModel->Model if you do need the Component in the model (see below the IAssignementAwareModel) then there is a quick model Unknown macro: {code}
ComponentModel that is pretty Unknown macro: {code}
ComponentDetachableModel as a replacement. Then onAttach -> attach, onDetach -> detach, onSetObject is just setObject and onGetObject is just getObject IWrapModel must be used as a return type of the 2 new Model interface markers IAssignementAwareModel and IInheritableModel both of these have a wrapOnXXXX method IAssignementAwareModel is used now when the Model implementation needs an Component to resolve things in set/getObject() calls. Because now we don't get the Unknown macro: {code}
public Object getObject() Unknown macro: {
return Application.get().getResourceSettings().getLocalizer().getString(resourceKey,component, defaultValue);
} So ResourceModel implements now IComponentAssignedModel Unknown macro: {code}
public IWrapModel wrapOnAssignment(final Component component) Unknown macro: {
return new AssignmentWrapper(resourceKey, defaultValue, component);
} That can be an innerclass that has reference to the component and the outer model (which is returned in the getWrappedModel() call of IWrapModel) InheritableModel is the replacement of the ICompoundModel interface it works the same as the ICompoundModel so child components Looking at the CompoundPropertyModel: Unknown macro: {code}
public void setObject(Object object) Unknown macro: {
this.target = object;
}
public IWrapModel wrapOnInheritance(Component component) Unknown macro: {
return new AttachedCompoundPropertyModel(component);
} as you can see the setObject just sets the target == main domain object, so you can do this: Unknown macro: {code}
CompoundPropertyModel model = new CompoundPropertyModel(); Also it wraps the component and the 'this' in an innerclass AttachedCompoundPropertyModel Unknown macro: {code}
private class AttachedCompoundPropertyModel extends AbstractPropertyModel implements IWrapModel, public AttachedCompoundPropertyModel(Component owner) Unknown macro: {
super(CompoundPropertyModel.this);
this.owner = owner;
}
protected String propertyExpression() Unknown macro: {
return CompoundPropertyModel.this.propertyExpression(owner);
}
public IModel getWrappedModel() Unknown macro: {
return CompoundPropertyModel.this;
} That innerclass extends AbstractPropertyModel in this case and implements IWrapModel So to summarize if you have implemented your own ICompoundModel that is now the IInheritableModel and you need Also the BoundCompoundPropertyModel doesn't have to be used anymore now where you did this before: Unknown macro: {code}
BoundCompoundPropertyModel model = new BoundCompoundPropertyModel(new Person()); can be replaced by Unknown macro: {code}
CompoundPropertyModel model = new CompoundPropertyModel(new Person()); PageParameters.If storing strings in PageParameters, it was previously possible to refer to one by calling: (String) pageParameters.get(keyValue) Now, one must call: pageParameters.getString(keyValue) Static Images.When using static images as resources, one could use <img wicket:id = "picture" alt="Picture" src=""/> in a page's HTML, and set the image dynamically using AttributeModifier in a WebComponent as follows: WebComponent wmc = new WebComponent("picture"); Because of the change from a Wicket Servlet to a Wicket Filter, this will no longer work consistently. Instead, one should use ContextImage as follows: ContextImage ci = new ContextImage("picture", new Model(pictureFileName) ); Component.onAttach/onBeforeRender/onAfterRender changes.Before we had this behaviour: new Page: Page constructed Listener request which sets a new page: Page1.componentCalled() >- Page2 is set to response. So the page1 ondetach is called but not the on attach Page1.onPageAttached() -> this is just called on page. Users can visit components if they need to The onAttach method on components is not available any more. ConvertersIConverter is now more specific to what we're doing in a web environment. The signature is Unknown macro: {code}
public interface IConverter extends IClusterable Unknown macro: {
/**
* Converts the given string value to class c.
*
* @param value
* The string value to convert
* @param locale
* The locale used to convert the value
* @return The converted value
*/
Object convertToObject(String value, Locale locale);
/**
* Converts the given value to a string.
*
* @param value
* The value to convert
* @param locale
* The locale used to convert the value
*
* @return The converted string value
*/
String convertToString(Object value, Locale locale);
} The new converters make it much easier to write custom ones. SimpleConverterAdaptor and ITypeConverter are deleted as they are not needed anymore. Wicket 1.2 had a default Converter implementation that actually served as a registry for converter instances. This is renamed to ConverterLocator and backed by interface IConverterLocator. The application's instance of the converter locator can be configured by overriding Application#newConverterLocator, which is called during startup. Note that in 1.2.x, the validator was called first, then the converter; this was considered a bug. In 1.3 it's the other way around, so you may need to adjust your code if you do both conversion and validation on the same field. Validation ChangesForm component level validation has been decoupled from FormComponent so that validators can be reused outside wicket. The new API can be found in wicket.validation package, with the validator implementations in wicket.validation.validator. From the point of view of validator development not much has changed if you extended the AbstractValidator; if you however implemented the IValidator interface directly you will need to use the new API, namely error reporting via ValidationError instead of FormComponent.error(List,Map). Errors with messages fully constructed inside the validator can still be reported using FormComponent.error(String). EmailAddressPatternValidator has changed name to EmailAddressValidator. Make sure you update your resource keys appropriately. The resource key "RequiredValidator", used to lookup the message by any component on which isRequired returns true, has changed to simply "Required". Mak sure you update your resource keys appropriately. WicketTester and MockWebApplicationMockWebApplication and WicketTester are no longer derived from WebApplication which allows to use MockWebApplication and therefore WicketTester both consistently use factory methods to create requests and responses now. This allows for custom request and response subclasses to be used in testing. Also, it is now possible to use WicketTester with a test framework other than JUnit, by extending BaseWicketTester where all most methods have been moved to. MountsThe path of a mount is now part of the IRequestTargetUrlCodingStrategy (String getMountPath()). See WICKET-410. RequestCycle, IRequestCycleFactory, Session, ISessionFactory, IPageMap and PageMap changesIRequestCycleFactory and ISessionFactory were removed from the code base. You now simply override Unknown macro: {code}
public RequestCycle newRequestCycle(final Request request, final Response response) and Unknown macro: {code}
public Session newSession(Request request, Response response) in your application to provide a custom request cycle or custom session respectively RequestCycle's constructor now takes Application as its first parameter instead of Session. Custom SessionsSession's constructor signature is now: Unknown macro: {code}
protected Session(Application application, Request request) The locale is not set right after construction in WebApplication, but rather in the constructor using the passed in request. You can now "fix" the session's locale by setting it in its constructor. Session.get() now lazily creates Sessions using the Application session factory and RequestCycle methods that work with Sessions now call Session.exists() and/or Session.get() directly. Finally, IPageMap and PageMap work in the same way and no longer hold a session reference. RepeatersThe repeaters package has moved from wicket-extensions into core. The package name has been changed from wicket.extensions.markup.html.repeater to wicket.markup.repeater. Notice that only DataView and backing classes have moved, the higher level components such as the DataTable are still in wicket-extensions. Also notice that the names of classes have not changed so it should be a simple matter of ctrl-shift-o in your eclipse project to relink to the new classes. TextTemplateThe TextTemplate package has moved from wicket-extensions into core. The package name has been changed from wicket.extensions.util.resource to org.apache.wicket.util.template. Notice that the names of classes have not changed so it should be a simple matter of ctrl-shift-o in your eclipse project to relink to the new classes. DatePickerThe DatePicker component has been removed from the wicket-extensions package, as it conflicts with the Apache license. There are two options for migration:
Portlets JSR-168
Portlet support has recently been brought back into wicket core and will be available with release 1.3.0-beta4 and supersedes the old Wicket 1.2.x portlet support. ISessionStoreISessionStore had the following changes: HttpSessionStore and all subclasses now require the application which they are created for to be passed in in the constructor. ButtonAjaxSubmitButton and AjaxSubmitLink now extend Button and Button extends IFormSubmittingComponent. As a result of this, method onSubmit changed from protected to public The Button component name is a little bit confusing, because it should be used only when the INPUT tag is contained inside a form, otherwise you should use Link:
IHeaderContributorvoid IHeaderContributor.renderHead(final Response response); -> void IHeaderContributor.renderHead(final IHeaderResponse response); Unknown macro: {code}
protected void onRenderHeadInitContribution(Response response) Unknown macro: {
writeJsReference(response, AUTOCOMPLETE_JS);
} should be converted to: Unknown macro: {code}
public void renderHead(IHeaderResponse response) Unknown macro: {
super.renderHead(response);
response.renderJavascriptReference(AUTOCOMPLETE_JS);
} or for instance code like Unknown macro: {code}
protected String getImplementationId() Unknown macro: {
return "ArchiveActions";
}
protected void onRenderHeadContribution(Response response) { Unknown macro: {
response.write("<script>");
response.write(getCallbackScript().toString());
response.write("</script>");
}
} would be rewritten like Unknown macro: {code}
public void renderHead(IHeaderResponse response) { Unknown macro: {
response.renderJavascript(getCallbackScript(), "ArchiveActions");
}
} IBehaviorIBehavior.rendered(Component) -> IBehavior.afterRender(Component) IBehavior.detachModel(Component) -> IBehavior.detach(Component) Replacement for getBodyContainerIf you had code like this: Unknown macro: {code}
public void renderHead(HtmlHeaderContainer container) Unknown macro: {
((WebPage) getPage()).getBodyContainer().addOnLoadModifier("foo();", null);
super.renderHead(container);
} you should instead let your component implement IHeaderContributor, and then in the interface method, do: Unknown macro: {code}
public void renderHead(IHeaderResponse response) Unknown macro: {
response.renderOnLoadJavascript("foo();");
} FormComponent.IVisitorThings have been refactored into interfaces here. If you previously implemented this directly, extend FormComponent.AbstractVisitor instead, and rename your formComponent() implementation to onFormComponent(). ClientPropertieswicket.protocol.http.ClientProperties was taken from the Echo2 project that uses a license which is incompatible with ASL2. It has therefore been rewritten and the usage of it has also changed. Instead of: Unknown macro: {code}
WebClientInfo clientInfo = (WebClientInfo) Session.get().getClientInfo(); // Before constants where used to get properties You now say: Unknown macro: {code}
WebClientInfo clientInfo = (WebClientInfo) Session.get().getClientInfo(); // Now you use a property with that name instead Application settingsApplication#getSettings is now private (so you can't call nor override that anymore), and the getXxxSettings are now overridable in case you want to do fancy stuff like creating a session-dependent settings object. Methods getApplicationPages and getApplicationSettings from component are now removed in favor of the getXxxSettings methods in Application. Setting get/setDefaultLocale is removed and is does not have a replacement. Custom resource loadingIn Wicket 1.2 you could override method newMarkupResourceStream from MarkupContainer to provide a custom resource stream for loading the component's markup. The new way of letting markup containers provide custom markup is to let them implement interface IMarkupResourceStreamProvider and implement it's method getMarkupResourceStream. Additionally, a new feature is that you can provide your own markup cache key, which is used in the MarkupCache class. The only real use case for that is to let a markup container return a cache key that is null, in which case the resource won't be cached, causing Wicket to get call getMarkupResourceStream everytime the component's markup is requested. A use case for that is when you have dynamic markup (e.g. from a database) that is request/ session dependent. To achieve this, let your markup container also implement IMarkupCacheKeyProvider and let method getCacheKey return null. Tree componentsThe tree components from wicket and wicket-extensions are switched. The one previously in extensions (ajax enabled etc) is now in core and is the recommended component to work with, and the old one is moved to the extensions project. The package names got switched as well. Test serialization setting removedThe setting IDebugSettings#SerializeSessionAttributes is removed. Instead you can use the SecondLevelCacheSessionStore, which serialized (old) pages to a second level cache (user.tmp by default). SecondLevelCacheSessionStore will (probably) be the default configured session store, but you can configure it yourself by doing in your application: Unknown macro: {code}
/**
Also, you can use Unknown macro: {code}
wicket.util.Objects#checkSerializable(Object) to check for non-serializable objects yourself. You could do this for instance in a custom session store implementation. Palette component in wicket-extensions now has default CSS.You can revert this back to 1.2.x behaviour by overriding getCSS() and returning null. IRequestCycleProcessor got simplifiedThe interface itself didn't change, but we've pulled out a redundant layer of indirection that was confusing more than it helped matters. There is now a simply class hierarchy, and WebRequestCycleProcessor is the class you'll most likely need. See for more info the JIRA issue at http://issues.apache.org/jira/browse/WICKET-287 Removed IPageSettings#maxPageVersionsThe IPageSettings#maxPageVersions is removed from 1.3. The setting is not relevant for SecondLevelCacheSessionStore (the new default session store implementation), which uses SecondLevelCachePageVersionManager. If you use HttpSessionManager or a custom one together with UndoPageVersionManager, you can provide max page versions number as a UndoPageVersionManager's constructor argument. By default this is now 20 (opposed to max int which it was earlier). See also http://issues.apache.org/jira/browse/WICKET-266 Simplified HeaderContributorRemoved instance methods of HeaderContributor and now just keep one IHeaderContributor instance for clarity and efficiency. Removed feedback messages from pageAll feedback messages are now maintained by the session. See https://issues.apache.org/jira/browse/WICKET-442 Slight change in the handling of multivalued widgetsListMultipleChoice and Palette now call model.setObject() after changing the list elements in updateModel() Made it easier to add IMarkupFilter to MarkupParserThe MarkupParser can no longer be re-used for multiple markup files. You have to get a new instance from IMarkupParserFactory for every markup file to be parsed (which Wicket-core did already anyway). The MarkupParser API has been changed to make that clear as well. Unknown macro: {code}
public class MyMarkupParserFactory Unknown macro: {
MarkupParser parser = new MarkupParser(resource);
parser.appendMarkupFilter(new MyFilter());
return parser;
}
} In order to allow better control over where in the chain of IMarkupFilter to place your own one, appendMarkupFilter has got a second parameter "markupFilterClass". Your own IMarkupFilter will inserted before the one identified by the parameter. Logging API ChangeThe Logging API changed from Commons Logging to SLF4J, so you need to update your POM in order to use it: Unknown macro: {code}
<dependency> *if you are using log4j Unknown macro: {code}
<dependency> Application#configure() DEPLOYMENT/DEVELOPMENT changesIn 1.2, you should have configured your app for DEPLOYMENT/DEVELOPMENT mode using any of a System property ("wicket.configuration"), a servlet-specific init-param or a servlet context init-param. This will still work exactly as before. You may have previously called Application#configure(String configurationType) to provide your own way of setting this. This previously resulted in #configure() being called twice (one with the system-derived param, and once with your own). This is no longer the case. You can override Application#getConfigurationType() to provide the configuration string, and configure() will be called correctly and only once internally by Wicket. This provides greater flexibility for configuring the default application type settings via Spring or any other mechanism you choose. HtmlBodyContainer <body> goneWicket no longer automatically creates a WebMarkupContainer for <body>, thus <body> is no longer treated any different than any other HTML tag. PasswordTextField no longer supports cookies by defaultCalling setPersistent(true) on a PasswordTextField will now yield an exception (FormComponent PasswordTextField does not support cookies) due to security issues. Overload the method supportsPersistence to get the old behavior: Unknown macro: {code}
add(password = new PasswordTextField("password", new PropertyModel(properties, "password")) { Unknown macro: {
return true;
}
}); New Featureswicket:enclosure tagsee http://www.nabble.com/two-small-feature-ideas-tf2107229.html#a5835972 Reloading class loadersee ReloadingClassLoader Relative URLsWicket now generates all its URLs as relative paths, which means it works with zero-config behind a proxy server. ApplicationSettings.get/setContextPath() is therefore no longer required or available. The contextPath servlet init parameter that configured this in 1.2.x is therefore also no longer required/honoured. If you were previously using PrependContextPathHandler, this has been removed and is no longer required (relative path prepending is included by default for all your markup).
Stop watching space
|
Change email notification preferences
View Online
|
View Changes
|
Add Comment
|
[CONF] Apache Wicket > Migrating to Wicket 1.3
Martijn Dashorst (Confluence) Mon, 24 Jun 2013 02:17:49 -0700
