• Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Java and Wicket web development thoughts, tutorials, and tips

roman@coderdreams.com
Coder DreamsCoder Dreams
  • Fat Cats Boardgame
  • Wicket UI Library
  • About Me

Initializing your Wicket components using the builder pattern

March 18, 2020 Posted by Roman Sery wicket No Comments

Interrupting your regular broadcast of virus/collapse news…

In one of my previous posts about Wicket events, I wrote about how to initialize your custom components using events. Here I want to mention a useful technique for initializing them using the builder pattern.

The custom components you build that are used throughout your application often require a lot of parameters passed to the constructors to initialize them. As your application evolves and becomes more complex you will need to add more parameters and more constructors to support it. You will eventually find that refactoring becomes very difficult as you add more and more parameters/constructors.

Builder pattern to the rescue

A different approach we can use is to create a class that contains all of your initialization arguments. We can then have a single constructor in our Wicket components that accepts this single argument. This is the approach I use in my Wicket UI library. Let’s take a closer look at the details.

The UI library contains components such as text fields, dropdowns, switches, and others. As you can imagine, all of these different components have many initialization parameters in common, and some have a few that are specific to that component.

Let’s create a class following the builder pattern, which will store all the possible initialization parameters:

public final class FieldArgs {
    private final String id;
    private final String fieldLabel;
    private final String propertiesId;
    private final IModel model;
    private final IModel choiceList;
    private final IModel<Boolean> isEnabledModel;
    private final IModel<String> txtModel;
    private final IChoiceRenderer cr;
    private final Class inputType;
    private final String markupId;

    private FieldArgs(Builder builder) {
        this.id = builder.id;
        this.fieldLabel = builder.fieldLabel;
        this.propertiesId = builder.propertiesId;
        this.model = builder.model;
        this.isEnabledModel = builder.isEnabledModel;
        this.cr = builder.cr;
        this.inputType = builder.inputType;
        this.choiceList = builder.choiceList;
        this.txtModel = builder.txtModel;
        this.markupId = builder.markupId;
    }

    public String getId() { return id; }
    public String getFieldLabel() { return fieldLabel; }
    public String getPropertiesId() { return propertiesId; }
    public IModel getModel() { return model; }
    public IModel<Boolean> getIsEnabledModel() { return isEnabledModel; }
    public IChoiceRenderer getCr() { return cr; }
    public Class getInputType() { return inputType; }
    public IModel getChoiceList() { return choiceList; }
    public IModel<String> getTxtModel() { return txtModel; }
    public String getMarkupId() { return markupId; }
    
    public static final class Builder {
        private final String id;
        private final String fieldLabel;
        private String propertiesId;
        private IModel model;
        private IModel choiceList;
        private IModel<Boolean> isEnabledModel;
        private IModel<String> txtModel;
        private IChoiceRenderer cr;
        private Class inputType;                                       
        private String markupId;
        
        private Builder(String id, String fieldLabel, IModel model) {
            this.id = id;
            this.fieldLabel = fieldLabel;
            this.model = model;
        }

        public static Builder of(String id, String fieldLabel, IModel model) {
            return new Builder(id, fieldLabel, model);
        }

        public Builder model(IModel model) {
            this.model = model;
            return this;
        }
        public Builder isEnabledModel(IModel<Boolean> isEnabledModel) {
            this.isEnabledModel = isEnabledModel;
            return this;
        }
        public Builder propertiesId(String propertiesId) {
            this.propertiesId = propertiesId;
            return this;
        }
        public Builder cr(IChoiceRenderer cr) {
            this.cr = cr;
            return this;
        }
        public Builder inputType(Class inputType) {
            this.inputType = inputType;
            return this;
        }       
        public Builder choiceList(IModel choiceList) {
            this.choiceList = choiceList;
            return this;
        }       
        public Builder txtModel(IModel<String> txtModel) {
            this.txtModel = txtModel;
            return this;
        }       
        public Builder markupId(String markupId) {
            this.markupId = markupId;
            return this;
        }      

        public FieldArgs build() {
            return new FieldArgs(this);
        }
    }	
}

This abbreviated version of the FieldArgs class contains all the parameters needed to initialize any UI component. Let’s take a look at how we do that.

Initializing using FieldArgs

Using the Wicket UI library components as an example, how do we use FieldArgs? Each component has a single constructor that accepts a FieldArgs parameter. Let’s look at a few examples:

TxtField<String> firstNameField = new TxtField<String>(FieldArgs.Builder.of("userFirstName", "First Name", LambdaModel.of(user::getFirstName, formData::setFirstName)).build());

CheckBoxGroupField chkGroupField = new CheckBoxGroupField(FieldArgs.Builder.of("CheckBoxGroupField", "CheckBoxGroupField", new ListModel<CheckBoxGroupModel>(getGroupChoices())).build())

Using the builder pattern, we construct a FieldArgs object and pass it to the constructor in exactly the same manner for each type of component.

Conclusion

I hope this will motivate you to utilize the builder pattern when writing your own Wicket components. The main benefit you will see is the ease of refactoring, adding new functionality, and making big changes to existing functionality.

Imagine you are working on new functionality that allows users to add inline comments to all UI fields. You will likely need to add some additional fields to the FieldArgs class and make some modifications to the base UI class BaseUiField. However, all of the existing usages of UI fields in your application, as well as the specific UI field implementations, won’t need to change.

No Comments
Share
2

About Roman Sery

I've been a software developer for over 10 years and still loving Java!

You also might be interested in

Tracking down a bug in production Wicket application

Jun 20, 2020

Investigating a problem with duplicate markup ID's generated by Wicket and how to solve it.

Wicket quick tip #4: Change default AjaxChannel to Active

Jul 7, 2020

Change the default behavior of Wicket's ajax request processing in order to avoid some common bugs.

Spring MVC vs Wicket

Jun 9, 2020

Let's compare Wicket and Spring MVC by trying to implement a simple application using both. Our application will allow users to add cars to a database.

Categories

  • aws
  • customization
  • database
  • debugging
  • enum
  • java
  • models
  • performance
  • projects
  • react
  • software design
  • Spring
  • tool
  • Uncategorized
  • wicket

Recent Posts

  • Rent Day
  • Self-contained Wicket Fragments
  • Pros and cons of unit testing
  • Themeable React Monopoly board
  • Please dont use client-specific release branches

Recent Comments

  • TCI Express Thanks for sharing such insightful information. TCI Express truly stands out as the best air logistics company, offering fast, secure, and efficient air express and cold chain transportation services....

    Tracking down a bug in production Wicket application ·  March 25, 2025

  • Tom Error: A zip file cannot include itself Can you please correct the plugin part so it doesn't use the same folder as input?

    Deploying Spring Boot app to AWS Beanstalk with Nginx customization ·  September 3, 2021

  • Golfman: Reality always wins I've used both Wicket and front-end JS frameworks and, having worked extensively on both, I can tell you that "Speed of development" is definitely NOT with the JS frameworks. You basically end up...

    Five reasons you should use Apache Wicket ·  August 29, 2021

  • Kiriller Sorry can not agree with you, wicket might be a well built technical framework. But the advantages of using a front-end framework like react.js and vue.js can not be beaten by Wicket nowadays. - Speed...

    Five reasons you should use Apache Wicket ·  August 23, 2021

  • Bernd Lauert Sorry but i have to refute your claims with the following arguments: 1. the Wicket community may be small but it is also very responsive, you usually get a helpful answer from the core devs on the...

    Five reasons you should use Apache Wicket ·  July 1, 2021

Archives

  • May 2021
  • October 2020
  • September 2020
  • August 2020
  • July 2020
  • June 2020
  • May 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • October 2019
  • September 2019
  • August 2019
  • July 2019

Contact Me

Send Message
Prev Next