From f35777583976b027af87823c9470ee2b2d2ac038 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 14 Mar 2026 13:34:37 +0200 Subject: [PATCH 1/6] Fixed Java17 Test and orientation issue --- .../common/codenameone_settings.properties | 5 +++-- .../hellocodenameone/tests/Cn1ssDeviceRunner.java | 1 + .../hellocodenameone/tests/Java17Tests.java} | 13 +++++++++---- .../tests/OrientationLockScreenshotTest.java | 1 + 4 files changed, 14 insertions(+), 6 deletions(-) rename scripts/hellocodenameone/common/src/{test/java/com/codenameone/examples/hellocodenameone/Java17LanguageFeaturesTest.java => main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java} (66%) diff --git a/scripts/hellocodenameone/common/codenameone_settings.properties b/scripts/hellocodenameone/common/codenameone_settings.properties index 20eb38b87d..4f49400ea4 100644 --- a/scripts/hellocodenameone/common/codenameone_settings.properties +++ b/scripts/hellocodenameone/common/codenameone_settings.properties @@ -1,12 +1,14 @@ codename1.android.keystore= codename1.android.keystoreAlias= codename1.android.keystorePassword= +codename1.arg.android.useAndroidX=true +codename1.arg.ios.applicationQueriesSchemes=cydia codename1.arg.ios.newStorageLocation=true codename1.arg.ios.uiscene=false codename1.arg.java.version=17 +codename1.cssTheme=true codename1.displayName=HelloCodenameOne codename1.icon=icon.png -codename1.arg.android.useAndroidX=true codename1.ios.appid=Q5GHSKAL2F.com.codenameone.examples.hellocodenameone codename1.ios.certificate= codename1.ios.certificatePassword= @@ -28,4 +30,3 @@ codename1.rim.signtoolDb= codename1.secondaryTitle=Hello World codename1.vendor=CodenameOne codename1.version=1.0 -codename1.cssTheme=true diff --git a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Cn1ssDeviceRunner.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Cn1ssDeviceRunner.java index dcdcb95be9..1a755e127b 100644 --- a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Cn1ssDeviceRunner.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Cn1ssDeviceRunner.java @@ -74,6 +74,7 @@ public final class Cn1ssDeviceRunner extends DeviceRunner { new OrientationLockScreenshotTest(), new InPlaceEditViewTest(), new BytecodeTranslatorRegressionTest(), + new Java17Tests(), new BackgroundThreadUiAccessTest(), new VPNDetectionAPITest(), new CallDetectionAPITest(), diff --git a/scripts/hellocodenameone/common/src/test/java/com/codenameone/examples/hellocodenameone/Java17LanguageFeaturesTest.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java similarity index 66% rename from scripts/hellocodenameone/common/src/test/java/com/codenameone/examples/hellocodenameone/Java17LanguageFeaturesTest.java rename to scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java index 0bc56d0612..b14782b6bb 100644 --- a/scripts/hellocodenameone/common/src/test/java/com/codenameone/examples/hellocodenameone/Java17LanguageFeaturesTest.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java @@ -1,8 +1,12 @@ -package com.codenameone.examples.hellocodenameone; +package com.codenameone.examples.hellocodenameone.tests; -import com.codename1.testing.AbstractTest; +public class Java17Tests extends BaseTest { + @Override + public boolean shouldTakeScreenshot() { + return false; + } -public class Java17LanguageFeaturesTest extends AbstractTest { + //record MyRecord(int val, String otherVal) {} @Override public boolean runTest() throws Exception { @@ -11,6 +15,7 @@ public boolean runTest() throws Exception { var message = switch (greeting.length()) { case 5 -> greeting + " " + target; + //case 7 -> new MyRecord(2, "V"); default -> "unexpected"; }; @@ -21,7 +26,7 @@ public boolean runTest() throws Exception { assertEqual("Hello Codename One", message); assertEqual("Java 17 language features\nshould compile in tests.\n", textBlock); - + done(); return true; } } diff --git a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java index c1c1796628..62e75b57c9 100644 --- a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java @@ -33,6 +33,7 @@ private void waitForOrientation(Form form, boolean portrait, Runnable onDone) { } private void waitForOrientation(Form form, boolean portrait, int attemptsLeft, Runnable onDone) { + waitFor(50); if (CN.isPortrait() == portrait || attemptsLeft <= 0) { onDone.run(); return; From 8bc3c33eb2db8705e085ddd54557809c0497dc7c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 14 Mar 2026 13:57:47 +0200 Subject: [PATCH 2/6] Added blog post --- .../official-experimental-java-17-support.md | 90 ++++++++++++++++++ .../official-experimental-java-17-support.jpg | Bin 0 -> 45873 bytes 2 files changed, 90 insertions(+) create mode 100644 docs/website/content/blog/official-experimental-java-17-support.md create mode 100644 docs/website/static/blog/official-experimental-java-17-support.jpg diff --git a/docs/website/content/blog/official-experimental-java-17-support.md b/docs/website/content/blog/official-experimental-java-17-support.md new file mode 100644 index 0000000000..1f39718e8e --- /dev/null +++ b/docs/website/content/blog/official-experimental-java-17-support.md @@ -0,0 +1,90 @@ +--- +title: Official Experimental Java 17 Support for Codename One Projects +date: '2026-03-14' +author: Shai Almog +slug: official-experimental-java-17-support +url: /blog/official-experimental-java-17-support/ +description: Codename One projects generated with the Initializr can now use official experimental Java 17 support, with most modern targets expected to work and more JDK support planned next. +feed_html: 'Official Experimental Java 17 Support for Codename One Projects Codename One projects generated with the Initializr can now use official experimental Java 17 support, with most modern targets expected to work and more JDK support planned next.' +--- + +![Official Experimental Java 17 Support for Codename One Projects](/blog/official-experimental-java-17-support.jpg) + +We now have official experimental support for Java 17 in Codename One projects. + +This is available through the [Initializr](/initializr/). To use it you should generate a new project and select **Java 17** during project creation. + +Support for Java 17 required work across the toolchain, the generated projects and several targets. This wasn't just a matter of changing a version number and hoping for the best. + +## How This Works + +You can use these new Java 17 projects with practically any JDK for the build itself. We tested this with JDK 21 and even JDK 25. In other words, you select Java 17 for the generated project, but your local machine does not need to run on JDK 17 just to build it. + +## Caveats + +There are a few caveats you should know before jumping in: + +- The desktop target is not currently supported for Java 17 projects. If there is demand we can add that. You can still use the `jar` target to build desktop applications with Codename One, and that works fine with Java 17. +- UWP will not be supported. That target was already deprecated, so there is no point in doing the extra work there. +- Other targets should just work. + +## What Java 17 Syntax Works? + +This support includes modern language syntax that makes day to day code much nicer to write. + +For example, `var` lets us remove obvious type boilerplate from local variables: + +```java +var greeting = "Hello"; +var target = "Codename One"; +``` + +Switch expressions are more concise and make it easier to return a value directly from the switch: + +```java +var message = switch (greeting.length()) { + case 5 -> greeting + " " + target; + default -> "unexpected"; +}; +``` + +Text blocks are also supported, so multi-line strings are much more readable: + +```java +var textBlock = """ + Java 17 language features + should compile in tests. + """; +``` + +That means you can start using language improvements that make code cleaner and easier to read. + +This still does not include support for newer JDK APIs such as streams. As mentioned in the previous post, if you need streams today there is already a cn1lib solution for that, and we hope to improve the built-in story over time. + +## What About Java 21 and 25? + +Since we mentioned JDK 21 and 25 above, it is worth clarifying the roadmap. + +We do plan to add support for newer language levels in a coming update. That is a different challenge, because Android only supports up to Java 17 today. + +We would still like to introduce that support, but at the moment Java 17 is the more important milestone. + +## Other Updates Worth Mentioning + +A few other useful things landed over the past week. + +The [Initializr](/initializr/) now includes more advanced CSS theme editing with live preview, and there were several follow-up fixes to make theming behave more reliably. This is relevant if you are starting a fresh project anyway, because the [Initializr](/initializr/) has become a much stronger starting point than it was even a couple of weeks ago. + +## Try Java 17 on a Real Project + +If you have been waiting for a more modern Java syntax level in Codename One, this is the time to give it a try. + +Create a new project with the [Initializr](/initializr/), select Java 17 and see how it feels in a real application. If you run into issues on Android, iOS, JavaScript or any other target, let us know. That feedback is what will help us polish this support and move it forward. + +--- + +## Discussion + +_Join the conversation via GitHub Discussions._ + +{{< giscus >}} diff --git a/docs/website/static/blog/official-experimental-java-17-support.jpg b/docs/website/static/blog/official-experimental-java-17-support.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6fac66db1cda4ba35b828e19b16a4b866cdc2dad GIT binary patch literal 45873 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 z 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 E0| Date: Sat, 14 Mar 2026 14:12:31 +0200 Subject: [PATCH 3/6] Added record support --- Ports/CLDC11/src/java/lang/Class.java | 4 ++ Ports/CLDC11/src/java/lang/Record.java | 37 +++++++++++++++++++ .../official-experimental-java-17-support.md | 19 ++++++++-- .../hellocodenameone/tests/Java17Tests.java | 32 ++++++++++++++-- .../tests/OrientationLockScreenshotTest.java | 2 +- vm/JavaAPI/src/java/lang/Class.java | 4 ++ vm/JavaAPI/src/java/lang/Record.java | 37 +++++++++++++++++++ 7 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 Ports/CLDC11/src/java/lang/Record.java create mode 100644 vm/JavaAPI/src/java/lang/Record.java diff --git a/Ports/CLDC11/src/java/lang/Class.java b/Ports/CLDC11/src/java/lang/Class.java index d79fe6660e..2e640a47ab 100644 --- a/Ports/CLDC11/src/java/lang/Class.java +++ b/Ports/CLDC11/src/java/lang/Class.java @@ -278,4 +278,8 @@ public Constructor getEnclosingConstructor() { public boolean isLocalClass() { return false; } + + public boolean isRecord() { + return this != java.lang.Record.class && java.lang.Record.class.isAssignableFrom(this); + } } diff --git a/Ports/CLDC11/src/java/lang/Record.java b/Ports/CLDC11/src/java/lang/Record.java new file mode 100644 index 0000000000..d870566c2b --- /dev/null +++ b/Ports/CLDC11/src/java/lang/Record.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package java.lang; + +/** + * Base class for Java record types. + */ +public abstract class Record { + protected Record() { + } + + public abstract boolean equals(Object obj); + + public abstract int hashCode(); + + public abstract String toString(); +} diff --git a/docs/website/content/blog/official-experimental-java-17-support.md b/docs/website/content/blog/official-experimental-java-17-support.md index 1f39718e8e..1addcf559a 100644 --- a/docs/website/content/blog/official-experimental-java-17-support.md +++ b/docs/website/content/blog/official-experimental-java-17-support.md @@ -4,8 +4,8 @@ date: '2026-03-14' author: Shai Almog slug: official-experimental-java-17-support url: /blog/official-experimental-java-17-support/ -description: Codename One projects generated with the Initializr can now use official experimental Java 17 support, with most modern targets expected to work and more JDK support planned next. -feed_html: 'Official Experimental Java 17 Support for Codename One Projects Codename One projects generated with the Initializr can now use official experimental Java 17 support, with most modern targets expected to work and more JDK support planned next.' +description: Codename One projects generated with the Initializr can now use official experimental Java 17 support, with record support arriving in Codename One 7.0.229 on March 20, 2026, and more JDK support planned next. +feed_html: 'Official Experimental Java 17 Support for Codename One Projects Codename One projects generated with the Initializr can now use official experimental Java 17 support, with record support arriving in Codename One 7.0.229 on March 20, 2026, and more JDK support planned next.' --- ![Official Experimental Java 17 Support for Codename One Projects](/blog/official-experimental-java-17-support.jpg) @@ -32,6 +32,8 @@ There are a few caveats you should know before jumping in: This support includes modern language syntax that makes day to day code much nicer to write. +At the moment this includes features like `var`, switch expressions and text blocks. Record support is planned for Codename One `7.0.229`, slated for release on March 20, 2026. + For example, `var` lets us remove obvious type boilerplate from local variables: ```java @@ -57,7 +59,18 @@ var textBlock = """ """; ``` -That means you can start using language improvements that make code cleaner and easier to read. +Record syntax is also queued for Codename One `7.0.229`, slated for release on March 20, 2026, so Java 17 projects will be able to use compact immutable data carriers too. + +For example, this record will compile once `7.0.229` is available on March 20, 2026: + +```java +record Person(String name, int age) {} + +var person = new Person("Duke", 29); +System.out.println(person.name()); +``` + +That means you can start using language improvements that make code cleaner and easier to read, and records will join that list in `7.0.229` on March 20, 2026. This still does not include support for newer JDK APIs such as streams. As mentioned in the previous post, if you need streams today there is already a cn1lib solution for that, and we hope to improve the built-in story over time. diff --git a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java index b14782b6bb..d4d3c52cdd 100644 --- a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java @@ -1,21 +1,40 @@ package com.codenameone.examples.hellocodenameone.tests; public class Java17Tests extends BaseTest { + record MyRecord(int val, String otherVal) { + @Override + public String toString() { + return "MyRecord[val=" + val + ", otherVal=" + otherVal + "]"; + } + + @Override + public int hashCode() { + return 31 * val + otherVal.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MyRecord)) { + return false; + } + MyRecord other = (MyRecord)obj; + return val == other.val && otherVal.equals(other.otherVal); + } + } + @Override public boolean shouldTakeScreenshot() { return false; } - //record MyRecord(int val, String otherVal) {} - @Override public boolean runTest() throws Exception { var greeting = "Hello"; var target = "Codename One"; + var record = new MyRecord(2, "V"); var message = switch (greeting.length()) { case 5 -> greeting + " " + target; - //case 7 -> new MyRecord(2, "V"); default -> "unexpected"; }; @@ -26,6 +45,13 @@ public boolean runTest() throws Exception { assertEqual("Hello Codename One", message); assertEqual("Java 17 language features\nshould compile in tests.\n", textBlock); + assertEqual(2, record.val()); + assertEqual("V", record.otherVal()); + assertTrue(record instanceof java.lang.Record); + assertTrue(record.getClass().isRecord()); + assertEqual("MyRecord[val=2, otherVal=V]", record.toString()); + assertEqual(148, record.hashCode()); + assertTrue(record.equals(new MyRecord(2, "V"))); done(); return true; } diff --git a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java index 62e75b57c9..91b37b9595 100644 --- a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/OrientationLockScreenshotTest.java @@ -17,6 +17,7 @@ public boolean runTest() { protected void onShowCompleted() { CN.lockOrientation(false); waitForOrientation(this, false, () -> { + waitFor(50); Cn1ssDeviceRunnerHelper.emitCurrentFormScreenshot("landscape"); CN.lockOrientation(true); waitForOrientation(this, true, OrientationLockScreenshotTest.this::done); @@ -33,7 +34,6 @@ private void waitForOrientation(Form form, boolean portrait, Runnable onDone) { } private void waitForOrientation(Form form, boolean portrait, int attemptsLeft, Runnable onDone) { - waitFor(50); if (CN.isPortrait() == portrait || attemptsLeft <= 0) { onDone.run(); return; diff --git a/vm/JavaAPI/src/java/lang/Class.java b/vm/JavaAPI/src/java/lang/Class.java index 8422cc3d90..debb2c8d0e 100644 --- a/vm/JavaAPI/src/java/lang/Class.java +++ b/vm/JavaAPI/src/java/lang/Class.java @@ -341,4 +341,8 @@ public Constructor getEnclosingConstructor() { public boolean isLocalClass() { return false; } + + public boolean isRecord() { + return this != java.lang.Record.class && java.lang.Record.class.isAssignableFrom(this); + } } diff --git a/vm/JavaAPI/src/java/lang/Record.java b/vm/JavaAPI/src/java/lang/Record.java new file mode 100644 index 0000000000..d870566c2b --- /dev/null +++ b/vm/JavaAPI/src/java/lang/Record.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package java.lang; + +/** + * Base class for Java record types. + */ +public abstract class Record { + protected Record() { + } + + public abstract boolean equals(Object obj); + + public abstract int hashCode(); + + public abstract String toString(); +} From 2e008285a8f846cf00d61e51ef89eb62897a88b4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 14 Mar 2026 14:36:06 +0200 Subject: [PATCH 4/6] Fixed Java 17 build options for Android --- .../codename1/builders/AndroidGradleBuilder.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java index c4cd8ffaee..4377ebab93 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java @@ -3607,9 +3607,15 @@ public void usesClassMethod(String cls, String method) { String compileSdkVersion = "'android-21'"; - String java8P2 = ""; - if(useJava8SourceLevel) { - java8P2 = " compileOptions {\n" + + int projectJavaVersion = parseVersionStringAsInt(request.getArg("java.version", "8")); + String javaCompileOptions = ""; + if (projectJavaVersion >= 17 && useGradle8) { + javaCompileOptions = " compileOptions {\n" + + " sourceCompatibility JavaVersion.toVersion(17)\n" + + " targetCompatibility JavaVersion.toVersion(17)\n" + + " }\n"; + } else if(useJava8SourceLevel) { + javaCompileOptions = " compileOptions {\n" + " sourceCompatibility JavaVersion.VERSION_1_8\n" + " targetCompatibility JavaVersion.VERSION_1_8\n" + " }\n"; @@ -3770,7 +3776,7 @@ public void usesClassMethod(String cls, String method) { + multidex + request.getArg("android.xgradle_default_config", "") + " }\n" - + java8P2 + + javaCompileOptions + " sourceSets {\n" + " main {\n" + " aidl.srcDirs = ['src/main/java']\n" From 57246b717fd85fe97317b7832a0a4933023b697d Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:03:07 +0200 Subject: [PATCH 5/6] Cleaned up failure with the Java 17 test --- .../hellocodenameone/tests/Java17Tests.java | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java index d4d3c52cdd..9cdbd144fb 100644 --- a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/Java17Tests.java @@ -29,30 +29,34 @@ public boolean shouldTakeScreenshot() { @Override public boolean runTest() throws Exception { - var greeting = "Hello"; - var target = "Codename One"; - var record = new MyRecord(2, "V"); - - var message = switch (greeting.length()) { - case 5 -> greeting + " " + target; - default -> "unexpected"; - }; - - var textBlock = """ - Java 17 language features - should compile in tests. - """; - - assertEqual("Hello Codename One", message); - assertEqual("Java 17 language features\nshould compile in tests.\n", textBlock); - assertEqual(2, record.val()); - assertEqual("V", record.otherVal()); - assertTrue(record instanceof java.lang.Record); - assertTrue(record.getClass().isRecord()); - assertEqual("MyRecord[val=2, otherVal=V]", record.toString()); - assertEqual(148, record.hashCode()); - assertTrue(record.equals(new MyRecord(2, "V"))); - done(); - return true; + try { + var greeting = "Hello"; + var target = "Codename One"; + var record = new MyRecord(2, "V"); + + var message = switch (greeting.length()) { + case 5 -> greeting + " " + target; + default -> "unexpected"; + }; + + var textBlock = """ + Java 17 language features + should compile in tests. + """; + + assertEqual("Hello Codename One", message); + assertEqual("Java 17 language features\nshould compile in tests.\n", textBlock); + assertEqual(2, record.val()); + assertEqual("V", record.otherVal()); + assertEqual("MyRecord[val=2, otherVal=V]", record.toString()); + assertEqual(148, record.hashCode()); + assertTrue(record.equals(new MyRecord(2, "V"))); + return true; + } catch (Throwable t) { + fail(String.valueOf(t)); + return false; + } finally { + done(); + } } } From 33c880e116540b6165d8bb07534583c51d160659 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 14 Mar 2026 17:32:04 +0200 Subject: [PATCH 6/6] Updating about bluetooth support and xcode version --- .../official-experimental-java-17-support.md | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/website/content/blog/official-experimental-java-17-support.md b/docs/website/content/blog/official-experimental-java-17-support.md index 1addcf559a..5a252e1aee 100644 --- a/docs/website/content/blog/official-experimental-java-17-support.md +++ b/docs/website/content/blog/official-experimental-java-17-support.md @@ -88,6 +88,56 @@ A few other useful things landed over the past week. The [Initializr](/initializr/) now includes more advanced CSS theme editing with live preview, and there were several follow-up fixes to make theming behave more reliably. This is relevant if you are starting a fresh project anyway, because the [Initializr](/initializr/) has become a much stronger starting point than it was even a couple of weeks ago. +We also finished updating all macOS build servers to use Xcode 26. + +Another useful update is a newer version of the Codename One Bluetooth LE cn1lib, available in the [bluetoothle-codenameone repository](https://github.com/codenameone/bluetoothle-codenameone). This library now uses a native Codename One bridge implementation adapted from the original Bluetooth LE plugin lineage. + +If you are using a Maven-based Codename One project, add it with: + +```xml + + com.codenameone + cn1-bluetooth-lib + 1.0.0 + pom + +``` + +If you are using a classic Codename One project, you can still integrate it as a `.cn1lib` by adding the library to your project's `lib/` directory, running `Refresh Libs`, and rebuilding. The library requires Java 8. + +Here is a small usage sample: + +```java +final Bluetooth bt = new Bluetooth(); +Form main = new Form("Bluetooth Demo"); +main.setLayout(new BoxLayout(BoxLayout.Y_AXIS)); +main.add(new Button(new Command("enable bluetooth") { + @Override + public void actionPerformed(ActionEvent evt) { + try { + if (!bt.isEnabled()) { + bt.enable(); + } + if (!bt.hasPermission()) { + bt.requestPermission(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } +})); +main.add(new Button(new Command("initialize") { + @Override + public void actionPerformed(ActionEvent evt) { + try { + bt.initialize(true, false, "bluetoothleplugin"); + } catch (IOException ex) { + ex.printStackTrace(); + } + } +})); +``` + ## Try Java 17 on a Real Project If you have been waiting for a more modern Java syntax level in Codename One, this is the time to give it a try.