fix(geolocation): replace setClient with Lookup-based factory SPI#24259
Merged
fix(geolocation): replace setClient with Lookup-based factory SPI#24259
Conversation
Promote GeolocationClient to a public SPI and add a GeolocationClientFactory extension point resolved through com.vaadin.flow.di.Lookup. Geolocation queries the factory at construction time and falls back to the built-in browser-backed client when none is registered. Replaces the package-private Geolocation#setClient seam introduced in 1e432d2. Package-private cross-JAR access is unreliable under split- classloader topologies (Quarkus, OSGi, JPMS): the JVM scopes runtime packages by classloader, so a class in flow-server.jar and one in an external JAR with the same package string land in different runtime packages once their JARs load through different classloaders. Lookup is classloader-aware and explicitly designed for this kind of pluggable SPI. setClient stays package-private as an in-JAR seam for flow-server's own tests; external test drivers and native bridges (Cordova, Electron, Capacitor) register a GeolocationClientFactory via META-INF/services. Fixes #24211 follow-up (browserless-test Quarkus IllegalAccessError).
heruan
added a commit
to vaadin/browserless-test
that referenced
this pull request
May 5, 2026
Stop calling the package-private Geolocation#setClient seam from GeolocationSimulator.forUI; instead ship a BrowserlessGeolocationClientFactory implementation of Flow's new GeolocationClientFactory SPI, registered via META-INF/services. Flow's Lookup discovers it during bootstrap, so the in-memory client is installed automatically the first time UI's constructor creates the Geolocation facade — for any UI subclass, including custom ones. The factory also publishes the GeolocationSimulator on the UI via ComponentUtil.setData; GeolocationSimulator.forUI is now a pure lookup that throws if the simulator is missing. The eager GeolocationSimulator.forUI(this) call in MockedUI.<init> is removed: the factory has already installed the simulator during super() before the init block runs. Fixes the Quarkus IllegalAccessError caused by package-private cross-JAR access under split-classloader topologies. Requires the matching Flow change in vaadin/flow#24259.
mcollovati
reviewed
May 5, 2026
Address review feedback on #24259: - Mark GeolocationClientFactory and the SPI Javadoc on BrowserGeolocationClient and GeolocationClient as "Framework internal". - Replace META-INF/services-specific wording with a generic reference to Lookup, since vaadin-spring and vaadin-quarkus install their own Lookup implementations that do not use service files. - Drop the speculative "native bridges in Cordova/Electron/Capacitor" use case from GeolocationClientFactory; document only the actual driver (browserless test drivers under split-classloader topologies). Also fix an NPE in Geolocation.lookupFactory observed in CI: some test scaffolding (Mockito-mocked VaadinService) returns null from getContext(). Treat a null context as "no factory registered" and fall back to the built-in browser-backed client.
|
mcollovati
approved these changes
May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
GeolocationClientto a public SPI and adds aGeolocationClientFactoryextension point resolved throughcom.vaadin.flow.di.Lookup.Geolocationqueries the factory at construction time and falls back to the built-in browser-backed client when none is registered.setClientis retained as a package-private in-JAR seam for flow-server's own tests; external test drivers and native bridges register a factory viaMETA-INF/services.Why
Follow-up to #24211. The
setClientseam (originally package-private) breaks under split-classloader topologies (Quarkus, OSGi, JPMS): the JVM scopes runtime packages by classloader, so a class inflow-server.jarand one in an external JAR with the same package name end up in different runtime packages when their JARs load through different classloaders. Cross-JAR package-private access then throwsIllegalAccessErrorat class definition time. Reproduced locally and in CI on browserless-test PR #51:Lookupis classloader-aware and explicitly designed for this kind of pluggable SPI — it's the canonical Flow pattern (InstantiatorFactory,RoutePathProvider,ResourceProvider,StaticFileHandlerFactory,BrowserLiveReloadAccessor).Changes
GeolocationClient→public interfacewith proper SPI Javadoc (no longer "framework internal").GeolocationClientFactory(new) →public interface, resolved viaLookup; documents the use cases (in-memory test drivers; native bridges in Cordova/Electron/Capacitor shells).Geolocationconstructor callsresolveClient(ui)→ looks up a factory viaVaadinService.getCurrent()→Lookup.lookup(GeolocationClientFactory.class); falls back tonew BrowserGeolocationClient(ui, seed)when no factory is registered.setClientstays package-private — flow-server's own tests use it; external code goes throughLookup.BrowserGeolocationClientJavadoc updated to mention it's the no-factory default.GeolocationClientSeamTestnow exercises both the public Lookup-factory path and the in-packagesetClientseam.No
META-INF/servicesfile is shipped from flow-server: production has no factory and uses the fallback. Implementations live in external JARs (e.g. browserless-test-shared).Test plan
mvn test -pl :flow-server -Dtest='*Geolocation*'— 38/38 pass locally.@SuppressWarnings("NullAway")introduced; constructor assigns theclientfield directly.IllegalAccessErrornow passes (junit6 21/21, quarkus 11/11, includingQuarkusBrowserlessBaseClassTestandQuarkusUnitSecurityTestthat were failing).cc @mcollovati