This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/docs by this push:
new 5a443accfa Document CopyUtils API move for 10.0.0 (TODO-264):
copyOf/cloneOf moved from CollectionUtils/ObjectUtils into subclassable
CopyUtils
5a443accfa is described below
commit 5a443accfad6f37ff721dd14fc7321943820dbcc
Author: James Bognar <[email protected]>
AuthorDate: Sun Jul 19 13:26:55 2026 -0400
Document CopyUtils API move for 10.0.0 (TODO-264): copyOf/cloneOf moved
from CollectionUtils/ObjectUtils into subclassable CopyUtils
- copyOf(...) family moved out of CollectionUtils and null-safe cloneOf(T)
moved out of ObjectUtils into new subclassable
org.apache.juneau.commons.utils.CopyUtils (clean break, no deprecation shim).
- SwaggerCopyUtils/OpenApiCopyUtils subclasses add domain bean copyOf
overloads, retiring the interim TODO-260 copyOrNull statics on the
swagger-v2/openapi-v3 beans; four one-off copyOrNull types kept.
- Static-import migration recipe + matching V10 migration-guide section.
Co-authored-by: Cursor <[email protected]>
---
pages/release-notes/10.0.0.md | 41 +++++++++++++++++++++++++++++++++++-
pages/topics/27.V10MigrationGuide.md | 14 ++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index 5758f85b4f..c289d03cb4 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -720,6 +720,33 @@ _TBD — to be filled in as development continues._
- **Unaffected:** `isAtLeast(...)` / `isAtMost(...)` (and therefore
`VersionRange`, client-version negotiation, and the `FluentVersionAssertion`
comparison methods, which use `compareTo`) are unchanged.
- **Migration:** replace any `v1.equals(v2)` call on two `Version` values
that depended on prefix matching with `v1.matches(v2)`. Exact equality
(`assertEquals`, `Set`/`Map` keys) now behaves per the corrected contract with
no code change.
+- **Typed-`View` template names in the FreeMarker / Mustache / Thymeleaf view
bridges are now path-traversal-gated (behavioral change).** The
`juneau-rest-server-view-freemarker`, `-mustache`, and `-thymeleaf` bridges
previously applied `FileUtils.resolveVirtualPathSafely(...)` only on the raw
`/{engine}/*` mount, while a typed `View` return value
(`FreemarkerView.of(name)` / `MustacheView.of(name)` /
`ThymeleafView.of(name)`) passed its template name straight to the engine. As
of 10.0.0 [...]
+
+- **`juneau-bean` DTO collection/array getters no longer expose live internal
state (behavioral change).** Getters on the DTO beans that previously returned
the bean's live internal collection or array now return a defensive, immutable
view so that caller-side mutation can no longer corrupt bean state:
+ - **Collection / `Map` / `Set` getters** in `juneau-bean-jsonapi`
(`JsonApiResource`, `JsonApiDocument`, `JsonApiResourceIdentifier`,
`JsonApiLink`, `JsonApiVersion`, `JsonApiRelationship`, `JsonApiError`),
`juneau-bean-jsonschema` (`JsonSchema`), `juneau-bean-mcp`
(`ListPromptsResult`, `ListToolsResult`, `ListResourcesResult`,
`ReadResourceResult`, `CallToolResult`, `GetPromptResult`, `Prompt`,
`CallToolRequest`, `GetPromptRequest`, `ServerCapabilities`,
`ClientCapabilities`, `JsonSch [...]
+ - **Array getters** in `juneau-bean-atom` (`CommonEntry.getAuthors()` /
`getCategories()` / `getContributors()` / `getLinks()`, `Feed.getEntries()`)
and the mutable-`Calendar` getter `CommonEntry.getUpdated()` now return a
**defensive copy** (array `clone()` / `Calendar` clone) rather than the live
field, and the corresponding setters store a defensive copy of their argument.
Mutating a returned array/`Calendar` (or an array previously handed to a
setter) no longer affects the bean. Ge [...]
+ - **Migration:** callers that mutated a value returned from one of these
getters must instead go through the bean's setter/adder API. No source changes
are required for read-only usage.
+
+- **`BasicHeader.hashCode()` is now consistent with `equals(Object)`
(behavioral change).** `org.apache.juneau.http.classic.header.BasicHeader`
(`juneau-rest-common-classic`) previously computed `equals(Object)` from `name`
+ value while `hashCode()` returned the identity hash. That inconsistency
violated the `equals`/`hashCode` contract and broke `HashMap`/`HashSet`
membership for equal-but-distinct `BasicHeader` instances. As of 10.0.0
`hashCode()` is derived from `name` + value, so tw [...]
+
+- **HTTP request/response/entity/part getters in `juneau-rest-common`,
`juneau-rest-common-classic`, and `juneau-rest-client-classic` no longer expose
live internal state (behavioral change).** To prevent cross-caller/cross-thread
state corruption (several of the affected objects are shared singletons — e.g.
the `Ok.OK` response and the ~33/~22 pre-built exception/response `INSTANCE`s),
the following now return defensive copies / unmodifiable views rather than the
live field:
+ - `setUnmodifiable()` on the classic `BasicHttpResponse` /
`BasicHttpException` now also freezes the backing `HeaderList` (previously only
the status line was frozen), so a frozen shared instance can no longer be
mutated through `getHeaders()`.
+ - `byte[]` getters
(`ByteArrayEntity`/`StreamEntity`/`FileEntity`/`ReaderEntity`/`StringEntity.asBytes()`),
`HeaderElement[]` getters (`BasicHeader.getElements()`,
`ResponseHeader.getElements()`), and CSV token-array getters
(`BasicCsvHeader`/`BasicCsvArrayPart`/`HttpCsvHeader`/`HttpCsvArrayPart.orElse(...)`)
now return a `clone()`/copy. Mutating a returned array no longer affects the
source object or any shared constant.
+ - The cached remote-interface metadata
(`RrpcInterfaceMeta`/`RrpcInterfaceMethodMeta`/`Policy`, and `RemoteMeta`'s
header list) now hands out copies/unmodifiable views instead of the live cached
array/list.
+ - **Migration:** none for read-only usage; callers that mutated a returned
array/list must instead rebuild the object through its builder/setter API.
+
+- **The classic remote proxy (`juneau-rest-client-classic`) now rejects
non-`http`/`https` URLs (behavioral change / security).**
`RestClient.getRemote(...)` proxies previously required only that the resolved
absolute URL contain `://`. As of 10.0.0 the resolved URL's scheme must be
`http` or `https` (parity with the core `juneau-rest-client`
`RemoteClient.requireHttpScheme` SSRF guardrail); any other scheme (`file`,
`jar`, `ftp`, …) now throws `RemoteMetadataException`. **Migration:** n [...]
+
+- **`juneau-sc-server` `GitControl` force-push is now opt-in and credentials
are caller-supplied (behavioral change / security).** `GitControl.pushToRepo()`
previously always performed a **force-push** (`setForce(true)`, a destructive
remote history rewrite) using hardcoded `"username"`/`"password"` credentials.
As of 10.0.0 force-push defaults to **off** and must be explicitly enabled, and
credentials are supplied by the caller (defaulting to anonymous transport when
none are given). A [...]
+
+- **`juneau-petstore-core` collection getters no longer expose live store
state (behavioral change).** For consistency with the already-hardened
`PetStore.getPets()`, `PetStore.getOrders()` / `getUsers()` now return an
immutable snapshot (`List.copyOf(...)`), and `Pet.getTags()` returns an
unmodifiable view while `Pet.setTags(...)` stores a defensive copy.
**Migration:** none for read-only usage (demo/sample domain code).
+
+- **`juneau-marshall` public class
`org.apache.juneau.marshall.httppart.Constants` removed.** This obsolete public
constants holder — exposing the `CF_*` (collection-format), `TYPE_*`
(data-type), and `FORMAT_*` (data-format) `String` constants — was unreferenced
anywhere in the framework and has been deleted. It is **distinct from** the
still-supported `org.apache.juneau.marshall.Constants` (which is unaffected).
**Migration:** none expected for normal usage; any external code that refe [...]
+
+- **`juneau-bean-openapi-v3` copy-constructors now deep-copy nested copyable
beans (bug fix).** Several `org.apache.juneau.bean.openapi3` copy-constructors
previously copied a bean-typed field **shallowly** (`this.x = copyFrom.x;`), so
a copy and its original shared one mutable nested-bean instance and a mutation
to one silently corrupted the other. These fields are now deep-copied via the
type's null-safe `copyOrNull(...)`: `OpenApi.components`/`externalDocs`,
`Operation.externalDocs`/` [...]
+
+- **`juneau-rest-server` `ThrownStats.copy(ThrownStats)` static method
removed; replaced by null-safe `copyOrNull(ThrownStats)` (TODO-260).** The
`org.apache.juneau.rest.server.stats.ThrownStats` deep-copy factory `public
static ThrownStats copy(ThrownStats)` has been **removed** and replaced by
`public static ThrownStats copyOrNull(ThrownStats value)`, which returns the
same deep copy but additionally returns `null` for a `null` argument (the old
`copy(null)` threw a `NullPointerExcepti [...]
+
_Other entries TBD — to be filled in before release. See also the major
version bump note above._
### Deprecations
@@ -728,4 +755,16 @@ _TBD — to be filled in before release._
### API Changes
-_TBD — to be filled in before release._
+- **Null-safe static `copyOrNull(T)` convenience methods added to copyable
bean/builder types (TODO-260).** A new `public static X copyOrNull(X value)`
method was added next to the existing instance `copy()` on each type below. It
returns a deep copy of the argument, or `null` if the argument is `null`,
replacing the `x == null ? null : x.copy()` null-check-ternary boilerplate that
appeared throughout the bean copy-constructors (all in-tree call sites were
swept to use it). The name is d [...]
+ - **`juneau-bean-swagger-v2`** (`org.apache.juneau.bean.swagger`):
`Contact`, `License`, `Info`, `Items`, `SchemaInfo`, `Xml`,
`ExternalDocumentation` (7).
+ - **`juneau-bean-openapi-v3`** (`org.apache.juneau.bean.openapi3`):
`Contact`, `License`, `Info`, `Items`, `SchemaInfo`, `Xml`,
`ExternalDocumentation`, `Server`, `Components`, `Discriminator`, `OAuthFlow`,
`Operation`, `RequestBodyInfo` (13). The last five were added by the
shallow-copy correctness sweep (see behavioral changes below).
+ - **`juneau-microservice`**: `LogConfig`.
+ - **`juneau-marshall`** builder types: `MarshallingContext.Builder` (`static
MarshallingContext.Builder copyOrNull(MarshallingContext.Builder)`) and
`Context.Builder` (`static Context.Builder<?> copyOrNull(Context.Builder<?>
value)`, wildcard-typed because the builder uses a self-referential `SELF` type
parameter that a static method cannot name).
+
+- **New subclassable `CopyUtils`; `CollectionUtils.copyOf` and
`ObjectUtils.cloneOf` moved to it (clean break, TODO-264).** The `copyOf(...)`
family (all collection / map / array overloads) has been **moved out** of
`org.apache.juneau.commons.utils.CollectionUtils` and the generic null-safe
`cloneOf(T)` has been **moved out** of
`org.apache.juneau.commons.utils.ObjectUtils` into a new
**`org.apache.juneau.commons.utils.CopyUtils`** class (with a `protected`
constructor so it can be subcl [...]
+ - **`juneau-bean-swagger-v2`**:
`org.apache.juneau.bean.swagger.SwaggerCopyUtils extends CopyUtils` —
`copyOf(...)` for `Contact`, `ExternalDocumentation`, `Info`, `Items`,
`License`, `SchemaInfo`, `Xml` (7).
+ - **`juneau-bean-openapi-v3`**:
`org.apache.juneau.bean.openapi3.OpenApiCopyUtils extends CopyUtils` —
`copyOf(...)` for `Components`, `Contact`, `Discriminator`,
`ExternalDocumentation`, `Info`, `Items`, `License`, `OAuthFlow`, `Operation`,
`RequestBodyInfo`, `SchemaInfo`, `Server`, `Xml` (13).
+ - The four single-site one-off types intentionally **keep** their TODO-260
`copyOrNull(T)` and are unchanged: `ThrownStats` (`juneau-rest-server`),
`LogConfig` (`juneau-microservice`), and the `MarshallingContext.Builder` /
`Context.Builder<?>` marshall builders.
+ - **Migration:** replace any `CollectionUtils.copyOf(...)` with
`CopyUtils.copyOf(...)` and any `ObjectUtils.cloneOf(...)` with
`CopyUtils.cloneOf(...)`. For files that resolved `copyOf`/`cloneOf` through a
`import static ...CollectionUtils.*;` / `...ObjectUtils.*;` wildcard, add
`import static org.apache.juneau.commons.utils.CopyUtils.*;` (keep the existing
wildcard for the other helpers you still use). Swagger-v2 / openapi-v3 call
sites that need a bean `copyOf(<BeanType>)` overload [...]
+
+_Other entries TBD — to be filled in before release._
diff --git a/pages/topics/27.V10MigrationGuide.md
b/pages/topics/27.V10MigrationGuide.md
index 538c179389..2c0d0d7aea 100644
--- a/pages/topics/27.V10MigrationGuide.md
+++ b/pages/topics/27.V10MigrationGuide.md
@@ -873,3 +873,17 @@ OpenAPI 3.1 emission is new in v10.0; existing Swagger v2
emission is unchanged.
| `BasicRestOperations.getSwagger(RestRequest)` and `getOpenApi(RestRequest)`
interface methods | Removed. The endpoints are now mounted via the api-docs
mixin pack on `BasicRestServlet` / `BasicRestResource`. User-written
`BasicRestOperations` implementers should remove their old `getSwagger` /
`getOpenApi` overrides — the methods are no longer on the interface. | If you
need a different api-docs surface, add `@Rest(noInherit={"mixins"},
mixins=...)` on your subclass. |
| `BasicGroupOperations.getChildrenSwagger(RestRequest)` /
`getChildrenOpenApi(RestRequest)` (the `?Swagger` / `?OpenApi` query mirrors on
group resources) and the `HasSwaggerQueryParam` / `HasOpenApiQueryParam`
matcher inner classes | Removed. Hit `/api`, `/swagger`, `/openapi`, or
`/redoc` directly — they are always mounted on `BasicRestServletGroup` /
`BasicRestResourceGroup` via the api-docs mixin pack. | External docs that
linked to `/?Swagger=true` need updating to `/api` (or `/swa [...]
| `RestRequest.getSwagger()` was the only way to ask the server for its
self-described API. | `RestRequest.getOpenApi()` provides the OpenAPI 3.1
sibling. `RestContext.getOpenApi(Locale)` and
`RestContext.getOpenApiProvider()` mirror the Swagger getters. | The OpenAPI
3.1 document is generated by transforming the Swagger 2.0 emission to OpenAPI
3.1 JSON, so every Swagger-aware annotation (`@Schema`, `@Content`,
`@StatusCode`, etc.) round-trips with no source changes. |
+
+## Copy/Clone Utilities Moved to `CopyUtils`
+
+The `copyOf(...)` collection/map/array helper family and the null-safe
reflective `cloneOf(T)` helper have been **moved** out of `CollectionUtils` and
`ObjectUtils` respectively into a new, subclassable
`org.apache.juneau.commons.utils.CopyUtils`. This is a clean break — there is
**no** deprecation shim, and neither original class keeps or references the
moved methods. Two per-module subclasses (`SwaggerCopyUtils`,
`OpenApiCopyUtils`) add domain bean `copyOf(<BeanType>)` overloads that c [...]
+
+| Old | New | Notes |
+|-----|-----|-------|
+| `org.apache.juneau.commons.utils.CollectionUtils.copyOf(...)` (all
collection / `List` / `Map` / `Set` / array + primitive-array overloads) |
`org.apache.juneau.commons.utils.CopyUtils.copyOf(...)` | Hard move.
`CollectionUtils` no longer declares `copyOf`. |
+| `org.apache.juneau.commons.utils.ObjectUtils.cloneOf(T)` |
`org.apache.juneau.commons.utils.CopyUtils.cloneOf(T)` | Hard move.
`ObjectUtils` no longer declares `cloneOf`. |
+| Swagger-v2 bean `Type.copyOrNull(x)` (interim TODO-260 statics on `Contact`,
`ExternalDocumentation`, `Info`, `Items`, `License`, `SchemaInfo`, `Xml`) |
Unqualified `copyOf(x)` via `import static
org.apache.juneau.bean.swagger.SwaggerCopyUtils.*;` | The `copyOrNull` statics
were removed from these 7 beans and re-expressed as `copyOf(<BeanType>)`
overloads on `SwaggerCopyUtils extends CopyUtils`. |
+| Openapi-v3 bean `Type.copyOrNull(x)` (interim TODO-260 statics on
`Components`, `Contact`, `Discriminator`, `ExternalDocumentation`, `Info`,
`Items`, `License`, `OAuthFlow`, `Operation`, `RequestBodyInfo`, `SchemaInfo`,
`Server`, `Xml`) | Unqualified `copyOf(x)` via `import static
org.apache.juneau.bean.openapi3.OpenApiCopyUtils.*;` | The `copyOrNull` statics
were removed from these 13 beans and re-expressed as `copyOf(<BeanType>)`
overloads on `OpenApiCopyUtils extends CopyUtils`. |
+| `ThrownStats.copyOrNull(x)`, `LogConfig.copyOrNull(x)`,
`MarshallingContext.Builder.copyOrNull(x)`, `Context.Builder.copyOrNull(x)` |
Unchanged — these four single-site one-off types **keep** their
`copyOrNull(T)`. | Intentionally not migrated to a `CopyUtils` subclass (they
have a single call site each). |
+
+**Static-import recipe:** for a file that resolved `copyOf` / `cloneOf`
through a wildcard static import (`import static
org.apache.juneau.commons.utils.CollectionUtils.*;` or `...ObjectUtils.*;`),
**add** `import static org.apache.juneau.commons.utils.CopyUtils.*;` alongside
the existing wildcard (keep the latter for the other helpers you still use).
For a qualified call, rewrite `CollectionUtils.copyOf(...)` →
`CopyUtils.copyOf(...)` and `ObjectUtils.cloneOf(...)` → `CopyUtils.cloneOf(
[...]