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>