This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/4.1.x-fixes by this push:
     new 083dc018d76 CXF-6821: Apply @XmlJavaTypeAdapter to list/array members 
of exceptions (#3573)
083dc018d76 is described below

commit 083dc018d76799b9ad797b729bd366fb7a8d1f46
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Tue Oct 13 13:38:15 2026 +0100

    CXF-6821: Apply @XmlJavaTypeAdapter to list/array members of exceptions 
(#3573)
    
    (cherry picked from commit 3348a09d89e5e2b8e3de41132d9b9cd5d68b3b50)
---
 .../org/apache/cxf/jaxb/JAXBEncoderDecoder.java    | 103 ++++---
 .../org/apache/cxf/jaxb/JAXBSchemaInitializer.java |   6 +-
 .../src/main/java/org/apache/cxf/jaxb/Utils.java   |  36 ++-
 .../apache/cxf/jaxws/AdaptedListExceptionTest.java | 312 +++++++++++++++++++++
 .../java/org/apache/cxf/jaxws/throwFieldFault.xml  |  26 ++
 .../java/org/apache/cxf/jaxws/throwGetterFault.xml |  26 ++
 6 files changed, 464 insertions(+), 45 deletions(-)

diff --git 
a/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java 
b/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
index 4f2d443586a..cc965a7fc91 100644
--- 
a/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
+++ 
b/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
@@ -43,6 +43,7 @@ import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -76,6 +77,8 @@ import jakarta.xml.bind.annotation.XmlAccessorOrder;
 import jakarta.xml.bind.annotation.XmlAttribute;
 import jakarta.xml.bind.annotation.XmlType;
 import jakarta.xml.bind.annotation.adapters.HexBinaryAdapter;
+import jakarta.xml.bind.annotation.adapters.XmlAdapter;
+import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import jakarta.xml.bind.attachment.AttachmentMarshaller;
 import jakarta.xml.bind.attachment.AttachmentUnmarshaller;
 import org.apache.cxf.common.i18n.Message;
@@ -239,7 +242,8 @@ public final class JAXBEncoderDecoder {
                         writeArrayObject(marshaller,
                                          source,
                                          elName,
-                                         mObj);
+                                         mObj,
+                                         null);
                     } else {
                         writeObject(marshaller, source, newJAXBElement(elName, 
cls, mObj));
                     }
@@ -447,8 +451,8 @@ public final class JAXBEncoderDecoder {
                     Field f = (Field)member;
                     QName fname = new QName(namespace, f.getName());
                     ReflectionUtil.setAccessible(f);
-                    if (JAXBSchemaInitializer.isArray(f.getGenericType())) {
-                        writeArrayObject(marshaller, writer, fname, 
f.get(elValue));
+                    if (Utils.isFieldArray(f)) {
+                        writeArrayObject(marshaller, writer, fname, 
f.get(elValue), Utils.getFieldXJTA(f));
                     } else {
                         Object o = Utils.getFieldValue(f, elValue);
                         writeObject(marshaller, writer, newJAXBElement(fname, 
String.class, o));
@@ -459,8 +463,8 @@ public final class JAXBEncoderDecoder {
                     String name = m.getName().substring(idx);
                     name = Character.toLowerCase(name.charAt(0)) + 
name.substring(1);
                     QName mname = new QName(namespace, name);
-                    if 
(JAXBSchemaInitializer.isArray(m.getGenericReturnType())) {
-                        writeArrayObject(marshaller, writer, mname, 
m.invoke(elValue));
+                    if (Utils.isMethodArray(m)) {
+                        writeArrayObject(marshaller, writer, mname, 
m.invoke(elValue), Utils.getMethodXJTA(m));
                     } else {
                         Object o = Utils.getMethodValue(m, elValue);
                         writeObject(marshaller, writer, newJAXBElement(mname, 
String.class, o));
@@ -488,17 +492,19 @@ public final class JAXBEncoderDecoder {
         }
         return m1Name;
     }
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     private static void writeArrayObject(Marshaller marshaller,
                                          Object source,
                                          QName mname,
-                                         Object mObj) throws Fault, 
JAXBException {
+                                         Object mObj,
+                                         XmlJavaTypeAdapter xjta) throws 
Exception {
         // Have to handle this ourselves.... which really
         // sucks.... but what can we do?
         if (mObj == null) {
             return;
         }
         Object objArray;
-        final Class<?> cls;
+        Class<?> cls;
         if (mObj instanceof List) {
             List<?> l = (List<?>)mObj;
             objArray = l.toArray();
@@ -507,14 +513,56 @@ public final class JAXBEncoderDecoder {
             objArray = mObj;
             cls = objArray.getClass().getComponentType();
         }
+        // an adapter on a multi-valued member applies to each item
+        XmlAdapter adapter = Utils.getXmlAdapter(xjta);
+        if (adapter != null) {
+            cls = getAdaptedItemClass(xjta);
+        }
         int len = Array.getLength(objArray);
         for (int x = 0; x < len; x++) {
             Object o = Array.get(objArray, x);
+            if (adapter != null) {
+                o = adapter.marshal(o);
+            }
             writeObject(marshaller, source,
                         newJAXBElement(mname, cls == null ? o.getClass() : 
cls, o));
         }
     }
 
+    private static Class<?> getAdaptedItemClass(XmlJavaTypeAdapter xjta) {
+        Type t = Utils.getTypeFromXmlAdapter(xjta);
+        if (t instanceof ParameterizedType) {
+            t = ((ParameterizedType)t).getRawType();
+        }
+        return t instanceof Class ? (Class<?>)t : null;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private static Object unmarshallArrayMember(Unmarshaller u, 
XMLStreamReader reader, QName q,
+                                                Type type, XmlJavaTypeAdapter 
xjta) throws Exception {
+        Class<?> compType = JAXBSchemaInitializer.getArrayComponentType(type);
+        // an adapter on a multi-valued member applies to each item
+        XmlAdapter adapter = Utils.getXmlAdapter(xjta);
+        Class<?> itemType = adapter != null ? getAdaptedItemClass(xjta) : 
compType;
+        List<Object> ret = unmarshallArray(u, reader, q, itemType, 
createList(type));
+        if (adapter != null) {
+            for (ListIterator<Object> it = ret.listIterator(); it.hasNext();) {
+                it.set(adapter.unmarshal(it.next()));
+            }
+        }
+        if (isList(type)) {
+            return ret;
+        }
+        if (compType.isPrimitive()) {
+            Object o = Array.newInstance(compType, ret.size());
+            for (int x = 0; x < ret.size(); x++) {
+                Array.set(o, x, ret.get(x));
+            }
+            return o;
+        }
+        return ret.toArray((Object[])Array.newInstance(compType, ret.size()));
+    }
+
     public static Exception unmarshallException(Unmarshaller u,
                                                 Object source,
                                                 MessagePartInfo part) {
@@ -557,22 +605,8 @@ public final class JAXBEncoderDecoder {
                 if (f != null) {
                     Type type = f.getGenericType();
                     ReflectionUtil.setAccessible(f);
-                    if (JAXBSchemaInitializer.isArray(type)) {
-                        Class<?> compType = 
JAXBSchemaInitializer.getArrayComponentType(type);
-                        List<Object> ret = unmarshallArray(u, reader, q, 
compType, createList(type));
-                        Object o = ret;
-                        if (!isList(type)) {
-                            if (compType.isPrimitive()) {
-                                o = 
java.lang.reflect.Array.newInstance(compType, ret.size());
-                                for (int x = 0; x < ret.size(); x++) {
-                                    Array.set(o, x, ret.get(x));
-                                }
-                            } else {
-                                o = ret.toArray((Object[]) 
Array.newInstance(compType, ret.size()));
-                            }
-                        }
-
-                        f.set(obj, o);
+                    if (Utils.isFieldArray(f)) {
+                        f.set(obj, unmarshallArrayMember(u, reader, q, type, 
Utils.getFieldXJTA(f)));
                     } else {
                         Object o = getElementValue(u.unmarshal(reader, 
Utils.getFieldType(f)));
                         Utils.setFieldValue(f, obj, o);
@@ -585,30 +619,15 @@ public final class JAXBEncoderDecoder {
                     }
                     Type type = m.getGenericReturnType();
                     Object o;
-                    if (JAXBSchemaInitializer.isArray(type)) {
-                        Class<?> compType = JAXBSchemaInitializer
-                            .getArrayComponentType(type);
-                        List<Object> ret = unmarshallArray(u, reader,
-                                                           q,
-                                                           compType,
-                                                           createList(type));
-                        o = ret;
-                        if (!isList(type)) {
-                            if (compType.isPrimitive()) {
-                                o = 
java.lang.reflect.Array.newInstance(compType, ret.size());
-                                for (int x = 0; x < ret.size(); x++) {
-                                    Array.set(o, x, ret.get(x));
-                                }
-                            } else {
-                                o = 
ret.toArray((Object[])Array.newInstance(compType, ret.size()));
-                            }
-                        }
+                    boolean isArray = Utils.isMethodArray(m);
+                    if (isArray) {
+                        o = unmarshallArrayMember(u, reader, q, type, 
Utils.getMethodXJTA(m));
                     } else {
                         o = getElementValue(u.unmarshal(reader, 
Utils.getMethodReturnType(m)));
                     }
                     Method m2 = Utils.getMethod(cls, accessType, "set" + s, 
m.getReturnType());
                     if (m2 != null) {
-                        if (JAXBSchemaInitializer.isArray(type)) {
+                        if (isArray) {
                             m2.invoke(obj, o);
                         } else {
                             Utils.setMethodValue(m, m2, obj, o);
diff --git 
a/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
 
b/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
index 7ccfbe0133c..34c44d6df01 100644
--- 
a/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
+++ 
b/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
@@ -550,7 +550,8 @@ class JAXBSchemaInitializer extends ServiceModelVisitor {
                 JAXBBeanInfo beanInfo = getBeanInfo(type);
                 if (beanInfo != null) {
                     XmlElement xmlElementAnno = 
f.getAnnotation(XmlElement.class);
-                    addElement(schema, seq, beanInfo, new QName(namespace, 
f.getName()), isArray(type), xmlElementAnno);
+                    addElement(schema, seq, beanInfo, new QName(namespace, 
f.getName()),
+                               isArray(type) || Utils.isFieldArray(f), 
xmlElementAnno);
                 }
             }
         }
@@ -573,7 +574,8 @@ class JAXBSchemaInitializer extends ServiceModelVisitor {
                     String name = m.getName().substring(idx);
                     name = Character.toLowerCase(name.charAt(0)) + 
name.substring(1);
                     XmlElement xmlElementAnno = 
m.getAnnotation(XmlElement.class);
-                    addElement(schema, seq, beanInfo, new QName(namespace, 
name), isArray(type), xmlElementAnno);
+                    addElement(schema, seq, beanInfo, new QName(namespace, 
name),
+                               isArray(type) || Utils.isMethodArray(m), 
xmlElementAnno);
                 }
             }
         }
diff --git a/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java 
b/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java
index 56942952f66..02747db9512 100644
--- a/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java
+++ b/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java
@@ -313,6 +313,40 @@ final class Utils {
     }
 
     static Type getTypeFromXmlAdapter(XmlJavaTypeAdapter xjta) {
+        return getXmlAdapterTypeArgument(xjta, 0);
+    }
+
+    /**
+     * Returns true if the field holds multiple values (a collection or an 
array) that are written as
+     * repeated elements. As in JAXB, an XmlJavaTypeAdapter on such a field is 
applied to each item,
+     * unless the field type is assignable to the adapter's bound type, in 
which case the adapter
+     * converts the whole value and the field is treated as single-valued.
+     */
+    static boolean isFieldArray(Field f) {
+        return JAXBSchemaInitializer.isArray(f.getGenericType())
+            && !isAdaptedAsWhole(getFieldXJTA(f), f.getType());
+    }
+
+    /**
+     * Same as {@link #isFieldArray(Field)} for a getter.
+     */
+    static boolean isMethodArray(Method m) {
+        return JAXBSchemaInitializer.isArray(m.getGenericReturnType())
+            && !isAdaptedAsWhole(getMethodXJTA(m), m.getReturnType());
+    }
+
+    private static boolean isAdaptedAsWhole(XmlJavaTypeAdapter xjta, Class<?> 
memberType) {
+        if (xjta == null) {
+            return false;
+        }
+        Type boundType = getXmlAdapterTypeArgument(xjta, 1);
+        if (boundType instanceof ParameterizedType) {
+            boundType = ((ParameterizedType)boundType).getRawType();
+        }
+        return boundType instanceof Class && 
((Class<?>)boundType).isAssignableFrom(memberType);
+    }
+
+    private static Type getXmlAdapterTypeArgument(XmlJavaTypeAdapter xjta, int 
index) {
         if (xjta != null) {
             Class<?> c2 = xjta.value();
             Type sp = c2.getGenericSuperclass();
@@ -321,7 +355,7 @@ final class Utils {
                 c2 = c2.getSuperclass();
             }
             if (sp instanceof ParameterizedType) {
-                return ((ParameterizedType)sp).getActualTypeArguments()[0];
+                return ((ParameterizedType)sp).getActualTypeArguments()[index];
             }
         }
         return null;
diff --git 
a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/AdaptedListExceptionTest.java
 
b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/AdaptedListExceptionTest.java
new file mode 100644
index 00000000000..ccabd474933
--- /dev/null
+++ 
b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/AdaptedListExceptionTest.java
@@ -0,0 +1,312 @@
+/**
+ * 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.jaxws;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import jakarta.jws.WebService;
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.adapters.XmlAdapter;
+import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.transport.local.LocalTransportFactory;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+/**
+ * CXF-6821: a member-level {@code @XmlJavaTypeAdapter} on a collection or 
array member of a
+ * custom exception class must be applied to each item, in the schema and on 
the wire.
+ */
+public class AdaptedListExceptionTest extends AbstractJaxWsTest {
+
+    private static final String ADDRESS = 
"local://localhost/adaptedListException";
+
+    @Test
+    public void testSchema() throws Exception {
+        Document doc = getWSDLDocument(createServer());
+
+        String fieldSeq = 
"//xsd:complexType[@name='FieldListException']/xsd:sequence/";
+        assertValid(fieldSeq + 
"xsd:element[@name='list'][@maxOccurs='unbounded'][@type='tns:myClass2']", doc);
+        assertValid(fieldSeq + 
"xsd:element[@name='array'][@maxOccurs='unbounded'][@type='tns:myClass2']", 
doc);
+        assertValid(fieldSeq + 
"xsd:element[@name='single'][@type='tns:myClass2']", doc);
+        assertInvalid(fieldSeq + "xsd:element[@name='single'][@maxOccurs]", 
doc);
+        assertValid(fieldSeq + 
"xsd:element[@name='joined'][@type='xs:string']", doc);
+        assertInvalid(fieldSeq + "xsd:element[@name='joined'][@maxOccurs]", 
doc);
+
+        String getterSeq = 
"//xsd:complexType[@name='GetterListException']/xsd:sequence/";
+        assertValid(getterSeq + 
"xsd:element[@name='list'][@maxOccurs='unbounded'][@type='tns:myClass2']", doc);
+        assertValid(getterSeq + 
"xsd:element[@name='array'][@maxOccurs='unbounded'][@type='tns:myClass2']", 
doc);
+        assertValid(getterSeq + 
"xsd:element[@name='single'][@type='tns:myClass2']", doc);
+        assertInvalid(getterSeq + "xsd:element[@name='single'][@maxOccurs]", 
doc);
+    }
+
+    @Test
+    public void testFaultDetailOnTheWire() throws Exception {
+        createServer();
+        addNamespace("ns", "http://jaxws.cxf.apache.org/";);
+
+        Node res = invoke(ADDRESS, LocalTransportFactory.TRANSPORT_ID, 
"throwFieldFault.xml");
+        String detail = "//s:Fault/detail/ns:FieldListException/";
+        assertValid(detail + "list[1]/value[text()='item0']", res);
+        assertValid(detail + "list[2]/value[text()='item1']", res);
+        assertValid(detail + "array[2]/value[text()='item1']", res);
+        assertValid(detail + "single/value[text()='single']", res);
+        assertValid(detail + "joined[text()='item0,item1']", res);
+
+        res = invoke(ADDRESS, LocalTransportFactory.TRANSPORT_ID, 
"throwGetterFault.xml");
+        detail = "//s:Fault/detail/ns:GetterListException/";
+        assertValid(detail + "list[1]/value[text()='item0']", res);
+        assertValid(detail + "list[2]/value[text()='item1']", res);
+        assertValid(detail + "array[2]/value[text()='item1']", res);
+        assertValid(detail + "single/value[text()='single']", res);
+    }
+
+    @Test
+    public void testFieldRoundTrip() throws Exception {
+        createServer();
+        try {
+            createClient().throwFieldFault(3);
+            fail("Expected FieldListException");
+        } catch (FieldListException ex) {
+            assertEquals(List.of("item0", "item1", "item2"), values(ex.list));
+            assertEquals(List.of("item0", "item1", "item2"), 
values(List.of(ex.array)));
+            assertEquals("single", ex.single.getValue());
+            assertEquals(List.of("item0", "item1", "item2"), ex.joined);
+        }
+    }
+
+    @Test
+    public void testGetterRoundTrip() throws Exception {
+        createServer();
+        try {
+            createClient().throwGetterFault(2);
+            fail("Expected GetterListException");
+        } catch (GetterListException ex) {
+            assertEquals(List.of("item0", "item1"), values(ex.getList()));
+            assertEquals(List.of("item0", "item1"), 
values(List.of(ex.getArray())));
+            assertEquals("single", ex.getSingle().getValue());
+        }
+    }
+
+    @Test
+    public void testEmptyAndNullRoundTrip() throws Exception {
+        createServer();
+        try {
+            createClient().throwFieldFault(-1);
+            fail("Expected FieldListException");
+        } catch (FieldListException ex) {
+            assertNull(ex.list);
+            assertNull(ex.single);
+        }
+    }
+
+    private Server createServer() {
+        JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
+        sf.setBus(getBus());
+        sf.setServiceClass(AdaptedFaultService.class);
+        sf.setServiceBean(new AdaptedFaultServiceImpl());
+        sf.setAddress(ADDRESS);
+        return sf.create();
+    }
+
+    private AdaptedFaultService createClient() {
+        JaxWsProxyFactoryBean cf = new JaxWsProxyFactoryBean();
+        cf.setBus(getBus());
+        cf.setServiceClass(AdaptedFaultService.class);
+        cf.setAddress(ADDRESS);
+        return cf.create(AdaptedFaultService.class);
+    }
+
+    private static List<String> values(List<MyClass1> list) {
+        List<String> values = new ArrayList<>();
+        for (MyClass1 c : list) {
+            values.add(c.getValue());
+        }
+        return values;
+    }
+
+    private static List<MyClass1> items(int count) {
+        if (count < 0) {
+            return null;
+        }
+        List<MyClass1> items = new ArrayList<>();
+        for (int i = 0; i < count; i++) {
+            items.add(new MyClass1("item" + i));
+        }
+        return items;
+    }
+
+    /**
+     * Not a JAXB-bindable class (no no-arg constructor), so it can only be 
written via the adapter.
+     */
+    public static final class MyClass1 {
+        private final String value;
+
+        public MyClass1(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+    @XmlAccessorType(XmlAccessType.FIELD)
+    public static class MyClass2 {
+        private String value;
+
+        public MyClass2() {
+        }
+
+        public MyClass2(String value) {
+            this.value = value;
+        }
+    }
+
+    public static class Cl1ToCl2Adapter extends XmlAdapter<MyClass2, MyClass1> 
{
+        @Override
+        public MyClass1 unmarshal(MyClass2 v) {
+            return v == null ? null : new MyClass1(v.value);
+        }
+
+        @Override
+        public MyClass2 marshal(MyClass1 v) {
+            return v == null ? null : new MyClass2(v.getValue());
+        }
+    }
+
+    /**
+     * Adapts the whole collection, so the member is single-valued.
+     */
+    public static class JoinAdapter extends XmlAdapter<String, List<String>> {
+        @Override
+        public List<String> unmarshal(String v) {
+            return v == null ? null : new ArrayList<>(List.of(v.split(",")));
+        }
+
+        @Override
+        public String marshal(List<String> v) {
+            return v == null ? null : String.join(",", v);
+        }
+    }
+
+    @XmlAccessorType(XmlAccessType.FIELD)
+    public static class FieldListException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        @XmlJavaTypeAdapter(Cl1ToCl2Adapter.class)
+        private List<MyClass1> list;
+
+        @XmlJavaTypeAdapter(Cl1ToCl2Adapter.class)
+        private MyClass1[] array;
+
+        @XmlJavaTypeAdapter(Cl1ToCl2Adapter.class)
+        private MyClass1 single;
+
+        @XmlJavaTypeAdapter(JoinAdapter.class)
+        private List<String> joined;
+
+        public FieldListException() {
+        }
+
+        public FieldListException(String message) {
+            super(message);
+        }
+    }
+
+    public static class GetterListException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        private List<MyClass1> list;
+        private MyClass1[] array;
+        private MyClass1 single;
+
+        public GetterListException() {
+        }
+
+        public GetterListException(String message) {
+            super(message);
+        }
+
+        @XmlJavaTypeAdapter(Cl1ToCl2Adapter.class)
+        public List<MyClass1> getList() {
+            return list;
+        }
+
+        public void setList(List<MyClass1> list) {
+            this.list = list;
+        }
+
+        @XmlJavaTypeAdapter(Cl1ToCl2Adapter.class)
+        public MyClass1[] getArray() {
+            return array;
+        }
+
+        public void setArray(MyClass1[] array) {
+            this.array = array;
+        }
+
+        @XmlJavaTypeAdapter(Cl1ToCl2Adapter.class)
+        public MyClass1 getSingle() {
+            return single;
+        }
+
+        public void setSingle(MyClass1 single) {
+            this.single = single;
+        }
+    }
+
+    @WebService
+    public interface AdaptedFaultService {
+        String throwFieldFault(int count) throws FieldListException;
+
+        String throwGetterFault(int count) throws GetterListException;
+    }
+
+    @WebService(endpointInterface = 
"org.apache.cxf.jaxws.AdaptedListExceptionTest$AdaptedFaultService")
+    public static class AdaptedFaultServiceImpl implements AdaptedFaultService 
{
+        public String throwFieldFault(int count) throws FieldListException {
+            FieldListException ex = new FieldListException("field fault");
+            ex.list = items(count);
+            if (count >= 0) {
+                ex.array = ex.list.toArray(new MyClass1[0]);
+                ex.single = new MyClass1("single");
+                ex.joined = values(ex.list);
+            }
+            throw ex;
+        }
+
+        public String throwGetterFault(int count) throws GetterListException {
+            GetterListException ex = new GetterListException("getter fault");
+            ex.setList(items(count));
+            ex.setArray(ex.getList().toArray(new MyClass1[0]));
+            ex.setSingle(new MyClass1("single"));
+            throw ex;
+        }
+    }
+}
diff --git 
a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/throwFieldFault.xml 
b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/throwFieldFault.xml
new file mode 100644
index 00000000000..7bc57c07a1f
--- /dev/null
+++ b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/throwFieldFault.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+ 
+  http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";>
+    <soap:Body>
+        <ns2:throwFieldFault xmlns:ns2="http://jaxws.cxf.apache.org/";>
+            <arg0>2</arg0>
+        </ns2:throwFieldFault>
+    </soap:Body>
+</soap:Envelope>
diff --git 
a/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/throwGetterFault.xml 
b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/throwGetterFault.xml
new file mode 100644
index 00000000000..ae02360bef6
--- /dev/null
+++ b/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/throwGetterFault.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+ 
+  http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";>
+    <soap:Body>
+        <ns2:throwGetterFault xmlns:ns2="http://jaxws.cxf.apache.org/";>
+            <arg0>2</arg0>
+        </ns2:throwGetterFault>
+    </soap:Body>
+</soap:Envelope>

Reply via email to