You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2026/10/13 07:22:38 UTC
(cxf) branch coheigea/CXF-6821 created (now 3f52e4fcaeb)
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a change to branch coheigea/CXF-6821
in repository https://gitbox.apache.org/repos/asf/cxf.git
at 3f52e4fcaeb CXF-6821: Apply @XmlJavaTypeAdapter to list/array members of exceptions
This branch includes the following new commits:
new 3f52e4fcaeb CXF-6821: Apply @XmlJavaTypeAdapter to list/array members of exceptions
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(cxf) 01/01: CXF-6821: Apply @XmlJavaTypeAdapter to list/array members of exceptions
Posted by co...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch coheigea/CXF-6821
in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 3f52e4fcaeb08de1d4ba71c61b6ed408e2f23f2a
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue Oct 13 08:22:10 2026 +0100
CXF-6821: Apply @XmlJavaTypeAdapter to list/array members of exceptions
---
.../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>