You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by be...@apache.org on 2026/04/05 09:38:49 UTC

(tapestry-5) branch javax updated (11e2cd86a -> aa925eccc)

This is an automated email from the ASF dual-hosted git repository.

benw pushed a change to branch javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git


    from 11e2cd86a TAP5-2819: Jenkinsfile fix stage nesting
     new abf017437 TAP5-2809: java-convention use source/targetCompatibility, not toolchain
     new f2cedbd0a tapestry-latest-java-tests: convert testng to junit
     new 108baa34d TAP5-2825: Java 21 support
     new aa925eccc tapestry-ioc: AbstractResource double-slash on jar resource fixed

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../main/groovy/tapestry.java-convention.gradle    |   9 +-
 .../ioc/internal/util/AbstractResource.java        |   7 +-
 .../groovy/ioc/specs/ClasspathResourceSpec.groovy  |   5 +-
 tapestry-latest-java-tests/build.gradle            |   7 +-
 .../ioc/services/Java10And11NewFeatureTests.java   |  35 ++---
 .../ioc/services/Java12And13NewFeatureTests.java   |  15 +-
 .../ioc/services/Java14NewFeatureTests.java        |  14 +-
 .../ioc/services/Java15To17NewFeatureTests.java    |  14 +-
 .../ioc/services/Java18To21ConcreteService.java    | 137 +++++++++++++++++
 .../ioc/services/Java18To21NewFeatureTests.java    | 166 +++++++++++++++++++++
 .../tapestry5/ioc/services/Java18To21Service.java  |  55 +++++++
 .../ioc/services/Java18To21ServiceImpl.java        | 142 ++++++++++++++++++
 .../ioc/services/Java9NewFeatureTests.java         |  15 +-
 13 files changed, 562 insertions(+), 59 deletions(-)
 create mode 100644 tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ConcreteService.java
 create mode 100644 tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21NewFeatureTests.java
 create mode 100644 tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21Service.java
 create mode 100644 tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ServiceImpl.java


(tapestry-5) 04/04: tapestry-ioc: AbstractResource double-slash on jar resource fixed

Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

benw pushed a commit to branch javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git

commit aa925eccc978704ec4e51388ee2f69594a8bef46
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Apr 5 11:38:40 2026 +0200

    tapestry-ioc: AbstractResource double-slash on jar resource fixed
---
 .../org/apache/tapestry5/ioc/internal/util/AbstractResource.java   | 7 +++++--
 .../src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy         | 3 ++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
index 5b6a5ff19..15def883c 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/AbstractResource.java
@@ -294,11 +294,14 @@ public abstract class AbstractResource extends LockSupport implements Resource
             int indexOfExclamationMark = urlAsString.indexOf('!');
 
             String resourceInJar = urlAsString.substring(indexOfExclamationMark + 2);
+            if (!resourceInJar.endsWith("/"))
+            {
+                resourceInJar += "/";
+            }
 
-            URL directoryResource = Thread.currentThread().getContextClassLoader().getResource(resourceInJar + "/");
+            URL directoryResource = Thread.currentThread().getContextClassLoader().getResource(resourceInJar);
 
             boolean isDirectory = directoryResource != null && "jar".equals(directoryResource.getProtocol());
-
             if (isDirectory)
             {
                 throw new IOException("Cannot open a stream for a resource that references a directory inside a JAR file (" + url + ").");
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy
index f465ffae5..d4db85cd5 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy
@@ -289,7 +289,8 @@ class ClasspathResourceSpec extends Specification {
       def resourcePath = 'META-INF/maven/org.slf4j/slf4j-api/pom.xml'
       
       // TAP5-2825: This failes on Java 21, as Groovy can no longer access the
-      // protected methods `findResources`, so we use `getResources` instead
+      // protected methods `findResources`, so we use `getResources` instead,
+      // as it returns the same underlying Enumeration<URL>.
       def resourceURLs = currentCl.getResources(resourcePath).toList()
       def slf4jApiURL = resourceURLs.find{it.toString().contains('.jar!')} 
       ClassLoader cl = new URLClassLoader(slf4jApiURL as URL[], (ClassLoader) null)


(tapestry-5) 02/04: tapestry-latest-java-tests: convert testng to junit

Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

benw pushed a commit to branch javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git

commit f2cedbd0a149bfe6c1451515b6490844363a229d
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Apr 5 10:48:51 2026 +0200

    tapestry-latest-java-tests: convert testng to junit
---
 .../ioc/services/Java10And11NewFeatureTests.java   | 35 +++++++++-------------
 .../ioc/services/Java12And13NewFeatureTests.java   | 15 +++++-----
 .../ioc/services/Java14NewFeatureTests.java        | 14 ++++-----
 .../ioc/services/Java15To17NewFeatureTests.java    | 14 ++++-----
 .../ioc/services/Java9NewFeatureTests.java         | 15 +++++-----
 5 files changed, 44 insertions(+), 49 deletions(-)

diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java10And11NewFeatureTests.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java10And11NewFeatureTests.java
index f91db00cf..aec435086 100644
--- a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java10And11NewFeatureTests.java
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java10And11NewFeatureTests.java
@@ -11,19 +11,15 @@
 // limitations under the License.
 package org.apache.tapestry5.ioc.services;
 
+import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.RegistryBuilder;
 import org.apache.tapestry5.ioc.ServiceBinder;
-import org.testng.annotations.BeforeSuite;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.BeforeAll;
 
-/**
- * Tests for Tapestry-IoC and the only Java language feature introduced in Java SE 10 and 11,
- * local variable type inference (introduced in 10 and improved in 11).
- */
-public class Java10And11NewFeatureTests 
+public class Java10And11NewFeatureTests
 {
-    
-    public static class Java10And11Module 
+
+    public static class Java10And11Module
     {
         public static void bind(ServiceBinder binder)
         {
@@ -31,24 +27,21 @@ public class Java10And11NewFeatureTests
             binder.bind(Java10And11ConcreteService.class);
         }
     }
-    
-    private Java10And11Service java10And11Service;
-    
-    private Java10And11ConcreteService java10And11ConcreteService;
-    
-    @BeforeSuite
-    public void setup() 
+
+    private static Java10And11Service java10And11Service;
+    private static Java10And11ConcreteService java10And11ConcreteService;
+
+    @BeforeAll
+    static void setup()
     {
-        var registry = RegistryBuilder.buildAndStartupRegistry(Java10And11Module.class);
+        Registry registry = RegistryBuilder.buildAndStartupRegistry(Java10And11Module.class);
         java10And11Service = registry.getService(Java10And11Service.class);
         java10And11ConcreteService = registry.getService(Java10And11ConcreteService.class);
     }
 
-    @Test
-    public void localVariableTypeInference() throws Exception 
+    void localVariableTypeInference() throws Exception
     {
         java10And11Service.localVariableTypeInference();
-        java10And11ConcreteService.localVariableTypeInference();;
+        java10And11ConcreteService.localVariableTypeInference();
     }
-    
 }
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java12And13NewFeatureTests.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java12And13NewFeatureTests.java
index 051b58615..773e204be 100644
--- a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java12And13NewFeatureTests.java
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java12And13NewFeatureTests.java
@@ -11,10 +11,11 @@
 // limitations under the License.
 package org.apache.tapestry5.ioc.services;
 
+import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.RegistryBuilder;
 import org.apache.tapestry5.ioc.ServiceBinder;
-import org.testng.annotations.BeforeSuite;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests for Tapestry-IoC and the Java language features introduced in Java SE 12 and 13,
@@ -32,14 +33,14 @@ public class Java12And13NewFeatureTests
         }
     }
     
-    private Java12And13Service java12And13Service;
+    private static Java12And13Service java12And13Service;
     
-    private Java12And13ConcreteService java12And13ConcreteService;
+    private static Java12And13ConcreteService java12And13ConcreteService;
     
-    @BeforeSuite
-    public void setup() 
+    @BeforeAll
+    public static void setup()
     {
-        var registry = RegistryBuilder.buildAndStartupRegistry(Java12And13Module.class);
+        Registry registry = RegistryBuilder.buildAndStartupRegistry(Java12And13Module.class);
         java12And13Service = registry.getService(Java12And13Service.class);
         java12And13ConcreteService = registry.getService(Java12And13ConcreteService.class);
     }
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java14NewFeatureTests.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java14NewFeatureTests.java
index 35746c2fb..77cb32561 100644
--- a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java14NewFeatureTests.java
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java14NewFeatureTests.java
@@ -14,9 +14,9 @@ package org.apache.tapestry5.ioc.services;
 import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.RegistryBuilder;
 import org.apache.tapestry5.ioc.ServiceBinder;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeSuite;
-import org.testng.annotations.Test;
 
 /**
  * Tests for Tapestry-IoC and Java language features introduced in Java SE 14: pattern matching for the
@@ -25,7 +25,7 @@ import org.testng.annotations.Test;
 public class Java14NewFeatureTests 
 {
     
-    private Registry registry;
+    private static Registry registry;
     
     public static class Java14Module 
     {
@@ -40,12 +40,12 @@ public class Java14NewFeatureTests
         }
     }
     
-    private Java14Service java14Service;
+    private static Java14Service java14Service;
     
-    private Java14ConcreteService java14ConcreteService;
+    private static Java14ConcreteService java14ConcreteService;
     
-    @BeforeSuite
-    public void setup() 
+    @BeforeAll
+    public static void setup()
     {
         registry = RegistryBuilder.buildAndStartupRegistry(Java14Module.class);
         java14Service = registry.getService(Java14Service.class);
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java15To17NewFeatureTests.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java15To17NewFeatureTests.java
index f8fb60dd9..c6db32c19 100644
--- a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java15To17NewFeatureTests.java
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java15To17NewFeatureTests.java
@@ -16,10 +16,10 @@ import org.apache.tapestry5.ioc.RegistryBuilder;
 import org.apache.tapestry5.ioc.ServiceBinder;
 import org.apache.tapestry5.ioc.annotations.Marker;
 import org.apache.tapestry5.ioc.annotations.Primary;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.testng.annotations.BeforeSuite;
-import org.testng.annotations.Test;
 
 /**
  * Tests for Tapestry-IoC To the only Java language feature introduced in Java SE 10 To 11,
@@ -80,14 +80,14 @@ public class Java15To17NewFeatureTests
 
     }
     
-    private Java15To17Service java15To17Service;
+    private static Java15To17Service java15To17Service;
     
-    private Java15To17ConcreteService java15To17ConcreteService;
+    private static Java15To17ConcreteService java15To17ConcreteService;
 
-    private Registry registry;
+    private static Registry registry;
     
-    @BeforeSuite
-    public void setup() 
+    @BeforeAll
+    public static void setup()
     {
         registry = RegistryBuilder.buildAndStartupRegistry(Java15To17Module.class);
         java15To17Service = registry.getService(Java15To17Service.class);
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java9NewFeatureTests.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java9NewFeatureTests.java
index f2ddcc690..02d449627 100644
--- a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java9NewFeatureTests.java
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java9NewFeatureTests.java
@@ -11,10 +11,11 @@
 // limitations under the License.
 package org.apache.tapestry5.ioc.services;
 
+import org.apache.tapestry5.ioc.Registry;
 import org.apache.tapestry5.ioc.RegistryBuilder;
 import org.apache.tapestry5.ioc.ServiceBinder;
-import org.testng.annotations.BeforeSuite;
-import org.testng.annotations.Test;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests for Tapestry-IoC and Java language features introduced in Java SE 9.
@@ -31,14 +32,14 @@ public class Java9NewFeatureTests
         }
     }
     
-    private Java9Service java9Service;
+    private static Java9Service java9Service;
     
-    private Java9ConcreteService java9ConcreteService;
+    private static Java9ConcreteService java9ConcreteService;
     
-    @BeforeSuite
-    public void setup() 
+    @BeforeAll
+    public static void setup()
     {
-        var registry = RegistryBuilder.buildAndStartupRegistry(Java9Module.class);
+        Registry registry = RegistryBuilder.buildAndStartupRegistry(Java9Module.class);
         java9Service = registry.getService(Java9Service.class);
         java9ConcreteService = registry.getService(Java9ConcreteService.class);
     }


(tapestry-5) 03/04: TAP5-2825: Java 21 support

Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

benw pushed a commit to branch javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git

commit 108baa34d8f3883cfeb7c24e1706939f4ea79181
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Apr 5 10:49:12 2026 +0200

    TAP5-2825: Java 21 support
---
 .../groovy/ioc/specs/ClasspathResourceSpec.groovy  |   4 +-
 tapestry-latest-java-tests/build.gradle            |   7 +-
 .../ioc/services/Java18To21ConcreteService.java    | 137 +++++++++++++++++
 .../ioc/services/Java18To21NewFeatureTests.java    | 166 +++++++++++++++++++++
 .../tapestry5/ioc/services/Java18To21Service.java  |  55 +++++++
 .../ioc/services/Java18To21ServiceImpl.java        | 142 ++++++++++++++++++
 6 files changed, 506 insertions(+), 5 deletions(-)

diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy
index 1550adfae..f465ffae5 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ClasspathResourceSpec.groovy
@@ -288,7 +288,9 @@ class ClasspathResourceSpec extends Specification {
       def currentCl = Thread.currentThread().contextClassLoader 
       def resourcePath = 'META-INF/maven/org.slf4j/slf4j-api/pom.xml'
       
-      def resourceURLs = currentCl.findResources resourcePath
+      // TAP5-2825: This failes on Java 21, as Groovy can no longer access the
+      // protected methods `findResources`, so we use `getResources` instead
+      def resourceURLs = currentCl.getResources(resourcePath).toList()
       def slf4jApiURL = resourceURLs.find{it.toString().contains('.jar!')} 
       ClassLoader cl = new URLClassLoader(slf4jApiURL as URL[], (ClassLoader) null)
      
diff --git a/tapestry-latest-java-tests/build.gradle b/tapestry-latest-java-tests/build.gradle
index c1e5c9ebc..4192d0201 100644
--- a/tapestry-latest-java-tests/build.gradle
+++ b/tapestry-latest-java-tests/build.gradle
@@ -5,15 +5,14 @@ plugins {
 description = 'Test suite for making sure Tapestry runs on latest Java'
 
 java {
-    toolchain {
-        languageVersion = JavaLanguageVersion.of(17)
-    }
+    sourceCompatibility = JavaVersion.VERSION_21
+    targetCompatibility = JavaVersion.VERSION_21
 
     withSourcesJar()
 }
 
 tasks.withType(JavaCompile).configureEach {
-    options.release = 17
+    options.release = 21
 }
 
 tasks.withType(JavaCompile).configureEach {
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ConcreteService.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ConcreteService.java
new file mode 100644
index 000000000..2de1c3dab
--- /dev/null
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ConcreteService.java
@@ -0,0 +1,137 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.services;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SequencedCollection;
+import java.util.SequencedMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Java18To21ConcreteService
+{
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(Java18To21ConcreteService.class);
+
+    /**
+     * For testing SequencedCollection as a return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    public SequencedCollection<String> getSequencedCollection()
+    {
+        SequencedCollection<String> list = new ArrayList<>();
+        list.add("first");
+        list.add("middle");
+        list.add("last");
+        return list;
+    }
+
+    /**
+     * For testing SequencedMap as a return type (JEP 431).
+     * https://openjdk.org/jeps/431
+     */
+    public SequencedMap<String, Integer> getSequencedMap()
+    {
+        SequencedMap<String, Integer> map = new LinkedHashMap<>();
+        map.put("one", 1);
+        map.put("two", 2);
+        map.put("three", 3);
+        return map;
+    }
+
+    /**
+     * For testing record patterns in instanceof expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    public void recordPatternsInInstanceOf()
+    {
+        IntExpression expr = new ConstantIntExpression(42);
+        if (expr instanceof ConstantIntExpression(int v))
+        {
+            LOGGER.info("Constant int value: " + v);
+        }
+
+        IntTuple tuple = new IntTuple(3, 7);
+        if (tuple instanceof IntTuple(int x, int y))
+        {
+            LOGGER.info("Tuple sum: " + (x + y));
+        }
+    }
+
+    /**
+     * For testing record patterns in switch expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    public void recordPatternsInSwitch()
+    {
+        IntExpression expr = new PlusExpression(new ConstantIntExpression(2), new ConstantIntExpression(3));
+        int result = evalIntExpression(expr);
+        LOGGER.info("Switch record pattern result: " + result);
+
+        IntExpression squareExpr = new SquareExpression(new ConstantIntExpression(5));
+        LOGGER.info("Square result: " + evalIntExpression(squareExpr));
+    }
+
+    private int evalIntExpression(IntExpression e)
+    {
+        return switch (e)
+        {
+            case ConstantIntExpression(int v)        -> v;
+            case PlusExpression(var left, var right) -> evalIntExpression(left) + evalIntExpression(right);
+            case SquareExpression(var inner) ->
+            {
+                int v = evalIntExpression(inner); yield v * v;
+            }
+        };
+    }
+    /**
+     * For testing pattern matching for switch with a sealed class hierarchy (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    public void patternMatchingForSwitchWithSealedClass()
+    {
+        for (Appliance appliance : new Appliance[] { new WashingMachine(), new Freezer(), new Refrigerator() })
+        {
+            String description = switch (appliance)
+            {
+                case WashingMachine wm -> "Washer: " + wm.getName();
+                case Freezer f         -> "Freezer: " + f.getName();
+                case Refrigerator r    -> "Fridge: " + r.getName();
+                case CoolingMachine cm -> "Cooler: " + cm.getName();
+            };
+            LOGGER.info(description);
+        }
+    }
+
+    /**
+     * For testing pattern matching for switch with a sealed interface (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    public void patternMatchingForSwitchWithSealedInterface()
+    {
+        BinaryExpression expr = new AndExpression(
+                new ConstantBinaryExpression(true),
+                new OrExpression(new ConstantBinaryExpression(false), new ConstantBinaryExpression(true)));
+
+        String description = switch (expr)
+        {
+            case ConstantBinaryExpression c -> "Constant: " + c.evaluate();
+            case AndExpression a            -> "And: " + a.evaluate();
+            case OrExpression o             -> "Or: " + o.evaluate();
+        };
+        LOGGER.info(description);
+    }
+}
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21NewFeatureTests.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21NewFeatureTests.java
new file mode 100644
index 000000000..9ea0ed495
--- /dev/null
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21NewFeatureTests.java
@@ -0,0 +1,166 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.services;
+
+import java.util.SequencedCollection;
+import java.util.SequencedMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.tapestry5.ioc.Registry;
+import org.apache.tapestry5.ioc.RegistryBuilder;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * Tests for Tapestry-IoC with Java language features introduced between Java SE 18 and 21.
+ * <ul>
+ *   <li>JEP 431: Sequenced collections</li>
+ *   <li>JEP 440: Record patterns</li>
+ *   <li>JEP 441: Pattern matching</li>
+ *   <li>JEP 444: Virtual threads</li>
+ * </ul>
+ */
+class Java18To21NewFeatureTests
+{
+    public static class Java18To21Module
+    {
+        public static void bind(ServiceBinder binder)
+        {
+            binder.bind(Java18To21Service.class, Java18To21ServiceImpl.class);
+            binder.bind(Java18To21ConcreteService.class);
+        }
+    }
+
+    private static Java18To21Service java18To21Service;
+
+    private static Java18To21ConcreteService java18To21ConcreteService;
+
+    private static Registry registry;
+
+    @BeforeAll
+    public static void setup()
+    {
+        registry = RegistryBuilder.buildAndStartupRegistry(Java18To21Module.class);
+        java18To21Service = registry.getService(Java18To21Service.class);
+        java18To21ConcreteService = registry.getService(Java18To21ConcreteService.class);
+    }
+
+    /**
+     * Tests SequencedCollection as a service return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    @Test
+    public void sequencedCollectionReturnType()
+    {
+        SequencedCollection<String> serviceCol = java18To21Service.getSequencedCollection();
+
+        assertNotNull(serviceCol);
+        assertEquals("first", serviceCol.getFirst());
+        assertEquals("last", serviceCol.getLast());
+
+        SequencedCollection<String> concreteCol = java18To21ConcreteService.getSequencedCollection();
+        assertNotNull(concreteCol);
+        assertEquals("first", concreteCol.getFirst());
+        assertEquals("last", concreteCol.getLast());
+    }
+
+    /**
+     * Tests SequencedMap as a service return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    @Test
+    public void sequencedMapReturnType()
+    {
+        SequencedMap<String, Integer> serviceMap = java18To21Service.getSequencedMap();
+        assertNotNull(serviceMap);
+        assertEquals("one", serviceMap.firstEntry().getKey());
+        assertEquals("three", serviceMap.lastEntry().getKey());
+
+        SequencedMap<String, Integer> concreteMap = java18To21ConcreteService.getSequencedMap();
+        assertNotNull(concreteMap);
+        assertEquals("one", concreteMap.firstEntry().getKey());
+        assertEquals("three", concreteMap.lastEntry().getKey());
+    }
+
+    /**
+     * Tests record patterns in switch expressions (JEP 440).
+     * https://openjdk.org/jeps/440
+     */
+    @Test
+    public void recordPatternsInSwitch()
+    {
+        java18To21Service.recordPatternsInSwitch();
+        java18To21ConcreteService.recordPatternsInSwitch();
+    }
+
+    /**
+     * Tests pattern matching for switch with a sealed class hierarchy (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    @Test
+    public void patternMatchingForSwitchWithSealedClass()
+    {
+        java18To21Service.patternMatchingForSwitchWithSealedClass();
+        java18To21ConcreteService.patternMatchingForSwitchWithSealedClass();
+    }
+
+    /**
+     * Tests pattern matching for switch with a sealed interface (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    @Test
+    public void patternMatchingForSwitchWithSealedInterface()
+    {
+        java18To21Service.patternMatchingForSwitchWithSealedInterface();
+        java18To21ConcreteService.patternMatchingForSwitchWithSealedInterface();
+    }
+
+    /**
+     * Tests record patterns in instanceof expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    @Test
+    public void recordPatternsInInstanceOf()
+    {
+        java18To21Service.recordPatternsInInstanceOf();
+        java18To21ConcreteService.recordPatternsInInstanceOf();
+    }
+
+    /**
+     * Tests that Tapestry service proxies are callable from virtual threads (JEP 444).
+     * @see https://openjdk.org/jeps/444
+     */
+    @Test
+    public void virtualThreadServiceCall() throws InterruptedException
+    {
+        AtomicReference<String> serviceResult = new AtomicReference<>();
+        AtomicReference<String> concreteResult = new AtomicReference<>();
+
+        Thread vt1 = Thread.ofVirtual().start(() ->
+                serviceResult.set(java18To21Service.getSequencedCollection().getFirst()));
+        Thread vt2 = Thread.ofVirtual().start(() ->
+                concreteResult.set(java18To21ConcreteService.getSequencedCollection().getFirst()));
+
+        vt1.join();
+        vt2.join();
+
+        assertEquals("first", serviceResult.get());
+        assertEquals("first", concreteResult.get());
+    }
+
+}
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21Service.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21Service.java
new file mode 100644
index 000000000..705b47aef
--- /dev/null
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21Service.java
@@ -0,0 +1,55 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.services;
+
+import java.util.SequencedCollection;
+import java.util.SequencedMap;
+
+public interface Java18To21Service
+{
+
+    /**
+     * Tests SequencedCollection as a return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    SequencedCollection<String> getSequencedCollection();
+
+    /**
+     * Tests SequencedMap as a return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    SequencedMap<String, Integer> getSequencedMap();
+
+    /**
+     * Tests record patterns in instanceof expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    void recordPatternsInInstanceOf();
+
+    /**
+     * Tests record patterns in switch expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    void recordPatternsInSwitch();
+
+    /**
+     * Tests pattern matching for switch with a sealed class hierarchy (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    void patternMatchingForSwitchWithSealedClass();
+
+    /**
+     * Tests pattern matching for switch with a sealed interface (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    void patternMatchingForSwitchWithSealedInterface();
+}
diff --git a/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ServiceImpl.java b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ServiceImpl.java
new file mode 100644
index 000000000..850696aa4
--- /dev/null
+++ b/tapestry-latest-java-tests/src/test/java/org/apache/tapestry5/ioc/services/Java18To21ServiceImpl.java
@@ -0,0 +1,142 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.services;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SequencedCollection;
+import java.util.SequencedMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Java18To21ServiceImpl implements Java18To21Service
+{
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(Java18To21ServiceImpl.class);
+
+    /**
+     * Tests SequencedCollection as a return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    @Override
+    public SequencedCollection<String> getSequencedCollection()
+    {
+        SequencedCollection<String> list = new ArrayList<>();
+        list.add("first");
+        list.add("middle");
+        list.add("last");
+        return list;
+    }
+
+    /**
+     * Tests SequencedMap as a return type (JEP 431).
+     * @see https://openjdk.org/jeps/431
+     */
+    @Override
+    public SequencedMap<String, Integer> getSequencedMap()
+    {
+        SequencedMap<String, Integer> map = new LinkedHashMap<>();
+        map.put("one", 1);
+        map.put("two", 2);
+        map.put("three", 3);
+        return map;
+    }
+
+    /**
+     * Tests record patterns in instanceof expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    @Override
+    public void recordPatternsInInstanceOf()
+    {
+        IntExpression expr = new ConstantIntExpression(42);
+        if (expr instanceof ConstantIntExpression(int v))
+        {
+            LOGGER.info("Constant int value: " + v);
+        }
+
+        IntTuple tuple = new IntTuple(3, 7);
+        if (tuple instanceof IntTuple(int x, int y))
+        {
+            LOGGER.info("Tuple sum: " + (x + y));
+        }
+    }
+
+    /**
+     * Tests record patterns in switch expressions (JEP 440).
+     * @see https://openjdk.org/jeps/440
+     */
+    @Override
+    public void recordPatternsInSwitch()
+    {
+        IntExpression expr = new PlusExpression(new ConstantIntExpression(2), new ConstantIntExpression(3));
+        int result = evalIntExpression(expr);
+        LOGGER.info("Switch record pattern result: " + result);
+
+        IntExpression squareExpr = new SquareExpression(new ConstantIntExpression(5));
+        LOGGER.info("Square result: " + evalIntExpression(squareExpr));
+    }
+
+    private int evalIntExpression(IntExpression e)
+    {
+        return switch (e)
+        {
+            case ConstantIntExpression(int v)            -> v;
+            case PlusExpression(var left, var right)     -> evalIntExpression(left) + evalIntExpression(right);
+            case SquareExpression(var inner)              -> { int v = evalIntExpression(inner); yield v * v; }
+        };
+    }
+
+    /**
+     * Tests pattern matching for switch with a sealed class hierarchy (JEP 441).
+     * @see https://openjdk.org/jeps/441
+     */
+    @Override
+    public void patternMatchingForSwitchWithSealedClass()
+    {
+        for (Appliance appliance : new Appliance[] { new WashingMachine(), new Freezer(), new Refrigerator() })
+        {
+            String description = switch (appliance)
+            {
+                case WashingMachine wm -> "Washer: " + wm.getName();
+                case Freezer f         -> "Freezer: " + f.getName();
+                case Refrigerator r    -> "Fridge: " + r.getName();
+                case CoolingMachine cm -> "Cooler: " + cm.getName();
+            };
+            LOGGER.info(description);
+        }
+    }
+
+    /**
+     * Tests pattern matching for switch with a sealed interface (JEP 441).
+        }
+     * https://openjdk.org/jeps/441
+     */
+    @Override
+    public void patternMatchingForSwitchWithSealedInterface()
+    {
+        BinaryExpression expr = new AndExpression(
+                new ConstantBinaryExpression(true),
+                new OrExpression(new ConstantBinaryExpression(false), new ConstantBinaryExpression(true)));
+
+        String description = switch (expr)
+        {
+            case ConstantBinaryExpression c -> "Constant: " + c.evaluate();
+            case AndExpression a            -> "And: " + a.evaluate();
+            case OrExpression o             -> "Or: " + o.evaluate();
+        };
+        LOGGER.info(description);
+    }
+}


(tapestry-5) 01/04: TAP5-2809: java-convention use source/targetCompatibility, not toolchain

Posted by be...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

benw pushed a commit to branch javax
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git

commit abf0174373770828713ff58a9cf7e437d1334b33
Author: Ben Weidig <be...@netzgut.net>
AuthorDate: Sun Apr 5 10:48:06 2026 +0200

    TAP5-2809: java-convention use source/targetCompatibility, not toolchain
---
 buildSrc/src/main/groovy/tapestry.java-convention.gradle | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/buildSrc/src/main/groovy/tapestry.java-convention.gradle b/buildSrc/src/main/groovy/tapestry.java-convention.gradle
index 2d5e52762..2f48e9991 100644
--- a/buildSrc/src/main/groovy/tapestry.java-convention.gradle
+++ b/buildSrc/src/main/groovy/tapestry.java-convention.gradle
@@ -6,13 +6,16 @@ plugins {
 }
 
 java {
-    toolchain {
-        languageVersion = JavaLanguageVersion.of(8)
-    }
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
 
     withSourcesJar()
 }
 
+tasks.withType(JavaCompile).configureEach {
+    options.release = 8
+}
+
 configurations {
     provided
     meta