Repository navigation
cn1lib: a library can carry a server half - #6139
Conversation
A jar marked with META-INF/codenameone/backend-library is a backend library: a server that depends on one wires its controllers, beans, entities, repositories and migrations as its own, on the JVM (Maven process-annotations, Gradle compileJava) and in the native backend build. The library itself is never processed. A .cn1lib carries the server half as backend.zip; the cn1lib archetype gains a backend module and Gradle cn1libs publish <name>-backend. The merge records what it copied, with each file's size and CRC, so a library upgraded or dropped leaves nothing stale, and a class the module compiled over a merged one stays the module's. The record is restamped after processing, failed or not, because weaving rewrites merged classes in place. Tested by BackendLibrariesTest, backend-cn1lib-test.sh (archetype-smoke, JVM and native) and gradle-cn1lib-test.sh; documented in the developer guide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guide's snippet gate requires every source block to come from docs/demos. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cloudflare Preview
|
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
ProcessAnnotationsMojoTest runs the mojo with no project; every other helper there allows for that, and the backend-library check did not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flutter vs Codename OneSame application, built both ways: Flutter's AOT compile of the gallery, and the identical Dart source transpiled to Java on Codename One. Lower is better for every metric, so a ratio above 1.00x means Codename One is ahead by that factor. android9 interleaved rounds; host load 1.0, 1.74, 1.35
Compute -- the VM workloads (
Gate: within tolerance against
ios9 interleaved rounds; host load 27.9, 37.13, 33.48
Compute -- the VM workloads ( Not measured: iOS compute is not measured: a device build needs signed hardware, and on the simulator Flutter runs its JIT debug engine rather than AOT code. The macOS row runs the same ParparVM and Dart AOT compilers on the same Apple silicon. Gate: within tolerance against
javascript9 interleaved rounds; host load 2.15, 1.57, 0.74
Compute -- the VM workloads (
Gate: within tolerance against
linux9 interleaved rounds; host load 0.31, 3.06, 2.7
Compute -- the VM workloads (
Gate: OUTSIDE THE BASELINE against
windows9 interleaved rounds
Compute -- the VM workloads (
Gate: within tolerance against
Codename One wins 21 of 21 measured metrics across 5 platform(s). |
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
|
Compared 195 screenshots: 195 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
|
Compared 231 screenshots: 231 matched. |
|
Compared 192 screenshots: 192 matched. Benchmark Results
Detailed Performance Metrics
|
|
Compared 196 screenshots: 196 matched. Benchmark Results
Detailed Performance Metrics
ParparVM vs HotSpot (JDK 25): macOS arm64Runner CPU: Apple M1 (Virtual) (baseline Ratios are ParparVM / JDK 25: below 1.00x ParparVM is faster (time) or smaller (RAM). Median of 5 interleaved, paired rounds; every run's output was verified. A ratio more than 20% (time) / 25% (RAM) above its baseline in
Result: no regression |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ ByteCodeTranslator Quality ReportTest & Coverage
Benchmark Results
Static Analysis
Generated automatically by the PR CI workflow. |
The Metal, tvOS and watchOS suites captured these differently on master before this branch, and the KmpCompat tests had no reference at all. Taken from run 41192866461's artifacts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
viewSafeAreaInsetsDidChange is not sent to a view a presented controller covers, so a rotation under one left landscape insets in place once the app was back in portrait: forms with a safe area were squeezed between the old notch margins and lost their top inset. The insets are now refreshed wherever the size is (#6080's cn1PublishViewSizeIfChanged). The goldens these broken captures replaced go back to the originals; only the KmpCompat references, which had none, stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rea goldens The method sat inside the non-Metal-Catalyst branch of the layout hooks, while viewSafeAreaInsetsDidChange calls it on every UIKit slice, so the Mac Catalyst build failed with -Wobjc-method-access. It now precedes that #if. Reading the insets with the view size (#6139) gives the first forms their status-bar inset: the animation captures on Metal and the watch Sheet now draw it, identically on master's run 41407471851 and this PR's run 41386600541. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* javafx-compat: list property content events, bound cell graphic, ObservableValue.map, Region.insetsProperty, ImageView fit CSS Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Mapping processor: canonical names for nested types, map inherited properties Nested class/enum field types were emitted as binary names (Outer$Inner), which javac rejects in source. Properties inherited from a non-@mapped base class were silently dropped by the generated mapper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Default network error path no longer blocks the EDT with a modal prompt An HTTP error code is not a crash, so Lifecycle no longer sends the log for it; the simulator's built_by_user prompt is skipped on the EDT or headless. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Storage entry size no longer spins forever on a stream that ends The default getStorageEntrySize looped until skip() answered -1, but skip() answers 0 at the end of a stream, so an implementation without its own override hung its background thread on the first cached image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: load http and https images in the background, cached in Storage Image downloads a remote URL through ConnectionRequest.downloadImageToStorage, the cache URLImage uses, and tells the views showing it when it arrives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: wrapText wraps a Label onto several lines A Label with wrapText on now has a horizontal content bias, a preferred height of its text wrapped at the given width, and a native peer (WrappingLabel) that paints the wrapped lines. VBox, HBox and ScrollPane already ask for height-for-width, so a column of wrapping labels in a fit-to-width scroll pane gets the right height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * getStorageEntrySize is abstract; every implementation asks its own storage Reading an entry through to count it was slow, and the loop the default used never ended on a stream whose skip() honours its contract. The native Linux and Windows ports ask the file length, the headless implementations the stored array. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Review fixes: no view leak or poisoned cache in remote images, lazy map/flatMap - Image holds view listeners only while a remote load is pending, and drops a cached entry that failed to decode so the next request downloads again. - DerivedValue observes its source only while it is observed itself. - WrappingLabel caches its lines per text, font and width; tabs break. - The mapping processor skips an inherited field whose type is a type variable of the superclass instead of mapping it erased. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * WrappingLabel: tabs break lines the same way in layout and paint Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: a labeled control with a graphic gives up theme padding before letters A tab bar of icon-over-text toggle buttons on a phone theme cut "Home" to "Ho..." between margins wide enough for the word: fitPadding refused to shed anything once a graphic was set. The theme's part of the padding is now given up as it is without a graphic; the graphic's own room never is, and the graphic is placed against the padding that remains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: a labeled control's minimum width keeps its graphic's room computeMinWidth counted the whole padding as sheddable, graphic room included, while fitPadding only gives up theme padding; a control shrunk to its minimum lost the text to the graphic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: a cell's graphic fits the cell, and rows measure at their width Cell laid its graphic out at its preferred width, so a list cell with wrapping text drew it on one line past the edge of the list. The graphic is now no wider than the cell, as in JavaFX, and is as tall as it is at that width; RowFlow measures the row height at the column width and measures again when that changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Smooth touch scrolling and press repaints in the JavaFX layer - Lists and scroll panes glide on after a touch drag, decelerating the way a UIScrollView does (runtime Fling, driven by the frame clock). They used to stop dead the moment the finger lifted. - A native button's own repaint (its pressed state) now goes through its node, so it no longer paints over the graphic drawn above it or outside the clips and effects of its ancestors. A touched tab lost its icon until the next full repaint. - ParentPeer's layout reports overlap support, so a peer that repaints alone also repaints the siblings drawn over it. - Component skips a backdrop blur that its own opaque fill hides; the iOS theme's text field blur was most of the time a frame took. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: clip to a shape's outline, fit text fields and lists to their CSS, auto-hide touch scroll bars; JavaSE measures text unzoomed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: keep an opaque region's shadow when a change inside it moves nothing A press on a tab button re-captured and re-blurred the whole shadowed navigation drawer, on press and on release. A shadow is made from the outline of what is drawn, so a paint-only change (colour, opacity, pressed state) inside a region whose opaque, square, unclipped background fill covers its box cannot change it. Measured in the new test: 5 presses made 5 captures before, 0 after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: a list's scroll moves its rows without relaying out the scene RowFlow.scrollTo called requestLayout on every drag or fling frame, which cleared the size caches of every ancestor up to the scene and laid each of them out again. A new offset changes no size: the flow now marks only itself and asks for a pulse, whose layout pass walks the tree and finds it. Measured in the new test: 10 drag frames laid out the list's holder 10 times before, 0 after. ScrollPane already only relocated its content; the test holds that too (0 content or row layouts over 20 offset changes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: keep a phone's scene out of the status bar and fill the strip with its background Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Revert every change outside the JavaFX layer to master The layer no longer needs them; the headless test harness answers a stored entry's size from its own map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Revert "javafx-compat: a list's scroll moves its rows without relaying out the scene" Recycled rows were filled with their new item but never laid out again, so a row showed the previous item's description while scrolling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: rebuild a shadow picture after the paint, never during it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: stretch a touch scroll past its ends and spring back A drag past the top or bottom of a ScrollPane or a list moves the content with UIScrollView's rubber-band resistance, a glide that reaches an end carries on and returns, and the row a drag began on loses its pressed look once the drag becomes a scroll. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: take a drag from its first pixel, and press without restyling the scene Codename One held every drag back until it crossed 5% of the screen, because the scene's components answered not draggable; the stage forms now claim drags over the scene, which tells a click from a drag itself. A pseudo-class some rule asks of an ancestor compound made any node in that state restyle everything below it, so pressing a tab restyled the whole scene twice per tap (27-112 ms each on the iOS simulator). It now counts only on a node that has the rest of that compound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: survive Codename One's shape clip bug, and re-pad a label whose graphic grew A rounded clip is narrowed by every rectangle painted inside it; Codename One's intersection throws when a curve ends a fraction of a pixel from the rectangle, which took the app down on iOS on a scrolled card list. Clip paths now end every segment on a whole pixel, and narrowing a shape clip falls back to a rectangle if it still throws. A label padded its text for its graphic once, when styled; an icon whose font arrived later grew past that padding and was drawn over the text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: keep desktop mouse drags free of overscroll and fling A mouse drag on the desktop (a ListView's rows, a pannable ScrollPane) stretched past the ends and glided on after release, which JavaFX on the desktop never does. Both now feed the spring and the glide only on a touch screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: place a label's graphic without the theme padding a bare label does not have The graphic was placed as if the label kept its theme's padding, which a bare label is drawn without: under the iOS theme every titled card drew its icon over the first letters. Also removes a scratch probe test that was committed by mistake. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reseed the Android DesktopCompatFxData golden for whole-pixel clip edges The JavaFX layer now snaps a clip path to device pixels; the list's antialiased edges move by at most 17/255 on 998 pixels. Identical on the Default, JDK 17 and JDK 21 legs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reseed the macOS DesktopCompatFxData golden for the ListView border edge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: let accessibility activate nodes that handle clicks A region with an onMouseClicked handler had no accessibility action, so VoiceOver, TalkBack and the MCP UI tools could not press a card or a list row. Its peer now offers activate, which taps the middle of the peer through the form so the scene delivers press, release and click as for a finger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: deliver accessibility activation to the node itself Firing press, release and click at the node, instead of tapping the centre through the form, keeps a child over the centre, a transform or a scrolled-off node from taking the press. Only handlers count (a filter on every mouse event tracks hovering), types above MOUSE_CLICKED count, a disabled node offers nothing, and only the action this layer added is ever removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * javafx-compat: cn1HandlesClicks counts handlers only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reseed DesktopCompatFxData on iOS Metal, Metal 27, watch and Catalyst The ListView border is now snapped edge by edge, as on Android and macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * iOS: define cn1ReadSafeAreaInsets on Catalyst and tvOS; reseed safe-area goldens The method sat inside the non-Metal-Catalyst branch of the layout hooks, while viewSafeAreaInsetsDidChange calls it on every UIKit slice, so the Mac Catalyst build failed with -Wobjc-method-access. It now precedes that #if. Reading the insets with the view size (#6139) gives the first forms their status-bar inset: the animation captures on Metal and the watch Sheet now draw it, identically on master's run 41407471851 and this PR's run 41386600541. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * iOS screenshots: reseed tvOS animation goldens with the safe-area inset tvOS now reads its safe-area insets on the Metal path too, so the animation frames carry the title bar's top inset, as Metal iPhone does. Taken from run 41466125366's tv-ui-tests artifacts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>























A cn1lib can now ship server code. Its controllers, beans, entities, repositories and migrations are wired into any server that depends on it, as if that server had compiled them.
How
META-INF/codenameone/backend-libraryis a backend library.BackendLibraries.mergecopies it into the server module's classes before annotation processing: Mavenprocess-annotations, GradlecompileJava, and the nativeBackendPackager. The library itself is never processed, so its generated wiring can't collide with the server's..cn1libgainsbackend.zip(Cn1libMojopacks it,Cn1libInstallerunpacks it to thebackendclassifier). The cn1lib archetype gets abackendmodule, and Gradle cn1libs publish<name>-backendfromsrc/backend/{java,resources}.compileJava. Without that, compile avoidance would skip the merge when a library changes a method body or a migration.cn1-nativefrom a library (jar or directory), so no class is translated twice.Tests
BackendLibrariesTest: 7 tests, including the module-class-wins and rewritten-class cases.maven/integration-tests/backend-cn1lib-test.sh: new, runs in archetype-smoke. A generated cn1lib with an endpoint, service, entity, repository and migration is consumed by a generated server, and checked with@BackendTestand natively compiled tests.gradle-cn1lib-test.shchecks the<name>-backendartifact.Docs: Backend-Beans ("Controllers and beans from a library"), Backend-Data, Advanced Topics (cn1lib contents) and Gradle-Project-Workflow.
🤖 Generated with Claude Code