Part 1Daan van Etten     October 29, 2010
I think most programmers spendthe first 5 years of their careermastering complexity, and the restof their lives learning s...
Architecture   Reusability andoverview       maintainability               Layout / logicOld to new               separati...
Old to new
Controllers
Controllers
Controllers@SpringBean
@SpringBean
Do not use SpringBean in generic UI components. (try a constructor argument instead)
Do not use SpringBean in generic UI components. (try a constructor argument instead)(If you do, the @SpringBean will be a ...
Only use the ‘name’ argument when thereare multiple beans that implement the sameinterface.@SpringBean (name = “selector”)...
public class SomePanel extends Panel {	 @SpringBean	 private UserService m_userService;	 @SpringBean	 private TranslationS...
HTML+CSS
for high level layout
24 columns
<wicket:extend>	 <h1 class="title">Settings</h1>		 <div class="span-12">	 	 <div wicket:id="personaldetails"></div>	 </div...
http://www.mdaines.com/plumb/
http://www.blueprintcss.org/tests/parts/grid.html
Do not assume too much...
Do not assume too much...  For example: do not assume that your  panel is always used with 4 columns.
Reusability
Maintainability
Principles of Object Oriented Design
Principles of Object Oriented Design         The first five principles are principles of class design:         SRP         T...
Composition over Inheritance
Tools for clear responsibilities  Page  Panel  Form  Validator  Renderer  DataProvider  Behavior
Tools for clear responsibilities  Page           Provides high level layout               only reusable by extending, so  ...
Tools for clear responsibilities  Page            Provides high level layout  Panel           Implement logic of a clearly...
Tools for clear responsibilities  Page            Provides high level layout  Panel           Implement logic of a clearly...
Panel                  “a class should do one thing”  Single Responsibility Principle  In the context of the Single Respon...
public class ChangePasswordBlock extends HeaderLayoutBlockPanel {	   public ChangePasswordBlock(String id) {	   	   super(...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page             Provides high level layout  Panel            Implement logic of a clear...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities  Page           Provides high level layout  Panel          Implement logic of a clearly s...
Tools for clear responsibilities: Behaviors   All Known Implementing Classes:   AbstractAjaxBehavior, AbstractAjaxTimerBeh...
Tools for clear responsibilities: Behaviors          Learn to write your own in 4 steps!                1. Choose the most...
Tools for clear responsibilities: Behaviors      Learn to write your own in 4 steps!         2. Extend from your chosen ba...
Tools for clear responsibilities: Behaviors      Learn to write your own in 4 steps!         3. Decide which methods to im...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                   3. Decide wh...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors             Learn to write your own in 4 steps!                    3. Decide w...
Tools for clear responsibilities: Behaviors           Learn to write your own in 4 steps!                4. Implement your...
Composing an AutoCompleteFieldAutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, ...
Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvi...
Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvi...
Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvi...
Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvi...
Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvi...
Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvi...
Give your classes clear names. If it’s a page, call it Page  (example: LoginPage instead of Login)If it’s a panel, call it...
Use wicket:message instead of Label     (for simple translations)
Use wicket:message instead of Label     (for simple translations)  <wicket:message key="SELECT_LANGUAGE_LABEL"/>
Use wicket:message instead of Label     (for simple translations)   <wicket:message key="SELECT_LANGUAGE_LABEL"/>Put this ...
Use wicket:message instead of Label      (for simple translations)<input type="button" wicket:id="someid" wicket:message="...
Use wicket:message instead of Label      (for simple translations)<input type="button" wicket:id="someid" wicket:message="...
Smells
http://xkcd.com/221/
Smell 1      Class names containing:                                  *With*                               *Without* publi...
LabelWithLabel: LabeledComponent<Label> lbl = new LabeledComponent<Label>(property, dopmd.getTranslationKey(), position, l...
Yes, we also have something like aLabelWithoutLabel: position = LabelPosition.NONE; LabeledComponent<Label> lbl = new Labe...
Smell 2                               instanceof          @Override          public MarkupContainer setDefaultModel(IModel...
Smell 3                        many constructors     public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> ...
Smell 3                                    many constructors               public class CheckBox extends LabeledComponent<...
Smell 3                                    many constructors               public class CheckBox extends LabeledComponent<...
Smell 3                                    many constructors               public class CheckBox extends LabeledComponent<...
Smell 3                                    many constructors               public class CheckBox extends LabeledComponent<...
Smell 3                                    many constructors               public class CheckBox extends LabeledComponent<...
Smell 4                        getPage() calls     Page page = (Page) event.getPage();     event.refreshComponents(m_grid,...
Smell 5            FeedbackPanel not inside Form     Page page = (Page) event.getPage();     event.refreshComponents(m_gri...
Smell 5          Refreshing FeedbackPanel, Toolbar or         other classes from unexpected locations     // Refresh the t...
Smell 6                                  Casting     // Refresh the toolbar     if (getPage() instanceof Page) {     	   T...
Smell 7                             Using getParent()    	   public void setButtonBar(ButtonBar buttonBar) {    	   	   if...
Smell 8                     Getting components                       from the Page   ToolBar tb = (ToolBar) ((Page) getPag...
Smell 9                      Doing layout and styling in Java 	   	   ColumnLayoutContainer pptfContainer = new ColumnLayo...
Smell 10                 Using onBeforeRender() too often 	   protected void onBeforeRender() { 	   	   super.onBeforeRend...
Smell 11           Calling ResourceModel.getObject()   feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject());
Smell 11           Calling ResourceModel.getObject()   feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject());
Smell 11           Calling ResourceModel.getObject()   feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject())...
Smell 11           Calling ResourceModel.getObject()   feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject())...
Smell 11                      Calling ResourceModel.getObject()         feedback.info(new ResourceModel(XTranslation.PROPE...
Smell 12           Hidden Javascript dependencies     AjaxRequestTarget target = AjaxRequestTarget.get();     if (target !...
Smell 13            Transient fields           (expect Exceptions!)
Resources
Groups
Wicket                    Mailing Listhttp://wicket.apache.org/help/email.htmlUsers list - Archives - Search - Subscribe -...
Wicket                             examplesNot always a good example of code quality, but get ideas from:http://wicketstuf...
Wicket                    Wikihttps://cwiki.apache.org/WICKET/
Reference                        libraryhttps://cwiki.apache.org/WICKET/reference-library.html
Wicket KT part 1
Wicket KT part 1
Wicket KT part 1
Wicket KT part 1
Wicket KT part 1
Wicket KT part 1
Wicket KT part 1
Upcoming SlideShare
Loading in …5
×

Wicket KT part 1

2,047 views

Published on

See http://stuq.nl/talks

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,047
On SlideShare
0
From Embeds
0
Number of Embeds
237
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Wicket KT part 1

  1. 1. Part 1Daan van Etten October 29, 2010
  2. 2. I think most programmers spendthe first 5 years of their careermastering complexity, and the restof their lives learning simplicity. — BUZZ ANDERSEN
  3. 3. Architecture Reusability andoverview maintainability Layout / logicOld to new separationBluePrint Resources
  4. 4. Old to new
  5. 5. Controllers
  6. 6. Controllers
  7. 7. Controllers@SpringBean
  8. 8. @SpringBean
  9. 9. Do not use SpringBean in generic UI components. (try a constructor argument instead)
  10. 10. Do not use SpringBean in generic UI components. (try a constructor argument instead)(If you do, the @SpringBean will be a hiddendependency when you add a generic component)
  11. 11. Only use the ‘name’ argument when thereare multiple beans that implement the sameinterface.@SpringBean (name = “selector”)private GenericService m_genericService;
  12. 12. public class SomePanel extends Panel { @SpringBean private UserService m_userService; @SpringBean private TranslationService m_translationService;
  13. 13. HTML+CSS
  14. 14. for high level layout
  15. 15. 24 columns
  16. 16. <wicket:extend> <h1 class="title">Settings</h1> <div class="span-12"> <div wicket:id="personaldetails"></div> </div> <div class="span-12 last"> <div wicket:id="emailnotification"></div> </div> <div class="span-12"> <div wicket:id="changePassword"></div> </div> <div class="span-12 last"> <div wicket:id="languagetimezone"></div> </div> </wicket:extend>
  17. 17. http://www.mdaines.com/plumb/
  18. 18. http://www.blueprintcss.org/tests/parts/grid.html
  19. 19. Do not assume too much...
  20. 20. Do not assume too much... For example: do not assume that your panel is always used with 4 columns.
  21. 21. Reusability
  22. 22. Maintainability
  23. 23. Principles of Object Oriented Design
  24. 24. Principles of Object Oriented Design The first five principles are principles of class design: SRP The Single Responsibility Principle A class should have one, and only one, reason to change. OCP The Open Closed Principle You should be able to extend a classes behavior, without modifying it. LSP The Liskov Substitution Principle Derived classes must be substitutable for their base classes. DIP The Dependency Inversion Principle Depend on abstractions, not on concretions. ISP The Interface Segregation Principle Make fine grained interfaces that are client specific.
  25. 25. Composition over Inheritance
  26. 26. Tools for clear responsibilities Page Panel Form Validator Renderer DataProvider Behavior
  27. 27. Tools for clear responsibilities Page Provides high level layout only reusable by extending, so do not implement reusable logic in Page!
  28. 28. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Panel is very good for reuse! Just make sure your interface is clear, and your Panel does not contain too much knowledge.
  29. 29. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Panel is very good for reuse! The interface of a Panel is the combination of all the public and protected methods. Think about reuse!
  30. 30. Panel “a class should do one thing” Single Responsibility Principle In the context of the Single Responsibility Principle, responsibility is “a reason for change.” If you can think of more than one motive for changing a class, then that class has more than one responsibility. Another way to put it: “a class should do one thing (and be good at it)” https://wiki.cordys.com/display/edv/How+to+write+a+good+Wicket+component
  31. 31. public class ChangePasswordBlock extends HeaderLayoutBlockPanel { public ChangePasswordBlock(String id) { super(id, new ResourceModel(PreferencesUITranslations.CHANGE_PASSWORD)); FeedbackPanel feedbackPanel = new FeedbackPanel("feedbackPanel"); feedbackPanel.setOutputMarkupId(true); Form<ChangePassword> passwordForm = createPasswordForm("passwordForm", feedbackPanel); add(passwordForm); passwordForm.add(feedbackPanel);[..] PasswordTextField confirmNewPassword = new PasswordTextField("confirmNewPassword"); confirmNewPassword.add(new RequiredValidator<String>()); passwordForm.add(confirmNewPassword); passwordForm.add(new EqualPasswordInputValidator(newPassword, confirmNewPassword)); passwordForm.add(new DefaultAjaxFallbackButton("changePasswordButton", passwordForm)); } private Form<ChangePassword> createPasswordForm(String id, final Component feedbackPanel) { return new Form<ChangePassword>(id, new CompoundPropertyModel<ChangePassword>(new ChangePassword())) { protected void onError() { WicketUtil.refresh(AjaxRequestTarget.get(), feedbackPanel); }; protected void onSubmit() { changePassword(getModel(), this); WicketUtil.refresh(AjaxRequestTarget.get(), feedbackPanel); }; }; } private void changePassword(IModel<ChangePassword> changedModel, Component feedbackComponent) { ChangePassword changed = changedModel.getObject(); try { m_userService.changePasswordForCurrentUser(changed.getCurrentPassword(), changed.getNewPassword()); feedbackComponent.info(new ResourceModel(PreferencesUITranslations.CHANGE_PASSWORD_SUCCESSFULL).getObject()); } catch (BadCredentialsException e) { feedbackComponent.error(new ResourceModel( PreferencesUITranslations.CURRENT_PASSWORD_INCORRECT).getObject()); } }
  32. 32. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel. Think: should your Form really implement the Save of an object?
  33. 33. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel. Think: should your Form really implement the Save of an object? Is reuse possible if you want the same Form for: creating new object / edit existing object?
  34. 34. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form
  35. 35. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Validations should only do Validation.
  36. 36. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Validations should only do Validation. Have a clear separation between Validation and Behavior!
  37. 37. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Renderer Render a given Object to a string representation
  38. 38. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Renderer Render a given Object to a string representation Renderer: do rendering only! No logic, no filtering, nothing. Just render.
  39. 39. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Renderer Render a given Object to a string representation DataProvider Provide the right data based on given input.
  40. 40. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Renderer Render a given Object to a string representation DataProvider Provide the right data based on given input. No rendering, no updating of FeedbackPanels or Toolbar.
  41. 41. Tools for clear responsibilities Page Provides high level layout Panel Implement logic of a clearly separated part of a page Form, put your FeedbackPanel in here and handle Form logic of submitting and refreshing FeedbackPanel Validator Handle validation of a FormComponent or a Form Renderer Render a given Object to a string representation DataProvider Provide the right data based on given input. Behavior Behaviors are plugins for components. They can provide custom markup, custom pieces of logic. Think of them as decorators.
  42. 42. Tools for clear responsibilities: Behaviors All Known Implementing Classes: AbstractAjaxBehavior, AbstractAjaxTimerBehavior, AbstractAutoCompleteBehavior, AbstractBehavior, AbstractDefaultAjaxBehavior, AbstractHeaderContributor, AbstractTransformerBehavior, AjaxEditableLabel.EditorAjaxBehavior, AjaxEditableLabel.LabelAjaxBehavior, AjaxEventBehavior, AjaxFormChoiceComponentUpdatingBehavior, AjaxFormComponentUpdatingBehavior, AjaxFormSubmitBehavior, AjaxFormValidatingBehavior, AjaxIndicatorAppender, AjaxPagingNavigationBehavior, AjaxSelfUpdatingTimerBehavior, AttributeAppender, AttributeModifier, AutoCompleteBehavior, BodyTagAttributeModifier, ContainerWithAssociatedMarkupHelper, ContextPathGenerator, DatePicker, HeaderContributor, OnChangeAjaxBehavior, OrderByLink.CssModifier, SimpleAttributeModifier, StringHeaderContributor, TextTemplateHeaderContributor, VelocityContributor, VelocityHeaderContributor, VelocityJavascriptContributor, WicketAjaxIndicatorAppender, WicketMessageTagHandler.AttributeLocalizer, XsltTransformerBehavior
  43. 43. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 1. Choose the most appropriate base class All Known Implementing Classes: AbstractAjaxBehavior, AbstractAjaxTimerBehavior, AbstractAutoCompleteBehavior, AbstractBehavior, AbstractDefaultAjaxBehavior, AbstractHeaderContributor, AbstractTransformerBehavior, AjaxEditableLabel.EditorAjaxBehavior, AjaxEditableLabel.LabelAjaxBehavior, AjaxEventBehavior, AjaxFormChoiceComponentUpdatingBehavior, AjaxFormComponentUpdatingBehavior, AjaxFormSubmitBehavior, AjaxFormValidatingBehavior, AjaxIndicatorAppender, AjaxPagingNavigationBehavior, AjaxSelfUpdatingTimerBehavior, AttributeAppender, AttributeModifier, AutoCompleteBehavior, BodyTagAttributeModifier, ContainerWithAssociatedMarkupHelper, ContextPathGenerator, DatePicker, HeaderContributor, OnChangeAjaxBehavior, OrderByLink.CssModifier, SimpleAttributeModifier, StringHeaderContributor, TextTemplateHeaderContributor, VelocityContributor, VelocityHeaderContributor, VelocityJavascriptContributor, WicketAjaxIndicatorAppender, WicketMessageTagHandler.AttributeLocalizer, XsltTransformerBehavior
  44. 44. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 2. Extend from your chosen base class public class MyBehavior extends AbstractBehavior { .. }
  45. 45. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement
  46. 46. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component)           Called when a component that has this behavior coupled was rendered.
  47. 47. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component)           Called when a component that has this behavior coupled was rendered. bind(Component component)           Bind this handler to the given component.
  48. 48. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component)           Called when a component that has this behavior coupled was rendered. bind(Component component)           Bind this handler to the given component. beforeRender(Component component)           Called when a component is about to render.
  49. 49. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component)           Called when a component that has this behavior coupled was rendered. bind(Component component)           Bind this handler to the given component. beforeRender(Component component)           Called when a component is about to render. cleanup()           This method is called either by onRendered (Component) or onException(Component, RuntimeException) AFTER they called their respective template methods.
  50. 50. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component) onRendered(Component component)           Called when a component that has this behavior           Called when a component that has this behavior coupled was rendered. coupled was rendered. bind(Component component)           Bind this handler to the given component. beforeRender(Component component)           Called when a component is about to render. cleanup()           This method is called either by onRendered (Component) or onException(Component, RuntimeException) AFTER they called their respective template methods.
  51. 51. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component) onRendered(Component component)           Called when a component that has this behavior           Called when a component that has this behavior coupled was rendered. coupled was rendered. bind(Component component) isTemporary()           Bind this handler to the given component.           Specifies whether or not this behavior is temporary. beforeRender(Component component)           Called when a component is about to render. cleanup()           This method is called either by onRendered (Component) or onException(Component, RuntimeException) AFTER they called their respective template methods.
  52. 52. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component) onRendered(Component component)           Called when a component that has this behavior           Called when a component that has this behavior coupled was rendered. coupled was rendered. bind(Component component) isTemporary()           Bind this handler to the given component.           Specifies whether or not this behavior is temporary. onComponentTag(Component component, beforeRender(Component component) ComponentTag tag)           Called when a component is about to render.           Called any time a component that has this behavior registered is rendering the component tag. cleanup()           This method is called either by onRendered (Component) or onException(Component, RuntimeException) AFTER they called their respective template methods.
  53. 53. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 3. Decide which methods to implement afterRender(Component component) onRendered(Component component)           Called when a component that has this behavior           Called when a component that has this behavior coupled was rendered. coupled was rendered. bind(Component component) isTemporary()           Bind this handler to the given component.           Specifies whether or not this behavior is temporary. onComponentTag(Component component, beforeRender(Component component) ComponentTag tag)           Called when a component is about to render.           Called any time a component that has this behavior registered is rendering the component tag. cleanup() detach(Component component)           This method is called either by onRendered (Component) or onException(Component,           Allows the behavior to detach any state it has RuntimeException) AFTER they called their respective attached during request processing. template methods.
  54. 54. Tools for clear responsibilities: Behaviors Learn to write your own in 4 steps! 4. Implement your behavior!public class AjaxFocusBehavior extends AbstractBehavior { private Component m_component; @Override public void bind(Component component) { this.m_component = component; component.setOutputMarkupId(true); } @Override public void renderHead(IHeaderResponse response) { super.renderHead(response); response.renderOnLoadJavascript("document.getElementById(" + m_component.getMarkupId() + ").focus()"); } /** * {@inheritDoc} */ @Override public boolean isTemporary() { return true; }
  55. 55. Composing an AutoCompleteFieldAutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);
  56. 56. Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvider(m_pizzaService);AutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);
  57. 57. Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvider(m_pizzaService);PizzaAutoSuggestRenderer renderer = new PizzaAutoSuggestRenderer();AutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);
  58. 58. Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvider(m_pizzaService);PizzaAutoSuggestRenderer renderer = new PizzaAutoSuggestRenderer();AutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);renderer.setOnSelectJavascriptProvider(autocomplete);
  59. 59. Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvider(m_pizzaService);PizzaAutoSuggestRenderer renderer = new PizzaAutoSuggestRenderer();AutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);renderer.setOnSelectJavascriptProvider(autocomplete);autocomplete.add(new PlaceHolderTextBehavior(Model.of("Search for pizza...")));
  60. 60. Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvider(m_pizzaService);PizzaAutoSuggestRenderer renderer = new PizzaAutoSuggestRenderer();AutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);renderer.setOnSelectJavascriptProvider(autocomplete);autocomplete.add(new PlaceHolderTextBehavior(Model.of("Search for pizza...")));autocomplete.add(new AjaxSelectTextOnClickBehavior());
  61. 61. Composing an AutoCompleteFieldAutoCompleteChoicesProvider<Long, Pizza> choicesProvider = new PizzaAutoCompleteChoicesProvider(m_pizzaService);PizzaAutoSuggestRenderer renderer = new PizzaAutoSuggestRenderer();AutoCompleteField<Long, Pizza> autocomplete = new AutoCompleteField<Long, Pizza>(id, model, choicesProvider, renderer, settings);renderer.setOnSelectJavascriptProvider(autocomplete);autocomplete.add(new PlaceHolderTextBehavior(Model.of("Search for pizza...")));autocomplete.add(new AjaxSelectTextOnClickBehavior());autocomplete.add(new RequiredValidator<Pizza>());
  62. 62. Give your classes clear names. If it’s a page, call it Page (example: LoginPage instead of Login)If it’s a panel, call it Panel (example: LoginPanel instead of Login)The same goes for Form,Validator, Renderer, etcetera.
  63. 63. Use wicket:message instead of Label (for simple translations)
  64. 64. Use wicket:message instead of Label (for simple translations) <wicket:message key="SELECT_LANGUAGE_LABEL"/>
  65. 65. Use wicket:message instead of Label (for simple translations) <wicket:message key="SELECT_LANGUAGE_LABEL"/>Put this in your HTML and it will be replaced byWicket for the translation in your property file.
  66. 66. Use wicket:message instead of Label (for simple translations)<input type="button" wicket:id="someid" wicket:message="value:CHANGE" />
  67. 67. Use wicket:message instead of Label (for simple translations)<input type="button" wicket:id="someid" wicket:message="value:CHANGE" /> Wicket will add a ‘value’ attribute and set it to the localized value!
  68. 68. Smells
  69. 69. http://xkcd.com/221/
  70. 70. Smell 1 Class names containing: *With* *Without* public class CheckBoxWithoutLabel extends CheckBox public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> Duplicated code hierarchies are ugly...
  71. 71. LabelWithLabel: LabeledComponent<Label> lbl = new LabeledComponent<Label>(property, dopmd.getTranslationKey(), position, label); (In DOMRComponentFactory...)
  72. 72. Yes, we also have something like aLabelWithoutLabel: position = LabelPosition.NONE; LabeledComponent<Label> lbl = new LabeledComponent<Label>(property, dopmd.getTranslationKey(), position, label);
  73. 73. Smell 2 instanceof @Override public MarkupContainer setDefaultModel(IModel<?> model) { IModel<String> model1 = new Model<String>(); if (model != null && !(model instanceof DOMRObjectModel)) { Revision revision = (Revision) model.getObject(); if (revision != null) { model1.setObject(revision.getId().toString()); } return super.setDefaultModel(model1); } return super.setDefaultModel(model); } CatalogAutoSuggestField
  74. 74. Smell 3 many constructors public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> { private static final long serialVersionUID = -8246992163993958051L;
  75. 75. Smell 3 many constructors public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> { private static final long serialVersionUID = -8246992163993958051L; public CheckBox(String translationKey, IModel<Boolean> model) { this(null, translationKey, model); }
  76. 76. Smell 3 many constructors public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> { private static final long serialVersionUID = -8246992163993958051L; public CheckBox(String id, String translationKey, IModel<Boolean> model) { this(id, translationKey, LabelPosition.RIGHT, model); }
  77. 77. Smell 3 many constructors public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> { private static final long serialVersionUID = -8246992163993958051L; public CheckBox(String translationKey, LabelPosition position, IModel<Boolean> model) { this(null, translationKey, position, model); }
  78. 78. Smell 3 many constructors public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> { private static final long serialVersionUID = -8246992163993958051L; public CheckBox(String id, String translationKey, LabelPosition position, IModel<Boolean> model) { super(id, translationKey, position, new CheckBoxWithoutLabel(id + "CheckBox", model)); getLabel().addCssClass("checkBoxWithLabel"); }
  79. 79. Smell 3 many constructors public class CheckBox extends LabeledComponent<CheckBoxWithoutLabel> { private static final long serialVersionUID = -8246992163993958051L; public CheckBox(IModel<Boolean> model) { this(null, model); }
  80. 80. Smell 4 getPage() calls Page page = (Page) event.getPage(); event.refreshComponents(m_grid, page.getFeedbackPanel());
  81. 81. Smell 5 FeedbackPanel not inside Form Page page = (Page) event.getPage(); event.refreshComponents(m_grid, page.getFeedbackPanel());
  82. 82. Smell 5 Refreshing FeedbackPanel, Toolbar or other classes from unexpected locations // Refresh the toolbar if (getPage() instanceof Page) { ToolBar tb = (ToolBar) ((Page) getPage()).getComponent("toolbar"); if (tb != null) { target.addComponent(tb); } }
  83. 83. Smell 6 Casting // Refresh the toolbar if (getPage() instanceof Page) { ToolBar tb = (ToolBar) ((Page) getPage()).getComponent("toolbar"); if (tb != null) { target.addComponent(tb); } }
  84. 84. Smell 7 Using getParent() public void setButtonBar(ButtonBar buttonBar) { if (!buttonBar.getId().equals(s_buttonPanel)) { throw new WicketRuntimeException("Buttonbar id is wrong."); } if (m_buttonBarPanel.getParent() == null) { if (m_form.get(s_buttonPanel) != null) { m_form.get(s_buttonPanel) .replaceWith(m_buttonBarPanel); } else { m_form.add(m_buttonBarPanel); } } m_buttonBarPanel.replaceWith(buttonBar); }
  85. 85. Smell 8 Getting components from the Page ToolBar tb = (ToolBar) ((Page) getPage()).getComponent("toolbar");
  86. 86. Smell 9 Doing layout and styling in Java ColumnLayoutContainer pptfContainer = new ColumnLayoutContainer("proofPaidTuitionFeeContainer") .addComponent(sourceLabel, Size.percent(30)) .addComponent(amountLabel, Size.percent(30)) .addComponent(factory.createDateTimeLabel("dateTime", m_dateTimeModel, LabelPosition.TOP, m_controller.getTimeZoneCurrentUser())) .newLine();
  87. 87. Smell 10 Using onBeforeRender() too often protected void onBeforeRender() { super.onBeforeRender(); if (isEnabled()) { AjaxRequestTarget target = AjaxRequestTarget.get(); if (target != null) { target.appendJavascript(TextTemplateHeaderContributor.forPlainJs(s_textTemplate, getHeaderContributor(false)).toString()); } else { add(TextTemplateHeaderContributor.forJavaScript(s_textTemplate, getHeaderContributor(true))); } } } tip: check onConfigure() (and in this case: check IHeaderContributor)
  88. 88. Smell 11 Calling ResourceModel.getObject() feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject());
  89. 89. Smell 11 Calling ResourceModel.getObject() feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject());
  90. 90. Smell 11 Calling ResourceModel.getObject() feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject()); feedback.info(getString(XTranslation.PROPERTY));
  91. 91. Smell 11 Calling ResourceModel.getObject() feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject()); feedback.info(getString(XTranslation.PROPERTY)); Call getString only outside constructor! (check methods that are called by the constructor)
  92. 92. Smell 11 Calling ResourceModel.getObject() feedback.info(new ResourceModel(XTranslation.PROPERTY).getObject()); feedback.info(getString(XTranslation.PROPERTY)); Call getString only outside constructor! (check methods that are called by the constructor) Tried to retrieve a localized string for a component that has not yet been added to the page. This can sometimes lead to an invalid or no localized resource returned. Make sure you are not calling Component#getString() inside your Components constructor. Offending component: [MarkupContainer [Component id = panelmenu, page = <No Page>, path = panelmenu.PanelMenu]]
  93. 93. Smell 12 Hidden Javascript dependencies AjaxRequestTarget target = AjaxRequestTarget.get(); if (target != null) { target.appendJavascript("clickFeedbackRefreshLink();"); }
  94. 94. Smell 13 Transient fields (expect Exceptions!)
  95. 95. Resources
  96. 96. Groups
  97. 97. Wicket Mailing Listhttp://wicket.apache.org/help/email.htmlUsers list - Archives - Search - Subscribe - Unsubscribe - Help
  98. 98. Wicket examplesNot always a good example of code quality, but get ideas from:http://wicketstuff.org/wicket14/index.html
  99. 99. Wicket Wikihttps://cwiki.apache.org/WICKET/
  100. 100. Reference libraryhttps://cwiki.apache.org/WICKET/reference-library.html

×