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 4caf3f5877 juneau-marshall improvements
4caf3f5877 is described below
commit 4caf3f58777f21379fde0efc3186c98eeb05ebf9
Author: James Bognar <[email protected]>
AuthorDate: Thu Dec 18 13:26:46 2025 -0500
juneau-marshall improvements
---
AI.md | 5 +
.../juneau/bean/openapi3/SecurityRequirement.java | 2 +-
.../annotation/AppliedAnnotationObject.java | 42 +--
.../apache/juneau/commons/reflect/ClassInfo.java | 9 +-
.../apache/juneau/commons/settings/Settings.java | 2 +-
.../juneau/commons/utils/AssertionUtils.java | 32 +-
.../main/java/org/apache/juneau/config/Config.java | 2 +-
.../java/org/apache/juneau/jena/RdfSerializer.java | 2 +-
.../main/java/org/apache/juneau/BeanContext.java | 370 +++++++++++--------
.../java/org/apache/juneau/BeanContextable.java | 18 +-
.../src/main/java/org/apache/juneau/BeanMeta.java | 4 +-
.../java/org/apache/juneau/BeanPropertyMeta.java | 3 +-
.../java/org/apache/juneau/BeanPropertyValue.java | 1 -
.../apache/juneau/BeanProxyInvocationHandler.java | 94 ++++-
.../main/java/org/apache/juneau/BeanRegistry.java | 26 +-
.../main/java/org/apache/juneau/BeanSession.java | 30 +-
.../src/main/java/org/apache/juneau/ClassMeta.java | 8 +-
.../src/main/java/org/apache/juneau/Context.java | 12 +-
.../java/org/apache/juneau/ContextSession.java | 2 +-
.../apache/juneau/httppart/BaseHttpPartParser.java | 2 +-
.../juneau/jsonschema/JsonSchemaGenerator.java | 14 +-
.../main/java/org/apache/juneau/parser/Parser.java | 13 +-
.../org/apache/juneau/serializer/Serializer.java | 6 +-
.../java/org/apache/juneau/xml/XmlSerializer.java | 15 +-
.../apache/juneau/xml/XmlSerializerSession.java | 9 +-
.../org/apache/juneau/rest/client/RestClient.java | 8 +-
.../org/apache/juneau/rest/client/RestRequest.java | 2 +-
.../java/org/apache/juneau/rest/RestContext.java | 36 +-
.../java/org/apache/juneau/rest/RestOpContext.java | 42 +--
.../java/org/apache/juneau/BeanContext_Test.java | 109 ++++++
.../org/apache/juneau/BeanPropertyValue_Test.java | 105 ++++++
.../juneau/BeanProxyInvocationHandler_Test.java | 405 +++++++++++++++++++++
.../annotation/BeanConfigAnnotation_Test.java | 7 +-
.../juneau/commons/collections/MultiSet_Test.java | 3 +-
.../juneau/commons/utils/AssertionUtils_Test.java | 14 +-
35 files changed, 1125 insertions(+), 329 deletions(-)
diff --git a/AI.md b/AI.md
index 33f4585ef1..af9c22b464 100644
--- a/AI.md
+++ b/AI.md
@@ -31,6 +31,11 @@ This document outlines the rules, guidelines, and best
practices that AI assista
## Core Working Principles
+### 0. Change Evaluation
+- After each code modification, provide a brief (1-2 sentence) evaluation of
the change
+- Explain what was changed and why it improves the codebase
+- This helps document the reasoning behind modifications and ensures changes
are intentional
+
### 1. Code Quality and Consistency
- Follow existing code patterns and conventions
- Maintain consistency with the existing codebase
diff --git
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
index 93c91ae776..2adc3fd0df 100644
---
a/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
+++
b/juneau-bean/juneau-bean-openapi-v3/src/main/java/org/apache/juneau/bean/openapi3/SecurityRequirement.java
@@ -60,7 +60,7 @@ public class SecurityRequirement extends OpenApiElement {
*/
public SecurityRequirement addRequirement(String schemeName,
String...scopes) {
assertArgNotNull("schemeName", schemeName);
- assertVarargsNotNull("scopes", scopes);
+ assertArgNoNulls("scopes", scopes);
if (requirements == null)
requirements = new LinkedHashMap<>();
requirements.put(schemeName, l(scopes));
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
index 6e43ea6f3e..a90dc7924c 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/annotation/AppliedAnnotationObject.java
@@ -168,7 +168,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public Builder on(String...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
for (var v : values)
on = addAll(on, v);
return this;
@@ -214,7 +214,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderC on(Constructor<?>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -227,7 +227,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderC on(ConstructorInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -274,7 +274,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderM on(Method...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -287,7 +287,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderM on(MethodInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -337,7 +337,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderMF on(Field...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -350,7 +350,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderMF on(FieldInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -363,7 +363,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderMF on(Method...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -376,7 +376,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderMF on(MethodInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -432,7 +432,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderT on(Class<?>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on = addAll(on, v.getName());
return this;
@@ -445,7 +445,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderT on(ClassInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on = addAll(on, cn(v));
return this;
@@ -459,7 +459,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
*/
@SuppressWarnings("unchecked")
public BuilderT onClass(Class<?>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
onClass = addAll(onClass, v);
return this;
@@ -473,7 +473,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
*/
@SuppressWarnings("unchecked")
public BuilderT onClass(ClassInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
onClass = addAll(onClass, v.inner());
return this;
@@ -514,7 +514,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTM on(Method...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -527,7 +527,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTM on(MethodInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -582,7 +582,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTMF on(Field...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -595,7 +595,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTMF on(FieldInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -608,7 +608,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTMF on(Method...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -621,7 +621,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTMF on(MethodInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
@@ -665,7 +665,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTMFC on(Constructor<?>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(info(v).getFullName());
return this;
@@ -678,7 +678,7 @@ public class AppliedAnnotationObject extends
AnnotationObject {
* @return This object.
*/
public BuilderTMFC on(ConstructorInfo...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
on(v.getFullName());
return this;
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
index 062c8ed55e..411abc63ca 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/reflect/ClassInfo.java
@@ -65,7 +65,7 @@ import org.apache.juneau.commons.collections.*;
*
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
-public class ClassInfo extends ElementInfo implements Annotatable, Type {
+public class ClassInfo extends ElementInfo implements Annotatable, Type,
Comparable<ClassInfo> {
private static final Cache<Class,ClassInfoTyped> CACHE =
Cache.of(Class.class, ClassInfoTyped.class).build();
@@ -495,6 +495,13 @@ public class ClassInfo extends ElementInfo implements
Annotatable, Type {
return (o instanceof ClassInfo o2) && eq(this, o2, (x, y) ->
eq(x.innerType, y.innerType));
}
+ @Override
+ public int compareTo(ClassInfo o) {
+ if (o == null)
+ return 1;
+ return getName().compareTo(o.getName());
+ }
+
/**
* Returns all fields on this class and all parent classes.
*
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
index 187645e70a..45876c2a19 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
@@ -224,7 +224,7 @@ public class Settings {
*/
@SafeVarargs
public final Builder setSources(SettingSource...sources) {
- assertVarargsNotNull("sources", sources);
+ assertArgNoNulls("sources", sources);
this.sources.clear();
for (var source : sources) {
this.sources.add(source);
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
index 514accf17f..7d853f9afc 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/AssertionUtils.java
@@ -16,6 +16,8 @@
*/
package org.apache.juneau.commons.utils;
+import java.util.Collection;
+
import static org.apache.juneau.commons.utils.ThrowableUtils.*;
import static org.apache.juneau.commons.utils.Utils.*;
@@ -349,11 +351,39 @@ public class AssertionUtils {
* @return The same object.
* @throws IllegalArgumentException Thrown if the specified varargs
array or any of its elements are <jk>null</jk>.
*/
- public static final <T> T[] assertVarargsNotNull(String name, T[] o)
throws IllegalArgumentException {
+ public static final <T> T[] assertArgNoNulls(String name, T[] o) throws
IllegalArgumentException {
assertArgNotNull(name, o);
for (var i = 0; i < o.length; i++)
assertArg(nn(o[i]), "Argument ''{0}'' parameter {1}
cannot be null.", name, i);
return o;
}
+ /**
+ * Throws an {@link IllegalArgumentException} if the specified
collection or any of its elements are <jk>null</jk>.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jk>import static</jk>
org.apache.juneau.commons.utils.AssertionUtils.*;
+ *
+ * <jk>public</jk> <jk>void</jk> setValues(List<String>
<jv>values</jv>) {
+ *
<jsm>assertCollectionArgNotNull</jsm>(<js>"values"</js>, <jv>values</jv>);
+ * ...
+ * }
+ * </p>
+ *
+ * @param <T> The element type.
+ * @param <C> The collection type.
+ * @param name The argument name.
+ * @param collection The collection to check.
+ * @return The same collection.
+ * @throws IllegalArgumentException Thrown if the specified collection
or any of its elements are <jk>null</jk>.
+ */
+ public static final <T, C extends Collection<T>> C
assertArgNoNulls(String name, C collection) throws IllegalArgumentException {
+ assertArgNotNull(name, collection);
+ var i = 0;
+ for (var element : collection)
+ assertArg(nn(element), "Argument ''{0}'' element at
index {1} cannot be null.", name, i++);
+ return collection;
+ }
+
}
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
index c01668f259..695850d4b3 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/Config.java
@@ -266,7 +266,7 @@ public class Config extends Context implements
ConfigEventListener {
* @return This object.
*/
public Builder mods(Mod...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
for (var value : values)
mods.put(value.getId(), value);
return this;
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
index 9b33a74512..2ef5a9a577 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
@@ -1182,7 +1182,7 @@ public class RdfSerializer extends WriterSerializer
implements RdfMetaProvider {
* @return This object.
*/
public Builder namespaces(Namespace...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
namespaces = addAll(namespaces, values);
return this;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 703c5837d7..9c604844d4 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -23,7 +23,6 @@ import static org.apache.juneau.commons.utils.ClassUtils.*;
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 static java.util.Comparator.*;
import java.beans.*;
import java.io.*;
@@ -175,18 +174,6 @@ public class BeanContext extends Context {
private static final Cache<HashKey,BeanContext> CACHE =
Cache.of(HashKey.class, BeanContext.class).build();
- private static Set<Class<?>> classSet() {
- return new TreeSet<>(comparing(Class::getName));
- }
-
- private static Set<Class<?>> toClassSet(Collection<Class<?>>
copy) {
- if (copy == null)
- return null;
- var x = classSet();
- x.addAll(copy);
- return x;
- }
-
private Visibility beanClassVisibility;
private Visibility beanConstructorVisibility;
private Visibility beanMethodVisibility;
@@ -213,9 +200,9 @@ public class BeanContext extends Context {
private Locale locale;
private TimeZone timeZone;
private Class<? extends PropertyNamer> propertyNamer;
- private List<Class<?>> beanDictionary;
+ private List<ClassInfo> beanDictionary;
private List<Object> swaps;
- private Set<Class<?>> notBeanClasses;
+ private Set<ClassInfo> notBeanClasses;
private Set<String> notBeanPackages;
/**
@@ -245,7 +232,7 @@ public class BeanContext extends Context {
ignoreUnknownEnumValues =
env("BeanContext.ignoreUnknownEnumValues", false);
locale = env("BeanContext.locale").map(x ->
Locale.forLanguageTag(x)).orElse(Locale.getDefault());
mediaType = env("BeanContext.mediaType").map(x ->
MediaType.of(x)).orElse(null);
- notBeanClasses = classSet();
+ notBeanClasses = new TreeSet<>();
notBeanPackages = new TreeSet<>();
propertyNamer = null;
sortProperties = env("BeanContext.sortProperties",
false);
@@ -284,7 +271,7 @@ public class BeanContext extends Context {
ignoreUnknownEnumValues =
copyFrom.ignoreUnknownEnumValues;
locale = copyFrom.locale;
mediaType = copyFrom.mediaType;
- notBeanClasses = toClassSet(copyFrom.notBeanClasses);
+ notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
notBeanPackages = toSortedSet(copyFrom.notBeanPackages,
false);
propertyNamer = copyFrom.propertyNamer;
sortProperties = copyFrom.sortProperties;
@@ -323,7 +310,7 @@ public class BeanContext extends Context {
ignoreUnknownEnumValues =
copyFrom.ignoreUnknownEnumValues;
locale = copyFrom.locale;
mediaType = copyFrom.mediaType;
- notBeanClasses = toClassSet(copyFrom.notBeanClasses);
+ notBeanClasses = new TreeSet<>(copyFrom.notBeanClasses);
notBeanPackages = toSortedSet(copyFrom.notBeanPackages);
propertyNamer = copyFrom.propertyNamer;
sortProperties = copyFrom.sortProperties;
@@ -462,7 +449,7 @@ public class BeanContext extends Context {
* @return The bean dictionary list.
* @see #beanDictionary(Class...)
*/
- public List<Class<?>> beanDictionary() {
+ public List<ClassInfo> beanDictionary() {
return beanDictionary;
}
@@ -549,7 +536,7 @@ public class BeanContext extends Context {
* <li class='ja'>{@link
org.apache.juneau.annotation.Beanp#dictionary()}
* <li class='ja'>{@link
org.apache.juneau.annotation.BeanConfig#dictionary()}
* <li class='ja'>{@link
org.apache.juneau.annotation.BeanConfig#dictionary_replace()}
- * <li class='jm'>{@link
org.apache.juneau.BeanContext.Builder#beanDictionary(Class...)}
+ * <li class='jm'>{@link
org.apache.juneau.BeanContext.Builder#beanDictionary(ClassInfo...)}
* </ul>
*
* @param values
@@ -557,26 +544,40 @@ public class BeanContext extends Context {
* <br>Cannot contain <jk>null</jk> values.
* @return This object.
*/
- public Builder beanDictionary(Class<?>...values) {
- assertVarargsNotNull("values", values);
+ public Builder beanDictionary(ClassInfo...values) {
+ assertArgNoNulls("values", values);
return beanDictionary(l(values));
}
/**
- * Same as {@link #beanDictionary(Class...)} but allows you to
pass in a collection of classes.
+ * Same as {@link #beanDictionary(ClassInfo...)} but allows you
to pass in a collection of class info objects.
*
* @param values
* The values to add to this setting.
- * <br>Cannot be <jk>null</jk>.
+ * <br>Cannot be <jk>null</jk> or contain <jk>null</jk>
values.
* @return This object.
- * @see #beanDictionary(Class...)
+ * @see #beanDictionary(ClassInfo...)
*/
- public Builder beanDictionary(Collection<Class<?>> values) {
- assertArgNotNull("values", values);
+ public Builder beanDictionary(Collection<ClassInfo> values) {
+ assertArgNoNulls("values", values);
beanDictionary().addAll(0, values);
return this;
}
+ /**
+ * Convenience method for {@link #beanDictionary(ClassInfo...)}
that accepts {@link Class} objects.
+ *
+ * @param values
+ * The values to add to this setting.
+ * <br>Cannot contain <jk>null</jk> values.
+ * @return This object.
+ * @see #beanDictionary(ClassInfo...)
+ */
+ public Builder beanDictionary(Class<?>...values) {
+ assertArgNoNulls("values", values);
+ return
beanDictionary(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new));
+ }
+
/**
* Minimum bean field visibility.
*
@@ -1733,7 +1734,7 @@ public class BeanContext extends Context {
*/
public Builder dictionaryOn(Class<?> on, Class<?>...values) {
assertArgNotNull("on", on);
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
return
annotations(BeanAnnotation.create(on).dictionary(values).build());
}
@@ -2549,7 +2550,7 @@ public class BeanContext extends Context {
* @return This object.
*/
public Builder interfaces(Class<?>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
for (var v : value)
annotations(BeanAnnotation.create(v).interfaceClass(v).build());
return this;
@@ -2642,15 +2643,15 @@ public class BeanContext extends Context {
}
/**
- * Returns the list of not-bean classes.
+ * Returns the set of not-bean classes.
*
* <p>
- * Gives access to the inner list if you need to make more than
simple additions via {@link #notBeanClasses(Class...)}.
+ * Gives access to the inner set if you need to make more than
simple additions via {@link #notBeanClasses(ClassInfo...)}.
*
- * @return The list of not-bean classes.
- * @see #notBeanClasses(Class...)
+ * @return The set of not-bean classes.
+ * @see #notBeanClasses(ClassInfo...)
*/
- public Set<Class<?>> notBeanClasses() {
+ public Set<ClassInfo> notBeanClasses() {
return notBeanClasses;
}
@@ -2700,31 +2701,44 @@ public class BeanContext extends Context {
*
* @param values
* The values to add to this setting.
- * <br>Values can consist of any of the following types:
- * <ul>
- * <li>Classes.
- * <li>Arrays and collections of classes.
- * </ul>
+ * <br>Cannot contain <jk>null</jk> values.
* @return This object.
*/
- public Builder notBeanClasses(Class<?>...values) {
- return notBeanClasses(l(values));
+ public Builder notBeanClasses(ClassInfo...values) {
+ assertArgNoNulls("values", values);
+ notBeanClasses().addAll(l(values));
+ return this;
}
/**
- * Same as {@link #notBeanClasses(Class...)} but allows you to
pass in a collection of classes.
+ * Same as {@link #notBeanClasses(ClassInfo...)} but allows you
to pass in a collection of class info objects.
*
* @param values
* The values to add to this setting.
+ * <br>Cannot be <jk>null</jk> or contain <jk>null</jk>
values.
* @return This object.
- * @see #notBeanClasses(Class...)
+ * @see #notBeanClasses(ClassInfo...)
*/
- public Builder notBeanClasses(Collection<Class<?>> values) {
- assertArgNotNull("values", values);
+ public Builder notBeanClasses(Collection<ClassInfo> values) {
+ assertArgNoNulls("values", values);
notBeanClasses().addAll(values);
return this;
}
+ /**
+ * Convenience method for {@link #notBeanClasses(ClassInfo...)}
that accepts {@link Class} objects.
+ *
+ * @param values
+ * The values to add to this setting.
+ * <br>Cannot contain <jk>null</jk> values.
+ * @return This object.
+ * @see #notBeanClasses(ClassInfo...)
+ */
+ public Builder notBeanClasses(Class<?>...values) {
+ assertArgNoNulls("values", values);
+ return
notBeanClasses(Stream.of(values).map(ReflectionUtils::info).toArray(ClassInfo[]::new));
+ }
+
/**
* Returns the list of not-bean Java package names.
*
@@ -2743,12 +2757,12 @@ public class BeanContext extends Context {
*
* @param values
* The values to add to this setting.
- * <br>Cannot be <jk>null</jk>.
+ * <br>Cannot be <jk>null</jk> or contain <jk>null</jk>
values.
* @return This object.
* @see #notBeanPackages(String...)
*/
public Builder notBeanPackages(Collection<String> values) {
- assertArgNotNull("values", values);
+ assertArgNoNulls("values", values);
notBeanPackages().addAll(values);
return this;
}
@@ -2791,7 +2805,7 @@ public class BeanContext extends Context {
* @return This object.
*/
public Builder notBeanPackages(String...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
return notBeanPackages(l(values));
}
@@ -2970,7 +2984,7 @@ public class BeanContext extends Context {
* @return This object.
*/
public Builder sortProperties(Class<?>...on) {
- assertVarargsNotNull("on", on);
+ assertArgNoNulls("on", on);
for (var c : on)
annotations(BeanAnnotation.create(c).sort(true).build());
return this;
@@ -3110,7 +3124,7 @@ public class BeanContext extends Context {
* @return This object.
*/
public Builder swaps(Class<?>...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
swaps().addAll(0, accumulate(values));
return this;
}
@@ -3198,7 +3212,7 @@ public class BeanContext extends Context {
* @return This object.
*/
public Builder swaps(Object...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
swaps().addAll(0, accumulate(values));
return this;
}
@@ -3503,7 +3517,7 @@ public class BeanContext extends Context {
* Any beans in packages in this list will not be considered beans.
*/
// @formatter:off
- private static final String[] DEFAULT_NOTBEAN_PACKAGES = {
+ private static final List<String> DEFAULT_NOTBEAN_PACKAGES = l(
"java.lang",
"java.lang.annotation",
"java.lang.ref",
@@ -3512,7 +3526,7 @@ public class BeanContext extends Context {
"java.net",
"java.nio.*",
"java.util.*"
- };
+ );
// @formatter:on
/*
@@ -3520,15 +3534,15 @@ public class BeanContext extends Context {
* Anything in this list will not be considered beans.
*/
// @formatter:off
- private static final Class<?>[] DEFAULT_NOTBEAN_CLASSES = {
- Map.class,
- Collection.class,
- Reader.class,
- Writer.class,
- InputStream.class,
- OutputStream.class,
- Throwable.class
- };
+ private static final List<ClassInfo> DEFAULT_NOTBEAN_CLASSES = l(
+ info(Map.class),
+ info(Collection.class),
+ info(Reader.class),
+ info(Writer.class),
+ info(InputStream.class),
+ info(OutputStream.class),
+ info(Throwable.class)
+ );
// @formatter:on
/** Default config. All default settings. */
@@ -3549,49 +3563,48 @@ public class BeanContext extends Context {
return new Builder();
}
- protected final boolean beanMapPutReturnsOldValue;
- protected final boolean beansRequireDefaultConstructor;
- protected final boolean beansRequireSerializable;
- protected final boolean beansRequireSettersForGetters;
- protected final boolean beansRequireSomeProperties;
- protected final boolean findFluentSetters;
- protected final boolean ignoreInvocationExceptionsOnGetters;
- protected final boolean ignoreInvocationExceptionsOnSetters;
- protected final boolean ignoreMissingSetters;
- protected final boolean ignoreTransientFields;
- protected final boolean ignoreUnknownBeanProperties;
- protected final boolean ignoreUnknownEnumValues;
- protected final boolean ignoreUnknownNullBeanProperties;
- protected final boolean sortProperties;
- protected final boolean useEnumNames;
- protected final boolean useInterfaceProxies;
- protected final boolean useJavaBeanIntrospector;
- protected final Class<? extends PropertyNamer> propertyNamer;
- protected final Class<?>[] notBeanClassesArray;
- protected final ClassMeta<Class> cmClass; // Reusable ClassMeta that
represents general Classes.
- protected final ClassMeta<Object> cmObject; // Reusable ClassMeta that
represents general Objects.
- protected final ClassMeta<String> cmString; // Reusable ClassMeta that
represents general Strings.
- protected final HashKey hashKey;
- protected final List<Class<?>> beanDictionary;
- protected final List<Class<?>> notBeanClasses;
- protected final List<Object> swaps;
- protected final List<String> notBeanPackages;
- protected final Locale locale;
- protected final Map<Class,ClassMeta> cmCache;
- protected final MediaType mediaType;
- protected final ObjectSwap[] swapArray;
- protected final String typePropertyName;
- protected final String[] notBeanPackageNames;
- protected final String[] notBeanPackagePrefixes;
- protected final TimeZone timeZone;
- protected final Visibility beanClassVisibility;
- protected final Visibility beanConstructorVisibility;
- protected final Visibility beanFieldVisibility;
- protected final Visibility beanMethodVisibility;
+ private final AtomicReference<WriterSerializer> beanToStringSerializer
= new AtomicReference<>();
private final BeanRegistry beanRegistry;
private final BeanSession defaultSession;
+ private final boolean beanMapPutReturnsOldValue;
+ private final boolean beansRequireDefaultConstructor;
+ private final boolean beansRequireSerializable;
+ private final boolean beansRequireSettersForGetters;
+ private final boolean beansRequireSomeProperties;
+ private final boolean findFluentSetters;
+ private final boolean ignoreInvocationExceptionsOnGetters;
+ private final boolean ignoreInvocationExceptionsOnSetters;
+ private final boolean ignoreMissingSetters;
+ private final boolean ignoreTransientFields;
+ private final boolean ignoreUnknownBeanProperties;
+ private final boolean ignoreUnknownEnumValues;
+ private final boolean ignoreUnknownNullBeanProperties;
+ private final boolean sortProperties;
+ private final boolean useEnumNames;
+ private final boolean useInterfaceProxies;
+ private final boolean useJavaBeanIntrospector;
+ private final Class<? extends PropertyNamer> propertyNamer;
+ private final ClassMeta<Class> cmClass; // Reusable ClassMeta that
represents general Classes.
+ private final ClassMeta<Object> cmObject; // Reusable ClassMeta that
represents general Objects.
+ private final ClassMeta<String> cmString; // Reusable ClassMeta that
represents general Strings.
+ private final HashKey hashKey;
+ private final List<ClassInfo> beanDictionary;
+ private final List<ClassInfo> notBeanClasses;
+ private final List<Object> swaps;
+ private final List<String> notBeanPackages;
+ private final Locale locale;
+ private final Map<Class,ClassMeta> cmCache;
+ private final MediaType mediaType;
+ private final List<ObjectSwap<?,?>> objectSwaps;
private final PropertyNamer propertyNamerBean;
- private final AtomicReference<WriterSerializer> beanToStringSerializer
= new AtomicReference<>();
+ private final String typePropertyName;
+ private final Set<String> notBeanPackageNames;
+ private final List<String> notBeanPackagePrefixes;
+ private final TimeZone timeZone;
+ private final Visibility beanClassVisibility;
+ private final Visibility beanConstructorVisibility;
+ private final Visibility beanFieldVisibility;
+ private final Visibility beanMethodVisibility;
/**
* Constructor.
@@ -3603,7 +3616,7 @@ public class BeanContext extends Context {
beanClassVisibility = builder.beanClassVisibility;
beanConstructorVisibility = builder.beanConstructorVisibility;
- beanDictionary =
opt(builder.beanDictionary).map(Collections::unmodifiableList).orElse(l());
+ beanDictionary = u(copyOf(builder.beanDictionary));
beanFieldVisibility = builder.beanFieldVisibility;
beanMapPutReturnsOldValue = builder.beanMapPutReturnsOldValue;
beanMethodVisibility = builder.beanMethodVisibility;
@@ -3622,22 +3635,23 @@ public class BeanContext extends Context {
ignoreUnknownNullBeanProperties = !
builder.disableIgnoreUnknownNullBeanProperties;
locale = nn(builder.locale) ? builder.locale :
Locale.getDefault();
mediaType = builder.mediaType;
- notBeanClasses =
opt(builder.notBeanClasses).map(ArrayList::new).map(Collections::unmodifiableList).orElse(l());
- notBeanPackages =
opt(builder.notBeanPackages).map(ArrayList::new).map(Collections::unmodifiableList).orElse(l());
+ notBeanPackages = u(new ArrayList<>(builder.notBeanPackages));
propertyNamer = nn(builder.propertyNamer) ?
builder.propertyNamer : BasicPropertyNamer.class;
sortProperties = builder.sortProperties;
- swaps =
opt(builder.swaps).map(Collections::unmodifiableList).orElse(l());
+ swaps = u(copyOf(builder.swaps));
timeZone = builder.timeZone;
typePropertyName = nn(builder.typePropertyName) ?
builder.typePropertyName : "_type";
useEnumNames = builder.useEnumNames;
useInterfaceProxies = ! builder.disableInterfaceProxies;
useJavaBeanIntrospector = builder.useJavaBeanIntrospector;
- notBeanClassesArray = notBeanClasses.isEmpty() ?
DEFAULT_NOTBEAN_CLASSES : Stream.of(notBeanClasses,
l(DEFAULT_NOTBEAN_CLASSES)).flatMap(Collection::stream).toArray(Class[]::new);
+ var builderNotBeanClasses = new
ArrayList<>(builder.notBeanClasses);
+ notBeanClasses = builderNotBeanClasses.isEmpty() ?
DEFAULT_NOTBEAN_CLASSES : Stream.concat(builderNotBeanClasses.stream(),
DEFAULT_NOTBEAN_CLASSES.stream()).distinct().toList();
- String[] _notBeanPackages = notBeanPackages.isEmpty() ?
DEFAULT_NOTBEAN_PACKAGES : Stream.of(notBeanPackages,
l(DEFAULT_NOTBEAN_PACKAGES)).flatMap(Collection::stream).toArray(String[]::new);
- notBeanPackageNames = Stream.of(_notBeanPackages).filter(x -> !
x.endsWith(".*")).toArray(String[]::new);
- notBeanPackagePrefixes = Stream.of(_notBeanPackages).filter(x
-> x.endsWith(".*")).map(x -> x.substring(0, x.length() -
2)).toArray(String[]::new);
+ List<String> _notBeanPackages = notBeanPackages.isEmpty() ?
DEFAULT_NOTBEAN_PACKAGES : Stream.concat(notBeanPackages.stream(),
DEFAULT_NOTBEAN_PACKAGES.stream()).toList();
+ LinkedHashSet<String> _notBeanPackageNames =
_notBeanPackages.stream().filter(x -> !
x.endsWith(".*")).collect(Collectors.toCollection(LinkedHashSet::new));
+ notBeanPackageNames = u(_notBeanPackageNames);
+ notBeanPackagePrefixes = _notBeanPackages.stream().filter(x ->
x.endsWith(".*")).map(x -> x.substring(0, x.length() - 2)).toList();
try {
propertyNamerBean =
propertyNamer.getDeclaredConstructor().newInstance();
@@ -3645,21 +3659,21 @@ public class BeanContext extends Context {
throw toRex(e);
}
- LinkedList<ObjectSwap<?,?>> _swaps = new LinkedList<>();
+ var _objectSwaps = new LinkedList<ObjectSwap<?,?>>();
swaps.forEach(x -> {
if (x instanceof ObjectSwap<?,?> os) {
- _swaps.add(os);
+ _objectSwaps.add(os);
} else {
var ci = info((Class<?>)x);
if (ci.isChildOf(ObjectSwap.class))
-
_swaps.add(BeanCreator.of(ObjectSwap.class).type(ci).run());
+
_objectSwaps.add(BeanCreator.of(ObjectSwap.class).type(ci).run());
else if (ci.isChildOf(Surrogate.class))
-
_swaps.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
+
_objectSwaps.addAll(SurrogateSwap.findObjectSwaps(ci.inner(), this));
else
throw rex("Invalid class {0} specified
in BeanContext.swaps property. Must be a subclass of ObjectSwap or
Surrogate.", cn(ci.inner()));
}
});
- swapArray = _swaps.toArray(new ObjectSwap[_swaps.size()]);
+ objectSwaps = u(_objectSwaps);
cmCache = new ConcurrentHashMap<>();
cmCache.put(String.class, new ClassMeta(String.class, this));
@@ -3668,7 +3682,7 @@ public class BeanContext extends Context {
cmObject = cmCache.get(Object.class);
cmClass = cmCache.get(Class.class);
- beanRegistry = new BeanRegistry(this, null);
+ beanRegistry = new BeanRegistry(this, null, list());
defaultSession = createSession().unmodifiable().build();
}
@@ -3762,8 +3776,10 @@ public class BeanContext extends Context {
* @see BeanContext.Builder#beanDictionary()
* @return
* The list of classes that make up the bean dictionary in this
bean context.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- public final List<Class<?>> getBeanDictionary() { return
beanDictionary; }
+ public final List<ClassInfo> getBeanDictionary() { return
beanDictionary; }
/**
* Minimum bean field visibility.
@@ -3780,13 +3796,13 @@ public class BeanContext extends Context {
*
* @param <T> The class type to get the meta-data on.
* @param c The class to get the meta-data on.
+ * <br>Cannot be <jk>null</jk>.
* @return
* The {@link BeanMeta} for the specified class, or <jk>null</jk>
if the class is not a bean per the settings on
* this context.
*/
public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
- if (c == null)
- return null;
+ assertArgNotNull("c", c);
return getClassMeta(c).getBeanMeta();
}
@@ -3876,11 +3892,11 @@ public class BeanContext extends Context {
*
* @param <T> The class of the object being passed in.
* @param o The class to find the class type for.
- * @return The ClassMeta object, or <jk>null</jk> if {@code o} is
<jk>null</jk>.
+ * <br>Cannot be <jk>null</jk>.
+ * @return The ClassMeta object.
*/
public final <T> ClassMeta<T> getClassMetaForObject(T o) {
- if (o == null)
- return null;
+ assertArgNotNull("o", o);
return (ClassMeta<T>)getClassMeta(o.getClass());
}
@@ -3902,6 +3918,41 @@ public class BeanContext extends Context {
*/
public final MediaType getDefaultMediaType() { return mediaType; }
+ /**
+ * Hash key.
+ *
+ * @return The hash key.
+ */
+ protected final HashKey getHashKey() { return hashKey; }
+
+ /**
+ * Class metadata cache.
+ *
+ * @return The class metadata cache.
+ */
+ protected final Map<Class,ClassMeta> getCmCache() { return cmCache; }
+
+ /**
+ * Locale.
+ *
+ * @return The locale.
+ */
+ protected final Locale getLocale() { return locale; }
+
+ /**
+ * Media type.
+ *
+ * @return The media type.
+ */
+ protected final MediaType getMediaType() { return mediaType; }
+
+ /**
+ * Time zone.
+ *
+ * @return The time zone.
+ */
+ protected final TimeZone getTimeZone() { return timeZone; }
+
/**
* Time zone.
*
@@ -3916,9 +3967,12 @@ public class BeanContext extends Context {
*
* @see BeanContext.Builder#notBeanPackages(String...)
* @return
- * The list of fully-qualified package names to exclude from being
classified as beans.
+ * The set of fully-qualified package names to exclude from being
classified as beans.
+ * <br>Never <jk>null</jk>.
+ * <br>Set is unmodifiable.
+ * <br>Backed by a {@link LinkedHashSet} to preserve insertion
order.
*/
- public final String[] getNotBeanPackagesNames() { return
notBeanPackageNames; }
+ public final Set<String> getNotBeanPackagesNames() { return
notBeanPackageNames; }
/**
* Bean property namer.
@@ -3938,8 +3992,10 @@ public class BeanContext extends Context {
* @see BeanContext.Builder#swaps(Class...)
* @return
* The list POJO swaps defined.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- public final ObjectSwap<?,?>[] getSwaps() { return swapArray; }
+ public final List<ObjectSwap<?,?>> getSwaps() { return objectSwaps; }
/**
* Returns <jk>true</jk> if the specified bean context shares the same
cache as this bean context.
@@ -3948,22 +4004,12 @@ public class BeanContext extends Context {
* Useful for testing purposes.
*
* @param bc The bean context to compare to.
+ * <br>Cannot be <jk>null</jk>.
* @return <jk>true</jk> if the bean contexts have equivalent settings
and thus share caches.
*/
public final boolean hasSameCache(BeanContext bc) {
- return bc.cmCache == this.cmCache;
- }
-
- /**
- * Returns <jk>true</jk> if the specified object is a bean.
- *
- * @param o The object to test.
- * @return <jk>true</jk> if the specified object is a bean.
<jk>false</jk> if the bean is <jk>null</jk>.
- */
- public boolean isBean(Object o) {
- if (o == null)
- return false;
- return getClassMetaForObject(o).isBean();
+ assertArgNotNull("bc", bc);
+ return bc.getCmCache() == this.getCmCache();
}
/**
@@ -4135,10 +4181,12 @@ public class BeanContext extends Context {
*
* @param <T> The class of the object being wrapped.
* @param c The name of the class to create a new instance of.
+ * <br>Cannot be <jk>null</jk>.
* @return A new instance of the class.
* @see BeanSession#newBeanMap(Class)
*/
public <T> BeanMap<T> newBeanMap(Class<T> c) {
+ assertArgNotNull("c", c);
return defaultSession.newBeanMap(c);
}
@@ -4155,11 +4203,13 @@ public class BeanContext extends Context {
* </p>
*
* @param <T> The class of the object being wrapped.
- * @param object The object to wrap in a map interface. Must not be
null.
+ * @param object The object to wrap in a map interface.
+ * <br>Cannot be <jk>null</jk>.
* @return The wrapped object.
* @see BeanSession#toBeanMap(Object)
*/
public <T> BeanMap<T> toBeanMap(T object) {
+ assertArgNotNull("object", object);
return defaultSession.toBeanMap(object);
}
@@ -4168,7 +4218,7 @@ public class BeanContext extends Context {
* Resolves the 'genericized' class meta at the specified position in
the ClassMeta array.
*/
private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) {
- ClassMeta<?> cm = c[pos++];
+ var cm = c[pos++];
if (cm.isCollection() || cm.isOptional()) {
var ce = c.length == pos ? object() :
getTypedClassMeta(c, pos);
return (ce.isObject() ? cm : new ClassMeta(cm, null,
null, ce));
@@ -4183,7 +4233,7 @@ public class BeanContext extends Context {
private ClassMeta<?> resolveType(Type...t) {
for (var tt : t) {
if (nn(tt)) {
- ClassMeta<?> cm = getClassMeta(tt);
+ var cm = getClassMeta(tt);
if (tt != cmObject)
return cm;
}
@@ -4221,7 +4271,7 @@ public class BeanContext extends Context {
* @return The serializer. May be <jk>null</jk> if all initialization
has occurred.
*/
protected WriterSerializer getBeanToStringSerializer() {
- WriterSerializer result = beanToStringSerializer.get();
+ var result = beanToStringSerializer.get();
if (result == null) {
if (JsonSerializer.DEFAULT == null)
return null;
@@ -4236,11 +4286,13 @@ public class BeanContext extends Context {
/**
* Bean class exclusions.
*
- * @see BeanContext.Builder#notBeanClasses(Class...)
+ * @see BeanContext.Builder#notBeanClasses(ClassInfo...)
* @return
* The list of classes that are explicitly not beans.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- protected final Class<?>[] getNotBeanClasses() { return
notBeanClassesArray; }
+ protected final List<ClassInfo> getNotBeanClasses() { return
notBeanClasses; }
/**
* Bean package exclusions.
@@ -4248,8 +4300,10 @@ public class BeanContext extends Context {
* @see BeanContext.Builder#notBeanPackages(String...)
* @return
* The list of package name prefixes to exclude from being
classified as beans.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- protected final String[] getNotBeanPackagesPrefixes() { return
notBeanPackagePrefixes; }
+ protected final List<String> getNotBeanPackagesPrefixes() { return
notBeanPackagePrefixes; }
/**
* Ignore transient fields.
@@ -4280,7 +4334,7 @@ public class BeanContext extends Context {
if (pn.startsWith(p2))
return true;
}
- for (var exclude : notBeanClassesArray)
+ for (var exclude : notBeanClasses)
if (ci.isChildOf(exclude))
return true;
return false;
@@ -4343,8 +4397,8 @@ public class BeanContext extends Context {
* @return The new {@code ClassMeta} object wrapped around the type.
*/
protected final <T> ClassMeta<T> resolveClassMeta(AnnotationInfo<Beanp>
p, ClassInfo ci, TypeVariables typeVarImpls) {
- ClassMeta<T> cm = resolveClassMeta(ci, typeVarImpls);
- ClassMeta<T> cm2 = cm;
+ var cm = resolveClassMeta(ci, typeVarImpls);
+ var cm2 = cm;
if (nn(p)) {
var beanp = p.inner();
@@ -4353,21 +4407,21 @@ public class BeanContext extends Context {
cm2 = resolveClassMeta(beanp.type(),
typeVarImpls);
if (cm2.isMap()) {
- Class<?>[] pParams = (beanp.params().length ==
0 ? a(Object.class, Object.class) : beanp.params());
+ var pParams = (beanp.params().length == 0 ?
a(Object.class, Object.class) : beanp.params());
if (pParams.length != 2)
throw rex("Invalid number of parameters
specified for Map (must be 2): {0}", pParams.length);
- ClassMeta<?> keyType = resolveType(pParams[0],
cm2.getKeyType(), cm.getKeyType());
- ClassMeta<?> valueType =
resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
+ var keyType = resolveType(pParams[0],
cm2.getKeyType(), cm.getKeyType());
+ var valueType = resolveType(pParams[1],
cm2.getValueType(), cm.getValueType());
if (keyType.isObject() && valueType.isObject())
return cm2;
return new ClassMeta<>(cm2, keyType, valueType,
null);
}
if (cm2.isCollection() || cm2.isOptional()) {
- Class<?>[] pParams = (beanp.params().length ==
0 ? a(Object.class) : beanp.params());
+ var pParams = (beanp.params().length == 0 ?
a(Object.class) : beanp.params());
if (pParams.length != 1)
throw rex("Invalid number of parameters
specified for {1} (must be 1): {0}", pParams.length, (cm2.isCollection() ?
"Collection" : cm2.isOptional() ? "Optional" : "Array"));
- ClassMeta<?> elementType =
resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
+ var elementType = resolveType(pParams[0],
cm2.getElementType(), cm.getElementType());
if (elementType.isObject())
return cm2;
return new ClassMeta<>(cm2, null, null,
elementType);
@@ -4416,7 +4470,7 @@ public class BeanContext extends Context {
if (o instanceof ParameterizedType o2) {
if (! o2.getRawType().equals(Enum.class)) {
- List<ClassMeta<?>> l = new LinkedList<>();
+ var l = new LinkedList<ClassMeta<?>>();
for (var pt2 : o2.getActualTypeArguments()) {
if (pt2 instanceof WildcardType || pt2
instanceof TypeVariable)
return null;
@@ -4482,20 +4536,20 @@ public class BeanContext extends Context {
return resolveClassMeta(ci.innerType(), typeVars);
}
- Class<?> c = TypeVariables.resolve(o, typeVars);
+ var c = TypeVariables.resolve(o, typeVars);
// This can happen when trying to resolve the "E getFirst()"
method on LinkedList, whose type is a TypeVariable
// These should just resolve to Object.
if (c == null)
return object();
- ClassMeta rawType = getClassMeta(c);
+ var rawType = getClassMeta(c);
// If this is a Map or Collection, and the parameter types
aren't part
// of the class definition itself (e.g. class AddressBook
extends List<Person>),
// then we need to figure out the parameters.
if (rawType.isMap() || rawType.isCollection() ||
rawType.isOptional()) {
- ClassMeta[] params = findParameters(o, c);
+ var params = findParameters(o, c);
if (params == null)
return rawType;
if (rawType.isMap()) {
@@ -4512,7 +4566,7 @@ public class BeanContext extends Context {
if (rawType.isArray()) {
if (o instanceof GenericArrayType o2) {
- ClassMeta elementType =
resolveClassMeta(o2.getGenericComponentType(), typeVars);
+ var elementType =
resolveClassMeta(o2.getGenericComponentType(), typeVars);
return new ClassMeta(rawType, null, null,
elementType);
}
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
index 7afda4b6cc..57cc48236f 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextable.java
@@ -358,7 +358,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder beanDictionary(Class<?>...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
bcBuilder.beanDictionary(values);
return this;
}
@@ -1465,7 +1465,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder dictionaryOn(Class<?> on, Class<?>...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
bcBuilder.dictionaryOn(assertArgNotNull("on", on),
values);
return this;
}
@@ -1849,7 +1849,7 @@ public abstract class BeanContextable extends Context {
return HashKey.of(
super.hashKey(),
bcBuilder.hashKey(),
- bc == null ? 0 : bc.hashKey
+ bc == null ? 0 : bc.getHashKey()
);
// @formatter:on
}
@@ -2161,7 +2161,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder interfaces(Class<?>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
bcBuilder.interfaces(value);
return this;
}
@@ -2310,7 +2310,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder notBeanClasses(Class<?>...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
bcBuilder.notBeanClasses(values);
return this;
}
@@ -2357,7 +2357,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder notBeanPackages(String...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
bcBuilder.notBeanPackages(values);
return this;
}
@@ -2534,7 +2534,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder sortProperties(Class<?>...on) {
- assertVarargsNotNull("on", on);
+ assertArgNoNulls("on", on);
bcBuilder.sortProperties(on);
return this;
}
@@ -2656,7 +2656,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder swaps(Class<?>...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
bcBuilder.swaps(values);
return this;
}
@@ -2748,7 +2748,7 @@ public abstract class BeanContextable extends Context {
* @return This object.
*/
public Builder swaps(Object...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
bcBuilder.swaps(values);
return this;
}
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 d228e9e0f8..bf1a543e4a 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
@@ -1196,13 +1196,13 @@ public class BeanMeta<T> {
*/
private BeanRegistry findBeanRegistry() {
// Bean dictionary on bean filter.
- var beanDictionaryClasses = opt(beanFilter).map(x ->
(List<ClassInfo>)copyOf(x.getBeanDictionary())).orElse(list());
+ var beanDictionaryClasses = opt(beanFilter).map(x -> new
ArrayList<>(x.getBeanDictionary())).orElse(new ArrayList<>());
// Bean dictionary from @Bean(typeName) annotation.
var ba = beanContext.getAnnotationProvider().find(Bean.class,
classMeta);
ba.stream().map(x ->
x.inner().typeName()).filter(Utils::isNotEmpty).findFirst().ifPresent(x ->
beanDictionaryClasses.add(classMeta));
- return new BeanRegistry(beanContext, null,
beanDictionaryClasses.stream().map(ClassInfo::inner).toArray(Class<?>[]::new));
+ return new BeanRegistry(beanContext, null,
beanDictionaryClasses);
}
/*
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 30a8983d92..a833496b54 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
@@ -36,6 +36,7 @@ import org.apache.juneau.annotation.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.commons.collections.*;
import org.apache.juneau.commons.reflect.*;
+import org.apache.juneau.commons.reflect.ReflectionUtils;
import org.apache.juneau.cp.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.parser.*;
@@ -351,7 +352,7 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
if (rawTypeMeta == null)
return false;
- beanRegistry = new BeanRegistry(bc, parentBeanRegistry,
bdClasses.toArray(new Class<?>[0]));
+ beanRegistry = new BeanRegistry(bc, parentBeanRegistry,
bdClasses.stream().map(ReflectionUtils::info).toList());
isDyna = "*".equals(name);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
index d4e5e1021e..d0572a6b80 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyValue.java
@@ -23,7 +23,6 @@ import org.apache.juneau.commons.collections.*;
/**
* Represents a simple bean property value and the meta-data associated with
it.
- *
*/
public class BeanPropertyValue implements Comparable<BeanPropertyValue> {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
index 9165bb3c32..0780120161 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanProxyInvocationHandler.java
@@ -26,14 +26,51 @@ import java.util.*;
import org.apache.juneau.json.*;
/**
- * Provides an {@link InvocationHandler} for creating beans from bean
interfaces.
+ * Provides an {@link InvocationHandler} for creating dynamic proxy instances
of bean interfaces.
*
* <p>
- * If the {@code useInterfaceProxies} setting is enabled in {@link
BeanContext}, this is the class that creates
- * instances of beans from interfaces.
+ * This class enables the creation of bean instances from interfaces without
requiring concrete implementations.
+ * When the {@code useInterfaceProxies} setting is enabled in {@link
BeanContext}, this handler is used to create
+ * proxy instances that implement bean interfaces.
*
+ * <p>
+ * The handler stores bean property values in an internal map and intercepts
method calls to:
+ * <ul>
+ * <li><b>Getter methods</b> - Returns values from the internal property
map</li>
+ * <li><b>Setter methods</b> - Stores values in the internal property
map</li>
+ * <li><b>{@code equals(Object)}</b> - Compares property maps, with
special handling for other proxy instances</li>
+ * <li><b>{@code hashCode()}</b> - Returns hash code based on the property
map</li>
+ * <li><b>{@code toString()}</b> - Serializes the property map to JSON</li>
+ * </ul>
+ *
+ * <p>
+ * When comparing two proxy instances using {@code equals()}, if both are
created with {@code BeanProxyInvocationHandler},
+ * the comparison is optimized by directly comparing their internal property
maps rather than converting to {@link BeanMap}.
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bjava'>
+ * <jc>// Define an interface</jc>
+ * <jk>public interface</jk> Person {
+ * <jk>String</jk> <jsm>getName</jsm>();
+ * <jk>void</jk> <jsm>setName</jsm>(<jk>String</jk> name);
+ * <jk>int</jk> <jsm>getAge</jsm>();
+ * <jk>void</jk> <jsm>setAge</jsm>(<jk>int</jk> age);
+ * }
+ *
+ * <jc>// Create a proxy instance</jc>
+ * <jk>var</jk> bc =
<jsm>BeanContext</jsm>.<jsm>create</jsm>().<jsm>useInterfaceProxies</jsm>().<jsm>build</jsm>();
+ * <jk>var</jk> person =
bc.<jsm>getClassMeta</jsm>(Person.<jk>class</jk>).<jsm>newInstance</jsm>();
*
- * @param <T> The interface class
+ * <jc>// Use it like a regular bean</jc>
+ * person.<jsm>setName</jsm>(<js>"John"</js>);
+ * person.<jsm>setAge</jsm>(25);
+ * <jk>var</jk> name = person.<jsm>getName</jsm>(); <jc>// Returns
"John"</jc>
+ * </p>
+ *
+ * @param <T> The interface class type
+ * @see BeanContext#isUseInterfaceProxies()
+ * @see BeanMeta#getBeanProxyInvocationHandler()
+ * @see Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)
*/
public class BeanProxyInvocationHandler<T> implements InvocationHandler {
@@ -41,9 +78,9 @@ public class BeanProxyInvocationHandler<T> implements
InvocationHandler {
private Map<String,Object> beanProps; // The map of property
names to bean property values.
/**
- * Constructs with the specified {@link BeanMeta}.
+ * Constructor.
*
- * @param meta The bean meta data.
+ * @param meta The bean metadata for the interface. Must not be
<jk>null</jk>.
*/
public BeanProxyInvocationHandler(BeanMeta<T> meta) {
this.meta = meta;
@@ -51,25 +88,46 @@ public class BeanProxyInvocationHandler<T> implements
InvocationHandler {
}
/**
- * Implemented to handle the method called.
+ * Handles method invocations on the proxy instance.
+ *
+ * <p>
+ * This method intercepts all method calls on the proxy and routes them
appropriately:
+ * <ul>
+ * <li>If the method is {@code equals(Object)}, compares property
maps</li>
+ * <li>If the method is {@code hashCode()}, returns the hash code
of the property map</li>
+ * <li>If the method is {@code toString()}, serializes the
property map to JSON</li>
+ * <li>If the method is a getter (identified via {@link
BeanMeta#getGetterProps()}), returns the property value</li>
+ * <li>If the method is a setter (identified via {@link
BeanMeta#getSetterProps()}), stores the property value</li>
+ * <li>Otherwise, throws {@link UnsupportedOperationException}</li>
+ * </ul>
+ *
+ * <p>
+ * The {@code equals()} method has special optimization: when comparing
two proxy instances created with this handler,
+ * it directly compares their internal property maps using {@link
Proxy#getInvocationHandler(Object)} to access the
+ * other instance's handler.
+ *
+ * @param proxy The proxy instance on which the method was invoked
+ * @param method The method that was invoked
+ * @param args The arguments passed to the method, or <jk>null</jk> if
no arguments
+ * @return The return value of the method invocation
+ * @throws UnsupportedOperationException If the method is not a
supported bean method (getter, setter, equals, hashCode, or toString)
*/
@Override /* Overridden from InvocationHandler */
public Object invoke(Object proxy, Method method, Object[] args) {
var mi = info(method);
- if (mi.hasName("equals") &&
mi.hasParameterTypes(java.lang.Object.class)) {
- Object arg = args[0];
+ if (mi.hasName("equals") && mi.hasParameterTypes(Object.class))
{
+ var arg = args[0];
if (arg == null)
return false;
if (proxy == arg)
return true;
- if (proxy.getClass() == arg.getClass()) {
- InvocationHandler ih =
Proxy.getInvocationHandler(arg);
+ if (eq(proxy.getClass(), arg.getClass())) {
+ var ih = Proxy.getInvocationHandler(arg);
if (ih instanceof BeanProxyInvocationHandler
ih2) {
- return
this.beanProps.equals(ih2.beanProps);
+ return beanProps.equals(ih2.beanProps);
}
}
- BeanMap<Object> bean =
this.meta.getBeanContext().toBeanMap(arg);
- return this.beanProps.equals(bean);
+ return eq(beanProps,
meta.getBeanContext().toBeanMap(arg));
}
if (mi.hasName("hashCode") && mi.getParameterCount() == 0)
@@ -78,13 +136,13 @@ public class BeanProxyInvocationHandler<T> implements
InvocationHandler {
if (mi.hasName("toString") && mi.getParameterCount() == 0)
return Json5Serializer.DEFAULT.toString(this.beanProps);
- String prop = this.meta.getGetterProps().get(method);
+ var prop = meta.getGetterProps().get(method);
if (nn(prop))
- return this.beanProps.get(prop);
+ return beanProps.get(prop);
- prop = this.meta.getSetterProps().get(method);
+ prop = meta.getSetterProps().get(method);
if (nn(prop)) {
- this.beanProps.put(prop, args[0]);
+ beanProps.put(prop, args[0]);
return null;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
index 7f0edc94fa..16489a2813 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
@@ -17,6 +17,7 @@
package org.apache.juneau;
import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
+import static org.apache.juneau.commons.utils.AssertionUtils.*;
import static org.apache.juneau.commons.utils.CollectionUtils.*;
import static org.apache.juneau.commons.utils.ThrowableUtils.*;
import static org.apache.juneau.commons.utils.Utils.*;
@@ -58,8 +59,9 @@ public class BeanRegistry {
private final AnnotationProvider ap;
private final boolean isEmpty;
- // TODO - Convert classes to use ClassInfo.
- BeanRegistry(BeanContext bc, BeanRegistry parent, Class<?>...classes) {
+ BeanRegistry(BeanContext bc, BeanRegistry parent, List<ClassInfo>
classes) {
+ assertArgNotNull("bc", bc);
+ assertArgNotNull("classes", classes);
this.bc = bc;
this.ap = bc.getAnnotationProvider();
this.map = new ConcurrentHashMap<>();
@@ -67,8 +69,7 @@ public class BeanRegistry {
bc.getBeanDictionary().forEach(this::addClass);
if (nn(parent))
parent.map.forEach(this::addToMap);
- for (var c : classes)
- addClass(c);
+ classes.forEach(this::addClass);
isEmpty = map.isEmpty();
}
@@ -128,17 +129,16 @@ public class BeanRegistry {
return r(properties());
}
- private void addClass(Class<?> c) {
+ private void addClass(ClassInfo ci) {
try {
- if (nn(c)) {
- var ci = info(c);
+ if (nn(ci) && nn(ci.inner())) {
if (ci.isChildOf(Collection.class)) {
Collection<?> cc =
BeanCreator.of(Collection.class).type(ci).run();
cc.forEach(x -> {
- if (x instanceof Class x2)
- addClass(x2);
+ if (x instanceof Class<?> x2)
+ addClass(info(x2));
else
- throw bex("Collection
class ''{0}'' passed to BeanRegistry does not contain Class objects.", cn(c));
+ throw bex("Collection
class ''{0}'' passed to BeanRegistry does not contain Class objects.",
ci.getName());
});
} else if (ci.isChildOf(Map.class)) {
Map<?,?> m =
BeanCreator.of(Map.class).type(ci).run();
@@ -150,7 +150,7 @@ public class BeanRegistry {
else if (isArray(v))
val =
getTypedClassMeta(v);
else
- throw bex("Class
''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is
not a Type object.", cn(c), cn(v));
+ throw bex("Class
''{0}'' was passed to BeanRegistry but value of type ''{1}'' found in map is
not a Type object.", ci.getName(), cn(v));
addToMap(typeName, val);
});
} else {
@@ -160,9 +160,9 @@ public class BeanRegistry {
.map(x -> x.inner().typeName())
.filter(Utils::isNotEmpty)
.findFirst()
- .orElseThrow(() -> bex("Class
''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName)
annotation defined.", cn(c)));
+ .orElseThrow(() -> bex("Class
''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName)
annotation defined.", ci.getName()));
// @formatter:on
- addToMap(typeName, bc.getClassMeta(c));
+ addToMap(typeName,
bc.getClassMeta(ci.inner()));
}
}
} catch (BeanRuntimeException e) {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index b4bbbef1fa..9d17da9ead 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -72,9 +72,9 @@ public class BeanSession extends ContextSession {
protected Builder(BeanContext ctx) {
super(assertArgNotNull("ctx", ctx));
this.ctx = ctx;
- locale = ctx.locale;
- mediaType = ctx.mediaType;
- timeZone = ctx.timeZone;
+ locale = ctx.getLocale();
+ mediaType = ctx.getMediaType();
+ timeZone = ctx.getTimeZone();
}
@Override /* Overridden from Builder */
@@ -535,8 +535,10 @@ public class BeanSession extends ContextSession {
* @see BeanContext.Builder#beanDictionary(Class...)
* @return
* The list of classes that make up the bean dictionary in this
bean context.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- public final List<Class<?>> getBeanDictionary() { return
ctx.getBeanDictionary(); }
+ public final List<ClassInfo> getBeanDictionary() { return
ctx.getBeanDictionary(); }
/**
* Minimum bean field visibility.
@@ -714,20 +716,24 @@ public class BeanSession extends ContextSession {
/**
* Bean class exclusions.
*
- * @see BeanContext.Builder#notBeanClasses(Class...)
+ * @see BeanContext.Builder#notBeanClasses(ClassInfo...)
* @return
* The list of classes that are explicitly not beans.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- public final Class<?>[] getNotBeanClasses() { return
ctx.getNotBeanClasses(); }
+ public final List<ClassInfo> getNotBeanClasses() { return
ctx.getNotBeanClasses(); }
/**
* Bean package exclusions.
*
* @see BeanContext.Builder#notBeanPackages(String...)
* @return
- * The list of fully-qualified package names to exclude from being
classified as beans.
+ * The set of fully-qualified package names to exclude from being
classified as beans.
+ * <br>Never <jk>null</jk>.
+ * <br>Set is unmodifiable.
*/
- public final String[] getNotBeanPackagesNames() { return
ctx.getNotBeanPackagesNames(); }
+ public final Set<String> getNotBeanPackagesNames() { return
ctx.getNotBeanPackagesNames(); }
/**
* Bean property namer.
@@ -744,8 +750,10 @@ public class BeanSession extends ContextSession {
* @see BeanContext.Builder#swaps(Class...)
* @return
* The list POJO swaps defined.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- public final ObjectSwap<?,?>[] getSwaps() { return ctx.getSwaps(); }
+ public final List<ObjectSwap<?,?>> getSwaps() { return ctx.getSwaps(); }
/**
* Time zone.
@@ -1626,8 +1634,10 @@ public class BeanSession extends ContextSession {
* @see BeanContext.Builder#notBeanPackages(String...)
* @return
* The list of package name prefixes to exclude from being
classified as beans.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- protected final String[] getNotBeanPackagesPrefixes() { return
ctx.getNotBeanPackagesPrefixes(); }
+ protected final List<String> getNotBeanPackagesPrefixes() { return
ctx.getNotBeanPackagesPrefixes(); }
/**
* Creates either an {@link JsonMap} or {@link LinkedHashMap} depending
on whether the key type is
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 cd558edac0..32088e60f1 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
@@ -185,8 +185,8 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
this.cat = new Categories();
// We always immediately add this class meta to the bean
context cache so that we can resolve recursive references.
- if (nn(beanContext) && nn(beanContext.cmCache) &&
isCacheable(innerClass))
- beanContext.cmCache.put(innerClass, this);
+ if (nn(beanContext) && nn(beanContext.getCmCache()) &&
isCacheable(innerClass))
+ beanContext.getCmCache().put(innerClass, this);
var ap = beanContext.getAnnotationProvider();
@@ -1359,7 +1359,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
var list = new ArrayList<ObjectSwap<T,?>>();
var swapArray = beanContext.getSwaps();
- if (swapArray != null && swapArray.length > 0) {
+ if (! swapArray.isEmpty()) {
var innerClass = inner();
for (var f : swapArray)
if (f.getNormalClass().isParentOf(innerClass))
@@ -1388,7 +1388,7 @@ public class ClassMeta<T> extends ClassInfoTyped<T> {
if (beanContext == null)
return l();
var swapArray = beanContext.getSwaps();
- if (swapArray == null || swapArray.length == 0)
+ if (swapArray.isEmpty())
return l();
var list = new ArrayList<ObjectSwap<?,?>>();
var innerClass = inner();
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index a4fa7d68b8..01f550d722 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -302,7 +302,7 @@ public abstract class Context {
* @return This object.
*/
public Builder annotations(Annotation...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
annotations.addAll(l(values));
return this;
}
@@ -312,11 +312,11 @@ public abstract class Context {
*
* @param values
* The annotations to register with the context.
- * <br>Cannot be <jk>null</jk>.
+ * <br>Cannot be <jk>null</jk> or contain <jk>null</jk>
values.
* @return This object.
*/
public Builder annotations(List<Annotation> values) {
- annotations.addAll(assertArgNotNull("values", values));
+ annotations.addAll(assertArgNoNulls("values", values));
return this;
}
@@ -364,7 +364,7 @@ public abstract class Context {
* @return This object.
*/
public Builder applyAnnotations(Class<?>...from) {
- assertVarargsNotNull("from", from);
+ assertArgNoNulls("from", from);
return applyAnnotations((Object[])from);
}
@@ -452,7 +452,7 @@ public abstract class Context {
* @return This object.
*/
public Builder applyAnnotations(Object...from) {
- assertVarargsNotNull("from", from);
+ assertArgNoNulls("from", from);
var work = AnnotationWorkList.create();
Arrays.stream(from).forEach(x -> traverse(work, x));
return apply(work);
@@ -693,7 +693,7 @@ public abstract class Context {
* <br>Cannot contain <jk>null</jk> values.
*/
protected void registerBuilders(Object...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
for (var b : values) {
if (b == this)
builders.add(b);
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
index c6d65930ae..1d0d1c1edc 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ContextSession.java
@@ -197,7 +197,7 @@ public abstract class ContextSession {
return;
if (warnings == null)
warnings = new LinkedList<>();
- warnings.add((warnings.size() + 1) + ": " +
f(assertArgNotNull("msg", msg), assertVarargsNotNull("args", args)));
+ warnings.add((warnings.size() + 1) + ": " +
f(assertArgNotNull("msg", msg), assertArgNoNulls("args", args)));
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
index c16a3b4134..6adfb3aea1 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/BaseHttpPartParser.java
@@ -141,7 +141,7 @@ public abstract class BaseHttpPartParser extends
BeanContextable implements Http
* @throws SchemaValidationException If the input or resulting HTTP
part object fails schema validation.
*/
public <T> T parse(HttpPartType partType, HttpPartSchema schema, String
in, Type toType, Type...toTypeArgs) throws ParseException,
SchemaValidationException {
- assertVarargsNotNull("toTypeArgs", toTypeArgs);
+ assertArgNoNulls("toTypeArgs", toTypeArgs);
return getPartSession().parse(partType, schema, in,
getClassMeta(assertArgNotNull("toType", toType), toTypeArgs));
}
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
index 90b3a7bb58..fdeccf15c8 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
@@ -154,7 +154,7 @@ public class JsonSchemaGenerator extends
BeanTraverseContext implements JsonSche
* @return This object.
*/
public Builder addDescriptionsTo(TypeCategory...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
addDescriptionsTo = addAll(addDescriptionsTo, values);
return this;
}
@@ -194,7 +194,7 @@ public class JsonSchemaGenerator extends
BeanTraverseContext implements JsonSche
* @return This object.
*/
public Builder addExamplesTo(TypeCategory...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
addExamplesTo = addAll(addExamplesTo, values);
return this;
}
@@ -613,7 +613,7 @@ public class JsonSchemaGenerator extends
BeanTraverseContext implements JsonSche
* @return This object.
*/
public Builder ignoreTypes(String...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
ignoreTypes = addAll(ignoreTypes, values);
return this;
}
@@ -851,7 +851,7 @@ public class JsonSchemaGenerator extends
BeanTraverseContext implements JsonSche
private final BeanDefMapper beanDefMapperBean;
private final Map<BeanPropertyMeta,JsonSchemaBeanPropertyMeta>
jsonSchemaBeanPropertyMetas = new ConcurrentHashMap<>();
private final Map<ClassMeta<?>,JsonSchemaClassMeta>
jsonSchemaClassMetas = new ConcurrentHashMap<>();
- private final Pattern[] ignoreTypePatterns;
+ private final List<Pattern> ignoreTypePatterns;
/**
* Constructor.
@@ -871,7 +871,7 @@ public class JsonSchemaGenerator extends
BeanTraverseContext implements JsonSche
Set<Pattern> ignoreTypePatterns = set();
ignoreTypes.forEach(y -> split(y, x ->
ignoreTypePatterns.add(Pattern.compile(x.replace(".", "\\.").replace("*",
".*")))));
- this.ignoreTypePatterns = ignoreTypePatterns.toArray(new
Pattern[ignoreTypePatterns.size()]);
+ this.ignoreTypePatterns = u(new
ArrayList<>(ignoreTypePatterns));
try {
beanDefMapperBean =
beanDefMapper.getDeclaredConstructor().newInstance();
@@ -899,8 +899,10 @@ public class JsonSchemaGenerator extends
BeanTraverseContext implements JsonSche
* @see Builder#ignoreTypes(String...)
* @return
* Custom schema information for particular class types.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- public List<Pattern> getIgnoreTypes() { return l(ignoreTypePatterns); }
+ public List<Pattern> getIgnoreTypes() { return ignoreTypePatterns; }
@Override
public JsonSchemaBeanPropertyMeta
getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
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 1f22387009..365772b0df 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
@@ -997,7 +997,7 @@ public class Parser extends BeanContextable {
protected final int debugOutputLines;
protected final Class<? extends ParserListener> listener;
protected final String consumes;
- private final MediaType[] consumesArray;
+ private final List<MediaType> consumesArray;
/**
* Constructor.
@@ -1016,10 +1016,11 @@ public class Parser extends BeanContextable {
unbuffered = builder.unbuffered;
String[] _consumes = splita(nn(consumes) ? consumes : "");
- this.consumesArray = new MediaType[_consumes.length];
- for (var i = 0; i < _consumes.length; i++) {
- this.consumesArray[i] = MediaType.of(_consumes[i]);
+ List<MediaType> _consumesList = new ArrayList<>();
+ for (var consume : _consumes) {
+ _consumesList.add(MediaType.of(consume));
}
+ this.consumesArray = u(_consumesList);
}
/**
@@ -1074,14 +1075,14 @@ public class Parser extends BeanContextable {
*
* @return The list of media types. Never <jk>null</jk>.
*/
- public final List<MediaType> getMediaTypes() { return l(consumesArray);
}
+ public final List<MediaType> getMediaTypes() { return consumesArray; }
/**
* Returns the first media type handled based on the values passed to
the <c>consumes</c> constructor parameter.
*
* @return The media type.
*/
- public final MediaType getPrimaryMediaType() { return consumesArray ==
null || consumesArray.length == 0 ? null : consumesArray[0]; }
+ public final MediaType getPrimaryMediaType() { return
consumesArray.isEmpty() ? null : consumesArray.get(0); }
@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 985fa175fb..66e08d51f4 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
@@ -1292,7 +1292,7 @@ public class Serializer extends BeanTraverseContext {
protected final UriRelativity uriRelativity;
protected final UriResolution uriResolution;
private final MediaRanges acceptRanges;
- private final MediaType[] acceptMediaTypes;
+ private final List<MediaType> acceptMediaTypes;
private final MediaType producesMediaType;
/**
@@ -1320,7 +1320,7 @@ public class Serializer extends BeanTraverseContext {
this.producesMediaType = MediaType.of(produces);
this.acceptRanges = nn(accept) ? MediaRanges.of(accept) :
MediaRanges.of(produces);
- this.acceptMediaTypes = nn(builder.accept) ?
MediaType.ofAll(splita(builder.accept)) : a(this.producesMediaType);
+ this.acceptMediaTypes = u(nn(builder.accept) ?
l(MediaType.ofAll(splita(builder.accept))) : l(this.producesMediaType));
}
@Override /* Overridden from Context */
@@ -1366,7 +1366,7 @@ public class Serializer extends BeanTraverseContext {
*
* @return The media type. Never <jk>null</jk>.
*/
- public final MediaType getPrimaryMediaType() { return
acceptMediaTypes[0]; }
+ public final MediaType getPrimaryMediaType() { return
acceptMediaTypes.get(0); }
/**
* Optional method that returns the response <c>Content-Type</c> for
this serializer if it is different from
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index ba4caff303..b829ea149a 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -182,7 +182,7 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
disableAutoDetectNamespaces =
copyFrom.disableAutoDetectNamespaces;
disableJsonTags = copyFrom.disableJsonTags;
enableNamespaces = copyFrom.enableNamespaces;
- namespaces = copyOf(copyFrom.namespaces);
+ namespaces = copyFrom.namespaces == null ? null : new
ArrayList<>(copyFrom.namespaces);
textNodeDelimiter = copyFrom.textNodeDelimiter;
}
@@ -200,7 +200,7 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
disableAutoDetectNamespaces = !
copyFrom.autoDetectNamespaces;
disableJsonTags = ! copyFrom.addJsonTags;
enableNamespaces = copyFrom.enableNamespaces;
- namespaces = copyFrom.namespaces.length == 0 ? null :
list(copyFrom.namespaces);
+ namespaces = copyFrom.namespaces.isEmpty() ? null : new
ArrayList<>(copyFrom.namespaces);
textNodeDelimiter = copyFrom.textNodeDelimiter;
}
@@ -826,7 +826,7 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
* @return This object.
*/
public Builder namespaces(Namespace...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
namespaces = addAll(namespaces, values);
return this;
}
@@ -1185,7 +1185,6 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
}
}
- private static final Namespace[] EMPTY_NAMESPACE_ARRAY = {};
/** Default serializer without namespaces. */
public static final XmlSerializer DEFAULT = new XmlSerializer(create());
@@ -1222,7 +1221,7 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
protected final boolean autoDetectNamespaces;
protected final boolean enableNamespaces;
protected final Namespace defaultNamespace;
- protected final Namespace[] namespaces;
+ protected final List<Namespace> namespaces;
protected final String textNodeDelimiter;
private final boolean addBeanTypes;
@@ -1244,7 +1243,7 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
autoDetectNamespaces = ! builder.disableAutoDetectNamespaces;
defaultNamespace = nn(builder.defaultNamespace) ?
builder.defaultNamespace : DEFAULT_JUNEAU_NAMESPACE;
enableNamespaces = builder.enableNamespaces;
- namespaces = nn(builder.namespaces) ?
builder.namespaces.toArray(EMPTY_NAMESPACE_ARRAY) : EMPTY_NAMESPACE_ARRAY;
+ namespaces = u(nn(builder.namespaces) ? new
ArrayList<>(builder.namespaces) : new ArrayList<>());
textNodeDelimiter = builder.textNodeDelimiter;
addBeanTypes = addBeanTypesXml || super.isAddBeanTypes();
}
@@ -1307,8 +1306,10 @@ public class XmlSerializer extends WriterSerializer
implements XmlMetaProvider {
* @see Builder#namespaces(Namespace...)
* @return
* The default list of namespaces associated with this serializer.
+ * <br>Never <jk>null</jk>.
+ * <br>List is unmodifiable.
*/
- protected final Namespace[] getNamespaces() { return namespaces; }
+ protected final List<Namespace> getNamespaces() { return namespaces; }
/**
* Add <js>"_type"</js> properties when needed.
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 905ec070c2..19d581dda0 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
@@ -243,7 +243,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
private final String textNodeDelimiter;
private final XmlSerializer ctx;
private Namespace defaultNamespace;
- private Namespace[] namespaces = {};
+ private List<Namespace> namespaces = new ArrayList<>();
/**
* Constructor.
@@ -254,7 +254,8 @@ public class XmlSerializerSession extends
WriterSerializerSession {
super(builder);
ctx = builder.ctx;
defaultNamespace =
findDefaultNamespace(ctx.getDefaultNamespace());
- namespaces = ctx.getNamespaces();
+ var ctxNamespaces = ctx.getNamespaces();
+ namespaces = ctxNamespaces == null ? new ArrayList<>() : new
ArrayList<>(ctxNamespaces);
textNodeDelimiter = ctx.textNodeDelimiter;
}
@@ -676,8 +677,10 @@ public class XmlSerializerSession extends
WriterSerializerSession {
* @see XmlSerializer.Builder#namespaces(Namespace...)
* @return
* The default list of namespaces associated with this serializer.
+ * <br>Never <jk>null</jk>.
+ * <br>List is modifiable (namespaces can be added during
serialization).
*/
- protected final Namespace[] getNamespaces() { return namespaces; }
+ protected final List<Namespace> getNamespaces() { return namespaces ==
null ? l() : namespaces; }
/**
* Add <js>"_type"</js> properties when needed.
diff --git
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 3e6951c123..a932d3de18 100644
---
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -3972,7 +3972,7 @@ public class RestClient extends BeanContextable
implements HttpClient, Closeable
*/
@SuppressWarnings("unchecked")
public Builder parsers(Class<? extends Parser>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
parsers().add(value);
return this;
}
@@ -4011,7 +4011,7 @@ public class RestClient extends BeanContextable
implements HttpClient, Closeable
* @return This object.
*/
public Builder parsers(Parser...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
parsers().add(value);
return this;
}
@@ -4834,7 +4834,7 @@ public class RestClient extends BeanContextable
implements HttpClient, Closeable
*/
@SuppressWarnings("unchecked")
public Builder serializers(Class<? extends Serializer>...value)
{
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
serializers().add(value);
return this;
}
@@ -4873,7 +4873,7 @@ public class RestClient extends BeanContextable
implements HttpClient, Closeable
* @return This object.
*/
public Builder serializers(Serializer...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
serializers().add(value);
return this;
}
diff --git
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
index 64ff1553dc..af112d3f39 100644
---
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
+++
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
@@ -1225,7 +1225,7 @@ public class RestRequest extends BeanSession implements
HttpUriRequest, Configur
* @throws RestCallException If init method on interceptor threw an
exception.
*/
public RestRequest interceptors(RestCallInterceptor...interceptors)
throws RestCallException {
- assertVarargsNotNull("interceptors", interceptors);
+ assertArgNoNulls("interceptors", interceptors);
try {
for (var i : interceptors) {
this.interceptors.add(i);
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 3dc12d9983..f8eafc4c70 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -865,7 +865,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder children(Object...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
addAll(children, values);
return this;
}
@@ -1056,7 +1056,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder consumes(MediaType...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
consumes = addAll(consumes, values);
return this;
}
@@ -1239,7 +1239,7 @@ public class RestContext extends Context {
* @see #defaultClasses()
*/
public Builder defaultClasses(Class<?>...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
defaultClasses().add(values);
return this;
}
@@ -1319,7 +1319,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder
defaultRequestAttributes(NamedAttribute...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
defaultRequestAttributes().add(values);
return this;
}
@@ -1392,7 +1392,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder defaultRequestHeaders(Header...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
defaultRequestHeaders().setDefault(values);
return this;
}
@@ -1461,7 +1461,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder defaultResponseHeaders(Header...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
defaultResponseHeaders().setDefault(values);
return this;
}
@@ -1627,7 +1627,7 @@ public class RestContext extends Context {
*/
@SafeVarargs
public final Builder encoders(Class<? extends Encoder>...value)
{
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
encoders().add(value);
return this;
}
@@ -1651,7 +1651,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder encoders(Encoder...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
encoders().add(value);
return this;
}
@@ -2337,7 +2337,7 @@ public class RestContext extends Context {
*/
@SafeVarargs
public final Builder parsers(Class<? extends Parser>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
parsers().add(value);
return this;
}
@@ -2361,7 +2361,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder parsers(Parser...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
parsers().add(value);
return this;
}
@@ -2690,7 +2690,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder produces(MediaType...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
produces = addAll(produces, values);
return this;
}
@@ -2867,7 +2867,7 @@ public class RestContext extends Context {
*/
@SafeVarargs
public final Builder responseProcessors(Class<? extends
ResponseProcessor>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
responseProcessors().add(value);
return this;
}
@@ -2891,7 +2891,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder responseProcessors(ResponseProcessor...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
responseProcessors().add(value);
return this;
}
@@ -2993,7 +2993,7 @@ public class RestContext extends Context {
*/
@SafeVarargs
public final Builder restOpArgs(Class<? extends
RestOpArg>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
restOpArgs().add(value);
return this;
}
@@ -3161,7 +3161,7 @@ public class RestContext extends Context {
*/
@SafeVarargs
public final Builder serializers(Class<? extends
Serializer>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
serializers().add(value);
return this;
}
@@ -3185,7 +3185,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder serializers(Serializer...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
serializers().add(value);
return this;
}
@@ -3778,7 +3778,7 @@ public class RestContext extends Context {
*/
@SafeVarargs
public final Builder vars(Class<? extends Var>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
varResolver.vars(value);
return this;
}
@@ -3802,7 +3802,7 @@ public class RestContext extends Context {
* @return This object.
*/
public Builder vars(Var...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
varResolver.vars(value);
return this;
}
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
index 1105253bdf..c34b8fa9bc 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
@@ -370,7 +370,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder consumes(MediaType...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
consumes = addAll(consumes, values);
return this;
}
@@ -401,7 +401,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
*/
@SafeVarargs
public final Builder converters(Class<? extends
RestConverter>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
converters().append(value);
return this;
}
@@ -420,7 +420,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder converters(RestConverter...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
converters().append(value);
return this;
}
@@ -540,7 +540,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder defaultRequestAttributes(NamedAttribute...value)
{
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
defaultRequestAttributes().add(value);
return this;
}
@@ -570,7 +570,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder defaultRequestFormData(NameValuePair...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
defaultRequestFormData().append(value);
return this;
}
@@ -600,7 +600,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder
defaultRequestHeaders(org.apache.http.Header...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
defaultRequestHeaders().append(value);
return this;
}
@@ -630,7 +630,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder defaultRequestQueryData(NameValuePair...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
defaultRequestQueryData().append(value);
return this;
}
@@ -660,7 +660,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder
defaultResponseHeaders(org.apache.http.Header...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
defaultResponseHeaders().append(value);
return this;
}
@@ -701,7 +701,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
*/
@SafeVarargs
public final Builder encoders(Class<? extends Encoder>...value)
{
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
encoders().add(value);
return this;
}
@@ -720,7 +720,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder encoders(Encoder...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
encoders().add(value);
return this;
}
@@ -751,7 +751,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
*/
@SafeVarargs
public final Builder guards(Class<? extends RestGuard>...value)
{
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
guards().append(value);
return this;
}
@@ -770,7 +770,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder guards(RestGuard...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
guards().append(value);
return this;
}
@@ -915,7 +915,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
*/
@SafeVarargs
public final Builder matchers(Class<? extends
RestMatcher>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
matchers().append(value);
return this;
}
@@ -934,7 +934,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder matchers(RestMatcher...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
matchers().append(value);
return this;
}
@@ -1030,7 +1030,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
*/
@SafeVarargs
public final Builder parsers(Class<? extends Parser>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
parsers().add(value);
return this;
}
@@ -1049,7 +1049,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder parsers(Parser...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
parsers().add(value);
return this;
}
@@ -1168,7 +1168,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder path(String...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
path = prependAll(path, values);
return this;
}
@@ -1201,7 +1201,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder produces(MediaType...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
produces = addAll(produces, values);
return this;
}
@@ -1299,7 +1299,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder rolesDeclared(String...values) {
- assertVarargsNotNull("values", values);
+ assertArgNoNulls("values", values);
rolesDeclared = addAll(rolesDeclared, values);
return this;
}
@@ -1330,7 +1330,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
*/
@SafeVarargs
public final Builder serializers(Class<? extends
Serializer>...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
serializers().add(value);
return this;
}
@@ -1349,7 +1349,7 @@ public class RestOpContext extends Context implements
Comparable<RestOpContext>
* @return This object.
*/
public Builder serializers(Serializer...value) {
- assertVarargsNotNull("value", value);
+ assertArgNoNulls("value", value);
serializers().add(value);
return this;
}
diff --git a/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
index bf4ebea05e..4c3d8506a9 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/BeanContext_Test.java
@@ -19,7 +19,11 @@ package org.apache.juneau;
import static org.apache.juneau.TestUtils.*;
import static org.junit.jupiter.api.Assertions.*;
+import java.util.Locale;
+import java.util.TimeZone;
+
import org.apache.juneau.commons.reflect.*;
+import org.apache.juneau.commons.settings.Settings;
import org.apache.juneau.json.*;
import org.apache.juneau.testutils.pojos.*;
import org.junit.jupiter.api.*;
@@ -29,6 +33,11 @@ class BeanContext_Test extends TestBase {
BeanContext bc = BeanContext.DEFAULT;
BeanSession bs = BeanContext.DEFAULT_SESSION;
+ @AfterEach
+ void tearDown() {
+ Settings.get().clearLocal();
+ }
+
public interface A1 {
int getF1();
void setF1(int f1);
@@ -66,4 +75,104 @@ class BeanContext_Test extends TestBase {
var p2 = JsonParser.create().ignoreUnknownEnumValues().build();
assertNull(p2.parse("'UNKNOWN'", TestEnum.class));
}
+
+
//====================================================================================================
+ // BeanContext.Builder locale, mediaType, and timeZone from Settings
+
//====================================================================================================
+
+ @Test void c01_locale_fromSettings() {
+ Settings.get().setLocal("BeanContext.locale", "fr-CA");
+ try {
+ var bc = BeanContext.create().build();
+ assertEquals(Locale.forLanguageTag("fr-CA"),
bc.getLocale());
+ } finally {
+ Settings.get().clearLocal();
+ }
+ }
+
+ @Test void c02_locale_defaultWhenNotSet() {
+ var bc = BeanContext.create().build();
+ assertEquals(Locale.getDefault(), bc.getLocale());
+ }
+
+ @Test void c03_mediaType_fromSettings() {
+ Settings.get().setLocal("BeanContext.mediaType",
"application/json");
+ try {
+ var bc = BeanContext.create().build();
+ assertEquals(MediaType.of("application/json"),
bc.getMediaType());
+ } finally {
+ Settings.get().clearLocal();
+ }
+ }
+
+ @Test void c04_mediaType_nullWhenNotSet() {
+ var bc = BeanContext.create().build();
+ assertNull(bc.getMediaType());
+ }
+
+ @Test void c05_timeZone_fromSettings() {
+ Settings.get().setLocal("BeanContext.timeZone",
"America/New_York");
+ try {
+ var bc = BeanContext.create().build();
+ assertEquals(TimeZone.getTimeZone("America/New_York"),
bc.getTimeZone());
+ } finally {
+ Settings.get().clearLocal();
+ }
+ }
+
+ @Test void c06_timeZone_nullWhenNotSet() {
+ var bc = BeanContext.create().build();
+ assertNull(bc.getTimeZone());
+ }
+
+
//====================================================================================================
+ // BeanContext.copy() - Copy constructor coverage
+
//====================================================================================================
+
+ @Test void d01_copy() {
+ // Create a BeanContext with some properties set to exercise
the copy constructor
+ var original = BeanContext.create()
+ .sortProperties()
+ .locale(Locale.CANADA)
+ .mediaType(MediaType.JSON)
+ .timeZone(TimeZone.getTimeZone("America/New_York"))
+ .build();
+
+ // Call copy() which uses the copy constructor
Builder(BeanContext copyFrom)
+ // This exercises lines 273-277 which convert boolean fields
from BeanContext to Builder disable flags
+ var builder = original.copy();
+
+ // Build a new context from the copied builder
+ var copied = builder.build();
+
+ // Verify the copied context has the same values
+ assertEquals(original.getBeanClassVisibility(),
copied.getBeanClassVisibility());
+ assertEquals(original.getBeanConstructorVisibility(),
copied.getBeanConstructorVisibility());
+ assertEquals(original.getBeanFieldVisibility(),
copied.getBeanFieldVisibility());
+ assertEquals(original.getBeanMethodVisibility(),
copied.getBeanMethodVisibility());
+ assertEquals(original.getBeanDictionary(),
copied.getBeanDictionary());
+ assertEquals(original.getLocale(), copied.getLocale());
+ assertEquals(original.getMediaType(), copied.getMediaType());
+ assertEquals(original.getTimeZone(), copied.getTimeZone());
+ }
+
+
//====================================================================================================
+ // BeanContext.Builder.impl() - Line 2372 coverage
+
//====================================================================================================
+
+ @Test void e01_impl() {
+ // Create a BeanContext to use as the implementation
+ var impl = BeanContext.create()
+ .sortProperties()
+ .locale(Locale.CANADA)
+ .build();
+
+ // Call impl() which exercises line 2372: super.impl(value);
+ var builder = BeanContext.create()
+ .impl(impl);
+
+ // Build should return the pre-instantiated context
+ var result = builder.build();
+ assertSame(impl, result);
+ }
}
\ No newline at end of file
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/BeanPropertyValue_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/BeanPropertyValue_Test.java
new file mode 100644
index 0000000000..6dec302000
--- /dev/null
+++ b/juneau-utest/src/test/java/org/apache/juneau/BeanPropertyValue_Test.java
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.*;
+
+class BeanPropertyValue_Test extends TestBase {
+
+ public static class TestBean {
+ public String name;
+ public int age;
+ public boolean active;
+ }
+
+ BeanContext bc = BeanContext.DEFAULT;
+
+
//====================================================================================================
+ // compareTo() - Line 51 coverage
+
//====================================================================================================
+
+ @Test void a01_compareTo_lessThan() {
+ var bm = bc.getBeanMeta(TestBean.class);
+ var pMeta1 = bm.getPropertyMeta("active");
+ var pMeta2 = bm.getPropertyMeta("age");
+
+ var pv1 = new BeanPropertyValue(pMeta1, "active", true, null);
+ var pv2 = new BeanPropertyValue(pMeta2, "age", 25, null);
+
+ assertTrue(pv1.compareTo(pv2) < 0);
+ }
+
+ @Test void a02_compareTo_greaterThan() {
+ var bm = bc.getBeanMeta(TestBean.class);
+ var pMeta1 = bm.getPropertyMeta("name");
+ var pMeta2 = bm.getPropertyMeta("age");
+
+ var pv1 = new BeanPropertyValue(pMeta1, "name", "John", null);
+ var pv2 = new BeanPropertyValue(pMeta2, "age", 25, null);
+
+ assertTrue(pv1.compareTo(pv2) > 0);
+ }
+
+ @Test void a03_compareTo_equal() {
+ var bm = bc.getBeanMeta(TestBean.class);
+ var pMeta = bm.getPropertyMeta("name");
+
+ var pv1 = new BeanPropertyValue(pMeta, "name", "John", null);
+ var pv2 = new BeanPropertyValue(pMeta, "name", "Jane", null);
+
+ assertEquals(0, pv1.compareTo(pv2));
+ }
+
+
//====================================================================================================
+ // properties() and toString() - Lines 89-100 coverage
+
//====================================================================================================
+
+ @Test void b01_properties() {
+ var bm = bc.getBeanMeta(TestBean.class);
+ var pMeta = bm.getPropertyMeta("name");
+ var pv = new BeanPropertyValue(pMeta, "name", "John", null);
+
+ var props = pv.properties();
+ assertEquals("name", props.get("name"));
+ assertEquals("John", props.get("value"));
+ assertNotNull(props.get("type"));
+ }
+
+ @Test void b02_toString() {
+ var bm = bc.getBeanMeta(TestBean.class);
+ var pMeta = bm.getPropertyMeta("name");
+ var pv = new BeanPropertyValue(pMeta, "name", "John", null);
+
+ var str = pv.toString();
+ assertNotNull(str);
+ assertTrue(str.contains("name"));
+ assertTrue(str.contains("John"));
+ }
+
+ @Test void b03_toString_withNullValue() {
+ var bm = bc.getBeanMeta(TestBean.class);
+ var pMeta = bm.getPropertyMeta("name");
+ var pv = new BeanPropertyValue(pMeta, "name", null, null);
+
+ var str = pv.toString();
+ assertNotNull(str);
+ assertTrue(str.contains("name"));
+ }
+}
+
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/BeanProxyInvocationHandler_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/BeanProxyInvocationHandler_Test.java
new file mode 100644
index 0000000000..85a2c0cd09
--- /dev/null
+++
b/juneau-utest/src/test/java/org/apache/juneau/BeanProxyInvocationHandler_Test.java
@@ -0,0 +1,405 @@
+/*
+ * 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;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.lang.reflect.*;
+
+import org.junit.jupiter.api.*;
+
+class BeanProxyInvocationHandler_Test extends TestBase {
+
+ public interface TestInterface {
+ String getName();
+ void setName(String name);
+ int getAge();
+ void setAge(int age);
+ boolean isActive();
+ void setActive(boolean active);
+ }
+
+ // Helper class with methods that have same names as Object methods but
wrong signatures
+ // We can't put these in an interface because they conflict with Object
methods
+ public static class HelperClassWithWrongSignatures {
+ public boolean equals(String other) { return false; } //
Wrong: should be equals(Object)
+ public int hashCode(int dummy) { return 0; } // Wrong: should
be hashCode()
+ public String toString(String format) { return ""; } // Wrong:
should be toString()
+ }
+
+ BeanContext bc = BeanContext.DEFAULT;
+
+
//====================================================================================================
+ // Constructor
+
//====================================================================================================
+
+ @Test void a01_constructor() {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ assertNotNull(handler);
+ }
+
+
//====================================================================================================
+ // invoke() - equals() method
+
//====================================================================================================
+
+ @Test void b01_equals_null() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = Object.class.getMethod("equals", Object.class);
+ var result = handler.invoke(proxy, method, new Object[]{null});
+ assertFalse((Boolean)result);
+ }
+
+ @Test void b02_equals_sameProxy() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = Object.class.getMethod("equals", Object.class);
+ var result = handler.invoke(proxy, method, new Object[]{proxy});
+ assertTrue((Boolean)result);
+ }
+
+ @Test void b03_equals_sameClassDifferentHandler() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler1 = new BeanProxyInvocationHandler<>(bm);
+ var handler2 = new BeanProxyInvocationHandler<>(bm);
+ var proxy1 = createProxy(TestInterface.class, handler1);
+ var proxy2 = createProxy(TestInterface.class, handler2);
+
+ // Set same values
+ proxy1.setName("John");
+ proxy1.setAge(25);
+ proxy2.setName("John");
+ proxy2.setAge(25);
+
+ var method = Object.class.getMethod("equals", Object.class);
+ var result = handler1.invoke(proxy1, method, new
Object[]{proxy2});
+ assertTrue((Boolean)result);
+ }
+
+ @Test void b04_equals_differentValues() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler1 = new BeanProxyInvocationHandler<>(bm);
+ var handler2 = new BeanProxyInvocationHandler<>(bm);
+ var proxy1 = createProxy(TestInterface.class, handler1);
+ var proxy2 = createProxy(TestInterface.class, handler2);
+
+ // Set different values
+ proxy1.setName("John");
+ proxy1.setAge(25);
+ proxy2.setName("Jane");
+ proxy2.setAge(30);
+
+ var method = Object.class.getMethod("equals", Object.class);
+ var result = handler1.invoke(proxy1, method, new
Object[]{proxy2});
+ assertFalse((Boolean)result);
+ }
+
+ @Test void b05_equals_withBeanMap() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ proxy.setName("John");
+ proxy.setAge(25);
+
+ // Create a regular bean with same values
+ var bean = new TestBean();
+ bean.name = "John";
+ bean.age = 25;
+
+ var method = Object.class.getMethod("equals", Object.class);
+ var result = handler.invoke(proxy, method, new Object[]{bean});
+ assertTrue((Boolean)result);
+ }
+
+ public static class TestBean {
+ public String name;
+ public int age;
+ }
+
+
//====================================================================================================
+ // invoke() - hashCode() method
+
//====================================================================================================
+
+ @Test void c01_hashCode() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ proxy.setName("John");
+ proxy.setAge(25);
+
+ var method = Object.class.getMethod("hashCode");
+ var result = handler.invoke(proxy, method, null);
+ assertNotNull(result);
+ assertTrue(result instanceof Integer);
+ }
+
+ @Test void c02_hashCode_sameValues() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler1 = new BeanProxyInvocationHandler<>(bm);
+ var handler2 = new BeanProxyInvocationHandler<>(bm);
+ var proxy1 = createProxy(TestInterface.class, handler1);
+ var proxy2 = createProxy(TestInterface.class, handler2);
+
+ proxy1.setName("John");
+ proxy1.setAge(25);
+ proxy2.setName("John");
+ proxy2.setAge(25);
+
+ var method = Object.class.getMethod("hashCode");
+ var hashCode1 = handler1.invoke(proxy1, method, null);
+ var hashCode2 = handler2.invoke(proxy2, method, null);
+ assertEquals(hashCode1, hashCode2);
+ }
+
+
//====================================================================================================
+ // invoke() - toString() method
+
//====================================================================================================
+
+ @Test void d01_toString() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ proxy.setName("John");
+ proxy.setAge(25);
+ proxy.setActive(true);
+
+ var method = Object.class.getMethod("toString");
+ var result = handler.invoke(proxy, method, null);
+ assertNotNull(result);
+ assertTrue(result instanceof String);
+ var str = (String)result;
+ assertTrue(str.contains("John") || str.contains("25") ||
str.contains("true"));
+ }
+
+ @Test void d02_toString_empty() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = Object.class.getMethod("toString");
+ var result = handler.invoke(proxy, method, null);
+ assertNotNull(result);
+ assertTrue(result instanceof String);
+ }
+
+
//====================================================================================================
+ // invoke() - getter methods
+
//====================================================================================================
+
+ @Test void e01_getter_string() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ proxy.setName("John");
+
+ var method = TestInterface.class.getMethod("getName");
+ var result = handler.invoke(proxy, method, null);
+ assertEquals("John", result);
+ }
+
+ @Test void e02_getter_int() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ proxy.setAge(25);
+
+ var method = TestInterface.class.getMethod("getAge");
+ var result = handler.invoke(proxy, method, null);
+ assertEquals(25, result);
+ }
+
+ @Test void e03_getter_boolean() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ proxy.setActive(true);
+
+ var method = TestInterface.class.getMethod("isActive");
+ var result = handler.invoke(proxy, method, null);
+ assertEquals(true, result);
+ }
+
+ @Test void e04_getter_null() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ // Don't set name, should return null
+ var method = TestInterface.class.getMethod("getName");
+ var result = handler.invoke(proxy, method, null);
+ assertNull(result);
+ }
+
+
//====================================================================================================
+ // invoke() - setter methods
+
//====================================================================================================
+
+ @Test void f01_setter_string() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = TestInterface.class.getMethod("setName",
String.class);
+ var result = handler.invoke(proxy, method, new
Object[]{"John"});
+ assertNull(result);
+
+ // Verify value was set
+ assertEquals("John", proxy.getName());
+ }
+
+ @Test void f02_setter_int() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = TestInterface.class.getMethod("setAge", int.class);
+ var result = handler.invoke(proxy, method, new Object[]{25});
+ assertNull(result);
+
+ // Verify value was set
+ assertEquals(25, proxy.getAge());
+ }
+
+ @Test void f03_setter_boolean() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = TestInterface.class.getMethod("setActive",
boolean.class);
+ var result = handler.invoke(proxy, method, new Object[]{true});
+ assertNull(result);
+
+ // Verify value was set
+ assertTrue(proxy.isActive());
+ }
+
+ @Test void f04_setter_null() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ var method = TestInterface.class.getMethod("setName",
String.class);
+ var result = handler.invoke(proxy, method, new Object[]{null});
+ assertNull(result);
+
+ // Verify null was set
+ assertNull(proxy.getName());
+ }
+
+
//====================================================================================================
+ // invoke() - unsupported method
+
//====================================================================================================
+
+ @Test void g01_unsupportedMethod() throws Exception {
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ // Create a method that's not a getter, setter, equals,
hashCode, or toString
+ var method = Object.class.getMethod("getClass");
+ var exception =
assertThrows(UnsupportedOperationException.class, () -> {
+ handler.invoke(proxy, method, null);
+ });
+ assertNotNull(exception.getMessage());
+ assertTrue(exception.getMessage().contains("Unsupported bean
method"));
+ }
+
+
//====================================================================================================
+ // invoke() - methods with same name but wrong signatures (lines 59,
74, 77 coverage)
+
//====================================================================================================
+
+ @Test void h01_equals_wrongSignature() throws Exception {
+ // Test equals(String) - should not match the equals(Object)
check on line 59
+ // Get the method from a helper class since we can't put it in
an interface
+ var method =
HelperClassWithWrongSignatures.class.getMethod("equals", String.class);
+
+ // Create handler with TestInterface (any interface will do for
testing)
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ // This should fall through to getter/setter/unsupported logic
since it doesn't match line 59
+ // (has name "equals" but wrong parameter type - String instead
of Object)
+ var exception =
assertThrows(UnsupportedOperationException.class, () -> {
+ handler.invoke(proxy, method, new Object[]{"test"});
+ });
+ assertNotNull(exception.getMessage());
+ assertTrue(exception.getMessage().contains("Unsupported bean
method"));
+ }
+
+ @Test void h02_hashCode_wrongSignature() throws Exception {
+ // Test hashCode(int) - should not match the hashCode() check
on line 74
+ // Get the method from a helper class since we can't put it in
an interface
+ var method =
HelperClassWithWrongSignatures.class.getMethod("hashCode", int.class);
+
+ // Create handler with TestInterface (any interface will do for
testing)
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ // This should fall through to getter/setter/unsupported logic
since it doesn't match line 74
+ // (has name "hashCode" but wrong parameter count - 1 instead
of 0)
+ var exception =
assertThrows(UnsupportedOperationException.class, () -> {
+ handler.invoke(proxy, method, new Object[]{42});
+ });
+ assertNotNull(exception.getMessage());
+ assertTrue(exception.getMessage().contains("Unsupported bean
method"));
+ }
+
+ @Test void h03_toString_wrongSignature() throws Exception {
+ // Test toString(String) - should not match the toString()
check on line 77
+ // Get the method from a helper class since we can't put it in
an interface
+ var method =
HelperClassWithWrongSignatures.class.getMethod("toString", String.class);
+
+ // Create handler with TestInterface (any interface will do for
testing)
+ var bm = bc.getBeanMeta(TestInterface.class);
+ var handler = new BeanProxyInvocationHandler<>(bm);
+ var proxy = createProxy(TestInterface.class, handler);
+
+ // This should fall through to getter/setter/unsupported logic
since it doesn't match line 77
+ // (has name "toString" but wrong parameter count - 1 instead
of 0)
+ var exception =
assertThrows(UnsupportedOperationException.class, () -> {
+ handler.invoke(proxy, method, new Object[]{"format"});
+ });
+ assertNotNull(exception.getMessage());
+ assertTrue(exception.getMessage().contains("Unsupported bean
method"));
+ }
+
+
//====================================================================================================
+ // Helper methods
+
//====================================================================================================
+
+ private static <T> T createProxy(Class<T> interfaceClass,
InvocationHandler handler) {
+ return (T)Proxy.newProxyInstance(
+ interfaceClass.getClassLoader(),
+ new Class[]{interfaceClass},
+ handler
+ );
+ }
+}
+
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
index 0e26305ab6..aca26665f4 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/annotation/BeanConfigAnnotation_Test.java
@@ -42,7 +42,7 @@ class BeanConfigAnnotation_Test extends TestBase {
assertEquals(expected, TO_STRING.apply(o));
}
- private static final Function<Object,String> TO_STRING = new
Function<>() {
+ private static final Function<Object,String> TO_STRING = new
Function<>() {
@Override
public String apply(Object t) {
if (t == null)
@@ -52,6 +52,11 @@ class BeanConfigAnnotation_Test extends TestBase {
.stream()
.map(TO_STRING)
.collect(Collectors.joining(","));
+ if (t instanceof Set)
+ return ((Set<?>)t)
+ .stream()
+ .map(TO_STRING)
+ .collect(Collectors.joining(","));
if (isArray(t))
return apply(toList(t, Object.class));
if (t instanceof JsonMap)
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
index aed9307575..ecc2c51e9b 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/collections/MultiSet_Test.java
@@ -320,13 +320,14 @@ class MultiSet_Test extends TestBase {
assertFalse(it.hasNext()); // i2 is null, should return false
}
+ @SuppressWarnings("unlikely-arg-type")
@Test
void equals_notASet_otherTypes() {
// Line 308: return (o instanceof Set o2) && ...
// Test when object is not a Set (testing the instanceof check)
var l1 = l(a("1", "2"));
var multiSet = new MultiSet<>(l1);
-
+
// Not a Set - should return false immediately due to
instanceof check
assertFalse(multiSet.equals("not a set"));
assertFalse(multiSet.equals(123));
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
index 75bdd20e88..3e96125121 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/AssertionUtils_Test.java
@@ -392,39 +392,39 @@ class AssertionUtils_Test extends TestBase {
void a012_assertVarargsNotNull() {
// Should not throw when array and elements are not null
var array = a("a", "b", "c");
- var result = assertVarargsNotNull("arg", array);
+ var result = assertArgNoNulls("arg", array);
assertSame(array, result);
// Should not throw with empty array
var emptyArray = new String[0];
- var result2 = assertVarargsNotNull("arg", emptyArray);
+ var result2 = assertArgNoNulls("arg", emptyArray);
assertSame(emptyArray, result2);
// Should work with integer array
var intArray = a(1, 2, 3);
- var result3 = assertVarargsNotNull("arg", intArray);
+ var result3 = assertArgNoNulls("arg", intArray);
assertSame(intArray, result3);
// Should work with object array
var objArray = a(new Object(), new Object());
- var result4 = assertVarargsNotNull("arg", objArray);
+ var result4 = assertArgNoNulls("arg", objArray);
assertSame(objArray, result4);
// Should throw when array is null
assertThrowsWithMessage(IllegalArgumentException.class,
l("arg", "cannot be null"), () -> {
- assertVarargsNotNull("arg", (String[])null);
+ assertArgNoNulls("arg", (String[])null);
});
// Should throw when element is null
var nullElementArray = a("a", null, "c");
assertThrowsWithMessage(IllegalArgumentException.class,
l("arg", "parameter", "1"), () -> {
- assertVarargsNotNull("arg", nullElementArray);
+ assertArgNoNulls("arg", nullElementArray);
});
// Should fail on first null when multiple elements are null
var multipleNullArray = a("a", null, null, "d");
assertThrowsWithMessage(IllegalArgumentException.class, "1", ()
-> {
- assertVarargsNotNull("arg", multipleNullArray);
+ assertArgNoNulls("arg", multipleNullArray);
});
}
}