This is an automated email from the ASF dual-hosted git repository. benweidig pushed a commit to branch 5.9 in repository https://gitbox.apache.org/repos/asf/tapestry-5-site.git
commit ed028908a91a6a8620582db3fdc1b3de1b8702f9 Author: Ben Weidig <[email protected]> AuthorDate: Sat Aug 29 11:14:52 2026 +0200 Add 5.9 version of the User Guide Branched from 5.8 and updated for the Jakarta EE 9 release: - antora.yml: version 5.9, add tapestry-version attribute - New page: Migrating to Jakarta EE (dual artifact builds, package renames, migration tool usage) - New page: Release Notes 5.9 (5.9.0 and 5.9.1) - Document Session.LockMode and containsAttribute in Session Storage - Document the Recursive/RecursiveBody components in Component Reference - Document the t5/core/ajax headers option in Ajax and Zones - Replace javax.* with jakarta.* in index, configuration, jpa, bean-validation, uploading-files and the JSR-330 page - Update the Spring integration page for Spring 6 / Java 17 --- antora.yml | 3 +- modules/ROOT/nav.adoc | 2 + modules/ROOT/pages/ajax-and-zones.adoc | 19 ++ modules/ROOT/pages/bean-validation.adoc | 4 +- modules/ROOT/pages/component-reference.adoc | 5 + modules/ROOT/pages/configuration.adoc | 13 +- modules/ROOT/pages/index.adoc | 3 +- .../pages/integrating-with-spring-framework.adoc | 9 +- modules/ROOT/pages/jakarta-ee-migration.adoc | 242 +++++++++++++++++++++ modules/ROOT/pages/jpa.adoc | 46 ++-- modules/ROOT/pages/release-notes-5.9.adoc | 86 ++++++++ modules/ROOT/pages/session-storage.adoc | 45 ++++ modules/ROOT/pages/uploading-files.adoc | 13 +- .../pages/using-jsr-330-standard-annotations.adoc | 19 +- 14 files changed, 462 insertions(+), 47 deletions(-) diff --git a/antora.yml b/antora.yml index 82316c5..06d455e 100644 --- a/antora.yml +++ b/antora.yml @@ -1,6 +1,6 @@ name: userguide title: User Guide -version: 5.8 +version: 5.9 nav: - modules/ROOT/nav.adoc - modules/cookbook/nav.adoc @@ -8,4 +8,5 @@ nav: asciidoc: attributes: javadoc-version: current + tapestry-version: 5.9.1 tapestry-namespace: http://tapestry.apache.org/schema/tapestry_5_4.xsd diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index fcc0eee..f49113c 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -3,6 +3,7 @@ .Tapestry Core * Basics // ** xref:supported-environments-and-versions.adoc[] +** xref:jakarta-ee-migration.adoc[] ** xref:project-layout.adoc[] ** xref:configuration.adoc[] ** xref:runtime-exceptions.adoc[] @@ -100,6 +101,7 @@ * xref:third-party-modules.adoc[] .Release Notes +* xref:release-notes-5.9.adoc[] * xref:release-notes-5.8.adoc[] * xref:release-notes-5.7.adoc[] * xref:release-notes-5.6.adoc[] diff --git a/modules/ROOT/pages/ajax-and-zones.adoc b/modules/ROOT/pages/ajax-and-zones.adoc index fc486f8..eb76e08 100644 --- a/modules/ROOT/pages/ajax-and-zones.adoc +++ b/modules/ROOT/pages/ajax-and-zones.adoc @@ -387,3 +387,22 @@ require(["t5/core/ajax", "jquery"], function (ajax, $) { If you're trying to invoke a page class event handler, you can change line 5 above to element: `null`. You do need to explicitly set the element property, otherwise the ajax function will treat the first parameter, url, as an URL and not as an event name. + +=== Custom request headers + +Since Tapestry 5.9 (issue:2782[]), the `options` parameter accepts a `headers` object whose key/value pairs are added to the request headers: + +[source,javascript] +---- +require(["t5/core/ajax"], function (ajax) { + ajax('answer', { + element: null, + headers: { + "X-Tenant-Id": currentTenantId + }, + success: function(response) { /* ... */ } + }); +}); +---- + +This is useful for passing correlation ids, tenant identifiers or tokens that a server-side filter reads from the request, without encoding them into the URL or the form data. diff --git a/modules/ROOT/pages/bean-validation.adoc b/modules/ROOT/pages/bean-validation.adoc index 0488fd4..2094a00 100644 --- a/modules/ROOT/pages/bean-validation.adoc +++ b/modules/ROOT/pages/bean-validation.adoc @@ -15,7 +15,7 @@ In order to use this library you have to choose an implementation of the JSR-303 This library is not specific to any implementation of JSR-303 and will work with any implementation of your choice. === Bootstraping the Bean Validator -The javadoc:org.apache.tapestry5.beanvalidator.BeanValidatorSource[] service is responsible for bootstrapping the `javax.validation.Validator`. +The javadoc:org.apache.tapestry5.beanvalidator.BeanValidatorSource[] service is responsible for bootstrapping the `jakarta.validation.Validator`. You can contribute a javadoc:org.apache.tapestry5.beanvalidator.BeanValidatorConfigurer[] to the configuration of this service in order to participate on the configuration of `Validator`. .Module Class @@ -26,7 +26,7 @@ public static void provideBeanValidatorConfigurer(OrderedConfiguration<BeanValid { configuration.add("MyConfigurer", new BeanValidatorConfigurer() { - public void configure(javax.validation.Configuration<?> configuration) + public void configure(jakarta.validation.Configuration<?> configuration) { configuration.ignoreXmlConfiguration(); } diff --git a/modules/ROOT/pages/component-reference.adoc b/modules/ROOT/pages/component-reference.adoc index ec82000..e472aab 100644 --- a/modules/ROOT/pages/component-reference.adoc +++ b/modules/ROOT/pages/component-reference.adoc @@ -57,6 +57,11 @@ Conditionally renders its body. May render its tag and any informal parameters. javadoc:org.apache.tapestry5.corelib.components.Loop[]:: Loops over a number of items (provided by its source parameter), rendering its body for each one. +javadoc:org.apache.tapestry5.corelib.components.Recursive[]:: +Loop-like component that renders its body recursively over parent/child data such as trees or nested menus. +The point at which the children are rendered is marked with javadoc:org.apache.tapestry5.corelib.components.RecursiveBody[]. +Since 5.9. + javadoc:org.apache.tapestry5.corelib.components.Unless[]:: Inverse of the javadoc:org.apache.tapestry5.corelib.components.If[] component, renders its body if the condition is `false`. diff --git a/modules/ROOT/pages/configuration.adoc b/modules/ROOT/pages/configuration.adoc index baabbd8..a24160c 100644 --- a/modules/ROOT/pages/configuration.adoc +++ b/modules/ROOT/pages/configuration.adoc @@ -12,10 +12,11 @@ Most of the configuration is boilerplate, nearly the same for all applications. .web.xml (partial) [source,xml] ---- -<!DOCTYPE web-app - PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" - "http://java.sun.com/dtd/web-app_2_3.dtd"> -<web-app> +<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" + xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee + https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" + version="5.0"> <display-name>My Tapestry Application</display-name> <context-param> <param-name>tapestry.app-package</param-name> @@ -33,6 +34,10 @@ Most of the configuration is boilerplate, nearly the same for all applications. ---- <1> Or org.apache.tapestry5.*http*.TapestryFilter if you're using tapestry-http without tapestry-core +NOTE: The descriptor above targets Jakarta EE 9, which is what Tapestry 5.9 is built on. +If you are using the javax build, keep the `javaee` namespace (or the older DTD) and a `version` of 3.1 or below. +See xref:jakarta-ee-migration.adoc[] for the difference between the two builds. + The application-specific part, the `tapestry.app-package` context parameter, provides your application's root package name. Tapestry uses this to locate your page and component classes. It expects page classes in the pages sub-package and components in the components sub-package. diff --git a/modules/ROOT/pages/index.adoc b/modules/ROOT/pages/index.adoc index 80fb94d..3062afe 100644 --- a/modules/ROOT/pages/index.adoc +++ b/modules/ROOT/pages/index.adoc @@ -40,7 +40,8 @@ Once you work in Tapestry there's no going back! Tapestry is released under the Apache Software License 2.0. == Tapestry as a Java Servlet Filter -Tapestry integrates with the Java Servlet API by implementing https://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html[javax.servlet.Filter]. +Tapestry integrates with the Jakarta Servlet API by implementing https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/filter[jakarta.servlet.Filter]. +If you are using the javax build of Tapestry 5.9, it implements `javax.servlet.Filter` instead; see xref:jakarta-ee-migration.adoc[]. Similar to servlets, filters are added to a web application in the deployment descriptor (`web.xml`). .web.xml (partial) diff --git a/modules/ROOT/pages/integrating-with-spring-framework.adoc b/modules/ROOT/pages/integrating-with-spring-framework.adoc index 8b0bd75..c446ac2 100644 --- a/modules/ROOT/pages/integrating-with-spring-framework.adoc +++ b/modules/ROOT/pages/integrating-with-spring-framework.adoc @@ -6,8 +6,13 @@ You can also go the other way, injecting Tapestry services in Spring beans. For integrating Spring Security into your application, see xref:security.adoc[]. == Spring Version -This module is compiled and tested against Spring Framework 2.5.6. -It should be reasonable to override the dependency to earlier versions of Spring, though the code makes use of some APIs that were added to Spring to support JDK 1.5 annotations. +As of Tapestry 5.9 this module is compiled and tested against Spring Framework 6.0.11. + +[IMPORTANT] +==== +Spring 6 requires *Java 17*. +The rest of Tapestry targets Java 8 bytecode and is tested on Java 11 and 17, so adding `tapestry-spring` raises the minimum Java version for your whole application to 17. +==== == Usage The integration is designed to be a very thin layer on top of Spring's normal configuration for a web application. diff --git a/modules/ROOT/pages/jakarta-ee-migration.adoc b/modules/ROOT/pages/jakarta-ee-migration.adoc new file mode 100644 index 0000000..3659d11 --- /dev/null +++ b/modules/ROOT/pages/jakarta-ee-migration.adoc @@ -0,0 +1,242 @@ += Migrating to Jakarta EE +:navtitle: Jakarta EE Migration + +Tapestry 5.9 is the first release built on https://jakarta.ee/[Jakarta EE] 9. +Everything that used to live under `javax.servlet`, `javax.persistence`, `javax.validation` and `javax.inject` now lives under `jakarta.*`. + +This page explains what changed, how to pick the right artifacts, and what to do in your own code. + +== Two builds of the same release + +The move to Jakarta EE 9 cannot be made backwards compatible: a class compiled against `javax.servlet.http.HttpServletRequest` will not run in a container that only provides `jakarta.servlet.http.HttpServletRequest`, and vice versa. + +Rather than force every application onto Jakarta at once, Tapestry 5.9 is released from two branches at the same version number: + +[%autowidth] +|=== +|Build |Servlet API |Artifact ids |Typical container + +|Jakarta +|`jakarta.servlet` 5.0 +|suffixed with `-jakarta`, e.g. `tapestry-core-jakarta` +|Tomcat 10+, Jetty 11+, WildFly 27+ + +|javax +|`javax.servlet` 3.0+ +|unchanged, e.g. `tapestry-core` +|Tomcat 9, Jetty 9-10 +|=== + +Both builds contain the same features and bug fixes. +The javax build exists so that applications which cannot move their container yet can still upgrade to 5.9. + +[IMPORTANT] +==== +Do not mix the two. +A project must use either all `-jakarta` artifacts or all unsuffixed ones, together with a matching Servlet API dependency and container. +==== + +=== Artifacts that carry the suffix + +These modules touch a Jakarta EE API and therefore ship twice: + +[cols="1,1,1",frame=none,grid=none] +|=== +a| +* `tapestry-core` +* `tapestry-http` +* `tapestry-ioc` +* `tapestry-ioc-jcache` +* `tapestry-ioc-junit` +* `tapestry-upload` +* `tapestry-webresources` +a| +* `tapestry-hibernate` +* `tapestry-hibernate-core` +* `tapestry-jpa` +* `tapestry-beanvalidator` +* `tapestry-spring` +* `tapestry-mongodb` +* `tapestry-jmx` +a| +* `tapestry-rest-jackson` +* `tapestry-openapi-viewer` +* `tapestry-kaptcha` +* `tapestry-clojure` +* `tapestry-test` +* `tapestry-runner` +* `tapestry-spock` +|=== + +=== Artifacts that do not + +These modules do not depend on any Jakarta EE API, so a single artifact serves both builds and the id never changes: + +`plastic`, `commons`, `beanmodel`, `tapestry-json`, `tapestry-func`, `tapestry5-annotations`, `genericsresolver-guava`, `tapestry-javadoc`, `tapestry-version-migrator` + +== Updating your build + +.Maven: a Jakarta project +[source,xml,subs="+attributes"] +---- +<properties> + <!-- Tapestry artifact id suffix: empty value or '-jakarta' --> + <tapestry-artifact-suffix>-jakarta</tapestry-artifact-suffix> +</properties> + +<dependency> + <groupId>org.apache.tapestry</groupId> + <artifactId>tapestry-core${tapestry-artifact-suffix}</artifactId> + <version>{tapestry-version}</version> +</dependency> + +<dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>5.0.0</version> + <scope>provided</scope> +</dependency> +---- + +Driving the suffix from a property means you can switch a project between the two builds by editing a single value. + +.Gradle: a Jakarta project +[source,gradle,subs="+attributes"] +---- +implementation 'org.apache.tapestry:tapestry-core-jakarta:{tapestry-version}' +compileOnly 'jakarta.servlet:jakarta.servlet-api:5.0.0' +---- + +=== Letting the migration tool do it + +The `tapestry-version-migrator` module can introduce the property and rewrite the artifact ids across a multi-module Maven build for you. +Run it from the root of your project: + +[subs="+attributes"] +---- +java -jar tapestry-version-migrator-{tapestry-version}.jar artifactSuffix -jakarta +---- + +It walks the current directory recursively, and for every `pom.xml` it finds it adds a `tapestry-artifact-suffix` property and appends `${tapestry-artifact-suffix}` to the artifact id of every Tapestry dependency that has a suffixed variant. +Passing no suffix at all switches a project back to the javax artifacts: + +[subs="+attributes"] +---- +java -jar tapestry-version-migrator-{tapestry-version}.jar artifactSuffix +---- + +NOTE: The tool rewrites `pom.xml` files in place through an XML transformer, so it will also reformat them. Run it on a clean working tree so you can review the diff. + +== Updating your code + +=== Package renames + +Change the imports in your own classes: + +[%autowidth] +|=== +|Before |After + +|`javax.servlet.*` +|`jakarta.servlet.*` + +|`javax.servlet.http.*` +|`jakarta.servlet.http.*` + +|`javax.persistence.*` +|`jakarta.persistence.*` + +|`javax.validation.*` +|`jakarta.validation.*` + +|`javax.inject.*` +|`jakarta.inject.*` + +|`javax.annotation.*` +|`jakarta.annotation.*` +|=== + +Tapestry's own packages are unchanged: javadoc:org.apache.tapestry5.TapestryFilter[] and everything else under `org.apache.tapestry5` keeps its name in both builds. + +=== web.xml + +The deployment descriptor namespace changes, but the Tapestry filter declaration itself does not: + +.web.xml (partial) +[source,xml] +---- +<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" + xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee + https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" + version="5.0"> +... + <filter> + <filter-name>app</filter-name> + <filter-class>org.apache.tapestry5.TapestryFilter</filter-class> + </filter> +... +</web-app> +---- + +See xref:configuration.adoc[] for the rest of the descriptor. + +=== File uploads + +`tapestry-upload` moved from Apache Commons FileUpload 1.x to https://commons.apache.org/proper/commons-fileupload/[Commons FileUpload 2] (`commons-fileupload2-jakarta`). +Two things are visible to applications: + +* `org.apache.commons.fileupload.FileUploadException` is now `org.apache.commons.fileupload2.core.FileUploadException`. +Adjust any exception handler that catches it by name. +* The protected `MultipartDecoderImpl.createFileUpload()` method now returns `JakartaServletFileUpload` instead of `ServletFileUpload`. +If you subclass it to customise upload handling, update the signature. + +See xref:uploading-files.adoc[] for details. + +=== Third-party libraries + +Anything else in your dependency tree that implements or consumes a Servlet API interface has to move to a Jakarta-compatible version as well. +The versions Tapestry 5.9 itself builds against are: + +[%autowidth] +|=== +|Library |Version |Note + +|Jakarta Servlet +|5.0.0 +| + +|Jakarta Persistence +|3.0.0 +|EclipseLink 3.0.4 is used in the tests + +|Jakarta Validation +|3.0.2 +|with Hibernate Validator 8.0.1.Final + +|Jakarta Inject +|2.0.1 +|see xref:using-jsr-330-standard-annotations.adoc[] + +|Commons FileUpload +|2.0.0-M1 +|`commons-fileupload2-jakarta` + +|Spring +|6.0.11 +|requires Java 17, see below +|=== + +[IMPORTANT] +==== +`tapestry-spring` depends on Spring 6, which requires *Java 17*. +The rest of Tapestry targets Java 8 bytecode and is tested on Java 11 and 17. +If your application uses `tapestry-spring`, Java 17 becomes the minimum for the whole project. +==== + +Note that `tapestry-hibernate` still builds against Hibernate 5.4, whose own upgrade was postponed because of the size of the API change between Hibernate 5 and 6. + +== Staying on javax + +If you are not ready, you do not have to do anything: keep using the unsuffixed artifacts and upgrade the version to {tapestry-version} as usual. +You get every 5.9 fix and feature, and can move to the `-jakarta` artifacts later. diff --git a/modules/ROOT/pages/jpa.adoc b/modules/ROOT/pages/jpa.adoc index feff5a6..da76b62 100644 --- a/modules/ROOT/pages/jpa.adoc +++ b/modules/ROOT/pages/jpa.adoc @@ -21,9 +21,9 @@ If you're using Maven, just add the `tapestry-jpa` dependency to your applicatio If you aren't using Maven (or Gradle, Ivy, etc), you'll have to download the jar and its dependencies yourself. == Selecting a JPA Implementation -The `tapestry-jpa` module includes a dependency on a JPA specification (API) from Geronimo but not an implementation. -You'll have to chose a JPA implementation, such as EclipseLink or Hibernate. -The`tapestry-jpa` module assumes you'll use EclipseLink. +The `tapestry-jpa` module depends on the Jakarta Persistence API (`jakarta.persistence:jakarta.persistence-api:3.0.0`) but not on an implementation. +You'll have to choose a JPA implementation, such as EclipseLink or Hibernate. +The `tapestry-jpa` module assumes you'll use EclipseLink. You just have to add the EclipseLink dependency: .pom.xml (partial) for EclipseLink @@ -36,40 +36,28 @@ You just have to add the EclipseLink dependency: </dependency> ---- -Or, if you'd rather use Hibernate as your JPA implementation, you'll want to exclude either the Gernonimo or Hibernate JPA specification JAR: +Whichever implementation you pick, it has to be a Jakarta Persistence 3.0 build – EclipseLink 3.x or Hibernate 6.x – because a JPA 2.x implementation still expects `javax.persistence`. +Tapestry's own integration tests run against EclipseLink 3.0.4. -.pom.xml (partial) for Hibernate -[source,xml] ----- -<dependency> - <groupId>org.hibernate</groupId> - <artifactId>hibernate-entitymanager</artifactId> - <version>${hibernate-version}</version> - <exclusions> - <exclusion> - <!-- omit Geronimo JPA spec to avoid conflict with Hibernate JPA spec --> - <groupId>org.apache.geronimo.specs</groupId> - <artifactId>geronimo-jpa_2.0_spec</artifactId> - </exclusion> - </exclusions> -</dependency> ----- +IMPORTANT: This applies to the Jakarta build of Tapestry 5.9. +If you are using the javax build, stay on a JPA 2.x implementation. +See xref:jakarta-ee-migration.adoc[]. == Configuring JPA The `persistence.xml` file is the standard configuration file in JPA used to define the persistence units. -Tapestry reads this file to create the `javax.persistence.EntityManagerFactory`. +Tapestry reads this file to create the `jakarta.persistence.EntityManagerFactory`. The following example demonstrates a `persistence.xml` file. .persistence.xml [source,xml] ---- <?xml version="1.0" encoding="UTF-8"?> -<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> +<persistence xmlns="https://jakarta.ee/xml/ns/persistence" version="3.0"> <persistence-unit name="DemoUnit" transaction-type="RESOURCE_LOCAL"> <properties> - <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" /> - <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test" /> - <property name="javax.persistence.jdbc.user" value="sa" /> + <property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" /> + <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:test" /> + <property name="jakarta.persistence.jdbc.user" value="sa" /> <property name="eclipselink.ddl-generation" value="create-tables"/> <property name="eclipselink.logging.level" value="fine"/> </properties> @@ -94,7 +82,7 @@ public static void provideFactoryDefaults(final MappedConfiguration<String, Stri == XML-less JPA configuration With Tapestry, configuring JPA can be much simpler than described by the JPA specification. -Tapestry allows you to configure the `javax.persistence.EntityManagerFactory` programmatically, without writing any XML. +Tapestry allows you to configure the `jakarta.persistence.EntityManagerFactory` programmatically, without writing any XML. For example, imagine that you want to use JDBC connections managed by the container and provided through JNDI. The resulting persistence descriptor might look like this: @@ -102,8 +90,8 @@ The resulting persistence descriptor might look like this: [source,xml] ---- <?xml version="1.0" encoding="UTF-8"?> -<persistence xmlns="http://java.sun.com/xml/ns/persistence" - version="2.0"> +<persistence xmlns="https://jakarta.ee/xml/ns/persistence" + version="3.0"> <persistence-unit name="JTAUnit" transaction-type="RESOURCE_LOCAL"> <non-jta-data-source>jdbc/JPATest</non-jta-data-source> <properties> @@ -138,7 +126,7 @@ In the example above you can see a contribution to the javadoc:org.apache.tapest This service is responsible for creating the `EntityManagerFactory` to be used to create `EntityManager`. When the service is initialized, it parses the `persistence.xml` file, if available. For any persistence unit defined in the XML descriptor a javadoc:org.apache.tapestry5.jpa.TapestryPersistenceUnitInfo[] object is created. -The `TapestryPersistenceUnitInfo` interface is a mutable extension of the `javax.persistence.spi.PersistenceUnitInfo` interface (defined in the JPA specification) that allows you to configure a persistence unit programmatically. +The `TapestryPersistenceUnitInfo` interface is a mutable extension of the `jakarta.persistence.spi.PersistenceUnitInfo` interface (defined in the JPA specification) that allows you to configure a persistence unit programmatically. After parsing the persistence descriptor, the `EntityManagerSource` service applies its configuration to create further persistence units and/or update the existing ones. The service’s configuration is a map in which persistence unit names are associated with javadoc:org.apache.tapestry5.jpa.PersistenceUnitConfigurer[] instances. diff --git a/modules/ROOT/pages/release-notes-5.9.adoc b/modules/ROOT/pages/release-notes-5.9.adoc new file mode 100644 index 0000000..e3e4a13 --- /dev/null +++ b/modules/ROOT/pages/release-notes-5.9.adoc @@ -0,0 +1,86 @@ += Tapestry 5.9 + +Tapestry 5.9 moves the framework to Jakarta EE 9. +Every module that touches the Servlet, Persistence, Validation or CDI APIs now compiles against the `jakarta.*` packages instead of `javax.*`. + +Because that is a breaking change for existing applications, 5.9 is released twice from two branches: +the Jakarta build publishes artifacts with a `-jakarta` suffix, and the javax build keeps the historical, unsuffixed artifact names. +Both carry the same version number and the same features. +See xref:jakarta-ee-migration.adoc[] for what this means for your project and how to move over. + +== Tapestry 5.9.1 +Tapestry 5.9.1 is a bugfix release and a drop-in replacement for Tapestry 5.9.0. + +=== Improvements Made +* issue:2814[] - Upgrade ASM to 9.9 +* issue:2758[] - Constructor/Builder injection should support javadoc:org.apache.tapestry5.ioc.annotations.Symbol[label=@Symbol] for `List`/`Collection`/`Map` even without javadoc:org.apache.tapestry5.ioc.annotations.Inject[label=@Inject] + +=== Bugs Fixed +* issue:2813[] - NPE when javadoc:org.apache.tapestry5.annotations.Cached[label=@Cached] applied to method returning a generic type in multiple classloader mode + + +== Tapestry 5.9.0 +Tapestry 5.9.0 is a major release built on Jakarta EE 9. + +Highlights: + +* issue:2741[] and issue:2788[] - *Jakarta EE 9 support.* +Tapestry now targets Jakarta Servlet 5.0, Jakarta Persistence 3.0, Jakarta Validation 3.0 and Jakarta Inject 2.0. +The corresponding `javax.*` imports in your own code have to be changed to `jakarta.*`. +* issue:2785[] - *Separate artifacts for the Jakarta and javax builds.* +The Jakarta build publishes `tapestry-core-jakarta`, `tapestry-ioc-jakarta` and so on, while the javax build keeps publishing `tapestry-core`, `tapestry-ioc` and so on. +This lets both live side by side in Maven Central at the same version, so projects that cannot move to Jakarta yet can still pick up 5.9. +* issue:2793[] - *New javadoc:org.apache.tapestry5.corelib.components.Recursive[] component.* +A javadoc:org.apache.tapestry5.corelib.components.Loop[]-like component that renders its body recursively over parent/child data such as trees and menus, with javadoc:org.apache.tapestry5.corelib.components.RecursiveBody[] marking the insertion point for the children. +Objects are adapted to the component through javadoc:org.apache.tapestry5.commons.RecursiveValueProvider[] implementations. +This was contributed by https://www.pubfactory.com[KGL PubFactory]. +* issue:2799[] - *Session locking is now explicit.* +Reading from a javadoc:org.apache.tapestry5.http.services.Session[] could lock up a thread. +The fix introduces `Session.LockMode` (`NONE`, `READ`, `WRITE`) together with `getAttributeNames(LockMode)` and `getAttributeNames(String, LockMode)` overloads, so the lock a call acquires is now something you can control. +See xref:session-storage.adoc#_session_locking[Session Locking]. +* issue:2782[] - The client-side `t5/core/ajax` function accepts an `options.headers` object, so application code can add custom headers to Ajax requests. +* issue:2789[] - A migration tool was added to help rewrite Maven and Gradle builds onto the suffixed artifact names. +* A large round of dependency upgrades came with the Jakarta move, including Hibernate Validator 8, EclipseLink 3.0, Spring 6, Jetty 11 and Apache Commons FileUpload 2. + +[IMPORTANT] +==== +`tapestry-spring` now depends on Spring 6, which requires *Java 17*. +The rest of Tapestry still builds for Java 8 bytecode and is tested on Java 11 and 17. +==== + +=== New Features +* issue:2793[] - Create a component for rendering recursive data +* issue:2789[] - Create Maven configuration tool to assist with suffixed artifacts +* issue:2785[] - Change build so it generates separate artifacts for jakarta- and javax-based subprojects + +=== Improvements Made +* issue:2800[] - Stylesheets not imported when javadoc:org.apache.tapestry5.annotations.Import[label=@Import] also imports a library when in multiple classloader mode +* issue:2796[] - Upgrade some more dependencies: TestNG, EasyMock, commons-codec, ANTLR, HSQLDB, snakeyaml +* issue:2795[] - Upgrade commons-lang dependency to 3.17.0 +* issue:2788[] - Further changes to upgrade to Jakarta EE +* issue:2782[] - `ajax.coffee` should support more options +* issue:2780[] - javadoc:org.apache.tapestry5.json.JSONObject[] does not conform to equals/hashCode contract +* issue:2778[] - JUnit upgrade to support Eclipse 2023-09+ +* issue:2777[] - Update the closure compiler for better support of modern JavaScript + +=== Dependency Upgrades +* issue:2798[] - Change selenium-java and selenium-leg-rc from api to testImplementation +* issue:2771[] - Upgrade to Spock 2.3 +* issue:2741[] - Update to Jakarta EE 9 + +=== Bugs Fixed +* issue:2799[] - Thread lockup when trying to read from a Session object +* issue:2794[] - Upgrade away from vulnerable commons-io and commons-fileupload dependencies +* issue:2792[] - POST with body throws exception +* issue:2791[] - CssCompressor for CSS files produces wrong minification for the `url()` function, at least with data URLs +* issue:2790[] - Palette with option groups within the javadoc:org.apache.tapestry5.SelectModel[] does not work properly +* issue:2787[] - Infinite loop in `PageSourceImpl` with multiple classloader mode on +* issue:2786[] - Attempt to override final method in subclass when in multiple classloader mode +* issue:2783[] - Hibernate module initialization fails when entities with compound ids exist +* issue:2779[] - Tapestry 5.8.3 to 5.8.7 issues caused by the multiple classloader feature +* issue:2775[] - `ClassNotFoundException` when in production mode and parameter type is array +* issue:2773[] - `NullPointerException` in 5.8.5 when in production mode and template extension points +* issue:2772[] - `ClassCastException` happening in some cases in production mode +* issue:2770[] - With multiple classloader mode on, `ClassCastException` when component and superclass both have javadoc:org.apache.tapestry5.annotations.Import[label=@Import] +* issue:2605[] - JS minimizer regression bug in 5.5.0-beta-1 +* issue:2563[] - Session replication fails with `NotSerializableException` on Tapestry class diff --git a/modules/ROOT/pages/session-storage.adoc b/modules/ROOT/pages/session-storage.adoc index be63556..22ba618 100644 --- a/modules/ROOT/pages/session-storage.adoc +++ b/modules/ROOT/pages/session-storage.adoc @@ -250,3 +250,48 @@ public static void contributeApplicationDefaults(MappedConfiguration<String,Stri // ... } ---- + +=== Controlling the lock per call + +Locking used to be entirely implicit, which made it possible for a thread to lock up while reading from the session (issue:2799[]). +Since 5.9, javadoc:org.apache.tapestry5.http.services.Session[] exposes the lock it acquires through `Session.LockMode`: + +`NONE`:: No lock is acquired. +`READ`:: A shared read lock is acquired. +`WRITE`:: An exclusive write lock is acquired. + +Each accessor has an overload taking a `LockMode`, alongside the original method which keeps its previous default: + +[%autowidth] +|=== +|Method |Default lock + +|`getAttribute(String)` +|`WRITE` + +|`getAttributeNames()`, `getAttributeNames(String prefix)` +|`READ` + +|`containsAttribute(String)` +|`READ` +|=== + +[source,java] +---- +@Inject +private Request request; + +public boolean isCartPresent() +{ + Session session = request.getSession(false); + + // A shared read lock is enough to look at what is there. + return session != null + && session.containsAttribute(CART_ATTRIBUTE, Session.LockMode.READ); +} +---- + +The actual lock taken also depends on what the current thread already holds: if a thread already owns a write lock, asking for a read lock does not downgrade it. + +NOTE: `containsAttribute(String)` and `containsAttribute(String, LockMode)` were both added in 5.9. +Passing `LockMode.NONE` skips locking for a single call without turning `tapestry.session-locking-enabled` off for the whole application. diff --git a/modules/ROOT/pages/uploading-files.adoc b/modules/ROOT/pages/uploading-files.adoc index 6537c01..d473734 100644 --- a/modules/ROOT/pages/uploading-files.adoc +++ b/modules/ROOT/pages/uploading-files.adoc @@ -1,6 +1,17 @@ = Uploading Files -Tapestry provides a file upload component based on https://commons.apache.org/fileupload/[Apache Commons FileUpload] to make it easier to handle files uploaded through web forms (via the standard `<input type="file">` HTML element). +Tapestry provides a file upload component based on https://commons.apache.org/proper/commons-fileupload/[Apache Commons FileUpload] to make it easier to handle files uploaded through web forms (via the standard `<input type="file">` HTML element). + +[IMPORTANT] +==== +Since 5.9, `tapestry-upload` builds on Commons FileUpload 2 (`commons-fileupload2-jakarta`) instead of the 1.x line. +Two things are visible to applications: + +* `org.apache.commons.fileupload.FileUploadException` moved to `org.apache.commons.fileupload2.core.FileUploadException`. +* The protected `MultipartDecoderImpl.createFileUpload()` method now returns `JakartaServletFileUpload` instead of `ServletFileUpload`, which matters if you subclass it. + +See xref:jakarta-ee-migration.adoc[]. +==== == Downloading `tapestry-upload` is not automatically included in Tapestry applications because of the additional dependencies it requires. diff --git a/modules/ROOT/pages/using-jsr-330-standard-annotations.adoc b/modules/ROOT/pages/using-jsr-330-standard-annotations.adoc index d26dc1a..aaea026 100644 --- a/modules/ROOT/pages/using-jsr-330-standard-annotations.adoc +++ b/modules/ROOT/pages/using-jsr-330-standard-annotations.adoc @@ -3,9 +3,14 @@ JSR-330 annotations can be used for injection in Tapestry 5.3 and later. The following table demonstrates that most of annotations in Tapestry IoC and JSR-330 are interchangeable. However, there are few differences in semantics. +NOTE: Since 5.9 the annotations come from `jakarta.inject:jakarta.inject-api:2.0.1` rather than `javax.inject:javax.inject:1`. +The annotation names are unchanged; only the package differs. +If you are using the javax build of 5.9, read `javax.inject` wherever this page says `jakarta.inject`. +See xref:jakarta-ee-migration.adoc[]. + [%autowidth] |=== -|JSR-330 `javax.inject` |Tapestry `org.apache.tapestry5.ioc.annotations` |Comment +|JSR-330 `jakarta.inject` |Tapestry `org.apache.tapestry5.ioc.annotations` |Comment |@Inject |@Inject @@ -66,8 +71,8 @@ For this purpose JSR-330 provides the `@Named` annotation which accompanies the [source,java] ---- -import javax.inject.Inject; -import javax.inject.Named; +import jakarta.inject.Inject; +import jakarta.inject.Named; ... @@ -148,14 +153,14 @@ public class Index { @Inject private Request request; - @javax.inject.Inject + @jakarta.inject.Inject private ComponentResources resources; - @javax.inject.Inject + @jakarta.inject.Inject @Named("FrenchGreeter") private Greeter greeter; - @javax.inject.Inject + @jakarta.inject.Inject @Symbol(SymbolConstants.PRODUCTION_MODE) private boolean productionMode; @@ -186,7 +191,7 @@ In JSR-330 a qualifier annotation like `@French` in the example above needs to b @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) [email protected] [email protected] public @interface French { } ----
