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 9a7d1a05f7 Marshall module improvements
9a7d1a05f7 is described below
commit 9a7d1a05f79c8e8f90f6c4bd166403f99626471f
Author: James Bognar <[email protected]>
AuthorDate: Fri Dec 12 17:20:15 2025 -0500
Marshall module improvements
---
.../org/apache/juneau/commons/function/Tuple1.java | 2 +-
.../org/apache/juneau/commons/function/Tuple2.java | 2 +-
.../org/apache/juneau/commons/function/Tuple3.java | 2 +-
.../org/apache/juneau/commons/function/Tuple4.java | 2 +-
.../org/apache/juneau/commons/function/Tuple5.java | 2 +-
.../org/apache/juneau/commons/io/LocalDir.java | 2 +-
.../org/apache/juneau/commons/utils/HashCode.java | 36 ++++++++-
.../org/apache/juneau/commons/utils/Utils.java | 26 ++++---
.../java/org/apache/juneau/BeanPropertyMeta.java | 86 +++++++++++-----------
.../java/org/apache/juneau/cp/BasicFileFinder.java | 4 +-
.../juneau/rest/staticfile/BasicStaticFiles.java | 4 +-
.../org/apache/juneau/rest/stats/ThrownStats.java | 4 +-
12 files changed, 104 insertions(+), 68 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple1.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple1.java
index 0e00ba0feb..7edc1872a3 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple1.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple1.java
@@ -112,7 +112,7 @@ public class Tuple1<A> {
*/
public Tuple1(A a) {
this.a = a;
- this.hashCode = HashCode.of(a);
+ this.hashCode = hash(a);
}
@Override /* Overridden from Object */
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple2.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple2.java
index b49e791d3a..fcdf0aca1d 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple2.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple2.java
@@ -120,7 +120,7 @@ public class Tuple2<A,B> {
public Tuple2(A a, B b) {
this.a = a;
this.b = b;
- this.hashCode = HashCode.of(a, b);
+ this.hashCode = hash(a, b);
}
@Override /* Overridden from Object */
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple3.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple3.java
index c7a7496a69..c8f151b690 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple3.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple3.java
@@ -79,7 +79,7 @@ public class Tuple3<A,B,C> {
this.a = a;
this.b = b;
this.c = c;
- this.hashCode = HashCode.of(a, b, c);
+ this.hashCode = hash(a, b, c);
}
@Override /* Overridden from Object */
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple4.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple4.java
index 5127cb6efc..5a67f01e9f 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple4.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple4.java
@@ -85,7 +85,7 @@ public class Tuple4<A,B,C,D> {
this.b = b;
this.c = c;
this.d = d;
- this.hashCode = HashCode.of(a, b, c, d);
+ this.hashCode = hash(a, b, c, d);
}
@Override /* Overridden from Object */
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple5.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple5.java
index cdab0c8ad6..717bf85a13 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple5.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/function/Tuple5.java
@@ -91,7 +91,7 @@ public class Tuple5<A,B,C,D,E> {
this.c = c;
this.d = d;
this.e = e;
- this.hashCode = HashCode.of(a, b, c, d, e);
+ this.hashCode = hash(a, b, c, d, e);
}
@Override /* Overridden from Object */
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
index a09bc08fd4..4ebebe3b89 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
@@ -146,7 +146,7 @@ public class LocalDir {
this.clazz = assertArgNotNull("clazz", clazz);
this.clazzPath = "/".equals(clazzPath) ? "/" :
StringUtils.nullIfEmpty(trimTrailingSlashes(clazzPath));
this.path = null;
- this.hashCode = HashCode.of(clazz, clazzPath);
+ this.hashCode = hash(clazz, clazzPath);
}
/**
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/HashCode.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/HashCode.java
index 7f63192b08..5d291a7ec2 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/HashCode.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/HashCode.java
@@ -16,6 +16,8 @@
*/
package org.apache.juneau.commons.utils;
+import java.lang.annotation.*;
+
/**
* Utility class for generating integer hash codes.
*
@@ -40,8 +42,24 @@ public class HashCode {
/**
* Calculates a hash code over the specified objects.
*
+ * <p>
+ * Uses the same algorithm as {@link java.util.Objects#hash(Object...)}
(31 * result + element hash).
+ *
+ * <p>
+ * Special handling is provided for:
+ * <ul>
+ * <li><b>Annotations:</b> Uses {@link
AnnotationUtils#hash(Annotation)} to ensure consistent hashing
+ * according to the {@link
java.lang.annotation.Annotation#hashCode()} contract.
+ * <li><b>Arrays:</b> Uses content-based hashing via {@link
java.util.Arrays#hashCode(Object[])}
+ * instead of identity-based hashing.
+ * <li><b>Null values:</b> Treated as 0 in the hash calculation.
+ * </ul>
+ *
* @param objects The objects to calculate a hashcode over.
* @return A numerical hashcode value.
+ * @see #add(Object)
+ * @see AnnotationUtils#hash(Annotation)
+ * @see java.util.Objects#hash(Object...)
*/
public static final int of(Object...objects) {
HashCode x = create();
@@ -70,16 +88,30 @@ public class HashCode {
* Hashes the hashcode of the specified object into this object.
*
* <p>
- * Arrays are handled specially to use content-based hashing via {@link
java.util.Arrays#hashCode(Object[])}
- * instead of identity-based hashing.
+ * The formula is <c>hashCode = 31*hashCode + elementHash;</c>
+ *
+ * <p>
+ * Special handling is provided for:
+ * <ul>
+ * <li><b>Null values:</b> Adds 0 to the hash code.
+ * <li><b>Annotations:</b> Uses {@link
AnnotationUtils#hash(Annotation)} to ensure consistent hashing
+ * according to the {@link
java.lang.annotation.Annotation#hashCode()} contract.
+ * <li><b>Arrays:</b> Uses content-based hashing via {@link
java.util.Arrays#hashCode(Object[])}
+ * instead of identity-based hashing. Supports all
primitive array types and object arrays.
+ * <li><b>Other objects:</b> Uses the object's {@link
Object#hashCode()} method.
+ * </ul>
*
* @param o The object whose hashcode will be hashed with this object.
* @return This object.
+ * @see AnnotationUtils#hash(Annotation)
+ * @see java.util.Arrays#hashCode(Object[])
*/
public HashCode add(Object o) {
o = unswap(o);
if (o == null) {
add(0);
+ } else if (o instanceof Annotation a) {
+ add(AnnotationUtils.hash(a));
} else if (o.getClass().isArray()) {
// Use content-based hashcode for arrays
if (o instanceof Object[])
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
index 510fe76bdc..0774097927 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
@@ -662,10 +662,18 @@ public class Utils {
* Calculates a hash code for the specified values.
*
* <p>
- * This method combines multiple values into a single hash code using
the same algorithm as
- * {@link Objects#hash(Object...)}. It handles annotations specially by
delegating to
- * {@link AnnotationUtils#hash(Annotation)} to ensure consistent
hashing according to the
- * {@link java.lang.annotation.Annotation#hashCode()} contract.
+ * This method delegates to {@link HashCode#of(Object...)} to combine
multiple values into a single hash code.
+ * It uses the same algorithm as {@link Objects#hash(Object...)} (31 *
result + element hash).
+ *
+ * <p>
+ * Special handling is provided for:
+ * <ul>
+ * <li><b>Annotations:</b> Uses {@link
AnnotationUtils#hash(Annotation)} to ensure consistent hashing
+ * according to the {@link
java.lang.annotation.Annotation#hashCode()} contract.
+ * <li><b>Arrays:</b> Uses content-based hashing via {@link
java.util.Arrays#hashCode(Object[])}
+ * instead of identity-based hashing.
+ * <li><b>Null values:</b> Treated as 0 in the hash calculation.
+ * </ul>
*
* <h5 class='section'>Example:</h5>
* <p class='bjava'>
@@ -675,6 +683,9 @@ public class Utils {
* <jc>// Hash with annotations</jc>
* <jk>int</jk> <jv>hash2</jv> = hash(<jv>myAnnotation</jv>,
<js>"value"</js>);
*
+ * <jc>// Hash with arrays (content-based)</jc>
+ * <jk>int</jk> <jv>hash3</jv> = hash(<jk>new</jk>
<jk>int</jk>[]{1, 2, 3});
+ *
* <jc>// Use in hashCode() implementation</jc>
* <jk>public</jk> <jk>int</jk> hashCode() {
* <jk>return</jk> hash(id, name, created);
@@ -683,16 +694,13 @@ public class Utils {
*
* @param values The values to hash.
* @return A hash code value for the given values.
+ * @see HashCode#of(Object...)
* @see AnnotationUtils#hash(Annotation)
* @see Objects#hash(Object...)
*/
public static final int hash(Object...values) {
assertArgNotNull("values", values);
- var result = 1;
- for (var value : values) {
- result = 31 * result + (value instanceof
java.lang.annotation.Annotation ?
AnnotationUtils.hash((java.lang.annotation.Annotation)value) :
Objects.hashCode(value));
- }
- return result;
+ return HashCode.of(values);
}
/**
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 69e7d93e52..39445898c5 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
@@ -35,7 +35,6 @@ 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.utils.*;
import org.apache.juneau.cp.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.parser.*;
@@ -433,33 +432,30 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
return new Builder(beanMeta, name);
}
- final BeanMeta<?> beanMeta; // The bean
that this property belongs to.
- private final BeanContext bc; // The context that
created this meta.
- private final AnnotationProvider ap;
- private final String name; // The name
of the property.
- private final FieldInfo field; // The
bean property field (if it has one).
- private final FieldInfo innerField; //
The bean property field (if it has one).
-
- private final MethodInfo getter; // The bean property getter.
- private final MethodInfo setter; // The bean property setter.
- private final MethodInfo extraKeys; // The bean property
extraKeys.
-
- private final boolean isUri; // True if
this is a URL/URI or annotated with @URI.
- private final boolean isDyna, isDynaGetterMap; // This is a
dyna property (i.e. name="*")
-
- private final ClassMeta<?> rawTypeMeta,
// The real class type of the bean property.
- typeMeta; // The
transformed class type of the bean property.
-
- private final List<String> properties; // The
value of the @Beanp(properties) annotation (unmodifiable).
- private final ObjectSwap swap; //
ObjectSwap defined only via @Beanp annotation.
- private final BeanRegistry beanRegistry;
- private final Object overrideValue; // The bean
property value (if it's an overridden delegate).
-
- private final BeanPropertyMeta delegateFor; // The bean
property that this meta is a delegate for.
-
- private final boolean canRead, canWrite, readOnly, writeOnly;
-
- private final int hashCode;
+ private final AnnotationProvider ap; // Annotation
provider for finding annotations on this property.
+ private final BeanContext bc; // The context
that created this meta.
+ private final BeanMeta<?> beanMeta; // The bean that
this property belongs to.
+ private final BeanRegistry beanRegistry; // Bean registry
for resolving bean types in this property.
+ private final boolean canRead; // True if this
property can be read.
+ private final boolean canWrite; // True if this
property can be written.
+ private final BeanPropertyMeta delegateFor; // The bean
property that this meta is a delegate for.
+ private final MethodInfo extraKeys; // The bean
property extraKeys method.
+ private final FieldInfo field; // The bean
property field (if it has one).
+ private final MethodInfo getter; // The bean
property getter.
+ private final int hashCode; // Cached hash
code for this property meta.
+ private final FieldInfo innerField; // The bean
property field even if private (if it has one).
+ private final boolean isDyna; // True if this
is a dyna property (i.e. name="*").
+ private final boolean isDynaGetterMap; // True if this
is a dyna property where the getter returns a Map directly.
+ private final boolean isUri; // True if this
is a URL/URI or annotated with @URI.
+ private final String name; // The name of
the property.
+ private final Object overrideValue; // The bean
property value (if it's an overridden delegate).
+ private final List<String> properties; // The value of
the @Beanp(properties) annotation (unmodifiable).
+ private final ClassMeta<?> rawTypeMeta; // The real
class type of the bean property.
+ private final boolean readOnly; // True if this
property is read-only.
+ private final MethodInfo setter; // The bean
property setter.
+ private final ObjectSwap swap; // ObjectSwap
defined only via @Beanp annotation.
+ private final ClassMeta<?> typeMeta; // The
transformed class type of the bean property.
+ private final boolean writeOnly; // True if this
property is write-only.
/**
* Creates a new BeanPropertyMeta using the contents of the specified
builder.
@@ -467,30 +463,30 @@ public class BeanPropertyMeta implements
Comparable<BeanPropertyMeta> {
* @param b The builder to copy fields from.
*/
protected BeanPropertyMeta(Builder b) {
- field = b.field;
- innerField = b.innerField;
- getter = b.getter;
- setter = b.setter;
- extraKeys = b.extraKeys;
- isUri = b.isUri;
- beanMeta = b.beanMeta;
bc = b.bc;
- ap = bc.getAnnotationProvider();
- name = b.name;
- rawTypeMeta = b.rawTypeMeta;
- typeMeta = b.typeMeta;
- properties = b.properties == null ? null : u(b.properties);
- swap = b.swap;
+ beanMeta = b.beanMeta;
beanRegistry = b.beanRegistry;
- overrideValue = b.overrideValue;
+ canRead = b.canRead;
+ canWrite = b.canWrite;
delegateFor = b.delegateFor;
+ extraKeys = b.extraKeys;
+ field = b.field;
+ getter = b.getter;
+ innerField = b.innerField;
isDyna = b.isDyna;
isDynaGetterMap = b.isDynaGetterMap;
- canRead = b.canRead;
- canWrite = b.canWrite;
+ isUri = b.isUri;
+ name = b.name;
+ overrideValue = b.overrideValue;
+ properties = u(b.properties);
+ rawTypeMeta = b.rawTypeMeta;
readOnly = b.readOnly;
+ setter = b.setter;
+ swap = b.swap;
+ typeMeta = b.typeMeta;
writeOnly = b.writeOnly;
- hashCode = HashCode.of(beanMeta, name);
+ ap = bc.getAnnotationProvider();
+ hashCode = hash(beanMeta, name);
}
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
index 19f52ff52f..6996d02e12 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BasicFileFinder.java
@@ -76,7 +76,7 @@ public class BasicFileFinder implements FileFinder {
this.exclude = builder.exclude;
this.includePatterns =
l(include).stream().map(Pattern::pattern).toArray(String[]::new);
this.excludePatterns =
l(exclude).stream().map(Pattern::pattern).toArray(String[]::new);
- this.hashCode = HashCode.of(getClass(), roots, cachingLimit,
includePatterns, excludePatterns);
+ this.hashCode = hash(getClass(), roots, cachingLimit,
includePatterns, excludePatterns);
}
/**
@@ -92,7 +92,7 @@ public class BasicFileFinder implements FileFinder {
this.exclude = new Pattern[0];
this.includePatterns = new String[0];
this.excludePatterns = new String[0];
- this.hashCode = HashCode.of(getClass(), roots, cachingLimit,
includePatterns, excludePatterns);
+ this.hashCode = hash(getClass(), roots, cachingLimit,
includePatterns, excludePatterns);
}
@Override /* Overridden from Object */
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
index a29d2ff2aa..1a04340f54 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
@@ -91,7 +91,7 @@ public class BasicStaticFiles implements StaticFiles {
public BasicStaticFiles(StaticFiles.Builder builder) {
this.headers = builder.headers.toArray(new
Header[builder.headers.size()]);
this.mimeTypes = builder.mimeTypes;
- this.hashCode = HashCode.of(hashCode(), headers);
+ this.hashCode = hash(hashCode(), headers);
this.fileFinder = builder.fileFinder.build();
}
@@ -104,7 +104,7 @@ public class BasicStaticFiles implements StaticFiles {
protected BasicStaticFiles() {
this.headers = new Header[0];
this.mimeTypes = null;
- this.hashCode = HashCode.of(hashCode(), headers);
+ this.hashCode = hash(hashCode(), headers);
this.fileFinder = null;
}
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
index 475c09cab6..e41102e614 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
@@ -148,7 +148,7 @@ public class ThrownStats implements Cloneable {
this.guid = x.guid;
this.thrownClass = x.thrownClass;
this.firstMessage = x.firstMessage;
- this.stackTrace = x.stackTrace == null ? null :
u(copyOf(x.stackTrace));
+ this.stackTrace = u(copyOf(x.stackTrace));
this.causedBy = opt(x.causedBy.isPresent() ?
x.causedBy.get().clone() : null);
this.hash = x.hash;
this.count = new AtomicInteger(x.count.get());
@@ -165,7 +165,7 @@ public class ThrownStats implements Cloneable {
this.guid = new Random().nextLong();
this.thrownClass = builder.throwable.getClass();
this.firstMessage = builder.throwable.getMessage();
- this.stackTrace = builder.stackTrace == null ? null :
u(copyOf(builder.stackTrace));
+ this.stackTrace = u(copyOf(builder.stackTrace));
this.causedBy = opt(builder.causedBy);
this.hash = builder.hash;
this.count = new AtomicInteger(0);