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 dd0ea450aa Bean API improvements
dd0ea450aa is described below
commit dd0ea450aa905c19093046315b98d1e12934bb1d
Author: James Bognar <[email protected]>
AuthorDate: Mon Feb 2 11:12:28 2026 -0500
Bean API improvements
---
.../juneau/commons/utils/CollectionUtils.java | 57 ++++++++++++++++++++--
.../src/main/java/org/apache/juneau/BeanMeta.java | 2 +-
.../src/main/java/org/apache/juneau/ClassMeta.java | 8 ++-
.../org/apache/juneau/collections/JsonMap.java | 2 +-
.../apache/juneau/csv/CsvSerializerSession.java | 4 +-
.../main/java/org/apache/juneau/parser/Parser.java | 2 +-
.../org/apache/juneau/serializer/Serializer.java | 2 +-
.../juneau/commons/utils/CollectionUtils_Test.java | 16 +++---
8 files changed, 71 insertions(+), 22 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
index 6a2a3e5eac..789eafb829 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/CollectionUtils.java
@@ -710,14 +710,61 @@ public class CollectionUtils {
}
/**
- * Returns the first element in a list.
+ * Returns the next value from an iterator, or an empty Optional if
there are no more elements.
+ *
+ * <p>
+ * This is a null-safe operation. Returns an empty Optional if the
iterator is <jk>null</jk> or
+ * has no more elements.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * Iterator<String> <jv>it</jv> = list.iterator();
+ * Optional<String> <jv>first</jv> =
<jsm>next</jsm>(<jv>it</jv>); <jc>// Optional.of("first")</jc>
+ * Optional<String> <jv>second</jv> =
<jsm>next</jsm>(<jv>it</jv>); <jc>// Optional.of("second")</jc>
+ * Optional<String> <jv>empty</jv> =
<jsm>next</jsm>(<jv>it</jv>); <jc>// Optional.empty()</jc>
+ * Optional<String> <jv>nullResult</jv> =
<jsm>next</jsm>(<jk>null</jk>); <jc>// Optional.empty()</jc>
+ * </p>
*
* @param <E> The element type.
- * @param l The list. Can be <jk>null</jk>.
- * @return The first element in the list, or <jk>null</jk> if the list
is <jk>null</jk> or empty.
+ * @param iterator The iterator. Can be <jk>null</jk>.
+ * @return An Optional containing the next element, or empty if the
iterator is <jk>null</jk> or has no more elements.
*/
- public static <E> E first(List<E> l) {
- return e(l) ? null : l.get(0);
+ public static <E> Optional<E> next(Iterator<? extends E> iterator) {
+ if (iterator == null || !iterator.hasNext())
+ return Optional.empty();
+ return Optional.of(iterator.next());
+ }
+
+ /**
+ * Returns the first element in an iterable.
+ *
+ * <p>
+ * This is a null-safe operation. Returns an empty Optional if the
iterable is <jk>null</jk> or empty.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * List<String> <jv>list</jv> = <jsm>l</jsm>(<js>"a"</js>,
<js>"b"</js>, <js>"c"</js>);
+ * Optional<String> <jv>first</jv> =
<jsm>first</jsm>(<jv>list</jv>); <jc>// Optional.of("a")</jc>
+ *
+ * Set<Integer> <jv>set</jv> = <jsm>s</jsm>(1, 2, 3);
+ * Optional<Integer> <jv>firstInt</jv> =
<jsm>first</jsm>(<jv>set</jv>); <jc>// Optional.of(1) or another element</jc>
+ *
+ * EnumSet<MyEnum> <jv>enumSet</jv> =
EnumSet.allOf(MyEnum.<jk>class</jk>);
+ * Optional<MyEnum> <jv>firstEnum</jv> =
<jsm>first</jsm>(<jv>enumSet</jv>); <jc>// Optional.of(first enum value)</jc>
+ *
+ * Optional<String> <jv>empty</jv> =
<jsm>first</jsm>(Collections.emptyList()); <jc>// Optional.empty()</jc>
+ * Optional<String> <jv>nullResult</jv> =
<jsm>first</jsm>(<jk>null</jk>); <jc>// Optional.empty()</jc>
+ * </p>
+ *
+ * @param <E> The element type.
+ * @param iterable The iterable. Can be <jk>null</jk>.
+ * @return An Optional containing the first element, or empty if the
iterable is <jk>null</jk> or empty.
+ */
+ public static <E> Optional<E> first(Iterable<? extends E> iterable) {
+ if (iterable == null)
+ return Optional.empty();
+ Iterator<? extends E> iterator = iterable.iterator();
+ return next(iterator);
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index a463f0c192..f65483bfa0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -956,7 +956,7 @@ public class BeanMeta<T> {
if (l.size() > 1)
throw bex(ci, "Multiple instances of '@Beanc' found.");
if (l.size() == 1) {
- var con = l.get(0).accessible();
+ var con = first(l).get().accessible();
var args = ap.find(Beanc.class, con).stream().map(x ->
x.inner().properties()).filter(StringUtils::isNotBlank).map(x ->
split(x)).findFirst().orElse(liste());
if (! con.hasNumParameters(args.size())) {
if (ne(args))
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 7de64f3665..2c9efd9337 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
@@ -1284,8 +1284,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
if (ci.isAssignableTo(Surrogate.class)) {
List<SurrogateSwap<?,?>> l =
SurrogateSwap.findObjectSwaps(c, beanContext);
- if (! l.isEmpty())
- return (ObjectSwap<T,?>)l.iterator().next();
+ return first(l).map(x ->
(ObjectSwap<T,?>)x).orElse(null);
}
throw new ClassMetaRuntimeException(c, "Invalid swap class
''{0}'' specified. Must extend from ObjectSwap or Surrogate.", c);
@@ -1410,7 +1409,6 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
return m.build();
}
- @SuppressWarnings("unchecked")
private String findExample() {
var example = beanMeta.get().optBeanMeta().map(x ->
x.getBeanFilter()).map(x -> x.getExample()).orElse(null);
@@ -1429,8 +1427,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
} else if (cat.is(CHARSEQ)) {
example = "foo";
} else if (cat.is(ENUM)) {
- Iterator<? extends Enum<?>> i =
EnumSet.allOf(asEnumClass(inner())).iterator();
- example = i.hasNext() ?
(beanContext.isUseEnumNames() ? i.next().name() : i.next().toString()) : null;
+ Optional<Enum<?>> e =
first(EnumSet.allOf(asEnumClass(inner())));
+ example = e.map(x ->
beanContext.isUseEnumNames() ? x.name() : x.toString()).orElse(null);
} else if (isAny(float.class, Float.class,
double.class, Double.class)) {
example = "1.0";
} else if (isAny(short.class, Short.class, int.class,
Integer.class, long.class, Long.class)) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/collections/JsonMap.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/collections/JsonMap.java
index 659ed8249d..37e431a2f5 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/collections/JsonMap.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/collections/JsonMap.java
@@ -1104,7 +1104,7 @@ public class JsonMap extends LinkedHashMap<String,Object>
{
*
* @return The first key in the map, or <jk>null</jk> if the map is
empty.
*/
- public String getFirstKey() { return isEmpty() ? null :
keySet().iterator().next(); }
+ public String getFirstKey() { return first(keySet()).orElse(null); }
/**
* Returns the specified entry value converted to an {@link Integer}.
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 e4830be95f..2f9c6c6bb8 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,7 +236,7 @@ public class CsvSerializerSession extends
WriterSerializerSession {
// TODO - Doesn't support DynaBeans.
if (ne(l)) {
- var entryType =
getClassMetaForObject(l.iterator().next());
+ var entryType =
getClassMetaForObject(first(l).get());
if (entryType.isBean()) {
var bm = entryType.getBeanMeta();
var addComma = Flag.create();
@@ -264,7 +264,7 @@ public class CsvSerializerSession extends
WriterSerializerSession {
});
} else if (entryType.isMap()) {
var addComma = Flag.create();
- var first = (Map)l.iterator().next();
+ var first = (Map)first(l).get();
first.keySet().forEach(x -> {
addComma.ifSet(() ->
w.w(',')).set();
w.writeEntry(x);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
index 4d4379e5fb..4794d121ef 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
@@ -1080,7 +1080,7 @@ public class Parser extends BeanContextable {
*
* @return The media type.
*/
- public final MediaType getPrimaryMediaType() { return
consumesArray.isEmpty() ? null : consumesArray.get(0); }
+ public final MediaType getPrimaryMediaType() { return
first(consumesArray).orElse(null); }
@Override /* Overridden from Context */
public ParserSession getSession() { return createSession().build(); }
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
index 7566dce830..f49cca7425 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
@@ -1364,7 +1364,7 @@ public class Serializer extends BeanTraverseContext {
*
* @return The media type. Never <jk>null</jk>.
*/
- public final MediaType getPrimaryMediaType() { return
acceptMediaTypes.get(0); }
+ public final MediaType getPrimaryMediaType() { return
first(acceptMediaTypes).get(); }
/**
* Optional method that returns the response <c>Content-Type</c> for
this serializer if it is different from
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
index 314240a6ea..8e59d8f108 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/CollectionUtils_Test.java
@@ -555,15 +555,20 @@ class CollectionUtils_Test extends TestBase {
}
//====================================================================================================
- // first(List<E>)
+ // first(Iterable<E>)
//====================================================================================================
@Test
void a031_first() {
- List<String> list = list("a", "b", "c");
- assertEquals("a", first(list));
+ var list = list("a", "b", "c");
+ assertEquals(Optional.of("a"), first(list));
+
+ assertEquals(Optional.empty(), first(null));
+ assertEquals(Optional.empty(), first(list()));
- assertNull(first(null));
- assertNull(first(list()));
+ // Test with Set
+ var set = set(1, 2, 3);
+ assertTrue(first(set).isPresent());
+ assertTrue(set.contains(first(set).get()));
}
//====================================================================================================
@@ -1297,7 +1302,6 @@ class CollectionUtils_Test extends TestBase {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("b");
- @SuppressWarnings("cast")
List<?> result1 = toList((Object)arrayList);
assertSame(arrayList, result1);