Skip to content

Add wicketstuff-spring-boot-starter: Apache Wicket on Spring Boot 4 - #1568

Open
danielbartl wants to merge 35 commits into
wicketstuff:masterfrom
danielbartl:spring-starter
Open

danielbartl wants to merge 35 commits into
wicketstuff:masterfrom
danielbartl:spring-starter

Conversation

@danielbartl

Copy link
Copy Markdown

Summary

Adds wicketstuff-spring-boot-starter, a small Spring Boot starter that runs Apache Wicket on Spring Boot 4 with a single dependency. Adding it and starting the application gives a running Wicket app: the starter registers the WicketFilter, wires @SpringBean injection, and exposes the Wicket settings as Spring properties.

The goal after this merge is to get Wicket listed on start.spring.io, the way Vaadin already is. That needs a released version on Maven Central, so the plan is: merge, ship with the next wicketstuff release, then request the listing from the Spring Initializr team. The Initializr entry is already written up in the module README.

What the starter provides

One auto-configuration, WicketAutoConfiguration. It is active for servlet web applications with Wicket on the classpath, and can be switched off with wicket.enabled=false.

  • Wicket application: uses the application's own WebApplication bean, or a built-in default page ("It works!") if there is none.
  • Spring injection: @SpringBean works in pages and components, and already inside the application's init().
  • Filter registration: WicketFilter is registered with the embedded container. It backs off when the application registers its own WicketFilter or FilterRegistrationBean<WicketFilter>.
  • Properties: wicket.configuration, wicket.filter-path, wicket.filter-name and wicket.filter-order, with IDE autocompletion.
  • Spring MVC: @RestController endpoints keep working next to Wicket pages.
  • DevTools: works out of the box. The starter ships a META-INF/spring-devtools.properties that moves the Wicket and wicketstuff jars into DevTools' restart classloader. Without it, restoring a stored page (e.g. on the back button) fails with a ClassCastException on @SpringBean fields.
  • Compatibility: Spring Boot 4.0.x and 4.1.x, Java 17+.

Changes outside the new module

  • pom.xml: adds the module, and adds wicketstuff-spring-boot-starter-examples to the central-publishing-maven-plugin exclusions.
  • wicketstuff-bom/pom.xml: adds the same examples module to the BOM exclusions, keeping the two lists in sync. The BOM will contain wicketstuff-spring-boot-starter itself.

Notes for reviewers

  • Version overrides. The starter's parent pom overrides eight of the root pom's version properties with Spring Boot's values (Spring, Jackson 2 and 3, slf4j, logback, log4j, commons-logging, JUnit). Otherwise the root pins win over the imported Spring Boot BOM, and the starter would be tested against library versions no Spring Boot application runs with, including a mix of jackson-databind 3.2 and jackson-core 3.1. BuildAlignedWithSpringBootTest fails as soon as an override drifts from the BOM. Dependabot PRs that bump these overrides will fail on purpose; they should be closed rather than merged, and the overrides updated together with spring-boot.version. This only affects the two starter modules.
  • Integration test. wicketstuff-spring-boot-starter/src/it holds a small project built on spring-boot-starter-parent, run by maven-invoker-plugin during verify. It checks the starter against exactly what a generated Spring Boot project gets. It downloads Spring Boot's parent pom on first use. -DskipTests skips it, and -Dspring-boot.version=… runs it against another Spring Boot line.
  • Examples module. It is not published. It demonstrates the documented patterns as integration tests, and an enforcer rule keeps its only compile dependency the starter itself.
  • History. The branch has 35 commits, including early iterations. A squash merge is probably cleaner.

Testing

  • mvn clean verify of the starter modules on Java 17 via the root toolchain: 18 unit tests, the integration test and 11 example tests, all passing.
  • The integration test also passes with -Dspring-boot.version=4.0.8.
  • DevTools: checked by hand in a running application. The back button works, three restarts in a row were clean, and the session survived them.
  • BOM: built together with the starter modules; it lists the starter and not the examples.
  • A full build of the whole repository has not been run locally; CI will cover it.

🤖 Generated with Claude Code

danielbartl and others added 30 commits September 28, 2026 22:09
…ed dependencies, and static resources integration
The starter module was added while the root reactor was at
10.10.0-SNAPSHOT; the root has since moved to 10.12.0-SNAPSHOT but the
starter, examples, and their aggregator parent POM were left pointing
at the old version, breaking parent resolution.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Import spring-boot-dependencies as a BOM instead of hardcoding
  spring-boot.version on every individual Spring Boot dependency, so
  versions stay consistent and are managed from one place.
- Guard WicketAutoConfiguration with @ConditionalOnWebApplication(SERVLET)
  so it doesn't try to register a servlet FilterRegistrationBean in a
  non-servlet (e.g. reactive) application.
- Add spring-boot-maven-plugin's repackage goal to the examples module
  so it produces a runnable jar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- wicket-spring-boot-starter: WicketAutoConfigurationTest exercises the
  autoconfiguration in isolation via ApplicationContextRunner (default
  bean wiring, custom wicket.* property binding, @ConditionalOnMissingBean
  back-off, and the SERVLET-only guard); DefaultWebApplicationTest uses
  WicketTester to verify the default home page renders and the mounted
  CSS/PNG resources are actually servable.
- wicket-spring-boot-starter-examples: WicketPropertiesBindingTest proves
  application.properties values reach the registered filter;
  SpringBeanInjectionQuickstartTest is an end-to-end proof of the README's
  Quickstart pattern (custom WebApplication + @SpringBean injection) over
  real HTTP through an embedded servlet container.

Also fixes dependency issues surfaced by actually running this suite:
- wicket-spring-boot-starter needs spring-web (test scope) for
  WebApplicationContextRunner; nothing else on its classpath supplies it
  since spring-boot-autoconfigure's own deps are optional and wicket-spring
  excludes spring-web.
- wicket-spring-boot-starter-parent pins the JUnit Platform/Jupiter family
  and logback-core to the versions the root pom already manages, ahead of
  the spring-boot-dependencies BOM import: the BOM's own versions of those
  artifacts were binary-incompatible with root-managed sibling artifacts
  (junit-jupiter-api/junit-platform-commons, logback-classic/logback-core).
- wicket-spring-boot-starter-examples needs spring-boot-restclient (test
  scope): spring-boot-resttestclient's own autoconfiguration needs
  RestTemplateBuilder from it but doesn't declare it as a dependency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the dependency snippet's undefined \${wicketstuff.version}
  property (not declared in any pom) with the actual current version and
  a pointer to Maven Central for the released version.
- Fix the Spring Initializr versionRange, which was copy-pasted from an
  unrelated example (a stray 4.2.0-M1 patch-level bound). Left it
  open-ended (4.0.0 and later) rather than guessing an unconfirmed future
  Spring Boot major version number.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace the copy inherited from Wicket's old quickstart archetype with
content specific to this starter: drop the dead Freenode IRC link and
outdated JIRA bug-report walkthrough, explain why the page is shown, and
link to the starter's own README Quickstart and the Wicket docs instead.
Also fixes the static "1.5-SNAPSHOT" placeholder text (cosmetic only --
always overwritten at runtime by the version Label).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The root pom.xml already declares Apache License 2.0 (inherited by this
module and its children), but there was no physical LICENSE file
anywhere in the repo to make that unambiguous to someone browsing this
module's directory directly, e.g. Spring Initializr maintainers
reviewing the submission.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WicketProperties.configuration was left null unless explicitly set, with
the DEVELOPMENT fallback only applied manually inside
WicketAutoConfiguration. This meant the property's generated IDE
metadata (spring-configuration-metadata.json) had no defaultValue,
unlike the other two wicket.* properties, contradicting both its own
Javadoc and the README's documented default. Initializing the field
directly fixes the metadata and lets the now-dead null-check in
WicketAutoConfiguration go away, along with its now-unused
RuntimeConfigurationType import.

Also cleans up DefaultWebApplication to use proper imports and Java 17
pattern-matching instanceof instead of inline fully-qualified names and
a manual cast.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ConditionalOnMissingBean(WicketFilter.class) was declared on a method
producing a FilterRegistrationBean<WicketFilter>, so the condition never
examined what the method actually creates. A user registering their own
FilterRegistrationBean<WicketFilter> -- the customization path the README
points at -- ended up with two Wicket filters, ours silently mapped at
/*. Conversely a raw WicketFilter bean made us back off entirely, leaving
Boot to auto-register it with no init parameters and no
SpringComponentInjector, quietly breaking @SpringBean.

Using a bare @ConditionalOnMissingBean lets Boot deduce the bean type
from the return value including its generics, so a user-supplied
FilterRegistrationBean<WicketFilter> now correctly wins. Covered by a new
regression test.

Also removes two pieces of dead/fragile code found while reviewing:
- DefaultWebApplication re-added "+*.css"/"+*.png" resource guard
  patterns that SecurePackageResourceGuard's constructor already
  registers by default.
- The @nonnull on a private helper's return type came from org.jspecify,
  which this module never declared and only got transitively via Wicket.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
The injector was registered inside an anonymous WicketFilter subclass's
init(). Now that the filter registration correctly backs off for an
application-supplied FilterRegistrationBean, that back-off took Spring
injection with it: requesting a page in that setup returned HTTP 500,
because @SpringBean fields were never injected and the page NPE'd.

Wicket's own documentation registers the injector on the WebApplication
rather than the filter, and SpringComponentInjector's constructor only
sets application metadata and binds, so it has no dependency on filter
initialisation. Moving it to its own bean keyed off the WebApplication
keeps injection working whoever owns the filter registration, and drops
the anonymous subclass entirely.

Exposing it as a @ConditionalOnMissingBean bean also gives applications
migrating from a hand-wired Wicket/Spring setup a way to suppress it,
instead of silently ending up with two injectors when their own
WebApplication.init() already registers one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
Third-party starters are generally expected to offer an opt-out, and
there was no way to keep the starter on the classpath while disabling
it. @ConditionalOnProperty sits on the auto-configuration class rather
than on individual beans so the default WebApplication, the injector and
the filter registration all switch off together instead of leaving a
half-configured application. matchIfMissing keeps it on by default, so
existing applications are unaffected.

The property is read only by the condition and never bound to a field,
so it is documented through additional-spring-configuration-metadata.json
rather than by adding an unused field to WicketProperties. The annotation
processor merges it into the generated metadata, so IDE completion covers
it alongside the other wicket.* properties.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
A project whose only dependency is this starter got no embedded servlet
container, no spring-web, and jakarta.servlet-api only at provided scope.
Spring Boot therefore booted it as a non-web application,
@ConditionalOnWebApplication(SERVLET) declined, and the application
exited having served nothing. That is precisely the project Spring
Initializr generates when a user selects Wicket and nothing else, and
Initializr metadata has no way to express "also add Spring Web", so every
generated project would have been dead on arrival.

Depending on spring-boot-starter-web fixes it: the same minimal project
now starts Tomcat, registers the WebApplication and serves the default
page. The examples module drops its own spring-boot-starter-web and
spring-boot-starter-logging declarations as a result, so it now depends
on nothing but the starter and demonstrates that one dependency is
genuinely enough.

Also drops the Google Fonts stylesheet from the default page. It was
fetched on every render of a page shipped into every generated project,
which breaks in offline and air-gapped environments and makes the page
hotlink a third-party service by default, for no benefit given the CSS
already declared fallback fonts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
The packaging bug fixed in the previous commit -- the starter not
bringing a servlet container, so a project depending only on it booted
as a non-web application -- was invisible to the whole test suite,
because both modules used to declare the web stack themselves.

StarterSelfSufficiencyTest closes that gap. This module declares nothing
but the starter at compile scope, so the container it boots can only have
come transitively from the starter. A bannedDependencies enforcer rule
keeps that precondition honest: declaring a Spring Boot starter here
would satisfy the test without the starter supplying anything, so the
rule fails the build and points at the starter instead. Only direct
declarations are checked, leaving the starter's own transitives alone.

Both guards were verified by deliberately breaking them. Note that when
the starter stops supplying the web stack the build fails during test
compilation, in the test that legitimately needs jakarta.servlet.Filter,
rather than with this test's assertion message. The regression is caught
either way, and the enforcer blocks the tempting local fix.

Also documents a footgun this surfaced: Wicket keys its application
registry by filter name and Spring caches test contexts, so tests that
each start a container must set distinct wicket.filter-name values.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
The README explained what to type but never what the starter does. It
did not mention the beans the auto-configuration contributes, that each
steps aside when you define your own, the conditions under which it
applies at all, or that a project gets a placeholder home page until it
registers a WebApplication -- which is the first thing a generated
project shows.

Adds How It Works (activation conditions and the three beans), The
Default Page, Overriding the Defaults, and a migration note for
applications that already register a SpringComponentInjector by hand and
would otherwise end up with two. Every claim was checked against
WicketAutoConfiguration rather than against the previous wording.

Also answers a question the previous commit created. Depending on
spring-boot-starter-web means every application now has Spring MVC's
DispatcherServlet alongside Wicket's filter at /*, so whether
@RestController endpoints still work is the obvious thing to ask.
WicketAndSpringMvcCoexistenceTest establishes that they do -- Wicket
forwards what it does not handle down the filter chain -- so the README
documents verified behaviour with a regression test behind it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
The artifact followed Spring's documented convention for third-party
starters ({name}-spring-boot-starter), but so does the established
com.giffing.wicket.spring.boot.starter:wicket-spring-boot-starter, so
both landed on an identical artifactId differing only by groupId. That
is legal and causes tooling no trouble, but it is confusing when
searching Maven Central, and claiming an existing project's name reads
as territorial when the two are better described as complementary.

Using "wicketstuff" as the name segment stays within the convention,
matches the sibling wicketstuff-* modules in this repo, and says where
the artifact comes from. The pom display names move with it, since
leaving them identical to the other project would have defeated the
point. The Java package was already org.wicketstuff.springboot.starter
and is unchanged.

Also adds a Motivation section to the README covering why a deliberately
small starter is worth having: it supplies the three pieces every Wicket
application on Spring Boot needs and stops there, which keeps it cheap to
re-verify across major versions, and it releases with wicketstuff-core so
the version matching your Wicket version is the one to use. It names the
broader alternative and describes what each is good for, so readers can
choose deliberately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
The module is called "examples" but its main source is a bare
@SpringBootApplication, so a reader browsing it learns nothing and the
emptiness looks like an oversight rather than the point. Meanwhile the
patterns the README documents -- a custom WebApplication, @SpringBean
injection, overriding the filter registration, REST controllers beside
Wicket pages -- are all demonstrated in the integration tests, where
nobody thinks to look.

Rather than move those demonstrations into src/main, where they would be
unverified sample code free to drift, this documents where they already
are: a module README mapping each pattern to the test that shows it, a
pom description saying what the module is for, javadoc on
ExampleApplication explaining that having nothing in it is the
demonstration, and comments in application.properties noting that none of
those settings are required.

Also records the compatibility result behind the Initializr metadata's
versionRange of 4.0.0: an application built on spring-boot-starter-parent
4.0.3 resolves Spring Boot 4.0.3 rather than being pulled to the 4.1.0
this starter is built against, and boots and serves correctly on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
spring-boot-starter-web is deprecated as of Spring Boot 4; its own pom
description says "deprecated in favor of spring-boot-starter-webmvc".
The replacement carries the same four dependencies plus
spring-boot-starter itself, so logging arrives explicitly rather than
incidentally, and it is what Vaadin's Initializr-listed starter depends
on.

Also documents WAR deployment. The starter ships an embedded Tomcat but
does not commit anyone to it: declaring spring-boot-starter-tomcat at
provided scope demotes the whole embedded chain even though it arrives
transitively through the starter. Verified by packaging a war against the
installed artifact -- no tomcat jars in WEB-INF/lib, while wicket-core,
the starter and spring-boot-webmvc are packaged as normal.

That also settles whether to adopt the conventional split between an
autoconfigure module and a dependency-only starter. Supporting an
external servlet container was the concrete reason to want it, and it
turns out not to need one, so the single combined module stays -- which
Spring's documentation explicitly allows, and which can still be split
later without changing any consumer's coordinates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
4.1.1 is the current stable release; the starter was pinned to 4.1.0.
This is the one dependency version the module pins itself rather than
inheriting from the root pom, so it does not move with the reactor and
needs bumping deliberately. Tomcat moves 11.0.22 to 11.0.24 with it.

Found while sweeping for deprecated dependencies before a first release.
That sweep came up clean otherwise: all 83 resolved artifacts checked for
deprecation notices (the four hits were false positives, matching only
their own showDeprecation compiler settings), and a clean recompile of
all sources with deprecation warnings enabled produced none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012N3ZXf1gtmcbQ2jWcqyDTF
Replace the placeholder "WicketStuff" author and add @author tags
across the module, matching the convention used elsewhere in the
repo of crediting the actual contributor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ConditionalOnMissingBean only matched a FilterRegistrationBean<WicketFilter>,
so an application declaring a plain WicketFilter bean got Wicket mapped twice.
@ConditionalOnMissingFilterBean covers both forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…izr metadata

Add an invoker integration test: a project shaped like one generated by
Spring Initializr, inheriting from spring-boot-starter-parent, so it runs
against exactly the library versions Spring Boot manages rather than the
ones wicketstuff-core pins. -Dspring-boot.version=... checks other Boot
lines; it passes on 4.0.8 and 4.1.1.

The Initializr metadata in the README used the old versionRange key, an
open-ended range and no starter version, which would generate a build that
does not resolve. Replace it with a bounded compatibilityRange and a
version mapping, and state the verified Boot lines in the compatibility
matrix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Versions pinned by wicketstuff-core win over the imported Spring Boot BOM,
so the starter was built and tested against e.g. logback 1.6 and
jackson-databind 3.2 next to jackson-core 3.1. Override those properties in
the starter parent with Spring Boot's values, drop the JUnit/logback-core
workaround this made necessary, and add BuildAlignedWithSpringBootTest to
fail the build as soon as the overrides drift from the BOM.

Also drop the redundant provided jakarta.servlet-api dependency; the
embedded Tomcat already supplies the servlet API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spring Boot initialises the embedded container's filters, and with them the
Wicket application, while the context is still refreshing. The injector was
an ordinary singleton created afterwards, so Injector.get() returned null in
WebApplication#init() and nothing could be injected there.

Register the injector from a BeanPostProcessor as soon as a WebApplication
bean is created instead. It still backs off for a user-defined
SpringComponentInjector bean and still works with custom filter
registrations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
spring-boot-autoconfigure-processor writes
META-INF/spring-autoconfigure-metadata.properties, which lets Spring Boot
evaluate the class conditions without loading the auto-configuration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s at root

- Add the Apache 2.0 license header to all sources, markup and CSS.
- Indent WicketAutoConfiguration and DefaultHomePage with tabs like the rest.
- Link the default page's stylesheet and logo with <wicket:link> as package
  resources instead of mounting them at the application root, where they
  could shadow an application's own static files.
- Show the release version, not a snapshot, in the README's Maven snippet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
danielbartl and others added 5 commits September 28, 2026 22:54
Defaults to Ordered.LOWEST_PRECEDENCE, the order the registration already
had, so Wicket keeps running after every other filter, including Spring
Security's. Changing it no longer requires replacing the whole filter
registration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With DevTools, Wicket's jars and a stale copy of the application classes
stay in the base classloader while the application runs in the restart
classloader. Restoring a stored page (the back button, or any page after a
restart) resolved the page class from the base classloader but rebuilt its
@SpringBean proxies for the restart classloader, failing with a
ClassCastException.

Ship META-INF/spring-devtools.properties to load all Wicket and wicketstuff
jars in the restart classloader, guard its patterns with a test against the
Wicket jars on the classpath, and document DevTools usage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The examples module is excluded from publishing, so the BOM must not
reference it either; its exclusion list is kept in sync with the publishing
one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Quickstart: define the injected service and show the page's markup and
  where it goes, so the example actually runs.
- List Spring MVC coexistence, DevTools support and the filter order among
  the features, mention the BOM, and describe accurately what the
  integration test verifies.
- Fix the examples' run command, which failed to resolve the spring-boot
  plugin prefix, and list SpringBeanInjectionDuringInitTest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
State the goal in the motivation and outline the steps: merge, release to
Maven Central, then request the listing with the prepared Initializr entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@klopfdreh
klopfdreh requested a review from solomax October 1, 2026 07:56
@klopfdreh

klopfdreh commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Hey,

thanks a lot for all the effort. I have just a question regarding the module itself. There is already a Spring Boot integration: https://github.com/MarcGiffing/wicket-spring-boot so, what is the advantage of this one over the one I linked?

@Bean
@ConditionalOnMissingBean(WebApplication.class)
public WebApplication webApplication() {
return new DefaultWebApplication();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can see https://github.com/MarcGiffing/wicket-spring-boot is not creating such a useless WebApplication stub ...

Maybe it worth to create PR against https://github.com/MarcGiffing/wicket-spring-boot with spring-boot version update to 4.1.1 ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I explained the motivation in the readme file of the module:

Running Wicket on Spring Boot always needs the same handful of pieces: a WebApplication, a filter registration for it, and a SpringComponentInjector so that @SpringBean works. None of it is difficult, but it is the same every time, it is easy to get subtly wrong, and it is the first thing standing between someone and a running Wicket page.

This starter supplies exactly those pieces and then gets out of the way. Everything past that point is ordinary Wicket and ordinary Spring, documented in their own projects.

Staying small is the point, not a limitation. A deliberately narrow starter is cheap to keep alive: when Wicket or Spring Boot publishes a new major version, there is very little surface to re-verify. It also lives inside wicketstuff-core and is released with it, so the version you need is simply the one matching your Wicket version, and there is no second release cycle to wait for.

The goal is also to make Apache Wicket selectable on start.spring.io, the way Vaadin already is, so that a new Wicket project is one click away. See Road to start.spring.io for the plan.

Is this the right starter for you?
There is an established alternative, MarcGiffing/wicket-spring-boot (com.giffing.wicket.spring.boot.starter), which is a much broader integration: Spring Security, native WebSockets, bean validation, CSRF protection, several serializers, session datastores, monitoring and a set of development-mode helpers.

Pick that one if you want those batteries included. Pick this one if you would rather start from the smallest thing that works and add what you need yourself. They solve the same problem with opposite philosophies, and neither is a replacement for the other.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense :)

@martin-g could you please take a look at this PR? :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not using Java for 7 years now, so I am not the right person to ask to review :-/

I was going to suggest to add the explanation above in the README, so that the users are aware why there are two similar projects but it is already there:
https://github.com/wicketstuff/core/pull/1568/changes#diff-bd8b825bb0a64ace15552bf450f0f28e38f97386eb73946cf1eafb140b77788eR26-R37

Side note:
The PR description says "Generated with Claude Code". IMO this is more than a disclaimer! The modern way to develop these days is to ask the LLM to do it for you. So, I am not sure there is much value is such starters anymore. Just write the prompt with the your requirements and then tune it (with more prompts :-) ).

This branch was successfully deployed

1 active deployment
CI_DEPLOY — 3d43c112 Deployed Oct 1, 2026 by danielbartl via Java 17 Test #1757
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants