Class SHelper
com.vaadin.swingbridge.surrogates.*. Surrogate-local mirror of
vaadinx.EHelper — module direction is :emulators → :surrogates,
so we can't reuse the emulator's helper without inverting it (SD_shelper_statics).-
Field Summary
FieldsModifier and TypeFieldDescriptionTest-only capture sink foronUnimplemented(Object, String, Object...). -
Method Summary
Modifier and TypeMethodDescriptionstatic <T extends EventListener>
T[]awtOrder(EventListenerList list, Class<T> type) The stored listeners oftypein AWT dispatch order — first-registered-first, which is the reverse of whatEventListenerListyields.static voidUniform funnel for Vaadin peer → Swing-side callbacks.static voidmarkContentPaneSpan(com.vaadin.flow.component.Component host, com.vaadin.flow.component.Component pane, com.vaadin.flow.component.Component old) Tags a window's content pane, and the window itself, so the content pane fills the window body instead of rendering at intrinsic height inside it.static voidmarkLayeredPane(com.vaadin.flow.component.Component layeredPane) Tags a layered panedisplay: contents, so its children become direct flex items of the root pane's column and the pane itself contributes no geometry.static voidmarkMenuBarSlot(com.vaadin.flow.component.Component bar, com.vaadin.flow.component.Component old) Tags a menu bar to take its intrinsic height in the root pane's column, leaving the rest to the content pane — the CSS spelling ofJRootPane.RootLayout'smenuBar.setBounds(0, 0, w, mbd.height).static voidmarkRootPane(com.vaadin.flow.component.Component rootPane) Tags a root pane so it becomes the flex column the menu bar and content pane stack inside, and the positioned ancestor the glass pane insets against.static voidofferSession(com.vaadin.flow.component.Component peer, com.vaadin.flow.server.VaadinSession session) Recordssessionaspeer's unless it already has one: how an emulator built off the UI thread, whose context knows the session, hands it to a surrogate whose constructor found none current.static voidDeliberate no-op hook for Swing API that's redundant in the Vaadin world (layout invalidation, repaint, peer lifecycle, paint dispatch).static voidonUnimplemented(Object self, String method, Object... args) Warn-and-continue stub hook for unimplemented surrogate API.static voidonUnsupportedPeerShape(String className, String situation) ERROR-log hook for situations where emulation can't honor a well-formed Swing request because the peer-element shape is wrong — e.g. setting aLayoutManageron a Container whose host element isn't a plain<div>.static com.vaadin.flow.component.UIownerUI(com.vaadin.flow.component.Component peer) The UI owningpeer's state tree, ornullif it has none.static StringresolveSwingClassName(Class<?> klass) Resolve a class to a non-emptyClass.getSimpleName()by walking up the superclass chain past anonymous-class frames (whose simpleName is"").static voidrunOnOwnerUI(com.vaadin.flow.component.Component owner, Runnable body) Runsbodyonowner's UI thread and returns once it has run — the surrogate-side hop for the carve-out in R_tolerate_off_ui_thread's surrogate limb, which allows it only inside a callback from a Swing model.static voidrunOnSession(com.vaadin.flow.server.VaadinSession session, com.vaadin.flow.component.Component peer, Runnable body) Runsbody, which touchespeer, undersession's lock and withpeer's UI current, and returns once it has run: the one implementation of the UI hop, behind bothrunOnOwnerUI(Component, Runnable)and the emulators'withPeer.static com.vaadin.flow.server.VaadinSessionsessionOf(com.vaadin.flow.component.Component peer) The sessionpeercaptured — at construction when one was current, else handed down by its emulator (offerSession(Component, VaadinSession)), else at first attach — ornullif it has none.static voidstampSwingClass(com.vaadin.flow.component.Component target, Class<?> klass) Stamp thedata-swing-classattribute on a peer / surrogate element so DevTools shows which Swing class a Vaadin element is standing in for.
-
Field Details
-
warnHook
Test-only capture sink foronUnimplemented(Object, String, Object...). Tests install a collector to assert "this path fires no stub-level WARNs" without having to reconfigure logging; production stays on the no-op default so call sites can feed the hook unconditionally.
-
-
Method Details
-
onUnimplemented
Warn-and-continue stub hook for unimplemented surrogate API. Logs WARN and returns; never throws (R_match_swing_errors / SD_dropin_stance). The first arg is the receiver instance — its runtime class shows up in the log, so a surrogate extending different Vaadin types each report their actual class name. -
callSwing
Uniform funnel for Vaadin peer → Swing-side callbacks. Every surrogate's Vaadin-listener body whose job is to fire a Swing-style event (model change, ChangeListener fan-out, focus, value-change, window closing, …) wraps through here instead of callingrunnable.run()directly.Today this is literally
runnable.run()and will stay that way (SD_sframe). Blocking-dialog handling is an:emulators-layer concern:Dialog.setOpened(boolean)and modalJOptionPane.showXxxDialogcalls don't block the Vaadin request thread without the UI-fiber hook, and that hook lives only invaadinx.EHelper.callSwing— surrogates can't hack around it without duplicating machinery we intentionally scope to the emulator layer. The seam survives here as a uniform peer→Swing funnel for future cross-cutting work (log instrumentation, error-handler routing, etc.) that would otherwise have to audit every listener.Exceptions propagate. Vaadin's
ErrorHandleris the proper escalation path; swallowing here would pre-empt user error handling and hide real bugs. -
runOnOwnerUI
Runsbodyonowner's UI thread and returns once it has run — the surrogate-side hop for the carve-out in R_tolerate_off_ui_thread's surrogate limb, which allows it only inside a callback from a Swing model.// SJComboBox's ListDataListener, on whatever thread mutated the model: // Allowed by R_tolerate_off_ui_thread because callback from model: ComboBoxModel ListDataListener SHelper.runOnOwnerUI(this, () -> onModelEvent(e));Goes through the session
ownercaptured (sessionOf(Component)); seerunOnSession(VaadinSession, Component, Runnable)for what happens under its lock.Synchronous by design, per SD_background_model_hop: Swing fires a model's listeners before the mutator returns, and a deferred body would reorder them against the caller's next line.
-
runOnSession
public static void runOnSession(com.vaadin.flow.server.VaadinSession session, com.vaadin.flow.component.Component peer, Runnable body) Runsbody, which touchespeer, undersession's lock and withpeer's UI current, and returns once it has run: the one implementation of the UI hop, behind bothrunOnOwnerUI(Component, Runnable)and the emulators'withPeer.Nothing about
peeris read before the lock is held. Its state node, its parent chain andgetUI()are written by the UI thread under that lock, so an unlocked read races it, andComposite.getElement()even initialises content. Under the lock, the UI owning the peer's state tree is the one made current; a peer detached after being attached still names its old tree, which Flow still guards.Inline when a UI is already current (the caller holds the lock), and when
sessionisnull: the peer has captured none, so it has never been attached, has no state tree, and has no lock to take. If the hop itself fails before the body starts, it is logged at WARN and the body runs inline, unlocked. An exception from the body always propagates, and the body never runs twice.- Parameters:
session- the sessionpeercaptured, ornullif it has none
-
ownerUI
public static com.vaadin.flow.component.UI ownerUI(com.vaadin.flow.component.Component peer) The UI owningpeer's state tree, ornullif it has none. Only call it holding the session lock. -
sessionOf
public static com.vaadin.flow.server.VaadinSession sessionOf(com.vaadin.flow.component.Component peer) The sessionpeercaptured — at construction when one was current, else handed down by its emulator (offerSession(Component, VaadinSession)), else at first attach — ornullif it has none. Reads the surrogate's privatehopSessionfield, which isvolatile; a component with no such field (a bare Vaadin component) answersnull. -
offerSession
public static void offerSession(com.vaadin.flow.component.Component peer, com.vaadin.flow.server.VaadinSession session) Recordssessionaspeer's unless it already has one: how an emulator built off the UI thread, whose context knows the session, hands it to a surrogate whose constructor found none current. No-op for a bare Vaadin component or anullsession. -
onNoop
Deliberate no-op hook for Swing API that's redundant in the Vaadin world (layout invalidation, repaint, peer lifecycle, paint dispatch). Logs at DEBUG only — these get hit hot, and unlikeonUnimplemented(Object, String, Object...)the call is answered by design, not deferred work. Does not feedwarnHook: the testapps WARN-inventory gates assert emptiness, and a deliberate-noop should not count as a stub regression.No varargs on purpose: args add no information for a call we ignored by design, and omitting them keeps the hot path allocation-free.
-
onUnsupportedPeerShape
ERROR-log hook for situations where emulation can't honor a well-formed Swing request because the peer-element shape is wrong — e.g. setting aLayoutManageron a Container whose host element isn't a plain<div>. Mirrorsvaadinx.EHelper.onUnsupportedPeerShapeverbatim —classNameis used directly, not resolved from an object's runtime class: callers here pass a descriptive name (e.g. the offendingLayoutManager's name) rather than the offending instance. Louder thanonUnimplemented(Object, String, Object...)'s WARN because the user has stepped into genuinely broken territory; returns without throwing per R_match_swing_errors. -
resolveSwingClassName
Resolve a class to a non-emptyClass.getSimpleName()by walking up the superclass chain past anonymous-class frames (whose simpleName is""). User code that doesnew SJButton() { ... }thus stamps as"SJButton", not blank. -
stampSwingClass
Stamp thedata-swing-classattribute on a peer / surrogate element so DevTools shows which Swing class a Vaadin element is standing in for. Last-write-wins: when an emulator wraps a surrogate, the emulator's stamp overwrites the surrogate's — stage-2 user code sees the emulator class, stage-3 user code sees the surrogate class. -
markContentPaneSpan
public static void markContentPaneSpan(com.vaadin.flow.component.Component host, com.vaadin.flow.component.Component pane, com.vaadin.flow.component.Component old) Tags a window's content pane, and the window itself, so the content pane fills the window body instead of rendering at intrinsic height inside it.Both classes are defined in
emul/swindow.css, which carries the measurements and the reasonflex-basismust stayauto. Call after the pane is planted, and on every swap — passing the pane being replaced asoldso it gives the class back.- Parameters:
old- the content pane being replaced, ornullon first plant
-
markRootPane
public static void markRootPane(com.vaadin.flow.component.Component rootPane) Tags a root pane so it becomes the flex column the menu bar and content pane stack inside, and the positioned ancestor the glass pane insets against. The rule is inemul/swindow.css; call once per root pane, at construction.Both layers call this on the same element — the emulator's
JRootPanepeers on the surrogate it tags — so the class is idempotent by construction. -
markLayeredPane
public static void markLayeredPane(com.vaadin.flow.component.Component layeredPane) Tags a layered panedisplay: contents, so its children become direct flex items of the root pane's column and the pane itself contributes no geometry. Measured a layout no-op; seeemul/swindow.cssfor what breaks with a bareDivinstead.Applies to the instance a root pane owns, never to
JLayeredPaneas a class —JDesktopPaneextends it, and a universal rule would strip every user-instantiated one of its containing block. -
markMenuBarSlot
public static void markMenuBarSlot(com.vaadin.flow.component.Component bar, com.vaadin.flow.component.Component old) Tags a menu bar to take its intrinsic height in the root pane's column, leaving the rest to the content pane — the CSS spelling ofJRootPane.RootLayout'smenuBar.setBounds(0, 0, w, mbd.height).- Parameters:
old- the menu bar being replaced, ornullon first plant
-
awtOrder
The stored listeners oftypein AWT dispatch order — first-registered-first, which is the reverse of whatEventListenerListyields.- Type Parameters:
T- an AWT listener type. Swing listener types must not come through here:AWTEventMulticasterdispatches first-registered-first while Swing's list is last-first, and each convention is correct for its own half of the JDK (D_awt_dead_hooks).- Returns:
- a fresh array, reversed in place; iterate it rather than re-reading the list, so in-dispatch listener mutation stays safe
-