Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Wicket Components: Stateful but Manageable

Posted on July 12, 2012 By Luis Fernandez

Apache Wicket gets a weird rep in Java circles. People love the HTML friendliness but get spooked by the word stateful. If you have been shipping apps on Tomcat or Jetty and someone told you Wicket will flood the session, stick around. From the trenches, Wicket components are stateful but manageable. You can keep memory tight, keep pages bookmarkable, and still enjoy a clean separation of markup and code.

Problem framing

Right now everyone is split across Spring MVC, JSF, Play and friends. Ajax is table stakes, mobile traffic is climbing, and ops keeps asking for smaller session footprints. Wicket scares folks because it stores page state so it can do component oriented magic. The fear is fair: if you throw domain objects into models and let page versioning run wild, memory will drift. The happy path is simple though. Choose stateless where it fits. Keep models lightweight. Turn off versioning when you do not need it. Use providers for big lists. The result is a calm codebase with friendly HTML and no surprise GC storms.

Three case walkthrough

Case 1: A stateless search page

Public pages like search and product detail should be bookmarkable and stateless. Wicket does that out of the box with bookmarkable pages, PageParameters and StatelessForm.

public class SearchPage extends WebPage {
  private final IModel<String> q = Model.of("");

  public SearchPage(PageParameters params) {
    String fromUrl = params.get("q").toString("");
    q.setObject(fromUrl);
    add(buildForm());
  }

  public SearchPage() {
    add(buildForm());
  }

  private Component buildForm() {
    StatelessForm<Void> form = new StatelessForm<>("form") {
      protected void onSubmit() {
        PageParameters p = new PageParameters();
        p.add("q", q.getObject());
        setResponsePage(SearchPage.class, p);
      }
    };
    form.add(new TextField<>("q", q));
    return form;
  }
}

This page renders the same URL for the same query, plays nice with caches, and stores no heavy data in the session.

Case 2: A multi step wizard without bloating the session

Wizards are stateful by nature. Keep the footprint small with lightweight DTOs, turn off page versioning if you do not need back button history, and load entities lazily with a LoadableDetachableModel.

public class EditCustomerPage extends WebPage {
  public EditCustomerPage(final Long id) {
    IModel<Customer> customer = new LoadableDetachableModel<>() {
      protected Customer load() { return customerService.get(id); }
    };
    setVersioned(false); // keep only the current page
    Form<Customer> form = new Form<>("form", new CompoundPropertyModel<>(customer)) {
      protected void onSubmit() {
        customerService.save(getModelObject());
        info("Saved");
      }
    };
    form.add(new TextField<>("name"));
    form.add(new TextField<>("email"));
    add(form);
  }
}

The model detaches after each request, so only an id stays in memory. No giant object graphs in the session.

Case 3: A big list that stays quick

Do not stash a thousand rows in a panel. Let Wicket stream items with IDataProvider and DataView. It only loads the page slice you need.

public class OrdersPage extends WebPage {
  public OrdersPage() {
    IDataProvider<Order> provider = new IDataProvider<>() {
      public Iterator<? extends Order> iterator(long first, long count) {
        return orderRepo.page(first, count).iterator();
      }
      public long size() { return orderRepo.count(); }
      public IModel<Order> model(Order o) {
        return new LoadableDetachableModel<>() {
          private final Long id = o.getId();
          protected Order load() { return orderRepo.get(id); }
        };
      }
      public void detach() { }
    };
    DataView<Order> view = new DataView<>("rows", provider, 25) {
      protected void populateItem(Item<Order> item) {
        Order o = item.getModelObject();
        item.add(new Label("id", o.getId()));
        item.add(new Label("total", o.getTotal()));
      }
    };
    add(view);
  }
}

Memory stays flat, paging is smooth, and markup remains clean for your CSS and your designer.

Objections and replies

  • Wicket will blow up my session. Only if you let it. Keep models lean, prefer providers, and tune settings. You can cap per session page bytes and back pages. Look at getStoreSettings() and getPageSettings() in your WebApplication.
  • I lose control of HTML. Wicket markup is plain HTML with wicket:id. You keep semantic tags. Your designer can work in a normal editor. Components bind without messing with the structure.
  • State breaks bookmarks. Use bookmarkable pages with PageParameters for search, detail and filter views. Mix stateless and stateful pages in the same app.

Action oriented close

Want sane state with Apache Wicket? Use this short list and ship.

  1. Favor stateless for entry points like home, login, search and detail. Use StatelessForm and PageParameters.
  2. Control page versioning. Call setVersioned(false) on pages that do not need back button history.
  3. Keep models tiny. Wrap entities in LoadableDetachableModel. Pass ids not graphs.
  4. Stream big data. Use IDataProvider with DataView or DataTable. No giant lists in memory.
  5. Tune the store. In your app init, set limits:
    getStoreSettings().setMaxSizePerSession(Bytes.kilobytes(512));
    getPageSettings().setVersionPagesByDefault(false);
  6. Measure. Turn on Wicket debug bars in dev, log page sizes, and watch session bytes in your container.

Wicket components are stateful by design, which is why they feel nice to code. Keep the state where it helps you, trim it where it does not, and you get a tidy Java web framework with clear HTML and steady memory. That is a deal I will take any day.

Software Architecture Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes