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 b9ec9884e4 Built-in support for Iterator/Stream objects with
load-as-you-serialize
b9ec9884e4 is described below
commit b9ec9884e4b6e1aca266f82c453b2c526fd36604
Author: James Bognar <[email protected]>
AuthorDate: Sat Feb 28 07:46:21 2026 -0500
Built-in support for Iterator/Stream objects with load-as-you-serialize
---
.gitignore | 1 +
RELEASE-NOTES.txt | 26 +++
TODO.md | 7 +-
.../src/main/java/org/apache/juneau/ClassMeta.java | 53 ++++-
.../apache/juneau/csv/CsvSerializerSession.java | 3 +
.../apache/juneau/html/HtmlSerializerSession.java | 6 +
.../apache/juneau/json/JsonSerializerSession.java | 17 ++
.../juneau/msgpack/MsgPackSerializerSession.java | 3 +
.../juneau/oapi/OpenApiSerializerSession.java | 4 +
.../juneau/serializer/SerializerSession.java | 52 +++++
.../java/org/apache/juneau/swap/DefaultSwaps.java | 2 -
.../org/apache/juneau/swaps/EnumerationSwap.java | 51 -----
.../java/org/apache/juneau/swaps/IteratorSwap.java | 51 -----
.../apache/juneau/uon/UonSerializerSession.java | 23 ++
.../urlencoding/UrlEncodingSerializerSession.java | 13 ++
.../apache/juneau/xml/XmlSerializerSession.java | 41 +++-
.../org/apache/juneau/examples/rest/TestUtils.java | 3 -
.../juneau/examples/rest/RequestEchoResource.java | 7 -
.../juneau/transforms/DefaultSwaps_Test.java | 4 +-
.../juneau/transforms/EnumerationSwapTest.java | 40 ----
.../apache/juneau/transforms/IteratorSwapTest.java | 42 ----
.../transforms/StreamableSerializationTest.java | 241 +++++++++++++++++++++
22 files changed, 484 insertions(+), 206 deletions(-)
diff --git a/.gitignore b/.gitignore
index d2fb04dec0..d16c40f54f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,4 @@ cursor-*
scripts/release-history-*.json
/SONARQUBE_ISSUES.txt
/AISESSION.md
+/plans/
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index bd9239129e..c231a807f3 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -26,6 +26,32 @@ Release Notes - Juneau - Version 9.2.1 - YYYY-MM-DD
* Bump Bump org.apache.maven.plugins:maven-compiler-plugin from 3.14.1 to
3.15.0 #314.
* Bump Bump jetty.version from 12.1.5 to 12.1.6 #312.
+<<<<<<< Updated upstream
+** New Features - Direct Iterator/Iterable/Stream/Enumeration Serialization
+
+ * Iterators, Iterables (non-Collection), Enumerations, and
java.util.stream.Streams
+ are now serialized directly as arrays without requiring intermediate
List materialization.
+ * Text-based serializers (JSON, XML, UON, URL Encoding, OpenAPI) write
elements lazily
+ to the output one at a time via forEachStreamableEntry().
+ * Binary/layout-dependent serializers (MsgPack, HTML, CSV) collect to a
List internally
+ since the format requires knowing the size or inspecting elements
upfront.
+ * New ClassMeta methods: isIterator(), isIterable(), isStream(),
isStreamable().
+ * New ClassMeta.Category enum values: ITERATOR, ITERABLE, STREAM.
+=======
+** New Features - Direct Iterator/Iterable/Stream Serialization
+
+ * Iterators, Iterables (non-Collection), Enumerations, and
java.util.stream.Streams
+ are now serialized directly as arrays without requiring intermediate
List materialization.
+ * For text-based serializers (JSON, XML, UON), elements are written lazily
one at a
+ time for improved memory efficiency with large datasets.
+ * For binary/structured serializers (MsgPack, HTML, CSV), elements are
collected to a
+ List internally since the format requires knowing the size or inspecting
elements upfront.
+ * New ClassMeta methods: isIterator(), isIterable(), isStream(),
isStreamable().
+>>>>>>> Stashed changes
+ * New SerializerSession methods: forEachStreamableEntry(),
toListFromStreamable().
+ * IteratorSwap and EnumerationSwap classes have been removed; Iterator,
Enumeration, Iterable,
+ and Stream types are now handled natively by all serializers.
+
Release Notes - Juneau - Version 9.2.0 - 2025-12-30
** Changes
diff --git a/TODO.md b/TODO.md
index 98c2469549..5b6f7e5210 100644
--- a/TODO.md
+++ b/TODO.md
@@ -11,4 +11,9 @@
- JsonSchemaGenerator should return JsonSchema beans.
- Create full-fledged CSV serializer/parser support.
- Add YAML serializer/parser support.
-- Update REST server API to use new BeanStore2.
\ No newline at end of file
+- Update REST server API to use new BeanStore2.
+- ClassInfo should have a findGetter(String propertyName) convenience method.
+- Make sure @Beanp("*") works on plain fields.
+- Add schema validation to beans during parsing.
+- Duration objects should be supported for serialization by default.
+
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 00b8ecdf15..42b94cb662 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -32,6 +32,7 @@ import java.util.*;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.*;
+import java.util.stream.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.commons.collections.*;
@@ -112,7 +113,10 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
LIST(17),
SET(18),
DELEGATE(19),
- BEAN(20);
+ BEAN(20),
+ ITERATOR(21),
+ ITERABLE(22),
+ STREAM(23);
private final int mask;
@@ -215,6 +219,12 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
} else if (isAssignableTo(List.class)) {
cat.set(LIST);
}
+ } else if (isAssignableTo(Iterable.class)) {
+ cat.set(ITERABLE);
+ } else if (isAssignableTo(Iterator.class) ||
isAssignableTo(Enumeration.class)) {
+ cat.set(ITERATOR);
+ } else if (isAssignableTo(BaseStream.class)) {
+ cat.set(STREAM);
} else if (isAssignableTo(Map.class)) {
cat.set(MAP);
if (isAssignableTo(BeanMap.class)) {
@@ -1019,6 +1029,33 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
*/
public boolean isInteger() { return isAny(Integer.class, int.class); }
+ /**
+ * Returns <jk>true</jk> if this class implements {@link Iterable} but
is not a {@link Collection}.
+ *
+ * @return <jk>true</jk> if this class implements {@link Iterable} but
is not a {@link Collection}.
+ * @since 9.2.1
+ */
+ public boolean isIterable() { return cat.is(ITERABLE); }
+
+ /**
+ * Returns <jk>true</jk> if this class implements {@link Iterator} or
{@link Enumeration}.
+ *
+ * @return <jk>true</jk> if this class implements {@link Iterator} or
{@link Enumeration}.
+ * @since 9.2.1
+ */
+ public boolean isIterator() { return cat.is(ITERATOR); }
+
+ /**
+ * Returns <jk>true</jk> if this class is an {@link Iterator}, {@link
Iterable} (non-Collection), or {@link BaseStream}.
+ *
+ * <p>
+ * These types represent lazily-evaluated sequences that can be
serialized as arrays.
+ *
+ * @return <jk>true</jk> if this class is a streamable type.
+ * @since 9.2.1
+ */
+ public boolean isStreamable() { return cat.is(ITERATOR) ||
cat.is(ITERABLE) || cat.is(STREAM); }
+
/**
* Returns <jk>true</jk> if this class extends from {@link List}.
*
@@ -1114,6 +1151,14 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
*/
public boolean isShort() { return isAny(Short.class, short.class); }
+ /**
+ * Returns <jk>true</jk> if this class is a subclass of {@link
BaseStream} (includes {@link java.util.stream.Stream}).
+ *
+ * @return <jk>true</jk> if this class is a subclass of {@link
BaseStream}.
+ * @since 9.2.1
+ */
+ public boolean isStream() { return cat.is(STREAM); }
+
/**
* Returns <jk>true</jk> if this class is a {@link String}.
*
@@ -1361,8 +1406,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
return null;
if (cat.is(ARRAY)) {
return
beanContext.getClassMeta(inner().getComponentType());
- } else if (cat.is(COLLECTION) || is(Optional.class)) {
- // If this is a COLLECTION, see if it's parameterized
(e.g. AddressBook extends LinkedList<Person>)
+ } else if (cat.is(COLLECTION) || cat.is(ITERABLE) ||
cat.is(ITERATOR) || cat.is(STREAM) || is(Optional.class)) {
var parameters = beanContext.findParameters(inner(),
inner());
if (nn(parameters) && parameters.length == 1) {
return parameters[0];
@@ -1401,7 +1445,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
var ap = beanContext.getAnnotationProvider();
ap.find(Swap.class,
this).stream().map(AnnotationInfo::inner).forEach(x -> list.add(createSwap(x)));
var ds = DefaultSwaps.find(this);
- if (ds == null)
+ if (ds == null && !isStreamable()) {
ds = AutoObjectSwap.find(beanContext, this);
if (ds == null)
ds = AutoNumberSwap.find(beanContext, this);
@@ -1409,6 +1453,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
ds = AutoMapSwap.find(beanContext, this);
if (ds == null)
ds = AutoListSwap.find(beanContext, this);
+ }
if (nn(ds))
list.add((ObjectSwap<T,?>)ds);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
index 4ed4ebeba8..bf52621b77 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/csv/CsvSerializerSession.java
@@ -236,6 +236,9 @@ public class CsvSerializerSession extends
WriterSerializerSession {
l = l((Object[])o);
} else if (cm.isCollection()) {
l = (Collection<?>)o;
+ } else if (cm.isStreamable()) {
+ // CSV must inspect first element for column
headers, so materialization is unavoidable.
+ l = toListFromStreamable(o, cm);
} else {
l = Collections.singleton(o);
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index fc59e1722f..72da37ad01 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -991,6 +991,12 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.nlIf(! isRoot, xIndent + 1);
serializeCollection(out, o, sType, eType, name,
pMeta);
+ } else if (sType.isStreamable()) {
+ // HTML must inspect elements to decide table
vs. list layout (getTableHeaders), so materialization is unavoidable.
+ out.nlIf(! isRoot, xIndent + 1);
+ var list = toListFromStreamable(o, sType);
+ serializeCollection(out, list,
getClassMeta(List.class), eType, name, pMeta);
+
} else if (isUri(sType, pMeta, o)) {
String label = getAnchorText(pMeta, o);
out.oTag("a").attrUri("href", o).w('>');
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
index 03606154f0..0fe6b80c6b 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
@@ -261,6 +261,21 @@ public class JsonSerializerSession extends
WriterSerializerSession {
return out;
}
+ private SerializerWriter serializeStreamable(JsonWriter out, Object o,
ClassMeta<?> sType, ClassMeta<?> type) throws SerializeException {
+ var elementType = type.getElementType();
+
+ out.w('[');
+ var addComma = Flag.create();
+ forEachStreamableEntry(o, sType, x -> {
+ addComma.ifSet(() -> out.w(',').smi(indent)).set();
+ out.cr(indent);
+ serializeAnything(out, x, elementType, "<iterator>",
null);
+ });
+
+ out.cre(indent - 1).w(']');
+ return out;
+ }
+
@SuppressWarnings({
"rawtypes", // Raw types necessary for generic collection/map
serialization
@@ -434,6 +449,8 @@ public class JsonSerializerSession extends
WriterSerializerSession {
serializeCollection(out, (Collection)o, eType);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType);
+ } else if (sType.isStreamable()) {
+ serializeStreamable(out, o, sType, eType);
} else if (sType.isReader()) {
pipe((Reader)o, out, SerializerSession::handleThrown);
} else if (sType.isInputStream()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
index b5ffd72297..47cbaed3d0 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
@@ -281,6 +281,9 @@ public class MsgPackSerializerSession extends
OutputStreamSerializerSession {
out.appendBinary((byte[])o);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType);
+ } else if (sType.isStreamable()) {
+ // MsgPack protocol requires array size in header
(startArray(size)), so materialization is unavoidable.
+ serializeCollection(out, toListFromStreamable(o,
sType), eType);
} else if (sType.isReader()) {
pipe((Reader)o, out, SerializerSession::handleThrown);
} else if (sType.isInputStream()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
index bf23d6c59c..687e3674b8 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
@@ -406,6 +406,8 @@ public class OpenApiSerializerSession extends
UonSerializerSession {
sb.append(serialize(partType, items, Array.get(value, i)));
} else if (type.isCollection()) {
((Collection<?>)value).forEach(x -> sb.append(serialize(partType, items, x)));
+ } else if (type.isStreamable()) {
+ forEachStreamableEntry(value,
type, x -> sb.append(serialize(partType, items, x)));
} else if
(vt.hasMutaterTo(String[].class)) {
String[] ss = toType(value,
CM_StringArray);
for (var element : ss)
@@ -475,6 +477,8 @@ public class OpenApiSerializerSession extends
UonSerializerSession {
l.add(toObject(partType, Array.get(o, i),
items));
} else if (type.isCollection()) {
((Collection<?>)o).forEach(x ->
l.add(toObject(partType, x, items)));
+ } else if (type.isStreamable()) {
+ forEachStreamableEntry(o, type, x ->
l.add(toObject(partType, x, items)));
} else {
l.add(toObject(partType, o, items));
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
index ea57a7eac8..2b1079ec20 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
@@ -27,6 +27,7 @@ import java.lang.reflect.*;
import java.text.*;
import java.util.*;
import java.util.function.*;
+import java.util.stream.*;
import org.apache.juneau.*;
import org.apache.juneau.commons.collections.FluentMap;
import org.apache.juneau.commons.reflect.*;
@@ -431,6 +432,57 @@ public class SerializerSession extends BeanTraverseSession
{
m.entrySet().forEach(consumer);
}
+ /**
+ * Iterates over a streamable object (Iterator, Iterable, or Stream),
consuming each entry.
+ *
+ * <p>
+ * For collections, delegates to {@link #forEachEntry(Collection,
Consumer)} which supports sorting.
+ * For other streamable types, iterates lazily without materializing
into a List.
+ *
+ * @param o The streamable object.
+ * @param type The class meta for the object.
+ * @param consumer The entry consumer.
+ * @since 9.2.1
+ */
+ @SuppressWarnings({
+ "rawtypes", // Raw types necessary for generic streamable
handling
+ "unchecked" // Type erasure requires unchecked operations
+ })
+ public final void forEachStreamableEntry(Object o, ClassMeta<?> type,
Consumer consumer) {
+ if (o == null)
+ return;
+ if (type.isCollection()) {
+ forEachEntry((Collection)o, consumer);
+ } else if (type.isIterable()) {
+ ((Iterable)o).forEach(consumer);
+ } else if (type.isIterator()) {
+ if (o instanceof Enumeration e)
+ e.asIterator().forEachRemaining(consumer);
+ else
+ ((Iterator)o).forEachRemaining(consumer);
+ } else if (type.isStream()) {
+ ((Stream)o).forEach(consumer);
+ }
+ }
+
+ /**
+ * Converts a streamable object (Iterator, Iterable, or Stream) to a
List.
+ *
+ * <p>
+ * Used by serializers that need to know the collection size or inspect
elements before serializing
+ * (e.g. MsgPack, HTML, CSV).
+ *
+ * @param o The streamable object.
+ * @param type The class meta for the object.
+ * @return A new list containing all elements.
+ * @since 9.2.1
+ */
+ public final List<?> toListFromStreamable(Object o, ClassMeta<?> type) {
+ var list = new ArrayList<>();
+ forEachStreamableEntry(o, type, list::add);
+ return list;
+ }
+
/**
* Returns the listener associated with this session.
*
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/DefaultSwaps.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/DefaultSwaps.java
index bbcd132667..e223c20d0b 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/DefaultSwaps.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/DefaultSwaps.java
@@ -46,8 +46,6 @@ public class DefaultSwaps {
private static final Map<Class<?>,ObjectSwap<?,?>> SWAPS = new
ConcurrentHashMap<>();
static {
- SWAPS.put(Enumeration.class, new EnumerationSwap());
- SWAPS.put(Iterator.class, new IteratorSwap());
SWAPS.put(Locale.class, new LocaleSwap());
SWAPS.put(Class.class, new ClassSwap());
SWAPS.put(Calendar.class, new
TemporalCalendarSwap.IsoOffsetDateTime());
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/EnumerationSwap.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/EnumerationSwap.java
deleted file mode 100644
index b07011ebe3..0000000000
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/EnumerationSwap.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.swaps;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.swap.*;
-
-/**
- * Transforms {@link Enumeration Enumerations} to {@code List<Object>} objects.
- *
- * <p>
- * This is a one-way transform, since {@code Enumerations} cannot be
reconstituted.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink"
href="https://juneau.apache.org/docs/topics/SwapBasics">Swap Basics</a>
-
- * </ul>
- */
-@SuppressWarnings({
- "unchecked", // Type erasure requires unchecked casts in ObjectSwap
operations
- "rawtypes", // Raw types necessary for ObjectSwap implementation
-})
-public class EnumerationSwap extends ObjectSwap<Enumeration,List> {
-
- /**
- * Converts the specified {@link Enumeration} to a {@link List}.
- */
- @Override /* Overridden from ObjectSwap */
- public List swap(BeanSession session, Enumeration o) {
- var l = new LinkedList();
- while (o.hasMoreElements())
- l.add(o.nextElement());
- return l;
- }
-}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/IteratorSwap.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/IteratorSwap.java
deleted file mode 100644
index 641b1b8002..0000000000
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/IteratorSwap.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.swaps;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.swap.*;
-
-/**
- * Transforms {@link Iterator Iterators} to {@code List<Object>} objects.
- *
- * <p>
- * This is a one-way transform, since {@code Iterators} cannot be
reconstituted.
- *
- * <h5 class='section'>See Also:</h5><ul>
- * <li class='link'><a class="doclink"
href="https://juneau.apache.org/docs/topics/SwapBasics">Swap Basics</a>
-
- * </ul>
- */
-@SuppressWarnings({
- "unchecked", // Type erasure requires unchecked casts in ObjectSwap
operations
- "rawtypes", // Raw types necessary for ObjectSwap implementation
-})
-public class IteratorSwap extends ObjectSwap<Iterator,List> {
-
- /**
- * Converts the specified {@link Iterator} to a {@link List}.
- */
- @Override /* Overridden from ObjectSwap */
- public List swap(BeanSession session, Iterator o) {
- var l = new LinkedList();
- while (o.hasNext())
- l.add(o.next());
- return l;
- }
-}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
index 50d5c0f81a..fc3cd01be3 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
@@ -302,6 +302,27 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
return out;
}
+ private SerializerWriter serializeStreamable(UonWriter out, Object o,
ClassMeta<?> sType, ClassMeta<?> type) throws SerializeException {
+
+ var elementType = type.getElementType();
+
+ if (! plainTextParams)
+ out.append('@').append('(');
+
+ var addComma = Flag.create();
+ forEachStreamableEntry(o, sType, x -> {
+ addComma.ifSet(() -> out.append(',')).set();
+ out.cr(indent);
+ serializeAnything(out, x, elementType, "<iterator>",
null);
+ });
+
+ addComma.ifSet(() -> out.cre(indent - 1));
+ if (! plainTextParams)
+ out.append(')');
+
+ return out;
+ }
+
@SuppressWarnings({
"rawtypes", // Raw types necessary for generic collection/map
serialization
"unchecked", // Type erasure requires unchecked casts in
collection/map serialization
@@ -475,6 +496,8 @@ public class UonSerializerSession extends
WriterSerializerSession implements Htt
serializeCollection(out, (Collection)o, eType);
} else if (sType.isArray()) {
serializeCollection(out, toList(sType.inner(), o),
eType);
+ } else if (sType.isStreamable()) {
+ serializeStreamable(out, o, sType, eType);
} else if (sType.isReader()) {
pipe((Reader)o, out, SerializerSession::handleThrown);
} else if (sType.isInputStream()) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
index 6cd622ac49..fd89a59fec 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
@@ -266,6 +266,8 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
} else if (sType.isCollection() || sType.isArray()) {
var m = sType.isCollection() ?
getCollectionMap((Collection)o) : getCollectionMap(o);
serializeCollectionMap(out, m, getClassMeta(Map.class,
Integer.class, Object.class));
+ } else if (sType.isStreamable()) {
+ serializeStreamableAsCollectionMap(out, o, sType);
} else if (sType.isReader()) {
pipe((Reader)o, out);
} else if (sType.isInputStream()) {
@@ -349,6 +351,17 @@ public class UrlEncodingSerializerSession extends
UonSerializerSession {
return out;
}
+ private SerializerWriter serializeStreamableAsCollectionMap(UonWriter
out, Object o, ClassMeta<?> sType) throws SerializeException {
+ var addAmp = Flag.create();
+ var i = IntegerValue.create();
+ forEachStreamableEntry(o, sType, v -> {
+ addAmp.ifSet(() -> out.cr(indent).append('&')).set();
+ out.append(i.getAndIncrement()).append('=');
+ super.serializeAnything(out, v, null, null, null);
+ });
+ return out;
+ }
+
@SuppressWarnings({
"java:S1213" // Method name matches private method in parent
class by design for override behavior
})
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index 5402c4b613..bf132d8152 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -556,6 +556,35 @@ public class XmlSerializerSession extends
WriterSerializerSession {
return out;
}
+ private XmlWriter serializeStreamable(XmlWriter out, Object in,
ClassMeta<?> sType, ClassMeta<?> eType, BeanPropertyMeta ppMeta, boolean
isMixed) throws SerializeException {
+
+ var eeType = eType.getElementType();
+
+ var eName = Value.<String>empty();
+ var eNs = Value.<Namespace>empty();
+
+ if (nn(ppMeta)) {
+ XmlBeanPropertyMeta bpXml =
getXmlBeanPropertyMeta(ppMeta);
+ eName.set(bpXml.getChildName());
+ eNs.set(bpXml.getNamespace());
+ }
+
+ var previousWasTextNode = Value.of(false);
+
+ forEachStreamableEntry(in, sType, x -> {
+ var currentIsTextNode = isTextNode(x);
+
+ if (isTrue(previousWasTextNode.get()) &&
currentIsTextNode && nn(textNodeDelimiter) && ! textNodeDelimiter.isEmpty()) {
+ out.append(textNodeDelimiter);
+ }
+
+ serializeAnything(out, x, eeType, null, eName.get(),
eNs.get(), false, XmlFormat.DEFAULT, isMixed, false, null);
+ previousWasTextNode.set(currentIsTextNode);
+ });
+
+ return out;
+ }
+
private ContentResult serializeMap(XmlWriter out, Map m, ClassMeta<?>
sType, ClassMeta<?> eKeyType, ClassMeta<?> eValueType, boolean isMixed) throws
SerializeException {
var keyType = eKeyType == null ? sType.getKeyType() : eKeyType;
@@ -831,8 +860,8 @@ public class XmlSerializerSession extends
WriterSerializerSession {
isExpectedType = aType.isNumber();
else if (eType.isMap())
isExpectedType = aType.isMap();
- else if (eType.isCollectionOrArray())
- isExpectedType = aType.isCollectionOrArray();
+ else if (eType.isCollectionOrArray() ||
eType.isStreamable())
+ isExpectedType = aType.isCollectionOrArray() ||
aType.isStreamable();
else
isExpectedType = false;
}
@@ -864,7 +893,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
} else if (sType.isMapOrBean()) {
isCollapsed = getXmlClassMeta(sType).getFormat() ==
COLLAPSED;
type = OBJECT;
- } else if (sType.isCollectionOrArray()) {
+ } else if (sType.isCollectionOrArray() || sType.isStreamable())
{
isCollapsed = (format == COLLAPSED && !
addNamespaceUris);
type = ARRAY;
} else {
@@ -980,6 +1009,12 @@ public class XmlSerializerSession extends
WriterSerializerSession {
serializeCollection(out, o, sType, eType,
pMeta, isMixedOrText);
if (isCollapsed)
indent++;
+ } else if (sType.isStreamable()) {
+ if (isCollapsed)
+ indent--;
+ serializeStreamable(out, o, sType, eType,
pMeta, isMixedOrText);
+ if (isCollapsed)
+ indent++;
} else if (sType.isReader()) {
pipe((Reader)o, out,
SerializerSession::handleThrown);
} else if (sType.isInputStream()) {
diff --git
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java
index 63857c276d..24f65fdb63 100644
---
a/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java
+++
b/juneau-examples/juneau-examples-rest-jetty-ftest/src/test/java/org/apache/juneau/examples/rest/TestUtils.java
@@ -24,7 +24,6 @@ import java.util.regex.*;
import org.apache.juneau.json.*;
import org.apache.juneau.serializer.*;
-import org.apache.juneau.swaps.*;
import org.apache.juneau.xml.*;
import org.junit.*;
@@ -45,12 +44,10 @@ public class TestUtils {
private static JsonSerializer js2 = JsonSerializer.create()
.json5()
- .swaps(IteratorSwap.class, EnumerationSwap.class)
.build();
private static JsonSerializer js3 = JsonSerializer.create()
.json5()
- .swaps(IteratorSwap.class, EnumerationSwap.class)
.sortProperties()
.build();
// @formatter:on
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
index 1099b8a2f2..46a5f06e2f 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
@@ -25,7 +25,6 @@ import org.apache.juneau.rest.converter.*;
import org.apache.juneau.rest.servlet.*;
import org.apache.juneau.rest.widget.*;
import org.apache.juneau.serializer.annotation.*;
-import org.apache.juneau.swaps.*;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
@@ -65,12 +64,6 @@ import jakarta.servlet.http.*;
},
nowrap="false"
)
-@BeanConfig(
- swaps={
- // Add a special filter for Enumerations
- EnumerationSwap.class
- }
-)
@SerializerConfig(
maxDepth="5",
detectRecursions="true"
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/transforms/DefaultSwaps_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/transforms/DefaultSwaps_Test.java
index 1c1b43ea8f..1c8fd0da76 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/transforms/DefaultSwaps_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/transforms/DefaultSwaps_Test.java
@@ -68,7 +68,7 @@ class DefaultSwaps_Test extends TestBase {
}
//------------------------------------------------------------------------------------------------------------------
- // POJO_SWAPS.put(Enumeration.class, new EnumerationSwap())
+ // Enumeration - natively serialized as array
//------------------------------------------------------------------------------------------------------------------
private static final Vector<String> A = new Vector<>();
static {
@@ -138,7 +138,7 @@ class DefaultSwaps_Test extends TestBase {
}
//------------------------------------------------------------------------------------------------------------------
- // POJO_SWAPS.put(Iterator.class, new IteratorSwap())
+ // Iterator - natively serialized as array
//------------------------------------------------------------------------------------------------------------------
private static final List<String> B = l("foo","bar");
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/transforms/EnumerationSwapTest.java
b/juneau-utest/src/test/java/org/apache/juneau/transforms/EnumerationSwapTest.java
deleted file mode 100755
index e4382de8c2..0000000000
---
a/juneau-utest/src/test/java/org/apache/juneau/transforms/EnumerationSwapTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.transforms;
-
-import static org.apache.juneau.commons.utils.CollectionUtils.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.swaps.*;
-import org.junit.jupiter.api.*;
-
-class EnumerationSwapTest extends TestBase {
-
-
//====================================================================================================
- // test
-
//====================================================================================================
- @Test void a01_test() throws Exception {
- var s =
JsonSerializer.create().json5().swaps(EnumerationSwap.class).build();
- var v = new Vector<>(l(a("foo","bar","baz")));
- var e = v.elements();
- assertEquals("['foo','bar','baz']", s.serialize(e));
- }
-}
\ No newline at end of file
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/transforms/IteratorSwapTest.java
b/juneau-utest/src/test/java/org/apache/juneau/transforms/IteratorSwapTest.java
deleted file mode 100755
index f987a5e133..0000000000
---
a/juneau-utest/src/test/java/org/apache/juneau/transforms/IteratorSwapTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.transforms;
-
-import static org.apache.juneau.commons.utils.CollectionUtils.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.util.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.swaps.*;
-import org.junit.jupiter.api.*;
-
-class IteratorSwapTest extends TestBase {
-
-
//====================================================================================================
- // test
-
//====================================================================================================
- @Test void a01_test() throws Exception {
- var s =
JsonSerializer.create().json5().swaps(IteratorSwap.class).build();
-
- // Iterators
- var l = new ArrayList<>(l(a("foo","bar","baz")));
- var i = l.iterator();
- assertEquals("['foo','bar','baz']", s.serialize(i));
- }
-}
\ No newline at end of file
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/transforms/StreamableSerializationTest.java
b/juneau-utest/src/test/java/org/apache/juneau/transforms/StreamableSerializationTest.java
new file mode 100644
index 0000000000..704b9f2b7a
--- /dev/null
+++
b/juneau-utest/src/test/java/org/apache/juneau/transforms/StreamableSerializationTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.transforms;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+import java.util.stream.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.csv.*;
+import org.apache.juneau.html.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.msgpack.*;
+import org.apache.juneau.uon.*;
+import org.apache.juneau.xml.*;
+import org.junit.jupiter.api.*;
+
+class StreamableSerializationTest extends TestBase {
+
+ static final JsonSerializer JSON =
JsonSerializer.create().json5().build();
+ static final XmlSerializer XML =
XmlSerializer.create().sq().ns().build();
+ static final UonSerializer UON = UonSerializer.DEFAULT;
+ static final HtmlSerializer HTML = HtmlSerializer.create().sq().build();
+ static final MsgPackSerializer MSGPACK = MsgPackSerializer.DEFAULT;
+ static final CsvSerializer CSV = CsvSerializer.DEFAULT;
+
+
//====================================================================================================
+ // Iterator serialization with JSON (lazy path)
+
//====================================================================================================
+ @Test void a01_iteratorWithJson() throws Exception {
+ var i = List.of("foo", "bar", "baz").iterator();
+ assertEquals("['foo','bar','baz']", JSON.serialize(i));
+ }
+
+
//====================================================================================================
+ // Iterable (non-Collection) serialization with JSON
+
//====================================================================================================
+ @Test void a02_iterableWithJson() throws Exception {
+ Iterable<String> iterable = () -> List.of("foo", "bar",
"baz").iterator();
+ assertEquals("['foo','bar','baz']", JSON.serialize(iterable));
+ }
+
+
//====================================================================================================
+ // Stream serialization with JSON
+
//====================================================================================================
+ @Test void a03_streamWithJson() throws Exception {
+ var stream = Stream.of("foo", "bar", "baz");
+ assertEquals("['foo','bar','baz']", JSON.serialize(stream));
+ }
+
+
//====================================================================================================
+ // Iterator with XML serializer
+
//====================================================================================================
+ @Test void a04_iteratorWithXml() throws Exception {
+ var i = List.of("foo", "bar", "baz").iterator();
+ var result = XML.serialize(i);
+ assertTrue(result.contains("foo"), "XML output should contain
'foo': " + result);
+ assertTrue(result.contains("bar"), "XML output should contain
'bar': " + result);
+ assertTrue(result.contains("baz"), "XML output should contain
'baz': " + result);
+ }
+
+
//====================================================================================================
+ // Iterable with XML serializer
+
//====================================================================================================
+ @Test void a05_iterableWithXml() throws Exception {
+ Iterable<String> iterable = () -> List.of("foo", "bar",
"baz").iterator();
+ var result = XML.serialize(iterable);
+ assertTrue(result.contains("foo"), "XML output should contain
'foo': " + result);
+ assertTrue(result.contains("bar"), "XML output should contain
'bar': " + result);
+ }
+
+
//====================================================================================================
+ // Stream with XML serializer
+
//====================================================================================================
+ @Test void a06_streamWithXml() throws Exception {
+ var stream = Stream.of("foo", "bar", "baz");
+ var result = XML.serialize(stream);
+ assertTrue(result.contains("foo"), "XML output should contain
'foo': " + result);
+ assertTrue(result.contains("baz"), "XML output should contain
'baz': " + result);
+ }
+
+
//====================================================================================================
+ // Iterator with UON serializer
+
//====================================================================================================
+ @Test void a07_iteratorWithUon() throws Exception {
+ var i = List.of("foo", "bar", "baz").iterator();
+ assertEquals("@(foo,bar,baz)", UON.serialize(i));
+ }
+
+
//====================================================================================================
+ // Iterator with MsgPack serializer (materialized path)
+
//====================================================================================================
+ @Test void a08_iteratorWithMsgPack() throws Exception {
+ var i = List.of("foo", "bar", "baz").iterator();
+ var result = MSGPACK.serialize(i);
+ assertNotNull(result);
+ assertTrue(result.length > 0, "MsgPack output should not be
empty");
+ }
+
+
//====================================================================================================
+ // Iterator with HTML serializer (materialized path)
+
//====================================================================================================
+ @Test void a09_iteratorWithHtml() throws Exception {
+ var i = List.of("foo", "bar", "baz").iterator();
+ var result = HTML.serialize(i);
+ assertTrue(result.contains("foo"), "HTML output should contain
'foo': " + result);
+ assertTrue(result.contains("bar"), "HTML output should contain
'bar': " + result);
+ assertTrue(result.contains("baz"), "HTML output should contain
'baz': " + result);
+ }
+
+
//====================================================================================================
+ // Stream with HTML serializer
+
//====================================================================================================
+ @Test void a10_streamWithHtml() throws Exception {
+ var stream = Stream.of("foo", "bar", "baz");
+ var result = HTML.serialize(stream);
+ assertTrue(result.contains("foo"), "HTML output should contain
'foo': " + result);
+ assertTrue(result.contains("baz"), "HTML output should contain
'baz': " + result);
+ }
+
+
//====================================================================================================
+ // Iterator with CSV serializer
+
//====================================================================================================
+ @Test void a11_iteratorWithCsv() throws Exception {
+ var i = List.of("foo", "bar", "baz").iterator();
+ var result = CSV.serialize(i);
+ assertTrue(result.contains("foo"), "CSV output should contain
'foo': " + result);
+ assertTrue(result.contains("bar"), "CSV output should contain
'bar': " + result);
+ }
+
+
//====================================================================================================
+ // Empty Iterator edge case
+
//====================================================================================================
+ @Test void a12_emptyIterator() throws Exception {
+ var i = Collections.emptyIterator();
+ assertEquals("[]", JSON.serialize(i));
+ }
+
+
//====================================================================================================
+ // Empty Stream edge case
+
//====================================================================================================
+ @Test void a13_emptyStream() throws Exception {
+ var stream = Stream.empty();
+ assertEquals("[]", JSON.serialize(stream));
+ }
+
+
//====================================================================================================
+ // Numeric Iterator
+
//====================================================================================================
+ @Test void a14_numericIterator() throws Exception {
+ var i = List.of(1, 2, 3).iterator();
+ assertEquals("[1,2,3]", JSON.serialize(i));
+ }
+
+
//====================================================================================================
+ // Iterable with UON serializer
+
//====================================================================================================
+ @Test void a15_iterableWithUon() throws Exception {
+ Iterable<String> iterable = () -> List.of("foo", "bar",
"baz").iterator();
+ assertEquals("@(foo,bar,baz)", UON.serialize(iterable));
+ }
+
+
//====================================================================================================
+ // Stream with UON serializer
+
//====================================================================================================
+ @Test void a16_streamWithUon() throws Exception {
+ var stream = Stream.of("foo", "bar", "baz");
+ assertEquals("@(foo,bar,baz)", UON.serialize(stream));
+ }
+
+
//====================================================================================================
+ // Enumeration serialization (backward compat via native support)
+
//====================================================================================================
+ @Test void a17_enumerationWithJson() throws Exception {
+ var v = new Vector<>(List.of("foo", "bar", "baz"));
+ var e = v.elements();
+ var result = JSON.serialize(e);
+ assertEquals("['foo','bar','baz']", result);
+ }
+
+
//====================================================================================================
+ // Stream with MsgPack serializer (materialized path)
+
//====================================================================================================
+ @Test void a19_streamWithMsgPack() throws Exception {
+ var stream = Stream.of("foo", "bar", "baz");
+ var result = MSGPACK.serialize(stream);
+ assertNotNull(result);
+ assertTrue(result.length > 0, "MsgPack output should not be
empty");
+ }
+
+
//====================================================================================================
+ // Iterable with MsgPack serializer (materialized path)
+
//====================================================================================================
+ @Test void a20_iterableWithMsgPack() throws Exception {
+ Iterable<String> iterable = () -> List.of("foo", "bar",
"baz").iterator();
+ var result = MSGPACK.serialize(iterable);
+ assertNotNull(result);
+ assertTrue(result.length > 0, "MsgPack output should not be
empty");
+ }
+
+
//====================================================================================================
+ // Mixed-type Iterator
+
//====================================================================================================
+ @Test void a21_mixedTypeIterator() throws Exception {
+ var i = List.<Object>of("foo", 123, true).iterator();
+ assertEquals("['foo',123,true]", JSON.serialize(i));
+ }
+
+
//====================================================================================================
+ // Iterable with CSV serializer
+
//====================================================================================================
+ @Test void a22_iterableWithCsv() throws Exception {
+ Iterable<String> iterable = () -> List.of("foo", "bar",
"baz").iterator();
+ var result = CSV.serialize(iterable);
+ assertTrue(result.contains("foo"), "CSV output should contain
'foo': " + result);
+ }
+
+
//====================================================================================================
+ // Stream with CSV serializer
+
//====================================================================================================
+ @Test void a23_streamWithCsv() throws Exception {
+ var stream = Stream.of("foo", "bar", "baz");
+ var result = CSV.serialize(stream);
+ assertTrue(result.contains("foo"), "CSV output should contain
'foo': " + result);
+ }
+}