Best Practices and GotchasPage edited by Josef
Comment:
Updated doctype to match html5
Changes (2)
Full ContentThis page will contain the accumulated thoughts on what the wicket best practices are. It will also list situations that cause erroneus behaviours and are hard to track down. Table of contents
Best PracticesHtml Template Declaration<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/" xml:lang="en" lang="en">
Wicket 1.3.xTo avoid this issue with Wicket 1.3, the recommandation has been changed to use a ServletFilter rather than a servlet - See the Migrate-1.3 page for details of the changes required. More info(Thanks, Igor) So, for example, let's say you have /myapp/images/foo.gif and you map your wicket servlet to /* What happens is that when a request comes in for /myapp/images/foo.gif it will match the wicket servlet - so now it is wicket servlet's job to serve this file to the browser. now we are nice enough to provide support for this - but obviously we cannot do as good a job as the application server which has a lot more context. So for 1.1 & 1.2, we recommend mapping the servlet to something like /app/* so that foo.gif will be processed by the application server and only wicket-specific requests are processed by the servlet. For 1.3 and onward, what we do is instead of using a servlet, use a filter. The advantage of a filter is that, unlike a servlet, it can choose not to process the request and let whatever is next in chain try. So when using a wicket filter and a request comes in for foo.gif the filter can choose not to process it because it knows it is not a wicket-related request. Since the filter didnt process it, it falls on to the application server to try, and then it works. Anonymous Inner classesDon't do this: class MyPage extends WebPage { private MyVeryLargeObject subject; // .... public MyPage() { // get my very large object from database subject = MyVeryLargeObjectDao.get(); // ... form.add(new TextField("name", new PropertyModel(MyPage.this, "some.very.large.navigational.structure.name")); } } The 'subject' instance of the MyVeryLargeObjectDao class will be serialized into the session with each page version. This can get out of hand, because with some business object models, the attached object can become very large. For this we introduced DetachableModels, which will retrieve the data from the database when needed, and will clean up when the data is not needed (at the end of the request for instance). The other thing to avoid is anonymous or nested instances of IModel. Usually you share an instance of a model between two page instances. If you create an anonymous or nested instance of IModel, then you automatically get a 'this' reference to the class that surrounds it. This will usually be the page, but can also be the form or a listview. Anyway, because the reference is /final/, you will copy that reference to the old page, with the model to the new page, thus duplicating the component tree (it gets versioned etc.). This will eventually lead to OutOfMemoryError. Search in the mailinglist for outofmemoryerror for other descriptions of this behaviour. I doubt that I have done the subject justice. ''Martijn Dashorst - Extracted from wicket-user mailing list Debugging NotSerializableExceptionIf you get a NotSerializableException on a deeply nested class like MyClass$2$1$1, it can be difficult to figure out which part of your code is causing the problem. Solution: use javap, but be sure to escape the $'s: javap mypackage.MyClass\$2\$1\$1 GotchasEmpty URL Parameter in CSS Style ( background-image: url(""); )I ran into this problem where clicking on links in DataTable's generated an internal error in wicket and an error log indicating that the requested component was not found. Strangely, the case was only with Firefox and I had no problem with IE.
<td style="background-image: url(''); ">
This kind of problem is tricky to detect and even if it isn't causing any errors it would generate an extra load on servers. --Iman Rahmatizadeh BODY:onLoad in Panel not added without wicket:headThe onLoad attribute will reference some _javascript_ and that must be added to a header. And because the Panel requires the onLoad AND the _javascript_ it is natural to add the _javascript_ to the Panels header. Thus you are able to create completely independent components which have all the information required to properly execute. No need to remember that you have to add a javascrpt reference to your Page. The Panel will handle it for you. Taken from the mailing list. Question by Joshua Lim, answer by Juergen Donnerstag Adding wicket:head to a PageThe <wicket:head> pair can be used in Panels, Borders and Fragments, and is used for doing a 'header contribution', meaning that the contents will be written to the <head> section of the page the component is placed in. If you are authoring a normal page, you don't need <wicket:head> tags but instead put it in the page's head section directly. The exception to this is when you use markup inheritance, and one of the pages to extend wants to contribute to the header of some extending page, and the header is not part of the <wicket:extend> region. In that case, you can use <wicket:head>. Starting download after form submission (Wicket 1.1)If you want to respond with a download to a form submission, you have to set the response page to null after writing your data into the response. protected void onSubmit() { WebResponse r = (WebResponse)getRequestCycle().getResponse(); r.setContentType("application/octet-stream"); r.setHeader("Content-Disposition", "attachment; filename=\"data.abc\""); r.write("data"); getRequestCycle().setResponsePage((WebPage)null); } See wicket.examples.displaytag.export.Export for a more complete example. Starting download after form submission (Wicket 1.2)The same as for 2.0, except that target.setFileName is from 1.2.3. You can override configure, cast to WebResponse, and call setAttachmentHeader on the response like this: ResourceStreamRequestTarget target = new ResourceStreamRequestTarget(new FileResourceStream(f), d.getContentType()) { @Override protected void configure(Response arg0, IResourceStream arg1) { super.configure(arg0, arg1); WebResponse response = (WebResponse) arg0; response.setAttachmentHeader(filename); } }; or do it like this: WebResource export = new WebResource() { @Override public IResourceStream getResourceStream() { CharSequence discounts = DataBase.getInstance() .exportDiscounts(); return new StringResourceStream(discounts, "text/plain"); } @Override protected void setHeaders(WebResponse response) { super.setHeaders(response); response.setAttachmentHeader("discounts.csv"); } }; export.setCacheable(false); new ResourceLink(this, "exportLink", export); Starting download after form submission (Wicket 2.0)This can be achieved using code like this (2.0): Form form = new Form(this, "exportForm"); new Button<String>(form, "exportButton", new Model<String>( "export")) { @Override protected void onSubmit() { CharSequence export = DataBase.getInstance() .exportDiscounts(); ResourceStreamRequestTarget target = new ResourceStreamRequestTarget( new StringResourceStream(export, "text/plain")); target.setFileName("discounts.csv"); RequestCycle.get().setRequestTarget(target); } }; PackageResources and relative pathsAssuming you have the following directory structure: /com /com/A.class /com/sun/B.class /com/sun/resource.txt with the following Application.mountBookmarkablePage() rules: mount("/A", A.class); mount("/A/B", B.class); Keep in mind that the path argument in the PackageResource methods ignores any Application mount() rules you might have applied. So it is legal to write:
PackageResource.get(com.sun.B.class, "resource.txt")
but it is not legal to write:
PackageResource.get(com.A.class, "B/resource.txt")
PBEWithMD5AndDES not found[For the moment, I'll leave this, but I'm not convinced this actually belongs here at all - Gwyn 13:56, 23 Aug 2006 (BST)] Not entirely clear what causes this. INFO - ClassCryptFactory - using encryption/decryption object wicket.util.crypt.SunJceCrypt@17d26fc ERROR - AbstractCrypt - Unable to encrypt text '' java.security.NoSuchAlgorithmException: Algorithm PBEWithMD5AndDES not available at javax.crypto.SunJCE_b.a(DashoA12275) at javax.crypto.SecretKeyFactory.getInstance(DashoA12275) at wicket.util.crypt.SunJceCrypt.generateSecretKey(SunJceCrypt.java:119) at wicket.util.crypt.SunJceCrypt.crypt(SunJceCrypt.java:95) at wicket.util.crypt.AbstractCrypt.encryptStringToByteArray(AbstractCrypt.java:204) at wicket.util.crypt.AbstractCrypt.encrypt(AbstractCrypt.java:107) at wicket.markup.html.form.PasswordTextField.getModelValue(PasswordTextField.java:97) at wicket.markup.html.form.FormComponent.getValue(FormComponent.java:387) at wicket.markup.html.form.TextField.onComponentTag(TextField.java:102) A possible fix is to add another security provider like this:
[Comments on the mailing list suggest this has been seen twice only, and may be due to misconfigured/corrupted JDK - Suggest reinstalling the JDK before adding BouncyCastle... Gwyn 13:56, 23 Aug 2006 (BST)] I've only seen this under the SysDeo Tomcat plug-in for Eclipse, when the boot classpath wasn't configured properly to include jce.jar, etc. – Al Maw I ran into a similar problem with Red Hat Enterprise Linux because the default JDK is from IBM, and I had to replace wicket's SunJceCrypt and CachingSunJceCryptFactory with my own IBM versions. – Jim Hunziker Adding id attribute to a tagDo not add an explicit id to a tag (div, input, select,...); this will break the _javascript_ code injected by Wicket (Ajax behavior,...). This is because the injected _javascript_ uses the wicket generated id. – David Bernard This is due to a hard to fix issue. As long as that issue is open, people should avoid setting id attributes on tags that are coupled to components that use rely on the markup id (setOutputMarkupId true). See http://issues.apache.org/jira/browse/WICKET-694 – Eelco Avoid using empty elements (i.e. <textarea />)Wicket will not automatically expand an empty element (i.e., an element that is expressed as a single tag ending in "/>") during the rendering phase. You should always include both an open tag and a close tag in your markup when you want Wicket to include content in the tag body. Don't do this
<textarea wicket:id="mytext" />
Do this Instead <textarea wicket:id="mytext">Content to be replaced by Wicket</textarea> --Jay
Change Notification Preferences
View Online
|
View Changes
|
Add Comment
|
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence
- [CONF] Apache Wicket > Best Practices and Gotchas confluence