Fix TCK failures when testing 'length' as a read-only property
Also update the Javadoc to better described the behaviour for the length
property and to fix a copy/paste issue.
diff --git a/api/src/main/java/jakarta/el/ArrayELResolver.java b/api/src/main/java/jakarta/el/ArrayELResolver.java
index 95a4d6c..c03004d 100644
--- a/api/src/main/java/jakarta/el/ArrayELResolver.java
+++ b/api/src/main/java/jakarta/el/ArrayELResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates and others.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates and others.
* All rights reserved.
* Copyright 2004 The Apache Software Foundation
*
@@ -24,8 +24,9 @@
* Defines property resolution behavior on arrays.
*
* <p>
- * This resolver handles base objects that are Java language arrays. It accepts any object as a property and coerces
- * that object into an integer index into the array. The resulting value is the value in the array at that index.
+ * This resolver handles base objects that are Java language arrays. It accepts the case sensitive string {@code
+ * "length"} or any other object as a property and coerces that object into an integer index into the array. The
+ * resulting value is the value in the array at that index.
* </p>
*
* <p>
@@ -73,15 +74,17 @@
* </p>
*
* <p>
- * Assuming the base is an <code>array</code> and that this resolver was not constructed in read-only mode, this
- * method will return <code>base.getClass().getComponentType()</code>, which is the most general type of component
- * that can be stored at any given index in the array.
+ * Assuming the base is an <code>array</code>, that this resolver was not constructed in read-only mode, and that
+ * the provided property can be coerced to a valid index for base array, this method will return
+ * <code>base.getClass().getComponentType()</code>, which is the most general type of component that can be stored
+ * at any given index in the array.
* </p>
*
* @param context The context of this evaluation.
* @param base The array to analyze. Only bases that are Java language arrays are handled by this resolver.
- * @param property The index of the element in the array to return the acceptable type for. Will be coerced into an
- * integer, but otherwise ignored by this resolver.
+ * @param property The case sensitive string {@code "length"} or the index of the element in the array to return the
+ * acceptable type for. If not the case sensitive string {@code "length"}, will be coerced into an integer and
+ * checked if it is a valid index for the array, but otherwise ignored by this resolver.
* @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
* the most general acceptable type which must be {@code null} if the either the property or the resolver is
* read-only; otherwise undefined
@@ -99,6 +102,10 @@
if (base != null && base.getClass().isArray()) {
context.setPropertyResolved(true);
+ if (LENGTH_PROPERTY_NAME.equals(property)) {
+ return null;
+ }
+
int index = toInteger(property);
if (index < 0 || index >= Array.getLength(base)) {
throw new PropertyNotFoundException();
@@ -163,9 +170,10 @@
}
/**
- * If the base object is a Java language array, attempts to set the value at the given index with the given value. The
- * index is specified by the <code>property</code> argument, and coerced into an integer. If the coercion could not be
- * performed, an <code>IllegalArgumentException</code> is thrown. If the index is out of bounds, a
+ * If the base object is a Java language array and the property is not the case sensitive string {@code length},
+ * attempts to set the value at the given index with the given value. The index is specified by the
+ * <code>property</code> argument, and coerced into an integer. If the coercion could not be performed, an
+ * <code>IllegalArgumentException</code> is thrown. If the index is out of bounds, a
* <code>PropertyNotFoundException</code> is thrown.
*
* <p>
@@ -175,19 +183,21 @@
* </p>
*
* <p>
- * If this resolver was constructed in read-only mode, this method will always throw
- * <code>PropertyNotWritableException</code>.
+ * If this resolver was constructed in read-only mode or the property is the case sensitive string {@code length},
+ * this method will always throw <code>PropertyNotWritableException</code>.
* </p>
*
* @param context The context of this evaluation.
* @param base The array to be modified. Only bases that are Java language arrays are handled by this resolver.
- * @param property The index of the value to be set. Will be coerced into an integer.
+ * @param property The case sensitive string {@code length} or an object to coerce to an integer to provide the
+ * index of the value to be set.
* @param val The value to be set at the given index.
* @throws ClassCastException if the class of the specified element prevents it from being added to this array.
* @throws NullPointerException if context is <code>null</code>.
* @throws IllegalArgumentException if the property could not be coerced into an integer, or if some aspect of the
* specified element prevents it from being added to this array.
- * @throws PropertyNotWritableException if this resolver was constructed in read-only mode.
+ * @throws PropertyNotWritableException if this resolver was constructed in read-only mode or the property was the
+ * case sensitive string {@code length}.
* @throws PropertyNotFoundException if the given index is out of bounds for this array.
* @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
* exception must be included as the cause property of this exception, if available.
@@ -201,7 +211,7 @@
if (base != null && base.getClass().isArray()) {
context.setPropertyResolved(base, property);
- if (isReadOnly) {
+ if (isReadOnly || LENGTH_PROPERTY_NAME.equals(property)) {
throw new PropertyNotWritableException();
}
Class<?> type = base.getClass().getComponentType();
@@ -226,14 +236,14 @@
* </p>
*
* <p>
- * If this resolver was constructed in read-only mode, this method will always return <code>true</code>. Otherwise, it
- * returns <code>false</code>.
+ * If this resolver was constructed in read-only mode or the property is the case sensitive string {@code length},
+ * this method will always return <code>true</code>. Otherwise, it returns <code>false</code>.
* </p>
*
* @param context The context of this evaluation.
* @param base The array to analyze. Only bases that are a Java language array are handled by this resolver.
- * @param property The index of the element in the array to return the acceptable type for. Will be coerced into an
- * integer, but otherwise ignored by this resolver.
+ * @param property The case sensitive string {@code length} or an object to coerce to an integer to provide the
+ * index to check if an attempt to call {@link #setValue} with that index will always fail.
* @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
* <code>true</code> if calling the <code>setValue</code> method will always fail or <code>false</code> if it is
* possible that such a call may succeed; otherwise undefined.
@@ -251,6 +261,11 @@
if (base != null && base.getClass().isArray()) {
context.setPropertyResolved(true);
+
+ if (LENGTH_PROPERTY_NAME.equals(property)) {
+ return true;
+ }
+
int index = toInteger(property);
if (index < 0 || index >= Array.getLength(base)) {
throw new PropertyNotFoundException();