Repository navigation
Minimal and backend-only Maven projects, default from 7.0.275 - #5937
Conversation
Maven projects can now omit every platform module: the root pom and common/ build all platforms, run the simulator and tests, and package the desktop app. A platform has its own module exactly when <platform>/pom.xml exists; adding one later moves that platform's build into it. A backend-only project is a single module at the root. The archetype generates the minimal layout by default (-DplatformModules, -DprojectType); the Initializr does once its plugin is 7.0.275 or newer, with the full layout as an opt-in. Also fixes JUnit tests in generated apps, which never ran: Surefire only had Codename One's stub provider. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Developer Guide build artifacts are available for download from this workflow run:
Developer Guide quality checks: |
Cloudflare Preview
|
|
Compared 157 screenshots: 157 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
|
Compared 193 screenshots: 193 matched. |
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 154 screenshots: 154 matched. Benchmark Results
Detailed Performance Metrics
|
✅ ByteCodeTranslator Quality ReportTest & Coverage
Benchmark Results
Static Analysis
Generated automatically by the PR CI workflow. |
|
Compared 166 screenshots: 166 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 15% (time) / 15% (RAM) away from its baseline in
Result: no regression |
|
Compared 155 screenshots: 155 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 150 screenshots: 150 matched. |
|
Compared 155 screenshots: 155 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
|
Compared 223 screenshots: 223 matched. |
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1c060c49d
ℹ️ 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".
- The archetype build injected the hosted profiles with Ant's <replace>, which
rewrites through an owner-only (0600) temp file. The staged common/pom.xml
was then unreadable to the runner and hashFiles('**/pom.xml') failed the
guibuilder job's cache step. Use a filtered <copy> of a deleted target.
- cn1-binaries-javase carries ${cn1.version}: the initializr's root pom does
not manage it, so its simulator profiles had no version. A test now checks
every fragment dependency against both root poms, and the initializr build
hook resolves the simulator profile.
- compile-javase-natives re-extracts cn1lib natives from scratch and records
resource names, so removed sources and deleted resources rebuild.
- cn1:update works for a backend-only project at the root.
Co-Authored-By: Claude Opus 5.5 (1M context) <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: 9dbddc3a2f
ℹ️ 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".
- The hosted simulator refuses a JDK older than 11 up front, as cn1:run and cn1:debug do, instead of letting a Java 8 launcher read its argument file as a class name. The simulator needs JDK 11+ at runtime whatever the project's source level; the integration test prepares it on the newer JDK CI names. - Desktop profiles that run JavaSE code from common, executable-jar and test included, ship cn1-binaries-javase like the javase module, so the packaged desktop app keeps the bundled FFmpeg binaries. - compile-javase-natives keys its cache on each cn1lib archive's content hash. - cn1:update fails with a clear message when a project lacks the cn1.version or cn1.plugin.version property, instead of an NPE. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Java CI leg runs integration-tests/all.sh on JDK 8 with no newer JDK named, so preparing the simulator there now refuses (it needs JDK 11+). Assert that refusal and its message on an older JDK; prepare and check the classpath on a newer one. Co-Authored-By: Claude Opus 5.5 (1M context) <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: a195783e67
ℹ️ 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".
- generate-desktop-app-wrapper deletes a stub it generated earlier once a custom javase/src/desktop/java stub appears, so the two are never compiled together. - compile-javase-natives skips builds for a platform other than javase: a device build uploads none of it, and a desktop-only compile error must not stop it. Builds that name no platform (mvn test) still compile it. - Its cache requires the output directory to exist, and the stamp goes with the output when there is nothing left to compile. - The hosted desktop jar takes the javase natives, resources and desktop resources before common's classes, the order a full layout's classpath resolves them in. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Merged master (#5937, minimal and backend-only Maven projects). The backend-only Maven project now gets the @backendtest setup and the two sample tests every other backend layout has; the generated project's mvn test runs them (3 tests). Review fixes: - CORS same-origin detection compares the scheme too: the request's own (X-Forwarded-Proto behind a TLS terminating proxy, else whether the server speaks TLS). http://api.example calling https://api.example skipped the policy. - Surefire %regex[...] includes, excludes and -Dtest entries select as Surefire does, over the class path. - hasTests() counts Kotlin test sources, so a Kotlin-only suite reaches the explicit "Kotlin tests cannot be compiled" failure. - assertEquals with a negative or NaN delta fails on the delta first, with JUnit 5.9's own failure (measured: AssertionFailedError, not IllegalArgumentException). - TestRestTemplate targets the server's real scheme and listen address. - A test or lifecycle method that returns a value is a build error for the compiled run, as JUnit does not run it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ilation Brings in #5937 (minimal and backend-only Maven projects), whose cn1app-minimal-layout-test.sh generates a project on JDK 8. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s for 17 This branch had changed the default from "auto" to 17, so a project generated on JDK 8 targeted Java 17 and did not compile there. Master's cn1app-minimal-layout-test.sh (#5937) generates on JDK 8 and failed with "invalid target release: 17" in archetype-smoke and build-linux-jdk8. "auto" already resolves to 17 on any JDK >= 17, which is what a Flutter project needs; the Flutter benchmark now passes -DjavaVersion=17 explicitly rather than depending on the JDK it runs on. Verified: generated on JDK 8 the project gets java.version=8 and common compiles. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…layout Since #5937 the archetype generates the minimal layout, which has no android/ or ios/ module: the builds write their Gradle and Xcode source projects under common/target. build_apps.sh looked only in android/target and ios/target, so the Android leg reported "no generated Gradle project" after a successful build. Both lookups now search the project's target directories. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…I cleanup (#5932) * Backend: Spring-style test framework, hellocodenameone e2e server, API cleanup - Public backend API is now what an app writes against: the Spring aliases and settings annotations are gone (application.properties is compiled in instead) and the generated-code plumbing moved to com.codename1.impl.backend, which the backend javadoc excludes. - codenameone-backend-test: @backendtest, MockMvc, TestRestTemplate, @TestConfiguration and @MockitoBean. The same JUnit 5 tests run on the JVM and, with -Dcn1.backend.compiledTests=true, translated into a native test binary. - CORS, multipart/@RequestPart and gzip in the server. - scripts/hellocodenameone/backend replaces demo/cn1ss and the legacy Java server as the single CI server: the screenshot websocket plus the REST surface new device tests in common drive. - Archetype, initializr template, docs and CI wired to all of the above. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Record the vendored JZlib sources in the copyright-header exclusions They are touched only to mark them @SharedWithBackend, which pulls them into the diff-scoped header check; they keep JCraft's BSD notice. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Fix the CI failures and the review findings on the backend testing PR CI: - The packaged archetype server refused to start on the compiled-in ${DATABASE_URL}: an unset reference no longer counts as a configured database when nothing needs one (Config.resolves); code that needs one still fails loudly. - The Gradle conversion kept the archetype's untouched backend once it carried the sample tests; the generated tests and their dependencies are part of the skeleton. - oteltest used Builder.management(), now internal; BackendOtelTest counted a bridge method's parameter type as McpServer being linked. - The device legs' backend tests: a failed request threw instead of failing (the suite timed out), and a step that hears nothing now fails by name; Android allows cleartext to the CI host; the CI JS, Linux and Windows launchers instantiate the generated bootstraps a real build does. - Ports the tests found broken: the Linux and Windows ports ignored the HTTP method, the connect and read timeouts, and (Windows) followed redirects natively; watchOS and tvOS had no HTTP at all (an NSURLSession path); the JS port answered null for every response header and stored binary bytes, and String.getBytes, unsigned. - LanguageTool terms. Review: - Compression and CORS no longer mutate a Response a handler shares. - An explicit gzip entry in Accept-Encoding wins over *. - The compiled runner: unannotated overrides hide inherited tests, package-private base-class methods are reached through a helper in their package, it runs the classes Surefire selects, and duplicate injected field names are a build error. - MockMvc: a lower-case Host is kept, and Content-Type is visible as a header. - Gradle: Kotlin tests get the test pass, and the properties files are task inputs. - server.sh installs and digests the build engine. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Fix the remaining backend test failures and the second review round CI: - The timeout probe set setFailSilently(true), and NetworkManager hands a fail-silent request's exception to nobody, overridden handleException included: a timed-out request ended with no callback on every port without native timeouts. The JS port also ignored timeouts; its synchronous XHR now gets xhr.timeout and reports a TimeoutError as an IOException. - The musl leg built the plugin's whole dependency tree inside its container to start the test server, past the suite's wait. prepare-suite now builds a server copy both Linux legs run (CN1SS_SERVER_DIST), and a server that does not start now fails with its own output. Review: - @backendtest holds a JUnit resource lock, so parallel execution never runs two classes that would stop each other's application. - An @BeforeAll assumption that does not hold skips the class in a compiled run. - application.properties and its profile files are compiled in as UTF-8, and a profile file is found without a base file. - Multipart: the part header limit is for the whole block, and a multipart body with no valid boundary is refused. - CORS answers carry Vary: Origin whenever the policy names origins. - MockMvc: queryParam on a multipart builder stays in the URL. - Generated test context and runner names that would collide are a build error. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the third backend review round - SurefireSelection honours negative -Dtest entries (!SlowTest). - The compiled test run refuses Kotlin test sources by name instead of running without them; the Gradle task passes the Kotlin test directory so it can tell. - Linux and Windows ports: an explicit GET or POST overrides the post flag, and an explicit GET sends no body. - Multipart: a part ends only at a complete delimiter, so data that contains the boundary followed by more is not cut there. - The compiled runner reports a teardown failure over an earlier assumption abort. - MockMvc drops the body of a HEAD, 1xx, 204, 205 or 304 answer, as the HTTP writers do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Let the backend timeout probe hear its own failure Android and the browser dropped the timeout step: the request did time out, but the app's Lifecycle.handleNetworkError consumes every network error (and shows a modal "Connection Error" dialog), and NetworkManager calls a request's own handleException only when no listener consumed it. The probe now carries a ReportsOwnErrors marker that the app's handler leaves alone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the fourth backend review round and the browser timeout probe The browser leg still dropped the timeout step: ConnectionRequest calls handleException on the network thread, and the probe ran the next step and finished the test from there. Error callbacks now go to the EDT, and the backend client tests get a budget their 12s step watchdog fits inside. Review fixes: - Linux sends a buffered body for any method but GET and HEAD (a DELETE with a body went out empty). - The compiled runner collects default @test and lifecycle methods from implemented interfaces, and an unannotated method suppresses an inherited test only when it really overrides it (package-private methods in another package do not). - @backendtest is @inherited; an abstract base's concrete subclasses each get a generated context. - -Dtest=Class#method narrows the compiled run to the same methods. - Mockito is detected in code, not in comments or strings. - A multipart @RequestParam that is not UTF-8 is a 400, not a 500. - A 206 / Content-Range response is never compressed. - A CORS origin with a path, query or fragment is refused at start. - The shim compares nested primitive arrays by content. - jsonPath exists()/doesNotExist() treat JSON null as absent, as Spring. - getBody() is documented as Spring's string converter behaves: a binary body is decoded when it is valid UTF-8. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the fifth backend review round and the remaining CI failures CI: - The browser timeout probe: a timed-out synchronous XHR can come back from send() without throwing, and reading on reached responseText, which an arraybuffer request throws for -- ending the network thread with no callback at all. send() now reports status 0 with no response as a failure, and responseText is never read on an arraybuffer request. - Developer guide: a sentence Vale's write-good rule refused. Review fixes: - Request.param throws for a malformed multipart body instead of reading it as "no field"; the generated guard answers that, and a non-UTF-8 field, with 400. - A @RequestBody binding answers a binary body that is not UTF-8 with 400 instead of a 500. - An eligible response varies by Accept-Encoding even when it went out uncompressed. - A gzip request body is decoded member by member; trailing bytes that are not another member are refused. - andExpectAll reports a matcher that throws and runs the rest. - Linux, Windows and JS advertise the read timeouts they now honour. - WebEnvironment.NONE keeps its loopback listener, documented with why; AssertionError(Object) keeps "null", which is what the JDK does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Keep exceptions that unwind through a finally on the JS port The browser's backend timeout probe was not a networking bug. The JS translator's dead-case pass kept a try/catch table entry's handler pc only when ",t:" followed it, so every catch-all handler -- a finally, a synchronized block's release -- lost its case label. An exception unwinding through one was dispatched to a pc with no case, fell to "default: return" and vanished: ConnectionRequest.performOperationComplete returned normally from a timed-out request and nothing heard of it. Reproduced against the CI bundle in headless Chromium, confirmed by restoring the one label, and covered by a translation test that fails without the fix (score 14, not 31). Review fixes: - bodyContent refuses a body over the cap (413), so MockMvc refuses what the listener does. - An empty body declared multipart is malformed, not "no parts". - Windows reports a failed body read (a stall past the read timeout) as an IOException instead of end of stream. - jsonPath isEmpty() needs the path to exist. - HttpStatusCode.isError() is 4xx or 5xx only. - Only a directly nested @TestConfiguration applies to its test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Stop a catch handler's throw being caught by its own sibling handler ParparVM: a try statement with several catch clauses registers one try block per clause, and throwException popped only the block that matched. When that handler threw -- a rethrow or a new exception -- its sibling handler for the same try was still registered and caught it: `catch (IOException e) { throw e; } catch (Exception e) {}` swallowed the rethrow on every native target. Each handler entry now resets tryBlockOffset to the depth at its label, as JUMP_TO does for a jump. Found when the JUnit stand-in's assertAll, which rethrows an OutOfMemoryError ahead of catch (Throwable), behaved differently compiled. CatchRethrowIntegrationTest covers it on every compiler configuration (RESULT 104 without the fix, 127 with), and SelfTest's long-skipped nested-finally probe -- already working, as the same test shows -- now runs as an ordinary check. Review fixes: - Vary given as a List is extended element by element, without duplicates. - A close delimiter must end at padding, CRLF or the end of the body. - The boundary search is linear (KMP). - Form decoding keeps a supplementary character beside + and %. - A strong ETag keeps its response uncompressed, as Tomcat does. - assertThrows builds a supplier message only on failure; assertAll rethrows an OutOfMemoryError; assertIterableEquals recurses. - Composed @test (and lifecycle) annotations are recognized. - The compiled run names only the selected tests to javac, finding what they use through -sourcepath; a non-strict run with nothing to compile (all Mockito, or nothing selected) warns and skips. - Gradle runs the test pass over the Java and Kotlin test outputs as one hierarchy, weaving each class where its file is. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the seventh backend review round Merged master first: the PR check compared against an old merge base, so the nightly fold of perf-baseline/base/ looked like this branch's change. - CORS: a cross-origin request whose origin or method the policy does not admit is refused with 403 before any handler runs, as Spring's CorsProcessor refuses it. A simple request needs no preflight, so its handler used to run and only the headers were withheld; allowedMethods was never checked for it at all. - A compiled-in cn1.profile applies when neither the process nor a file beside the binary names one; the profile file is read for it. - The native CI server installs the ParparVM toolchain and digests the translator and JavaAPI sources, so a translator change is what it builds with. - The compiled run selects a source by the classes it declares (read from the JVM build's test classes), not its file name, and clears earlier compiled reports before writing. - A composed @disabled is honoured. - MockMvc releases a file response it sends no body for (HEAD). - The shim rethrows OutOfMemoryError from assertDoesNotThrow and from assertThrows/assertThrowsExactly when it is not the expected type. - Gradle tracks src/main/resources/application*.properties as inputs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the eighth backend review round; tests for backend-only projects Merged master (#5937, minimal and backend-only Maven projects). The backend-only Maven project now gets the @backendtest setup and the two sample tests every other backend layout has; the generated project's mvn test runs them (3 tests). Review fixes: - CORS same-origin detection compares the scheme too: the request's own (X-Forwarded-Proto behind a TLS terminating proxy, else whether the server speaks TLS). http://api.example calling https://api.example skipped the policy. - Surefire %regex[...] includes, excludes and -Dtest entries select as Surefire does, over the class path. - hasTests() counts Kotlin test sources, so a Kotlin-only suite reaches the explicit "Kotlin tests cannot be compiled" failure. - assertEquals with a negative or NaN delta fails on the delta first, with JUnit 5.9's own failure (measured: AssertionFailedError, not IllegalArgumentException). - TestRestTemplate targets the server's real scheme and listen address. - A test or lifecycle method that returns a value is a build error for the compiled run, as JUnit does not run it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the ninth backend review round - The compiled test run compiles and translates with the module's test-scoped dependencies, as Surefire runs the tests with them; the JVM-only test libraries (JUnit, which the shim replaces, the backend test jar, Mockito and its byte-code helpers) and runtime-scoped dependencies stay out, and so does the backend runtime jar. - A generated test runner rethrows an OutOfMemoryError from a test or a lifecycle method instead of recording it and carrying on. - The opening multipart delimiter must start a line and be complete; a boundary-like string inside the preamble is skipped. - A bracketed JSON path name must close with its own quote and then ]; a name containing ] is no longer cut at it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the tenth backend review round - A multipart/form-data part must carry Content-Disposition: form-data and name its field (RFC 7578 4.2); one that does not is a malformed form, not a nameless part an optional binding ignores. - Windows: a failure to recreate the WinHTTP request for a custom method is recorded where the request is created, so httpFailure reports it and the caller gets an IOException, not response code -1. - A static @test is a build error for the compiled run, as JUnit does not run it. - Gradle, mixed Java and Kotlin backends: kept as is and documented. Annotated classes in both languages produce two entry point records and same-named generated classes, which the existing SplitOutputCheck after compileJava refuses; a test now covers the backend records. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the eleventh backend review round and the PMD findings PMD: a literal-first comparison in Multipart.isFormData, and the test server's loopback bind marked as the deliberate literal it is. - An unterminated quoted multipart parameter (boundary="b, name="f) is malformed: the lookup answers absent, which both callers refuse. - The compiled run reads Surefire's includes and excludes from the default-test execution's configuration too, over the plugin's. - A test that uses a Mockito-only support class -- directly or through a chain -- is left out with it, rather than pulled into javac through -sourcepath without Mockito on the classpath. - A credentialed preflight against allowedMethods=* echoes the requested method, as a browser reads * as a literal name with credentials. - Interface lifecycle hooks run at the level that implements them: base class setup, then the subclass's interfaces' hooks, then its own, as JUnit orders them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the twelfth backend review round - Override discovery follows Java across interfaces: a superclass's unannotated method hides an interface's default @test of the same signature, and an interface default never hides a class method; the lifecycle order keeps each class's interfaces at its level. - The probe server's /api/big clamps its size before allocating, as the download probe does, so a huge or negative size cannot take the shared test server down. - A urlencoded form value that is not UTF-8 once percent-decoded (%FF) is refused rather than decoded to a replacement character; a generated @RequestParam binding answers it with 400. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the thirteenth backend review round - A test that injects the DataSource or EntityManager itself starts the database even when the application needs none, instead of being filled with null. - MockMvc's multipart builder escapes quotes and backslashes in a part's name and filename, and refuses a line break, so a"b.txt arrives intact. - TestRestTemplate recognises an absolute URL's scheme case-insensitively. - Windows: a connect timeout bounds name resolution too, so an unanswered DNS lookup cannot block past the timeout the caller set. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the fourteenth backend review round - -Dtest's classless method selector (#fast*+slowTest) selects those methods in every class instead of being dropped, which ran every method. - Linux: the read timeout is a millisecond idle limit, checked by a progress callback when data arrives and while none does; libcurl's low-speed options measured average speed in whole seconds, so a response trickling a byte every 900ms beat a 500ms limit. - A run with no test sources does nothing, for Gradle's backendTest as for the Maven goal, instead of failing with "No test source can be compiled". - An explicit Builder.host() -- null or "" for every interface -- wins over cn1.server.address; a tokenless MCP endpoint refuses the explicit wildcard as it refuses any non-loopback address. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the fifteenth backend review round; document niche gaps Fixed: - Gradle conversion: the Surefire plugin counts as generated only when it is exactly the archetype's (reuseForks=false); a backend whose Surefire carries the developer's own settings is their work and is kept, not left behind. - The JUnit shim's @test and lifecycle annotations allow annotation types, so a composed test annotation compiles in the native run as on the JVM (the hellocodenameone suite now uses one). Documented as unsupported rather than implemented, as niche JUnit and Surefire parity: - repeating @tag on one element (vm/JavaAPI has no @repeatable); - a -Dtest regex selector with a method part (%regex[...#...]). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the sixteenth backend review round - Gradle backendTest passes the test source set's compile classpath, so a testImplementation helper compiles in the native run; JVM-only libraries are recognised in Gradle's cache layout too. - CORS preflights that echo the requested method or headers say so in Vary. - MockMvc and TestRestTemplate refuse a URI template with no variable for a placeholder instead of sending the literal braces. - Windows sends no buffered body for an explicit HEAD, as Linux does. - JS port: document that a synchronous XHR can only enforce the timeouts as a whole-request deadline. - Reword the Backend-Testing line Vale flagged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the seventeenth backend review round - The server's own 404 and 500 carry the CORS headers, through a package-private fallback hook Backend's chain implements, so a browser sees the real status instead of a CORS failure. - Linux read timeout: progress since the last callback counts before the idle check, and the first callback after connecting starts the clock. - Test contexts that differ only in injecting the database get distinct cache keys, so one started without it is not handed to the other. - Mockito reach matches class names in code only, not comments or strings. - JUnit shim: @disabled may be composed; an inert @nested lets a source declaring one compile. Nested classes inside @backendtest documented as unsupported. - Reword the Backend-Testing line LanguageTool flagged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the eighteenth backend review round - CORS: a wildcard policy answers "*" with or without Origin, so its un-varied responses are right from a cache; a preflight refused for its method varies by Access-Control-Request-Method. - Test context keys include each mock's field name, which names the bean. - Gradle backendTest compiles what test annotation processors generated. - cn1:backend-test clears earlier compiled reports even when the compiled run is off. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the nineteenth backend review round - cn1ss.sh uses the prebuilt server a job is handed (CN1SS_SERVER_DIST) instead of building one, launching it with server.sh exec-dist. - CORS allow-list origins are compared without their scheme's default port, as browsers serialize them. - Document that MockMvc does not validate request targets like the wire parsers, and that compiled reports keep method names as Surefire's do. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the twentieth backend review round; fix JS screenshot drop - JS port: the cn1ss screenshot websocket reconnects after an open socket closes. It stayed "open", so every later screenshot went to a closed socket and the javascript-screenshots run lost the rest of its images. - Linux read timeout starts after the TLS handshake for https, which is the connect timeout's business. - cn1:backend-test clears earlier compiled reports on every path, the no-tests and Windows ones included. - A test class with more than one constructor is skipped in the compiled run, as JUnit refuses it. - CatchRethrowIntegrationTest runs one compiler configuration: the bug is in the translator, and the diagonal cost ten minutes of vm-tests. - Document the Surefire include/exclude forms and Kotlin test directories the compiled run does not read. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Address the twenty-first backend review round - MockMvc reports the response as the wire sends it: the content type through the writers' default and validation, extra headers without the server-owned and unsafe ones the writers drop. - The build reads application-<profile>.properties even with no base application.properties, for every setting that needs generated linkage, cn1.otel.enabled included. - A PER_CLASS @backendtest resets its mocks after each test; a test pins it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Rebaseline objectAllocation on the AMD EPYC 9V74 Linux runner The runner's base baseline predates #5940's allocation path, and the fold that followed #5940 did not cover this CPU, so the gate failed every run on it as an improvement past the baseline (4.76x -> 1.17x). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Rebaseline objectAllocation on the Intel model 173 Windows x64 runner Same as the EPYC 9V74 row: the base baseline predates #5940's allocation path (4.10x -> 1.62x), so every run on this CPU failed as an improvement. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Skip build-engine's proxy-jar test copy when tests are skipped The hellocodenameone test server installs the backend modules with -DskipTests on every screenshot leg. build-engine's antrun copy of the ParparVM JavaScript proxy jars ran anyway and failed where that bundle is not built (the iOS legs), so server.sh fell back to -am and rebuilt every dependency: about seven minutes per leg, which pushed build-ios-metal past its 75-minute limit. The copy only feeds JavaScriptProxyPackagerTest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Drop the EPYC 9V74 rebaseline that #5938 already carries Master's pr/5938.json rebaselines the same objectAllocation row from the same value, and the gate refuses two overlays moving one row. The Intel model 173 Windows row stays: no other overlay covers it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Gradle projects got two shapes in #5922 that Maven lacked: a minimal tree with no per-OS modules, and a backend-only project. This brings both to Maven and makes them the default for new projects. The archetype switches over immediately. The Initializr switches once its plugin is 7.0.275 or newer, which happens automatically when
update-cn1-version.shbumps it.The layouts
common+javaseandroidiosjavascriptwinlinux+backendcommon-DplatformModules=all/ "Include all platform modules"common+backend-DprojectType=app-with-backend-DprojectType=backend-only-DplatformModules=all -DprojectType=app-with-backendreproduces the old layout exactly.How a project with no platform modules builds
One rule decides it: a platform has a module of its own exactly when
<root>/<platform>/pom.xmlexists.common's stand-ins skip themselves, so a project that adds a module later never builds a platform twice.commondoes the work.common/pom.xmlcarries one shared fragment,scripts/initializr/common/src/main/resources/common-hosted-platform-profiles.xml, which the archetype and the Initializr both inject. It contains:cn1-host-<platform>profiles, active on-Dcodename1.platform=<p>and a missing../<p>/pom.xml(Maven ANDs the two). They bindcn1:buildfromcommon.cn1-javase-natives, which compilesjavase/src/main/java(plus cn1libnativesesources and the desktop stub) intocommon/target/cn1-javase/classes. That is nevertarget/classes, which every device build uploads, and it is outside the bytecode-compliance check.javasemodule used to own:simulator,idea-simulator,debug-simulator,debug-eclipse,run-desktop,executable-jar,testandrun-android. Each of their goals carries<hostedPlatform>, and each third-party execution reads thecn1.hosted.<p>.skipproperty those goals set.<module>/pom.xmlto exist.activeByDefaultis dropped when there is nojavasemodule, because Maven applies it even when the profile's own conditions fail.<platform>/src/main/....cn1:generate-native-interfacescreates those directories with nopom.xml, and a build fromcommonuploads them exactly as a module would package them.New in the plugin:
HostedPlatformsandAbstractCN1Mojo.hostedPlatform.hosted-platform,compile-javase-nativesandjavase-executable-jar.cn1:build,prepare-simulator-classpath,generate-desktop-app-wrapper,cn1:test,cn1:run,cn1:debugandcn1:simulator.exec:exec's<classpath/>cannot be extended. The file also keeps long classpaths under the Windows command-line limit.ProjectLayoutgainshasPlatformModule,nativeResourcesDirandplatformUploadDirs; the Gradle plugin now uses the sharedplatformUploadDirs.MAVEN/BACKEND.The version gate:
origin/masterfor every Maven and Gradle download), apart from the JUnit fix below and the agent-skill text.hosted-platform/compile-javase-nativesgoal, rather than building nothing.cn1:updaterefuses to move such a project below 7.0.275.update-cn1-version.shnow fails if it did not rewriteCN1_PLUGIN_VERSION.A pre-existing bug this fixes: JUnit tests never ran
Generated Maven apps advertise
mvn testfor JUnit 5 tests, but the root pom gives Surefire Codename One's stub provider, which returns no tests. A deliberately failing@Testpassed the build in the full layout on master. Thejavasemodule,common.zipand the newcommonprofile now also declaresurefire-junit-platform, so JUnit tests run, a failing one fails the build, and-DskipTestsstill skips. Existing downloads change in this one respect.How this was verified
New integration test
maven/integration-tests/cn1app-minimal-layout-test.sh, inarchetype-smoke.ymlandall.sh. It generates a minimal app and a backend-only project and checks:pom.xml;cn1:testand JUnit both reach a JavaSE native that only a JDK compiles;-Pexecutable-jardesktop jar has the right Main-Class, stub, natives, icons and native theme;commonwith exactly their own native files, and no JavaSE classes reach the Android upload;android/pom.xmlmoves the Android build into the module;/healthz.Run locally against a fresh full install of the reactor:
cn1app-minimal-layout-test.sh(withCN1_BACKEND_PACKAGE_REQUIRED=1),cn1app-archetype-test.sh(full layout, including the native backend),cn1app-staged-jar-test.sh, and these integration scripts, which now pass the full-layout flags:build-hint-annotations-test.sh,cn1app-desktop-build-test.sh,initializr-roundtrip-test.sh,gradle-maven-parity-test.sh,gradle-migrate-test.shandnative-interfaces.sh.cn1:run,-pl common cn1:run, andverify -Psimulatorwith and without-Dcodename1.platform, on both layouts. This used a stand-injavaon PATH, so no window opened.GeneratorModelIntegrationBuildTestnow does this whenCN1_MAVEN_PLUGIN_VERSIONis set (opt-in, like its Gradle half).HostedPlatformsTestis new, and includes a structural test that every goal in the shared fragment steps aside for a module), Gradle plugin 19, and the Initializr's 6 tests (including the version gate and the Maven layout matrix across templates and IDEs).Docs
The developer guide covers the layouts and the opt-in flags in the archetype appendix, which pom to edit when there are no platform modules, backend-only projects in the backend chapter, and the native interface paths. The generated project's README has a project layout section, and the agent skill now uses root-level
mvn package -Dcodename1.platform=...commands that work in either layout.🤖 Generated with Claude Code