This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new 7fb40bdd92f CXF-8297 - Fix NPE in Aegis for generic array properties
(e.g. T[]) (#3574)
7fb40bdd92f is described below
commit 7fb40bdd92fa24758254d370360ecb54af040a75
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Wed Oct 14 11:48:58 2026 +0100
CXF-8297 - Fix NPE in Aegis for generic array properties (e.g. T[]) (#3574)
---
.../java/org/apache/cxf/aegis/type/TypeUtil.java | 22 ++++-
.../cxf/aegis/type/java5/GenericArrayTest.java | 104 +++++++++++++++++++++
2 files changed, 125 insertions(+), 1 deletion(-)
diff --git
a/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java
b/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java
index 47842fb455c..86d3099ba9a 100644
--- a/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java
+++ b/rt/databinding/aegis/src/main/java/org/apache/cxf/aegis/type/TypeUtil.java
@@ -22,6 +22,8 @@ import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
@@ -251,7 +253,10 @@ public final class TypeUtil {
if (type instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) type;
Type compType = gat.getGenericComponentType();
- Class<?> arrayBaseType = getTypeRelatedClass(compType);
+ Class<?> arrayBaseType =
getTypeRelatedClass(getErasedType(compType));
+ if (arrayBaseType == null) {
+ arrayBaseType = Object.class;
+ }
// believe it or not, this seems to be the only way to get the
// Class object for an array of primitive type.
Object instance = Array.newInstance(arrayBaseType, 0);
@@ -259,4 +264,19 @@ public final class TypeUtil {
}
return null;
}
+
+ /**
+ * Replace a type variable or wildcard by its (first) upper bound, e.g. so
that
+ * the component type of a generic array such as T[] can be resolved to a
class.
+ */
+ private static Type getErasedType(Type type) {
+ Type erased = type;
+ while (erased instanceof TypeVariable || erased instanceof
WildcardType) {
+ Type[] bounds = erased instanceof TypeVariable
+ ? ((TypeVariable<?>) erased).getBounds()
+ : ((WildcardType) erased).getUpperBounds();
+ erased = bounds.length > 0 ? bounds[0] : Object.class;
+ }
+ return erased;
+ }
}
diff --git
a/rt/databinding/aegis/src/test/java/org/apache/cxf/aegis/type/java5/GenericArrayTest.java
b/rt/databinding/aegis/src/test/java/org/apache/cxf/aegis/type/java5/GenericArrayTest.java
new file mode 100644
index 00000000000..e061bc4e312
--- /dev/null
+++
b/rt/databinding/aegis/src/test/java/org/apache/cxf/aegis/type/java5/GenericArrayTest.java
@@ -0,0 +1,104 @@
+/**
+ * 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.cxf.aegis.type.java5;
+
+import org.w3c.dom.Document;
+
+import org.apache.cxf.aegis.AbstractAegisTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * A bean property whose type is a generic array of a type variable (e.g. T[])
+ * used to cause a NullPointerException in TypeUtil.getTypeRelatedClass.
+ */
+public class GenericArrayTest extends AbstractAegisTest {
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ createService(GenericArrayService.class, "GenericArrayService");
+ }
+
+ @Test
+ public void testGenericArrayProperty() throws Exception {
+ Document doc = getWSDLDocument("GenericArrayService");
+ assertNotNull(doc);
+ assertValid("//xsd:complexType[@name='Page']", doc);
+ }
+
+ @Test
+ public void testBoundedGenericArrayProperty() throws Exception {
+ Document doc = getWSDLDocument("GenericArrayService");
+ assertNotNull(doc);
+ // T extends Score, so T[] should be mapped to an array of Score
+ assertValid("//xsd:complexType[@name='Subject']"
+ + "//xsd:element[@name='scores' and
@type='tns:ArrayOfScore']", doc);
+
assertValid("//xsd:complexType[@name='ArrayOfScore']//xsd:element[@type='tns:Score']",
doc);
+ }
+
+ public static class Page<T> {
+ private T[] items;
+
+ public T[] getItems() {
+ return items;
+ }
+
+ public void setItems(T[] items) {
+ this.items = items;
+ }
+ }
+
+ public static class Score {
+ private int value;
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+ }
+
+ public static class Subject<T extends Score> {
+ private T[] scores;
+
+ public T[] getScores() {
+ return scores;
+ }
+
+ public void setScores(T[] scores) {
+ this.scores = scores;
+ }
+ }
+
+ public static class GenericArrayService {
+ public Page<String> getPage() {
+ return new Page<>();
+ }
+
+ public Subject<Score> getSubject() {
+ return new Subject<>();
+ }
+ }
+}