Repository navigation
Swing, SwingX and JavaFX compatibility layers: desktop Java apps as Codename One apps - #5980
shai-almog wants to merge 293 commits into
Conversation
…ides columns Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lifecycle and input events Node, Parent, Group, Region and Pane with one lazily created Codename One peer per node, the JavaFX layout pass pushing bounds into the peers in device pixels, capture and bubble dispatch of pointer and key input, focus, hover and pressed state, the stage hosts (form, window, dialog), Application, Platform and FxLifecycle, the styling hooks, and the first controls (Control, Labeled, ButtonBase, Button, Label). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ene graph to zero SpotBugs findings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HBox, VBox, BorderPane, StackPane, GridPane (with ColumnConstraints, RowConstraints and ConstraintsBase), FlowPane, TilePane and AnchorPane, with the per child constraints, grow and shrink distribution, margins, spans, percentages, wrapping and anchors, and the style hooks the styling contract promises for them. LayoutPanesTest holds each pane to child bounds worked out by hand from the documented layout rules. Region gains a package-private way to position a child inside a margin without resizing it, which BorderPane needs for its edges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ab panes TextInputControl, TextField, PasswordField, TextArea, CheckBox, ToggleButton, RadioButton, Toggle, ToggleGroup, Hyperlink, Separator, Slider, ProgressIndicator, ProgressBar, ScrollPane, SplitPane, TabPane, Tab, SelectionModel, SingleSelectionModel and IndexRange, each over the matching Codename One component where one exists. The scroll, split and tab panes are built from scene-graph regions so their content stays a real descendant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
javafx.animation: Animation, Timeline, KeyFrame, KeyValue, Interpolator, AnimationTimer, Transition and the pause, fade, translate, scale, rotate, sequential and parallel transitions, all driven by one frame clock (runtime.FrameClock) that registers with the form on screen only while something runs and has a manual mode for tests. javafx.concurrent: Worker, WorkerStateEvent, Task and Service. Codename One has no java.util.concurrent beyond the atomic classes, so a Task is a Runnable rather than a FutureTask, has no blocking get(), and a Service has no executor property. The hand-over between threads uses atomics and Platform.runLater only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds javafx.scene.shape (Shape and its subclasses, Path and its elements, SVGPath with a complete path data parser), javafx.scene.text.Text, javafx.scene.transform (2D), javafx.scene.canvas and javafx.scene.image. Everything draws through the one Renderer over FxPath, which gain an elliptical arc, an elliptical round rectangle and a clip. Node.getTransforms() is folded into the paint matrix and so into localToParent, bounds and picking. A canvas keeps a display list that is replayed on paint and is bounded by clearRect and a cap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…logs ListView and TableView show their items in recycled cells over a shared row flow, with single and multiple row selection. ComboBox, ChoiceBox and DatePicker sit on the Codename One picker. ContextMenu, Menu and MenuBar open as popups in a layer over the owner's form, which every host reaches through SceneInput. Dialog, Alert, TextInputDialog and ChoiceDialog block through a modal stage. Control gains a context menu and a tooltip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(T) of an absent item as JavaFX has it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…llapsible pane's toggle action, action accelerators The click tests no longer wait the click count out; the test base resets it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…odelSupport Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… classes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…yout A text area given its text inside a scroll pane overflowed the stack on the pane's next layout: JViewport.doLayout showed the caret, showing a rectangle validated the viewport, and the viewport -- still invalid, because it was in the middle of that very layout -- laid itself out again. Container.validateTree and JViewport.doLayout no longer start a pass that is already under way, which covers the same shape in JList.ensureIndexIsVisible, ScrollDelegate.reveal (JTable, JTree) and JComponent.scrollRectToVisible. The caret is shown after the widget received the text that moved it, not before, so an appended log is followed to its last line. JXErrorPane's workaround is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maven/swing-compat and maven/javafx-compat are relocated into an application and translated by ParparVM with it, where a failed cast is not an exception. Both are roots of check-cast-semantics.sh now, and the PR build compiles them so that --require-all finds them. The six findings were all in javafx.beans.binding.Bindings: the create*Binding factories read the result of an erased Callable inside a try that catches Exception. The result is read as an Object and tested with instanceof. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l acts once The two scroll bars are children of the pane. A desktop port gives them room by policy and overflow and they are dragged with the mouse; a touch device gives them none and keeps Codename One's own indicator. Corner components are laid out, and the upper trailing one also beside a column header when there is no bar below it, which is where SwingX puts the column control. A MouseWheelListener still receives every wheel event: the window's root peer listens to Codename One's wheel events, which fire before anything scrolls. What was wrong is that the content scrolled as well. The Codename One event is consumed now when a listener received it, or when the pane has wheel scrolling turned off, and a wheel event passed on to the pane scrolls it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s on Without line wrap, the default as on the desktop, the area is as wide as its longest line and a scroll pane scrolls it sideways; with it, the area is as wide as the viewport. The Codename One widget always breaks at its width, so it is kept from breaking by being given the width the text needs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h links A pane with the content type text/html is drawn by the reader the labels use instead of as its text with the tags taken out, wrapped at the pane's width. The reader keeps the href of the link a run of text is in, and a click on one fires an ACTIVATED HyperlinkEvent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pup selects once An editable combo box is now a container of its ComboBoxEditor's component and an arrow button that opens a menu of the model's items; Enter in the field makes the text the selected item and fires comboBoxEdited. The modal popup of a combo box that is not editable keeps what the user highlights to itself until it closes, so a dismissed popup fires nothing, and hidePopup closes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A desktop application is compiled against a full JDK and names members the device's classes do not have. The remap now redirects them: - System properties (user.home, os.name, the separators), getenv, exit, lineSeparator; Runtime shutdown hooks, availableProcessors, maxMemory; Thread daemon/name/interrupt state, timed join and the default uncaught exception handler, which is fed from Display's EDT error handling. - String.join/matches/format(Locale)/toLowerCase(Locale), the StringBuilder and StringBuffer searches, substring and replace, and the Character tests. - The Integer/Long/Short/Byte/Double/Float/Boolean statics, and Math's exact, floor, hyperbolic and rounding functions; the transcendental ones go to MathUtil. StrictMath follows Math. - Whole classes: InvocationTargetException, Thread.UncaughtExceptionHandler, java.util.logging Logger and Level over Log, java.util.prefs Preferences over the framework's Preferences. A rule's target may now name a differently called method, which is how Long.decode and Integer.decode share one class. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…record The remap step writes the class the project settings name (codename1.packageName + codename1.mainName): for a Swing application a DesktopLifecycle whose runMain() calls the recorded main(String[]), for a JavaFX one an FxLifecycle whose createApplication() constructs the recorded Application -- its main is never called, and Application.launch does nothing. The kind is inferred when the record leaves it out, a missing record falls back to the only candidate, and everything else fails the build saying what cn1-desktop.properties should hold. The importer sets the template's main class aside so the generated one can take its name, and reports third-party libraries as bundled and relocated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
compat_unrelocated searched class files for the bytes of a package name, and so reported an application that merely holds "javax/swing/JTable" in a string. It now asks UnrelocatedTypes, a small program in the build engine that reads each class as the relocation does and reports type references only. A failure of the check itself no longer reads as a clean directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dependency jar that is part of the application (Maven's compile scope, Gradle's runtime classpath) and refers to a desktop layer is unpacked into the classes directory before the relocation, so it is relocated, redirected and compliance-checked as application code. A provided jar, and one that names no desktop layer, is left as it was. What was unpacked is recorded inside the classes: an unchanged jar is left alone on the next run, a compliance finding names the jar it is in, the check indexes the relocated copy rather than the jar, and the staged application no longer merges the jar a second time, unrelocated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ientations A wrapping list is a grid of equal cells, with the desktop's rules for how many rows and columns it has, and left and right move the selection by a column. Cell bounds, hit testing and sizes are checked against the JDK's own list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
java.awt.Desktop hands URLs to Display.execute; the toolkit's system clipboard is the device's, with a minimal java.awt.datatransfer; the toolkit and ImageIcon read images from a path, a URL or bytes, and an image that cannot be read has no size instead of failing. javax.imageio.ImageIO reads into a BufferedImage and writes PNG and JPEG with the device's encoder, and the Swing relocation now moves javax/imageio/ too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e type selector The default StyleEngine is now a CSS engine that reads the binary table the build compiles, and javafx.fxml.FXMLLoader loads documents the build compiled to Java through a generated dispatcher. Node.getTypeSelector no longer asks a class for its superclass, which the device library cannot answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compiles FXML documents to Java source and JavaFX style sheets to a binary table at build time, and generates the dispatcher that reaches a controller's @FXML members without reflection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…9dbe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… themed defaults setLookAndFeel takes any name or a LookAndFeel object and changes nothing; getInstalledLookAndFeels, getLookAndFeel, getDefaults and the border, insets and dimension getters exist. Keys nobody put answer from the theme for the common endings, and the widgets now read only what the application put, so a color put under a .background key reaches a table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 364b9f049b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…pty shapes and reload fixes from review - The importer decides whether the generated main class name is taken from what Kotlin sources declare, not from their file names, and accepts @JvmStatic public fun main. - Stream.sorted(null) throws, as the JDK does. - Color.decode reads a sign before the radix prefix and rejects values past a signed 32-bit int. - RowFilter compares two numbers of one class as that class does. - Rectangle2D, Ellipse2D and RoundRectangle2D of negative size have no outline. - An iterator taken before ServiceLoader.reload refuses to go on. - FlowLayout's wrap test and AffineTransform's Point2D[] overload stay as the JDK has them; the reasons are in comments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
When Image.createImage(bytes, offset, len) reaches this entry point, neither offset nor offset + length is checked against the Java array length before the pointer is passed to g_memory_input_stream_new_from_data. An invalid but ordinary slice such as an offset near the end with an oversized length therefore makes GdkPixbuf read beyond the managed array instead of producing a Java bounds exception, potentially crashing the native Linux process; validate the complete range before forming bytes + offset.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d-files event and map removal fixes from review - javax.swing.Timer.setDelay reschedules a running timer: the firing already due keeps its time and the new period applies after it. - Delays clamps a delay too long to add to the clock to the end of time instead of wrapping into the past and firing at once. - JFileChooser.setSelectedFiles fires SELECTED_FILES_CHANGED_PROPERTY, and the chooser's own selections go through it. - ObservableMapWrapper's entry iterator reads the removed entry's value at removal, so setValue on an earlier entry no longer changes it. - Linux createImage(byte[], int, int) rejects a range outside the array in Java and in the native decoder. - DefaultListSelectionModel.clearSelection: comment on why an empty selection never loops (the -1 end returns at once, as in the JDK). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5eea8e1241
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…mall-argument sinh/tanh from review - ScheduledPool: a fixed rate's firings that come during an overrun are owed and run late, one after another, as the JDK's scheduleAtFixedRate does, instead of being dropped. - ScheduledPool: work cancelled while it waited for a worker no longer starts once it gets one. - JdkNumbers.sinh/tanh: a Taylor series below |x| = 1, so a small argument is no longer cancelled to zero. - Code comments on four findings that contradict the JDK/OpenJFX: newScheduledThreadPool(0) is accepted, PropertyBase.bind compares by equals, JProgressBar.setModel fires no "model" event, and Interpolator.SPLINE checks the y coordinates too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca2f3a31b9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…vokeAll cancellation and in-place row replacement from review - LocalDate.datesUntil and Matcher.results are lazy streams, as in the JDK: limit(1) makes one date / finds one match. - plusWeeks/minusWeeks (LocalDate, LocalDateTime, ZonedDateTime) throw on a week count whose days overflow instead of wrapping. - invokeAll cancels the unfinished tasks when it exits early; a Future's get no longer starts waiting on an interrupted thread. - RowSelection keeps a row selected when items.set replaces it in place; setAll still clears the selection, as in JavaFX. - Files.move: comment on why a regular file needs no copy fallback (File.renameTo already copies and deletes outside its directory). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ain class preflight The desktop remap writes the application's main class into the classes directory with its own SourceFile marker, so no source file backs it and master's preflight reported it as a stale class. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Compared 181 screenshots: 181 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae409a7eec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ules, intact builders on refused replace, watch goldens - Files.walk and find discover the tree as it is taken. - StringBuilder/StringBuffer replace validate before clearing the builder. - awaitTermination clamps its deadline instead of overflowing. - Color.web checks the final opacity instead of clamping it and reads hsl() as hue/saturation/brightness, both as OpenJFX 23 and 27 do; out-of-range components stay clamped, as there. - Animation checks the delay in the property (zero, unbind, throw) and accepts any cycle count, as OpenJFX does. - Reseed eight watchOS theme goldens for the GeneralPath clip fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 469a61ed5a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ct Duration arithmetic, last Task update wins, complete close failures, stale FXML output cleared - Pattern.flags() reports the top-level inline flags the parse ended in, as the JDK does; splitAsStream finds pieces on demand. - Duration toNanos and multipliedBy throw on overflow instead of wrapping, borrowing a second for negative values so in-range edges still answer. - Task coalesces worker updates behind a queued flag rather than a null sentinel, so a null between two updates no longer outlives the last. - Stream close runs every handler past an Error and suppresses later failures into the first. - Maven and Gradle clear generated FXML/CSS output when the JavaFX layer leaves the class path. - Duration.valueOf keeps OpenJFX's number syntax; comment records why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 89cb8679b1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ode points, provided scope on import, constructor references adapted - java.util.prefs: every use of the Codename One store is serialized; two workers saving at once threw inside Storage, which only logged it. - Files.lines reads as the stream is consumed and closes with it; codePoints reads a StringBuilder when the stream runs. - "".repeat(n) returns at once; an impossible length throws as the JDK does. - The importer keeps Maven provided and Gradle compileOnly dependencies provided instead of bundling them. - Constructor references to adapted constructors (Locale::new, InputStreamReader::new with a Charset) go to static factories. - The fixed-rate overrun test waits longer and reports what it saw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e4ccd77277
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…sinh/cosh to the top of the range, exact Duration plus/minus/negate, block-wise Files.mismatch Preference entries are stored under escaped node path and key, so a key holding a slash or a line break can no longer reach another node's entry or the key index. Duration's plus and minus methods use exact arithmetic and throw where the JDK throws; multipliedBy sums its carry first, so negating the most negative duration answers. MenuItem.fire keeps OpenJFX's behaviour of firing while disabled (documented in the source). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
This overload does not validate cbuf, off, and len before calling read(). With an invalid range such as read(new char[1], 2, 1), it consumes one character and only then throws when assigning to the array, whereas Reader.read must reject the range without changing the stream; the len == 0 fast path also incorrectly accepts null buffers and invalid offsets. Perform the standard null and bounds checks before reading.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| long per = NANOS_PER_SECOND / u.nanos(); | ||
| return duration(amount / per, amount % per * u.nanos()); | ||
| } | ||
| return Duration.ofSeconds(amount * u.seconds()); |
There was a problem hiding this comment.
Check overflow when constructing scaled durations
When amount is large and the unit is seconds-based, this multiplication wraps before Duration.ofSeconds receives it. For example, remapped Duration.of(Long.MAX_VALUE, ChronoUnit.DAYS) returns a duration of negative one day because Long.MAX_VALUE * 86400 wraps to -86400, whereas the JDK throws ArithmeticException; use exact multiplication here as in the duration arithmetic methods below.
Useful? React with 👍 / 👎.
| public static ZonedDateTime plusMinutes(ZonedDateTime value, long minutes) { | ||
| return plusSeconds(value, minutes * 60); |
There was a problem hiding this comment.
Avoid overflowing zoned minute arithmetic
For large minute counts, scaling to seconds can wrap to an unrelated value before any range check occurs. In particular, plusMinutes(zdt, 4611686018427387904L) multiplies to zero modulo long and returns the original date-time, while ZonedDateTime.plusMinutes rejects this out-of-range result; decompose the amount or use checked arithmetic. The hour variants immediately below have the same defect.
Useful? React with 👍 / 👎.
| } catch (Throwable t) { | ||
| // The stage keeps the failure it was told about. | ||
| stage.relay(outcome); | ||
| return; |
There was a problem hiding this comment.
Preserve failures thrown by whenComplete actions
When the source future is already exceptional and the whenComplete action also throws, this catch silently discards the action's failure. The JDK retains the source failure as primary and adds the action failure as a suppressed exception, so diagnostics and code inspecting getSuppressed() lose the second failure here; attach t to the original failure before relaying it.
Useful? React with 👍 / 👎.
| if (braceDepth == 0 && part >= 0) { | ||
| throw new IllegalArgumentException("Unmatched braces in the pattern."); |
There was a problem hiding this comment.
Reject patterns with unmatched nested braces
This condition reports an unfinished format element only when braceDepth has returned to zero, so a pattern ending inside a nested choice element, such as {0,choice,0#{, is accepted and replaced by an empty parsed format. The JDK throws IllegalArgumentException for that malformed pattern; treating any remaining part >= 0 as unmatched prevents invalid localized messages from silently rendering as blank text.
Useful? React with 👍 / 👎.
| if (old == this) { | ||
| if (children.indexOf(n) != children.lastIndexOf(n)) { | ||
| throw new IllegalArgumentException("Duplicate child added: " + n); | ||
| } | ||
| continue; | ||
| } | ||
| for (Node up = this; up != null; up = up.getParent()) { | ||
| if (up == n) { | ||
| throw new IllegalArgumentException("A node cannot be its own ancestor: " + n); |
There was a problem hiding this comment.
Validate children before mutating the scene graph
When a null, duplicate, scene root, or ancestor node is added, these checks run from a list-change listener after ArrayObservableList has already inserted the elements. Throwing therefore leaves the rejected node in children; for example, after catching the exception from pane.getChildren().addAll(child, child), the list still contains the child twice, and a rejected ancestor insertion can leave a cycle that later traversal recurses through. Validate additions before committing them or roll the change back before propagating the exception.
Useful? React with 👍 / 👎.
| if (value == null) { | ||
| throw new NullPointerException("The root of a scene must not be null"); | ||
| } | ||
| if (value.getParent() != null) { | ||
| throw new IllegalArgumentException(value + " is already inside a scene graph and cannot be a root"); | ||
| } | ||
| if (value.getScene() != null && value.getScene() != Scene.this) { | ||
| throw new IllegalArgumentException(value + " is already the root of another scene"); |
There was a problem hiding this comment.
Keep the previous root when root validation fails
These checks execute from ObjectPropertyBase.invalidated() after root.set() has already stored the new value. Consequently, scene.setRoot(null) throws as expected but leaves scene.getRoot() equal to null while the old root still points at the scene; assigning a parented node similarly leaves the property holding the rejected node. Validate before committing the property value or restore the previous root on failure.
Useful? React with 👍 / 👎.
| for (Scheduled<?> task : live.get()) { | ||
| task.disarm(); | ||
| if (!task.outcome.isDone() && !task.running.get()) { | ||
| dropped.add(task); | ||
| } |
There was a problem hiding this comment.
Release tasks retained after shutdownNow
Every unfinished delayed task remains in live after shutdownNow(): disarming it does not complete outcome, so the whenComplete callback that calls forget() never runs. An executor kept after shutdown therefore retains every queued task and everything captured by its callable indefinitely; this is especially costly for many far-future scheduled jobs. Remove each dropped task from live while preserving the JDK behavior that its future remains incomplete.
Useful? React with 👍 / 👎.
| public void removeNode() throws BackingStoreException { | ||
| clear(); | ||
| } |
There was a problem hiding this comment.
Remove preference subtrees instead of only direct keys
For a non-root node, removeNode() must remove the node and all descendants, but delegating to clear() deletes only keys indexed directly at this path. Thus after node("account/tokens").put("secret", value), calling node("account").removeNode() leaves the secret persisted and retrievable; the removed node also remains usable. On the root this is reversed in a dangerous way: the JDK rejects userRoot().removeNode(), while this implementation clears its keys. Track child nodes and removed state, and refuse removal of the root.
Useful? React with 👍 / 👎.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What this adds
An existing Swing or JavaFX project builds as a Codename One application for every target, the way an Android module does with the Android compatibility layer. The sources are imported with
cn1:import-desktop-projectintocommon/src/main/desktopand built unmodified.maven/swing-compat:java.awt, Java2D,javax.swing,java.beans,javax.imageio, a SwingX subset and the FlatLaf entry points, written over Codename One components. Authored already relocated, because the JDK owns those package names; applications compile against the JDK's Swing.maven/javafx-compat: thejavafx.*subset (scene graph, controls, charts, layout panes, properties and bindings, animation, effects, Canvas), authored under the real names.maven/fxml-compiler: FXML and JavaFX CSS compiled at build time; nothing on a device parses XML or reflects.maven/compat-jdk: the JDK classes a device lacks (streams,java.util.function,java.nio.file, regex,CompletableFuture,java.timegaps and more), shared with the Android layer.maven/build-engine: one composed relocation pass over every layer, generated entry points and registries, records and pattern switches desugared, and the compliance check extended so that unsupported API is a build error reported under its original name and source line.scripts/desktop-compat-samples), screenshot tests inhellocodenameone, an integration test, a real-port interaction harness (maven/integration-tests/desktop-compat-realport) and a benchmark harness (scripts/desktop-compat-benchmarks).docs/developer-guide/Desktop-Interop.asciidoc, with measured size, memory and start-up tables.Verified locally
Not verified / known gaps
desktop-compat.ymladditions,desktop-compat-benchmarks.yml) have never run on GitHub. Windows is unmeasured; macOS runtime numbers needrun-macos-bench.sh.DesktopCompat*tests have to be seeded from the first CI run.🤖 Generated with Claude Code