Author: klape
Date: 2013-12-13 14:06:32 -0500 (Fri, 13 Dec 2013)
New Revision: 18178
Modified:
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ASMHelper.java
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBContextInitializer.java
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBDataBinding.java
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/test/java/org/apache/cxf/jaxb/JAXBDataBindingTest.java
Log:
[JBPAPP-10926][CXF-5437] Fix generics in @WebFault-annotated exceptions
Modified:
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ASMHelper.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ASMHelper.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ASMHelper.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -73,7 +73,7 @@
return buf.toString();
}
- protected static String periodToSlashes(String s) {
+ public static String periodToSlashes(String s) {
char ch[] = s.toCharArray();
for (int x = 0; x < ch.length; x++) {
if (ch[x] == '.') {
Modified:
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/common/common/src/main/java/org/apache/cxf/common/util/ReflectionUtil.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -23,9 +23,12 @@
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
+import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.*;
import org.apache.cxf.common.classloader.ClassLoaderUtils;
@@ -82,6 +85,19 @@
}
}
+ public static <T> Constructor<T>[] getDeclaredConstructors(final
Class<T> cls) {
+ return AccessController.doPrivileged(new
PrivilegedAction<Constructor<T>[]>() {
+ @SuppressWarnings("unchecked")
+ public Constructor<T>[] run() {
+ try {
+ return (Constructor<T>[])cls.getDeclaredConstructors();
+ } catch (SecurityException e) {
+ return null;
+ }
+ }
+ });
+ }
+
private static String getPackageName(String clzName) {
if (clzName.indexOf("/") == -1) {
return null;
Modified:
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBContextInitializer.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBContextInitializer.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBContextInitializer.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -21,6 +21,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
@@ -30,6 +31,7 @@
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Collection;
+import java.util.Map;
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
@@ -43,6 +45,8 @@
import javax.xml.namespace.QName;
import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.util.ASMHelper;
+import org.apache.cxf.common.util.ReflectionUtil;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.service.ServiceModelVisitor;
import org.apache.cxf.service.model.MessageInfo;
@@ -51,6 +55,10 @@
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.cxf.service.model.UnwrappedOperationInfo;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
/**
* Walks the service model and sets up the classes for the context.
*/
@@ -58,13 +66,16 @@
private Set<Class<?>> classes;
private Collection<Object> typeReferences;
+ private Map<String, Object> unmarshallerProperties;
public JAXBContextInitializer(ServiceInfo serviceInfo,
Set<Class<?>> classes,
- Collection<Object> typeReferences) {
+ Collection<Object> typeReferences,
+ Map<String, Object> unmarshallerProperties) {
super(serviceInfo);
this.classes = classes;
this.typeReferences = typeReferences;
+ this.unmarshallerProperties = unmarshallerProperties;
}
@Override
@@ -263,16 +274,24 @@
}
}
-
- private void addClass(Class<?> cls) {
- if (Throwable.class.isAssignableFrom(cls)) {
- if (!Throwable.class.equals(cls)
- && !Exception.class.equals(cls)) {
- walkReferences(cls);
+ void addClass(Class<?> claz) {
+ if (Throwable.class.isAssignableFrom(claz)) {
+ if (!Throwable.class.equals(claz)
+ && !Exception.class.equals(claz)) {
+ walkReferences(claz);
}
addClass(String.class);
+ } else if (claz.getName().startsWith("java.")
+ || claz.getName().startsWith("javax.")) {
+ return;
} else {
- cls = JAXBUtils.getValidClass(cls);
+ Class<?> cls = JAXBUtils.getValidClass(claz);
+ if (cls == null &&
ReflectionUtil.getDeclaredConstructors(claz).length > 0) {
+ //there is no init(), but other constructors
+ Object factory = createFactory(claz,
ReflectionUtil.getDeclaredConstructors(claz)[0]);
+ unmarshallerProperties.put("com.sun.xml.bind.ObjectFactory",
factory);
+ cls = claz;
+ }
if (null != cls) {
if (cls.getSuperclass() != null) {
//JAXB should do this, but it doesn't always.
@@ -439,4 +458,54 @@
}
return false;
}
+
+ @SuppressWarnings("unused")
+ private Object createFactory(Class<?> cls, Constructor<?> contructor) {
+ String newClassName = cls.getName() + "Factory";
+ ASMHelper helper = new ASMHelper();
+ ClassWriter cw = helper.createClassWriter();
+ MethodVisitor mv;
+
+ cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
+ ASMHelper.periodToSlashes(newClassName), null,
"java/lang/Object", null);
+
+ cw.visitSource(cls.getSimpleName() + "Factory" + ".java",
null);
+
+ mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
"()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
"<init>", "()V");
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+
+ mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "create" +
cls.getSimpleName(),
+ "()L" + ASMHelper.periodToSlashes(cls.getName()) +
";", null, null);
+ mv.visitCode();
+ String name = cls.getName().replace(".", "/");
+ mv.visitTypeInsn(Opcodes.NEW, name);
+ mv.visitInsn(Opcodes.DUP);
+ StringBuilder paraString = new StringBuilder("(");
+
+ for (Class<?> paraClass : contructor.getParameterTypes()) {
+ mv.visitInsn(Opcodes.ACONST_NULL);
+ paraString.append("Ljava/lang/Object;");
+ }
+ paraString.append(")V");
+
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, name, "<init>",
paraString.toString());
+
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+
+ cw.visitEnd();
+ Class<?> factoryClass = helper.loadClass(newClassName, cls,
cw.toByteArray());
+ try {
+ return factoryClass.newInstance();
+ } catch (Exception e) {
+ //ignore
+ }
+ return null;
+ }
}
Modified:
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBDataBinding.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBDataBinding.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBDataBinding.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -304,9 +304,16 @@
contextClasses = new LinkedHashSet<Class<?>>();
+ Map<String, Object> unmarshallerProps = new HashMap<String,
Object>();
+ this.setUnmarshallerProperties(unmarshallerProps);
for (ServiceInfo serviceInfo : service.getServiceInfos()) {
- JAXBContextInitializer initializer
- = new JAXBContextInitializer(serviceInfo, contextClasses, typeRefs);
+
+ JAXBContextInitializer initializer = new JAXBContextInitializer(
+ serviceInfo,
+ contextClasses,
+ typeRefs,
+ this.getUnmarshallerProperties()
+ );
initializer.walk();
if (serviceInfo.getProperty("extra.class") != null) {
Set<Class<?>> exClasses =
serviceInfo.getProperty("extra.class", Set.class);
Modified:
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -26,8 +26,10 @@
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
@@ -50,6 +52,7 @@
import org.apache.cxf.common.i18n.Message;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.ReflectionInvokationHandler;
+import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.common.xmlschema.SchemaCollection;
import org.apache.cxf.common.xmlschema.XmlSchemaUtils;
import org.apache.cxf.interceptor.Fault;
@@ -578,9 +581,13 @@
if ((type == null) && (f.getGenericType() instanceof
ParameterizedType)) {
type = f.getGenericType();
}
- JAXBBeanInfo beanInfo = getBeanInfo(type);
- if (beanInfo != null) {
- addElement(elementList, beanInfo, new QName(namespace, f.getName()),
isArray(type));
+ if (generateGenericType(type)) {
+ buildGenericElements(schema, elementList, f);
+ } else {
+ JAXBBeanInfo beanInfo = getBeanInfo(type);
+ if (beanInfo != null) {
+ addElement(elementList, beanInfo, new QName(namespace, f.getName()),
isArray(type));
+ }
}
}
for (Method m : Utils.getGetters(cls, accessType)) {
@@ -592,13 +599,18 @@
if ((type == null) && (m.getGenericReturnType() instanceof
ParameterizedType)) {
type = m.getGenericReturnType();
}
- JAXBBeanInfo beanInfo = getBeanInfo(type);
- if (beanInfo != null) {
- int idx = m.getName().startsWith("get") ? 3 : 2;
- String name = m.getName().substring(idx);
- name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
- addElement(elementList, beanInfo, new QName(namespace, name),
isArray(type));
- }
+
+ if (generateGenericType(type)) {
+ buildGenericElements(schema, elementList, m, type);
+ } else {
+ JAXBBeanInfo beanInfo = getBeanInfo(type);
+ if (beanInfo != null) {
+ int idx = m.getName().startsWith("get") ? 3 : 2;
+ String name = m.getName().substring(idx);
+ name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ addElement(elementList, beanInfo, new QName(namespace, name),
isArray(type));
+ }
+ }
}
if (propertyOrder != null && propertyOrder.length == elementList.size())
{
@@ -620,11 +632,110 @@
part.setProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION",
Boolean.TRUE);
}
+ private boolean generateGenericType(Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType paramType = (ParameterizedType)type;
+ if (paramType.getActualTypeArguments().length > 1) {
+ return true;
+
+ }
+ }
+ return false;
+ }
+
+ private void buildGenericElements(XmlSchema schema, List<XmlSchemaElement>
elementList, Field f) {
+ XmlSchemaComplexType generics = new XmlSchemaComplexType(schema);
+ Type type = f.getGenericType();
+ String rawType = ((ParameterizedType)type).getRawType().toString();
+ String typeName =
StringUtils.uncapitalize(rawType.substring(rawType.lastIndexOf(".") + 1));
+ generics.setName(typeName);
+
+ Class<?> genericsClass = f.getType();
+ buildGenericSeq(schema, generics, genericsClass);
+
+ String name = Character.toLowerCase(f.getName().charAt(0)) +
f.getName().substring(1);
+ XmlSchemaElement newel = new XmlSchemaElement();
+ newel.setName(name);
+ newel.setSchemaTypeName(generics.getQName());
+ newel.setMinOccurs(0);
+ elementList.add(newel);
+ }
+
+ private void buildGenericElements(XmlSchema schema,
+ List<XmlSchemaElement> elementList, Method m, Type type) {
+ String rawType = ((ParameterizedType)type).getRawType().toString();
+ String typeName =
StringUtils.uncapitalize(rawType.substring(rawType.lastIndexOf(".") + 1));
+
+ XmlSchemaComplexType generics =
(XmlSchemaComplexType)schema.getTypeByName(typeName);
+ if (generics == null) {
+ generics = new XmlSchemaComplexType(schema);
+ generics.setName(typeName);
+ }
+
+ Class<?> genericsClass = m.getReturnType();
+ buildGenericSeq(schema, generics, genericsClass);
+
+ int idx = m.getName().startsWith("get") ? 3 : 2;
+ String name = m.getName().substring(idx);
+ name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ XmlSchemaElement newel = new XmlSchemaElement();
+ newel.setName(name);
+ newel.setSchemaTypeName(generics.getQName());
+ newel.setMinOccurs(0);
+ elementList.add(newel);
+ }
+
+ private void buildGenericSeq(XmlSchema schema, XmlSchemaComplexType generics,
Class<?> genericsClass) {
+ XmlSchemaSequence genericsSeq = new XmlSchemaSequence();
+ generics.setParticle(genericsSeq);
+ XmlAccessType accessType = Utils.getXmlAccessType(genericsClass);
+
+ for (Field f : Utils.getFields(genericsClass, accessType)) {
+ if (f.getGenericType() instanceof TypeVariable) {
+ String genericName = Character.toLowerCase(f.getName().charAt(0)) +
f.getName().substring(1);
+ XmlSchemaElement genericEle = new XmlSchemaElement();
+ genericEle.setName(genericName);
+ genericEle.setMinOccurs(0);
+ JAXBBeanInfo anyBean = getBeanInfo(context, f.getType());
+ Iterator<QName> itr = anyBean.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ genericEle.setSchemaTypeName(typeName);
+ genericsSeq.getItems().add(genericEle);
+ }
+ }
+
+ for (Method genericMethod : Utils.getGetters(genericsClass, accessType)) {
+ if (genericMethod.getGenericReturnType() instanceof TypeVariable) {
+ int idx = genericMethod.getName().startsWith("get") ? 3 : 2;
+ String genericName = genericMethod.getName().substring(idx);
+ genericName = Character.toLowerCase(genericName.charAt(0)) +
genericName.substring(1);
+ XmlSchemaElement genericEle = new XmlSchemaElement();
+ genericEle.setName(genericName);
+ genericEle.setMinOccurs(0);
+ JAXBBeanInfo anyBean = getBeanInfo(context,
genericMethod.getReturnType());
+ Iterator<QName> itr = anyBean.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ genericEle.setSchemaTypeName(typeName);
+ genericsSeq.getItems().add(genericEle);
+ }
+
+ }
+ }
+
static boolean isArray(Type cls) {
if (cls instanceof Class) {
return ((Class)cls).isArray();
} else if (cls instanceof ParameterizedType) {
- return true;
+ ParameterizedType pt = (ParameterizedType)cls;
+ return pt.getActualTypeArguments().length == 1
+ && pt.getRawType() instanceof Class
+ &&
Collection.class.isAssignableFrom((Class<?>)pt.getRawType());
} else if (cls instanceof GenericArrayType) {
return true;
}
Modified:
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/main/java/org/apache/cxf/jaxb/Utils.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -204,7 +204,8 @@
static Class<?> getFieldType(Field f) {
XmlJavaTypeAdapter adapter = getFieldXJTA(f);
- if (adapter == null && f.getGenericType() instanceof ParameterizedType)
{
+ if (adapter == null && f.getGenericType() instanceof ParameterizedType
+ &&
((ParameterizedType)f.getGenericType()).getActualTypeArguments().length == 1) {
return null;
}
Class<?> adapterType = getTypeFromXmlAdapter(adapter);
Modified:
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/test/java/org/apache/cxf/jaxb/JAXBDataBindingTest.java
===================================================================
---
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/test/java/org/apache/cxf/jaxb/JAXBDataBindingTest.java 2013-12-13
12:26:19 UTC (rev 18177)
+++
thirdparty/cxf/branches/cxf-2.2.12/rt/databinding/jaxb/src/test/java/org/apache/cxf/jaxb/JAXBDataBindingTest.java 2013-12-13
19:06:32 UTC (rev 18178)
@@ -22,7 +22,9 @@
import java.io.OutputStream;
import java.io.StringWriter;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -229,4 +231,24 @@
String xml = stringWriter.toString();
assertTrue(xml, xml.contains("greenland=\"uri:ultima:thule"));
}
+
+ @Test
+ public void testResursiveType() throws Exception {
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ Collection<Object> typeReferences = new ArrayList<Object>();
+ Map<String, Object> props = new HashMap<String, Object>();
+ JAXBContextInitializer init = new JAXBContextInitializer(null, classes,
typeReferences, props);
+ init.addClass(Type2.class);
+ assertEquals(2, classes.size());
+ }
+
+ public abstract static class Type2 extends AddressEntity<Type2> {
+ }
+
+ public abstract static class AddressEntity<T extends AddressEntity<T>> {
+ public abstract Addressable<T> getEntity();
+ }
+
+ public interface Addressable<T extends AddressEntity<T>> {
+ }
}