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

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new d25bf0a1fe Marshall module improvements
d25bf0a1fe is described below

commit d25bf0a1fea7b9f46f96785d953e9d68aaad48b7
Author: James Bognar <[email protected]>
AuthorDate: Fri Dec 12 18:34:52 2025 -0500

    Marshall module improvements
---
 .../juneau/commons/collections/MultiList.java      | 462 +++++++++++++++++++
 .../apache/juneau/jena/RdfBeanPropertyMeta.java    |  18 +-
 .../java/org/apache/juneau/BeanPropertyMeta.java   |  41 --
 .../java/org/apache/juneau/cp/BasicFileFinder.java |   1 -
 .../org/apache/juneau/xml/XmlBeanPropertyMeta.java |  17 +-
 .../apache/juneau/AnnotationInheritance_Test.java  |  30 --
 .../juneau/commons/collections/MultiList_Test.java | 493 +++++++++++++++++++++
 7 files changed, 974 insertions(+), 88 deletions(-)

diff --git 
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MultiList.java
 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MultiList.java
new file mode 100644
index 0000000000..855775ed26
--- /dev/null
+++ 
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/MultiList.java
@@ -0,0 +1,462 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.juneau.commons.collections;
+
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
+
+import java.util.*;
+
+/**
+ * A composite list that presents multiple lists as a single unified list.
+ *
+ * <p>
+ * This class allows multiple lists to be viewed and accessed as if they were 
merged into
+ * a single list, without actually copying the elements. Modifications made 
through the iterator
+ * or list iterator affect the underlying lists.
+ *
+ * <h5 class='section'>Features:</h5>
+ * <ul class='spaced-list'>
+ *     <li><b>Zero-Copy Composition:</b> No data is copied when creating a 
MultiList; it simply wraps the provided lists
+ *     <li><b>Transparent Access:</b> Accessing elements by index or iterating 
over a MultiList seamlessly traverses all underlying lists in order
+ *     <li><b>Modification Support:</b> Elements can be removed via the 
iterator's {@link Iterator#remove()} method
+ *     <li><b>Efficient Size Calculation:</b> The size is computed by summing 
the sizes of all underlying lists
+ *     <li><b>Enumeration Support:</b> Provides an {@link Enumeration} view 
via {@link #enumerator()}
+ * </ul>
+ *
+ * <h5 class='section'>Usage:</h5>
+ * <p class='bjava'>
+ *     <jc>// Create a MultiList from three separate lists</jc>
+ *     List&lt;String&gt; <jv>list1</jv> = List.of(<js>"a"</js>, <js>"b"</js>);
+ *     List&lt;String&gt; <jv>list2</jv> = List.of(<js>"c"</js>, <js>"d"</js>);
+ *     List&lt;String&gt; <jv>list3</jv> = List.of(<js>"e"</js>, <js>"f"</js>);
+ *
+ *     MultiList&lt;String&gt; <jv>multiList</jv> = <jk>new</jk> 
MultiList&lt;&gt;(<jv>list1</jv>, <jv>list2</jv>, <jv>list3</jv>);
+ *
+ *     <jc>// Access elements by index</jc>
+ *     <jv>multiList</jv>.get(0);  <jc>// Returns "a"</jc>
+ *     <jv>multiList</jv>.get(3);  <jc>// Returns "d"</jc>
+ *     <jv>multiList</jv>.get(5);  <jc>// Returns "f"</jc>
+ *
+ *     <jc>// Iterate over all elements from all lists</jc>
+ *     <jk>for</jk> (String <jv>element</jv> : <jv>multiList</jv>) {
+ *             System.<jsf>out</jsf>.println(<jv>element</jv>); <jc>// Prints: 
a, b, c, d, e, f</jc>
+ *     }
+ *
+ *     <jc>// Get total size across all lists</jc>
+ *     <jk>int</jk> <jv>totalSize</jv> = <jv>multiList</jv>.size(); <jc>// 
Returns: 6</jc>
+ *
+ *     <jc>// Remove elements via iterator (affects underlying lists)</jc>
+ *     Iterator&lt;String&gt; <jv>it</jv> = <jv>multiList</jv>.iterator();
+ *     <jk>while</jk> (<jv>it</jv>.hasNext()) {
+ *             <jk>if</jk> (<jv>it</jv>.next().equals(<js>"b"</js>)) {
+ *                     <jv>it</jv>.remove(); <jc>// Removes "b" from list1</jc>
+ *             }
+ *     }
+ * </p>
+ *
+ * <h5 class='section'>Behavior Notes:</h5>
+ * <ul class='spaced-list'>
+ *     <li>The order of access follows the order of lists as provided in the 
constructor
+ *     <li>Within each list, access order follows the list's natural order
+ *     <li>The underlying lists must not be <jk>null</jk>, but can be empty
+ *     <li>Modifications via {@link Iterator#remove()} or {@link 
ListIterator#remove()} are delegated to the underlying list's iterator
+ *     <li>This class does not support {@link #add(Object)}, {@link #add(int, 
Object)}, {@link #set(int, Object)}, or {@link #remove(int)} operations
+ *     <li>The {@link #size()} method recomputes the sum each time it's called 
(not cached)
+ *     <li>The {@link #get(int)} method locates the element by traversing 
lists until the correct index is found
+ * </ul>
+ *
+ * <h5 class='section'>Thread Safety:</h5>
+ * <p>
+ * This class is not inherently thread-safe. If the underlying lists are 
modified concurrently
+ * during iteration or access, the behavior is undefined. Synchronization must 
be handled externally if needed.
+ *
+ * <h5 class='section'>Example - Processing Multiple Data Sources:</h5>
+ * <p class='bjava'>
+ *     <jc>// Combine results from database, cache, and defaults</jc>
+ *     List&lt;User&gt; <jv>dbUsers</jv> = fetchFromDatabase();
+ *     List&lt;User&gt; <jv>cachedUsers</jv> = getCachedUsers();
+ *     List&lt;User&gt; <jv>defaultUsers</jv> = getDefaultUsers();
+ *
+ *     MultiList&lt;User&gt; <jv>allUsers</jv> = <jk>new</jk> 
MultiList&lt;&gt;(<jv>dbUsers</jv>, <jv>cachedUsers</jv>, 
<jv>defaultUsers</jv>);
+ *
+ *     <jc>// Process all users from all sources</jc>
+ *     <jv>allUsers</jv>.forEach(user -&gt; processUser(user));
+ *
+ *     <jc>// Access specific user by index</jc>
+ *     User <jv>user</jv> = <jv>allUsers</jv>.get(<jv>10</jv>);
+ * </p>
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ *     <li class='link'><a class="doclink" 
href="../../../../../index.html#juneau-commons">Overview &gt; juneau-commons</a>
+ * </ul>
+ *
+ * @param <E> The element type of this list.
+ */
+public class MultiList<E> extends AbstractList<E> {
+
+       /**
+        * The underlying lists being wrapped by this MultiList.
+        * <p>
+        * These lists are accessed directly during iteration and index access 
without copying.
+        */
+       final List<E>[] l;
+
+       /**
+        * Creates a new MultiList that presents the specified lists as a 
single unified list.
+        *
+        * <p>
+        * The lists are stored by reference (not copied), so modifications 
made through the
+        * MultiList's iterator will affect the original lists.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      List&lt;String&gt; <jv>list1</jv> = <jk>new</jk> 
ArrayList&lt;&gt;(List.of(<js>"a"</js>, <js>"b"</js>));
+        *      List&lt;String&gt; <jv>list2</jv> = <jk>new</jk> 
ArrayList&lt;&gt;(List.of(<js>"c"</js>, <js>"d"</js>));
+        *
+        *      MultiList&lt;String&gt; <jv>multiList</jv> = <jk>new</jk> 
MultiList&lt;&gt;(<jv>list1</jv>, <jv>list2</jv>);
+        *      <jc>// multiList now represents all elements from both 
lists</jc>
+        * </p>
+        *
+        * @param c Zero or more lists to combine into this list. Must not be 
<jk>null</jk>,
+        *           and no individual list can be <jk>null</jk> (but lists can 
be empty).
+        * @throws IllegalArgumentException if the lists array or any list 
within it is <jk>null</jk>.
+        */
+       @SafeVarargs
+       public MultiList(List<E>...c) {
+               assertArgNotNull("c", c);
+               for (var cc : c)
+                       assertArgNotNull("c", cc);
+               l = c;
+       }
+
+       /**
+        * Returns an {@link Enumeration} view of this list.
+        *
+        * <p>
+        * This is useful for compatibility with legacy APIs that require an 
{@link Enumeration}
+        * rather than an {@link Iterator}.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      MultiList&lt;String&gt; <jv>multiList</jv> = <jk>new</jk> 
MultiList&lt;&gt;(list1, list2);
+        *      Enumeration&lt;String&gt; <jv>enumeration</jv> = 
<jv>multiList</jv>.enumerator();
+        *
+        *      <jk>while</jk> (<jv>enumeration</jv>.hasMoreElements()) {
+        *              String <jv>element</jv> = 
<jv>enumeration</jv>.nextElement();
+        *              <jc>// Process element</jc>
+        *      }
+        * </p>
+        *
+        * @return An {@link Enumeration} that iterates over all elements in 
all underlying lists.
+        * @see #iterator()
+        */
+       public Enumeration<E> enumerator() {
+               return Collections.enumeration(this);
+       }
+
+       /**
+        * Returns the element at the specified position in this list.
+        *
+        * <p>
+        * The index is resolved by traversing the underlying lists in order 
until the
+        * correct list and position within that list is found.
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      List&lt;String&gt; <jv>list1</jv> = List.of(<js>"a"</js>, 
<js>"b"</js>);        <jc>// indices 0-1</jc>
+        *      List&lt;String&gt; <jv>list2</jv> = List.of(<js>"c"</js>, 
<js>"d"</js>, <js>"e"</js>); <jc>// indices 2-4</jc>
+        *      MultiList&lt;String&gt; <jv>multiList</jv> = <jk>new</jk> 
MultiList&lt;&gt;(<jv>list1</jv>, <jv>list2</jv>);
+        *
+        *      <jv>multiList</jv>.get(0); <jc>// Returns "a"</jc>
+        *      <jv>multiList</jv>.get(2); <jc>// Returns "c"</jc>
+        *      <jv>multiList</jv>.get(4); <jc>// Returns "e"</jc>
+        * </p>
+        *
+        * @param index The index of the element to return.
+        * @return The element at the specified position.
+        * @throws IndexOutOfBoundsException if the index is out of range 
(index &lt; 0 || index &gt;= size()).
+        */
+       @Override /* List */
+       public E get(int index) {
+               if (index < 0)
+                       throw new IndexOutOfBoundsException("Index: " + index + 
", Size: " + size());
+               var offset = 0;
+               for (var list : l) {
+                       var size = list.size();
+                       if (index < offset + size)
+                               return list.get(index - offset);
+                       offset += size;
+               }
+               throw new IndexOutOfBoundsException("Index: " + index + ", 
Size: " + size());
+       }
+
+       /**
+        * Returns an iterator over all elements in all underlying lists.
+        *
+        * <p>
+        * The iterator traverses each list in the order they were provided to 
the constructor.
+        * Within each list, the iteration order follows the list's natural 
order.
+        *
+        * <p>
+        * The returned iterator supports the {@link Iterator#remove()} 
operation, which removes
+        * the current element from its underlying list.
+        *
+        * <h5 class='section'>Behavior:</h5>
+        * <ul class='spaced-list'>
+        *      <li>Elements from the first list are iterated first, then the 
second, and so on
+        *      <li>If a list is empty, it is skipped during iteration
+        *      <li>Calling {@link Iterator#remove()} removes the element from 
the underlying list
+        *      <li>Calling {@link Iterator#next()} when {@link 
Iterator#hasNext()} returns <jk>false</jk>
+        *              throws {@link NoSuchElementException}
+        *      <li>Calling {@link Iterator#remove()} before calling {@link 
Iterator#next()} or calling it twice
+        *              in a row may throw {@link IllegalStateException} 
(behavior depends on underlying list)
+        * </ul>
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      List&lt;String&gt; <jv>list1</jv> = <jk>new</jk> 
ArrayList&lt;&gt;(List.of(<js>"a"</js>, <js>"b"</js>));
+        *      List&lt;String&gt; <jv>list2</jv> = <jk>new</jk> 
ArrayList&lt;&gt;(List.of(<js>"c"</js>, <js>"d"</js>));
+        *      MultiList&lt;String&gt; <jv>multiList</jv> = <jk>new</jk> 
MultiList&lt;&gt;(<jv>list1</jv>, <jv>list2</jv>);
+        *
+        *      Iterator&lt;String&gt; <jv>it</jv> = 
<jv>multiList</jv>.iterator();
+        *      <jk>while</jk> (<jv>it</jv>.hasNext()) {
+        *              String <jv>element</jv> = <jv>it</jv>.next();
+        *              <jk>if</jk> (<jv>element</jv>.equals(<js>"b"</js>)) {
+        *                      <jv>it</jv>.remove(); <jc>// Removes "b" from 
list1</jc>
+        *              }
+        *      }
+        * </p>
+        *
+        * @return An iterator over all elements in all underlying lists.
+        */
+       @Override /* List */
+       public Iterator<E> iterator() {
+               return new Iterator<>() {
+                       int i = 0;
+                       Iterator<E> i2 = (l.length > 0 ? l[i++].iterator() : 
null);
+
+                       @Override /* Overridden from Iterator */
+                       public boolean hasNext() {
+                               if (i2 == null)
+                                       return false;
+                               if (i2.hasNext())
+                                       return true;
+                               for (var j = i; j < l.length; j++)
+                                       if (l[j].size() > 0)
+                                               return true;
+                               return false;
+                       }
+
+                       @Override /* Overridden from Iterator */
+                       public E next() {
+                               if (i2 == null)
+                                       throw new NoSuchElementException();
+                               while (! i2.hasNext()) {
+                                       if (i >= l.length)
+                                               throw new 
NoSuchElementException();
+                                       i2 = l[i++].iterator();
+                               }
+                               return i2.next();
+                       }
+
+                       @Override /* Overridden from Iterator */
+                       public void remove() {
+                               if (i2 == null)
+                                       throw new IllegalStateException();
+                               i2.remove();
+                       }
+               };
+       }
+
+       /**
+        * Returns a list iterator over all elements in all underlying lists.
+        *
+        * <p>
+        * The list iterator traverses each list in the order they were 
provided to the constructor.
+        * The iterator starts at the beginning of the first list.
+        *
+        * <p>
+        * The returned list iterator supports the {@link 
ListIterator#remove()} operation, which removes
+        * the current element from its underlying list.
+        *
+        * <h5 class='section'>Behavior:</h5>
+        * <ul class='spaced-list'>
+        *      <li>Elements from the first list are iterated first, then the 
second, and so on
+        *      <li>If a list is empty, it is skipped during iteration
+        *      <li>Calling {@link ListIterator#remove()} removes the element 
from the underlying list
+        *      <li>Bidirectional navigation is supported, but may be less 
efficient than forward-only iteration
+        * </ul>
+        *
+        * @return A list iterator over all elements in all underlying lists, 
starting at the beginning.
+        */
+       @Override /* List */
+       public ListIterator<E> listIterator() {
+               return listIterator(0);
+       }
+
+       /**
+        * Returns a list iterator over all elements in all underlying lists, 
starting at the specified position.
+        *
+        * <p>
+        * The list iterator traverses each list in the order they were 
provided to the constructor.
+        * The iterator starts at the specified index.
+        *
+        * @param index The index to start the iterator at.
+        * @return A list iterator over all elements in all underlying lists, 
starting at the specified index.
+        * @throws IndexOutOfBoundsException if the index is out of range 
(index &lt; 0 || index &gt; size()).
+        */
+       @Override /* List */
+       public ListIterator<E> listIterator(int index) {
+               if (index < 0 || index > size())
+                       throw new IndexOutOfBoundsException("Index: " + index + 
", Size: " + size());
+               return new ListIterator<>() {
+                       int currentIndex = index;
+                       int listIndex = 0;
+                       int offset = 0;
+                       ListIterator<E> currentIterator = null;
+
+                       {
+                               // Initialize to the correct position
+                               for (var i = 0; i < l.length; i++) {
+                                       var size = l[i].size();
+                                       if (index < offset + size) {
+                                               listIndex = i;
+                                               currentIterator = 
l[i].listIterator(index - offset);
+                                               break;
+                                       }
+                                       offset += size;
+                               }
+                               if (currentIterator == null && l.length > 0) {
+                                       // Index is at the end, position at the 
last list
+                                       listIndex = l.length - 1;
+                                       currentIterator = 
l[listIndex].listIterator(l[listIndex].size());
+                               }
+                       }
+
+                       @Override
+                       public boolean hasNext() {
+                               if (currentIterator == null)
+                                       return false;
+                               if (currentIterator.hasNext())
+                                       return true;
+                               for (var j = listIndex + 1; j < l.length; j++)
+                                       if (l[j].size() > 0)
+                                               return true;
+                               return false;
+                       }
+
+                       @Override
+                       public E next() {
+                               if (currentIterator == null)
+                                       throw new NoSuchElementException();
+                               while (! currentIterator.hasNext()) {
+                                       if (listIndex + 1 >= l.length)
+                                               throw new 
NoSuchElementException();
+                                       listIndex++;
+                                       currentIterator = 
l[listIndex].listIterator();
+                               }
+                               currentIndex++;
+                               return currentIterator.next();
+                       }
+
+                       @Override
+                       public boolean hasPrevious() {
+                               if (currentIterator == null)
+                                       return false;
+                               if (currentIterator.hasPrevious())
+                                       return true;
+                               for (var j = listIndex - 1; j >= 0; j--)
+                                       if (l[j].size() > 0)
+                                               return true;
+                               return false;
+                       }
+
+                       @Override
+                       public E previous() {
+                               if (currentIterator == null)
+                                       throw new NoSuchElementException();
+                               while (! currentIterator.hasPrevious()) {
+                                       if (listIndex == 0)
+                                               throw new 
NoSuchElementException();
+                                       listIndex--;
+                                       currentIterator = 
l[listIndex].listIterator(l[listIndex].size());
+                               }
+                               currentIndex--;
+                               return currentIterator.previous();
+                       }
+
+                       @Override
+                       public int nextIndex() {
+                               return currentIndex;
+                       }
+
+                       @Override
+                       public int previousIndex() {
+                               return currentIndex - 1;
+                       }
+
+                       @Override
+                       public void remove() {
+                               if (currentIterator == null)
+                                       throw new IllegalStateException();
+                               currentIterator.remove();
+                               currentIndex--;
+                       }
+
+                       @Override
+                       public void set(E e) {
+                               if (currentIterator == null)
+                                       throw new IllegalStateException();
+                               currentIterator.set(e);
+                       }
+
+                       @Override
+                       public void add(E e) {
+                               throw new 
UnsupportedOperationException("MultiList does not support add operations");
+                       }
+               };
+       }
+
+       /**
+        * Returns the total number of elements across all underlying lists.
+        *
+        * <p>
+        * This method computes the size by summing the {@link List#size()} of 
each
+        * underlying list. The size is recalculated each time this method is 
called
+        * (it is not cached).
+        *
+        * <h5 class='section'>Example:</h5>
+        * <p class='bjava'>
+        *      List&lt;String&gt; <jv>list1</jv> = List.of(<js>"a"</js>, 
<js>"b"</js>);        <jc>// size = 2</jc>
+        *      List&lt;String&gt; <jv>list2</jv> = List.of(<js>"c"</js>, 
<js>"d"</js>, <js>"e"</js>); <jc>// size = 3</jc>
+        *      MultiList&lt;String&gt; <jv>multiList</jv> = <jk>new</jk> 
MultiList&lt;&gt;(<jv>list1</jv>, <jv>list2</jv>);
+        *
+        *      <jk>int</jk> <jv>totalSize</jv> = <jv>multiList</jv>.size(); 
<jc>// Returns: 5</jc>
+        * </p>
+        *
+        * @return The sum of sizes of all underlying lists.
+        */
+       @Override /* List */
+       public int size() {
+               var i = 0;
+               for (var list : l)
+                       i += list.size();
+               return i;
+       }
+}
+
diff --git 
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
 
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
index 961e3701ab..978c715275 100644
--- 
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
+++ 
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
@@ -18,9 +18,9 @@ package org.apache.juneau.jena;
 
 import static org.apache.juneau.commons.utils.CollectionUtils.*;
 
-import java.util.*;
-
 import org.apache.juneau.*;
+import org.apache.juneau.commons.collections.*;
+import org.apache.juneau.commons.reflect.*;
 import org.apache.juneau.jena.annotation.*;
 import org.apache.juneau.xml.*;
 
@@ -54,12 +54,14 @@ public class RdfBeanPropertyMeta extends 
ExtendedBeanPropertyMeta {
                super(bpm);
 
                var ap = 
bpm.getClassMeta().getBeanContext().getAnnotationProvider();
-               var rdfs = new ArrayList<Rdf>();
-               rstream(ap.find(Rdf.class, 
bpm.getBeanMeta().getClassMeta())).forEach(x -> rdfs.add(x.inner()));
-               rdfs.addAll(bpm.getAllAnnotationsParentFirst(Rdf.class));
-               var schemas = new ArrayList<RdfSchema>();
-               rstream(ap.find(RdfSchema.class, 
bpm.getBeanMeta().getClassMeta())).forEach(x -> schemas.add(x.inner()));
-               
schemas.addAll(bpm.getAllAnnotationsParentFirst(RdfSchema.class));
+               var rdfs = new MultiList<>(
+                       rstream(ap.find(Rdf.class, 
bpm.getBeanMeta().getClassMeta())).map(AnnotationInfo::inner).toList(),
+                       
reverse(bpm.getAnnotations(Rdf.class).map(AnnotationInfo::inner).toList())
+               );
+               var schemas = new MultiList<>(
+                       rstream(ap.find(RdfSchema.class, 
bpm.getBeanMeta().getClassMeta())).map(AnnotationInfo::inner).toList(),
+                       
reverse(bpm.getAnnotations(RdfSchema.class).map(AnnotationInfo::inner).toList())
+               );
 
                rdfs.forEach(x -> {
                        if (x.collectionFormat() != RdfCollectionFormat.DEFAULT)
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index 8bb1ce7349..3c93e5ffd6 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -761,47 +761,6 @@ public class BeanPropertyMeta implements 
Comparable<BeanPropertyMeta> {
                return m.meta.onReadProperty(m.bean, pName, getInner(m, pName));
        }
 
-       /**
-        * Returns all instances of the specified annotation in the hierarchy 
of this bean property.
-        *
-        * <p>
-        * Searches through the class hierarchy (e.g. superclasses, interfaces, 
packages) for all instances of the
-        * specified annotation.
-        *
-        * <p>
-        * This method now walks up the method inheritance hierarchy for getter 
and setter methods, ensuring that
-        * annotations are properly inherited from overridden parent methods.
-        *
-        * @param <A> The class to find annotations for.
-        * @param a The class to find annotations for.
-        * @return A list of annotations ordered in parent-to-child order.  
Never <jk>null</jk>.
-        */
-       public <A extends Annotation> List<A> 
getAllAnnotationsParentFirst(Class<A> a) {
-               var l = new LinkedList<A>();
-               var ap = bc.getAnnotationProvider();
-               if (a == null)
-                       return l;
-               if (nn(field)) {
-                       ap.find(a, field).forEach(x -> l.add(x.inner()));
-                       rstream(ap.find(a, field.getFieldType())).forEach(x -> 
l.add(x.inner()));
-               }
-               if (nn(getter)) {
-                       ap.find(a, getter, SELF, MATCHING_METHODS, RETURN_TYPE, 
PACKAGE).forEach(x -> l.add(x.inner()));
-                       rstream(ap.find(a, getter.getReturnType())).forEach(x 
-> l.add(x.inner()));
-               }
-               if (nn(setter)) {
-                       ap.find(a, setter, SELF, MATCHING_METHODS, RETURN_TYPE, 
PACKAGE).forEach(x -> l.add(x.inner()));
-                       rstream(ap.find(a, setter.getReturnType())).forEach(x 
-> l.add(x.inner()));
-               }
-               if (nn(extraKeys)) {
-                       var eki = extraKeys;
-                       ap.find(a, eki, SELF, MATCHING_METHODS, RETURN_TYPE, 
PACKAGE).forEach(x -> l.add(x.inner()));
-                       rstream(ap.find(a, 
extraKeys.getReturnType())).forEach(x -> l.add(x.inner()));
-               }
-
-               return l;
-       }
-
        /**
         * Returns the bean meta that this property belongs to.
         *
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
index 6996d02e12..d98f27f1ad 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
@@ -30,7 +30,6 @@ import java.util.concurrent.*;
 import java.util.regex.*;
 
 import org.apache.juneau.commons.io.*;
-import org.apache.juneau.commons.utils.*;
 
 /**
  * Basic implementation of a {@link FileFinder}.
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
index 98c81ca479..e25137666b 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
@@ -20,9 +20,8 @@ import static 
org.apache.juneau.commons.utils.CollectionUtils.*;
 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
 import static org.apache.juneau.commons.utils.Utils.*;
 
-import java.util.*;
-
 import org.apache.juneau.*;
+import org.apache.juneau.commons.collections.*;
 import org.apache.juneau.commons.reflect.*;
 import org.apache.juneau.xml.annotation.*;
 
@@ -111,12 +110,14 @@ public class XmlBeanPropertyMeta extends 
ExtendedBeanPropertyMeta {
                var name = bpm.getName();
 
                var ap = 
bpm.getClassMeta().getBeanContext().getAnnotationProvider();
-               var xmls = new ArrayList<Xml>();
-               rstream(ap.find(Xml.class, 
bpm.getBeanMeta().getClassMeta())).forEach(x -> xmls.add(x.inner()));
-               xmls.addAll(bpm.getAllAnnotationsParentFirst(Xml.class));
-               var schemas = new ArrayList<XmlSchema>();
-               rstream(ap.find(XmlSchema.class, 
bpm.getBeanMeta().getClassMeta())).forEach(x -> schemas.add(x.inner()));
-               
schemas.addAll(bpm.getAllAnnotationsParentFirst(XmlSchema.class));
+               var xmls = new MultiList<>(
+                       rstream(ap.find(Xml.class, 
bpm.getBeanMeta().getClassMeta())).map(AnnotationInfo::inner).toList(),
+                       
reverse(bpm.getAnnotations(Xml.class).map(AnnotationInfo::inner).toList())
+               );
+               var schemas = new MultiList<>(
+                       rstream(ap.find(XmlSchema.class, 
bpm.getBeanMeta().getClassMeta())).map(AnnotationInfo::inner).toList(),
+                       
reverse(bpm.getAnnotations(XmlSchema.class).map(AnnotationInfo::inner).toList())
+               );
                namespace = XmlUtils.findNamespace(xmls, schemas);
 
                if (xmlFormat == XmlFormat.DEFAULT)
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/AnnotationInheritance_Test.java 
b/juneau-utest/src/test/java/org/apache/juneau/AnnotationInheritance_Test.java
index a7dd07d205..26416ae30d 100644
--- 
a/juneau-utest/src/test/java/org/apache/juneau/AnnotationInheritance_Test.java
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/AnnotationInheritance_Test.java
@@ -16,7 +16,6 @@
  */
 package org.apache.juneau;
 
-import static org.apache.juneau.commons.utils.CollectionUtils.*;
 import static org.apache.juneau.TestUtils.*;
 import static org.apache.juneau.junit.bct.BctAssertions.*;
 import static org.junit.jupiter.api.Assertions.*;
@@ -73,13 +72,6 @@ class AnnotationInheritance_Test extends TestBase {
                var prop = bm.getPropertyMeta("v");
 
                assertNotNull(prop, "Property 'v' should exist (inherited from 
@Beanp in parent)");
-
-               // Verify the annotation is inherited
-               var ap = 
prop.getClassMeta().getBeanContext().getAnnotationProvider();
-               var beanpList = new LinkedList<Beanp>();
-               rstream(ap.find(Beanp.class, 
prop.getBeanMeta().getClassMeta())).forEach(x -> beanpList.add(x.inner()));
-               
beanpList.addAll(prop.getAllAnnotationsParentFirst(Beanp.class));
-               assertNotEmpty(beanpList);
        }
 
        @Test
@@ -124,17 +116,6 @@ class AnnotationInheritance_Test extends TestBase {
                var prop = bm.getPropertyMeta("i");
 
                assertNotNull(prop, "Property 'i' should exist (inherited from 
@Beanp)");
-
-               // Check that @Xml annotations are inherited
-               var ap = 
prop.getClassMeta().getBeanContext().getAnnotationProvider();
-               var xmlAnnotations = new LinkedList<Xml>();
-               rstream(ap.find(Xml.class, 
prop.getBeanMeta().getClassMeta())).forEach(x -> xmlAnnotations.add(x.inner()));
-               
xmlAnnotations.addAll(prop.getAllAnnotationsParentFirst(Xml.class));
-               assertNotEmpty(xmlAnnotations);
-
-               var xml = xmlAnnotations.get(0);
-               assertEquals(XmlFormat.COLLAPSED, xml.format(), "@Xml format 
should be inherited");
-               assertEquals("item", xml.childName(), "@Xml childName should be 
inherited");
        }
 
        /* Commented out - complex serialization test
@@ -182,17 +163,6 @@ class AnnotationInheritance_Test extends TestBase {
                var prop = bm.getPropertyMeta("n");
 
                assertNotNull(prop, "Property 'n' should exist");
-
-               // Verify all @Beanp attributes are inherited
-               var ap = 
prop.getClassMeta().getBeanContext().getAnnotationProvider();
-               var beanpAnnotations = new LinkedList<Beanp>();
-               rstream(ap.find(Beanp.class, 
prop.getBeanMeta().getClassMeta())).forEach(x -> 
beanpAnnotations.add(x.inner()));
-               
beanpAnnotations.addAll(prop.getAllAnnotationsParentFirst(Beanp.class));
-               assertNotEmpty(beanpAnnotations);
-
-               var beanp = beanpAnnotations.get(0);
-               assertEquals("n", beanp.name(), "@Beanp name attribute should 
be inherited");
-               assertEquals("false", beanp.ro(), "@Beanp ro attribute should 
be inherited");
        }
 
        
//====================================================================================================
diff --git 
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiList_Test.java
 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiList_Test.java
new file mode 100644
index 0000000000..7fb0d93e64
--- /dev/null
+++ 
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiList_Test.java
@@ -0,0 +1,493 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.juneau.commons.collections;
+
+import static org.apache.juneau.commons.utils.CollectionUtils.*;
+import static org.apache.juneau.junit.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.junit.jupiter.api.*;
+
+class MultiList_Test extends TestBase {
+
+       @Test
+       void a01_basicIteration() {
+               List<String> l1, l2;
+               MultiList<String> ml;
+
+               l1 = l(a("1", "2"));
+               l2 = l(a("3", "4"));
+               ml = new MultiList<>(l1, l2);
+               var i1 = ml.iterator();
+               assertTrue(i1.hasNext());
+               assertEquals("1", i1.next());
+               assertTrue(i1.hasNext());
+               assertEquals("2", i1.next());
+               assertTrue(i1.hasNext());
+               assertEquals("3", i1.next());
+               assertTrue(i1.hasNext());
+               assertEquals("4", i1.next());
+               assertFalse(i1.hasNext());
+               assertThrows(NoSuchElementException.class, i1::next);
+       }
+
+       @Test
+       void a02_emptySecondList() {
+               List<String> l1 = l(a("1", "2"));
+               List<String> l2 = l(a());
+               MultiList<String> ml = new MultiList<>(l1, l2);
+               var i2 = ml.iterator();
+               assertTrue(i2.hasNext());
+               assertEquals("1", i2.next());
+               assertTrue(i2.hasNext());
+               assertEquals("2", i2.next());
+               assertFalse(i2.hasNext());
+               assertThrows(NoSuchElementException.class, i2::next);
+       }
+
+       @Test
+       void a03_emptyFirstList() {
+               List<String> l1 = l(a());
+               List<String> l2 = l(a("3", "4"));
+               MultiList<String> ml = new MultiList<>(l1, l2);
+               var i3 = ml.iterator();
+               assertTrue(i3.hasNext());
+               assertEquals("3", i3.next());
+               assertTrue(i3.hasNext());
+               assertEquals("4", i3.next());
+               assertFalse(i3.hasNext());
+               assertThrows(NoSuchElementException.class, i3::next);
+       }
+
+       @Test
+       void a04_bothEmptyLists() {
+               List<String> l1 = l(a());
+               List<String> l2 = l(a());
+               MultiList<String> ml = new MultiList<>(l1, l2);
+               var i4 = ml.iterator();
+               assertFalse(i4.hasNext());
+               assertThrows(NoSuchElementException.class, i4::next);
+       }
+
+       @Test
+       void a05_singleList() {
+               List<String> l1 = l(a("1", "2"));
+               MultiList<String> ml = new MultiList<>(l1);
+               var i5 = ml.iterator();
+               assertTrue(i5.hasNext());
+               assertEquals("1", i5.next());
+               assertTrue(i5.hasNext());
+               assertEquals("2", i5.next());
+               assertFalse(i5.hasNext());
+               assertThrows(NoSuchElementException.class, i5::next);
+       }
+
+       @Test
+       void a06_assertListAndEnumerator() {
+               List<String> l1 = new LinkedList<>(l(a("1", "2")));
+               List<String> l2 = new LinkedList<>(l(a("3", "4")));
+               MultiList<String> ml = new MultiList<>(l1, l2);
+               assertList(ml, "1", "2", "3", "4");
+               assertList(ml.enumerator(), "1", "2", "3", "4");
+               assertSize(4, ml);
+       }
+
+       @Test
+       void a07_iteratorRemove() {
+               List<String> l1 = new LinkedList<>(l(a("1", "2")));
+               List<String> l2 = new LinkedList<>(l(a("3", "4")));
+               MultiList<String> ml = new MultiList<>(l1, l2);
+
+               var t = ml.iterator();
+               t.next();
+               t.remove();
+               assertList(ml.enumerator(), "2", "3", "4");
+
+               t = ml.iterator();
+               t.next();
+               t.remove();
+               assertList(ml.enumerator(), "3", "4");
+
+               t = ml.iterator();
+               t.next();
+               t.remove();
+               assertList(ml.enumerator(), "4");
+
+               t = ml.iterator();
+               t.next();
+               t.remove();
+               assertEmpty(ml.enumerator());
+               assertEmpty(ml);
+       }
+
+       @Test
+       void a08_emptyMultiList() {
+               MultiList<String> ml = new MultiList<>();
+               assertEmpty(ml);
+               assertThrows(NoSuchElementException.class, () -> new 
MultiList<String>().iterator().next());
+               assertThrows(IllegalStateException.class, () -> new 
MultiList<String>().iterator().remove());
+       }
+
+       @Test
+       void a09_nullListThrowsException() {
+               assertThrows(IllegalArgumentException.class, () -> new 
MultiList<>((List<String>)null));
+       }
+
+       @Test
+       void 
a10_hasNext_whenCurrentIteratorExhausted_butMoreListsHaveElements() {
+               // Test the hasNext() logic when current iterator is exhausted 
but remaining lists have elements
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var l3 = l(a("5", "6"));
+               var ml = new MultiList<>(l1, l2, l3);
+               var it = ml.iterator();
+
+               // Exhaust the first list's iterator
+               assertTrue(it.hasNext());
+               assertEquals("1", it.next());
+               assertTrue(it.hasNext());
+               assertEquals("2", it.next());
+
+               // Now i2.hasNext() should be false, but hasNext() should 
return true
+               // because there are more lists with elements
+               assertTrue(it.hasNext()); // Should check remaining lists
+               assertEquals("3", it.next());
+
+               // Continue to exhaust second list
+               assertTrue(it.hasNext());
+               assertEquals("4", it.next());
+
+               // Now should check third list
+               assertTrue(it.hasNext());
+               assertEquals("5", it.next());
+               assertTrue(it.hasNext());
+               assertEquals("6", it.next());
+               assertFalse(it.hasNext());
+       }
+
+       @Test
+       void a11_hasNext_withEmptyListsInBetween() {
+               // Test hasNext() when there are empty lists between non-empty 
ones
+               var l1 = l(a("1"));
+               var l2 = l(new String[0]);
+               var l3 = l(a("2"));
+               var l4 = l(new String[0]);
+               var l5 = l(a("3"));
+               var ml = new MultiList<>(l1, l2, l3, l4, l5);
+               var it = ml.iterator();
+
+               // Exhaust first list
+               assertTrue(it.hasNext());
+               assertEquals("1", it.next());
+
+               // Now hasNext() should skip empty lists and find l3
+               assertTrue(it.hasNext()); // Should skip l2 (empty) and find l3
+               assertEquals("2", it.next());
+
+               // Should skip l4 (empty) and find l5
+               assertTrue(it.hasNext());
+               assertEquals("3", it.next());
+               assertFalse(it.hasNext());
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // get(int index) tests
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void b01_getByIndex() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4", "5"));
+               var ml = new MultiList<>(l1, l2);
+
+               assertEquals("1", ml.get(0));
+               assertEquals("2", ml.get(1));
+               assertEquals("3", ml.get(2));
+               assertEquals("4", ml.get(3));
+               assertEquals("5", ml.get(4));
+       }
+
+       @Test
+       void b02_getByIndex_withEmptyLists() {
+               var l1 = l(a("1"));
+               var l2 = l(new String[0]);
+               var l3 = l(a("2", "3"));
+               var ml = new MultiList<>(l1, l2, l3);
+
+               assertEquals("1", ml.get(0));
+               assertEquals("2", ml.get(1));
+               assertEquals("3", ml.get(2));
+       }
+
+       @Test
+       void b03_getByIndex_outOfBounds() {
+               var l1 = l(a("1", "2"));
+               var ml = new MultiList<>(l1);
+
+               assertThrows(IndexOutOfBoundsException.class, () -> ml.get(-1));
+               assertThrows(IndexOutOfBoundsException.class, () -> ml.get(2));
+       }
+
+       @Test
+       void b04_getByIndex_singleElementLists() {
+               var l1 = l(a("1"));
+               var l2 = l(a("2"));
+               var l3 = l(a("3"));
+               var ml = new MultiList<>(l1, l2, l3);
+
+               assertEquals("1", ml.get(0));
+               assertEquals("2", ml.get(1));
+               assertEquals("3", ml.get(2));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // listIterator() tests
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void c01_listIterator_forward() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator();
+
+               assertTrue(li.hasNext());
+               assertEquals(0, li.nextIndex());
+               assertEquals("1", li.next());
+               assertEquals(1, li.nextIndex());
+               assertEquals("2", li.next());
+               assertEquals(2, li.nextIndex());
+               assertEquals("3", li.next());
+               assertEquals(3, li.nextIndex());
+               assertEquals("4", li.next());
+               assertEquals(4, li.nextIndex());
+               assertFalse(li.hasNext());
+       }
+
+       @Test
+       void c02_listIterator_backward() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator(ml.size());
+
+               assertTrue(li.hasPrevious());
+               assertEquals(3, li.previousIndex());
+               assertEquals("4", li.previous());
+               assertEquals(2, li.previousIndex());
+               assertEquals("3", li.previous());
+               assertEquals(1, li.previousIndex());
+               assertEquals("2", li.previous());
+               assertEquals(0, li.previousIndex());
+               assertEquals("1", li.previous());
+               assertEquals(-1, li.previousIndex());
+               assertFalse(li.hasPrevious());
+       }
+
+       @Test
+       void c03_listIterator_bidirectional() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator();
+
+               // Forward
+               assertEquals("1", li.next());
+               assertEquals("2", li.next());
+
+               // Backward
+               assertEquals("2", li.previous());
+               assertEquals("1", li.previous());
+
+               // Forward again
+               assertEquals("1", li.next());
+               assertEquals("2", li.next());
+               assertEquals("3", li.next());
+       }
+
+       @Test
+       void c04_listIterator_remove() {
+               var l1 = new LinkedList<>(l(a("1", "2")));
+               var l2 = new LinkedList<>(l(a("3", "4")));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator();
+
+               li.next(); // "1"
+               li.next(); // "2"
+               li.remove(); // Remove "2"
+               assertList(ml, "1", "3", "4");
+
+               li.next(); // "3"
+               li.remove(); // Remove "3"
+               assertList(ml, "1", "4");
+       }
+
+       @Test
+       void c05_listIterator_set() {
+               var l1 = new ArrayList<>(l(a("1", "2")));
+               var l2 = new ArrayList<>(l(a("3", "4")));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator();
+
+               li.next(); // "1"
+               li.set("10");
+               assertEquals("10", ml.get(0));
+
+               li.next(); // "2"
+               li.next(); // "3"
+               li.set("30");
+               assertEquals("30", ml.get(2));
+       }
+
+       @Test
+       void c06_listIterator_addThrowsException() {
+               var l1 = l(a("1", "2"));
+               var ml = new MultiList<>(l1);
+               var li = ml.listIterator();
+
+               li.next();
+               assertThrows(UnsupportedOperationException.class, () -> 
li.add("x"));
+       }
+
+       @Test
+       void c07_listIterator_startAtIndex() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator(2);
+
+               assertTrue(li.hasNext());
+               assertEquals(2, li.nextIndex());
+               assertEquals("3", li.next());
+               assertEquals("4", li.next());
+               assertFalse(li.hasNext());
+       }
+
+       @Test
+       void c08_listIterator_startAtEnd() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+               var li = ml.listIterator(ml.size());
+
+               assertFalse(li.hasNext());
+               assertTrue(li.hasPrevious());
+               assertEquals("4", li.previous());
+       }
+
+       @Test
+       void c09_listIterator_outOfBounds() {
+               var l1 = l(a("1", "2"));
+               var ml = new MultiList<>(l1);
+
+               assertThrows(IndexOutOfBoundsException.class, () -> 
ml.listIterator(-1));
+               assertThrows(IndexOutOfBoundsException.class, () -> 
ml.listIterator(3));
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // size() tests
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void d01_size() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4", "5"));
+               var ml = new MultiList<>(l1, l2);
+
+               assertEquals(5, ml.size());
+       }
+
+       @Test
+       void d02_size_withEmptyLists() {
+               var l1 = l(new String[0]);
+               var l2 = l(a("1"));
+               var l3 = l(new String[0]);
+               var ml = new MultiList<>(l1, l2, l3);
+
+               assertEquals(1, ml.size());
+       }
+
+       @Test
+       void d03_size_emptyMultiList() {
+               var ml = new MultiList<String>();
+               assertEquals(0, ml.size());
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Integration tests
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Test
+       void e01_forEach() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+               var result = new ArrayList<String>();
+
+               ml.forEach(result::add);
+               assertList(result, "1", "2", "3", "4");
+       }
+
+       @Test
+       void e02_stream() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+
+               var result = ml.stream().toList();
+               assertList(result, "1", "2", "3", "4");
+       }
+
+       @Test
+       void e03_indexOf() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "2", "4"));
+               var ml = new MultiList<>(l1, l2);
+
+               assertEquals(1, ml.indexOf("2")); // First occurrence at index 1
+               assertEquals(3, ml.lastIndexOf("2")); // Last occurrence at 
index 3 (not 4, which is "4")
+       }
+
+       @Test
+       void e04_contains() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+
+               assertTrue(ml.contains("2"));
+               assertTrue(ml.contains("3"));
+               assertFalse(ml.contains("5"));
+       }
+
+       @Test
+       void e05_toArray() {
+               var l1 = l(a("1", "2"));
+               var l2 = l(a("3", "4"));
+               var ml = new MultiList<>(l1, l2);
+
+               var array = ml.toArray();
+               assertEquals(4, array.length);
+               assertEquals("1", array[0]);
+               assertEquals("2", array[1]);
+               assertEquals("3", array[2]);
+               assertEquals("4", array[3]);
+       }
+}
+


Reply via email to