Author: scheu Date: Mon Jul 12 20:08:38 2010 New Revision: 963459 URL: http://svn.apache.org/viewvc?rev=963459&view=rev Log: AXIS2-4765 Contributor:Rich Scheuerle Inspect generics to determine how to build a JAXBContext for JAX-WS applications.
Added: axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/utility/ClassUtilsTests.java Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/GorillaDLWProxyTests.java axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/GorillaProxyImpl.java axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/sei/GorillaInterface.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/PackageSetBuilder.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/utility/ClassUtils.java Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/GorillaDLWProxyTests.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/GorillaDLWProxyTests.java?rev=963459&r1=963458&r2=963459&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/GorillaDLWProxyTests.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/GorillaDLWProxyTests.java Mon Jul 12 20:08:38 2010 @@ -159,6 +159,8 @@ public class GorillaDLWProxyTests extend assertTrue(observedKey.contains("org.apache.axis2.jaxws.proxy.gorilla_dlw.data")); // Check for the package referenced only by an @XmlSeeAlso assertTrue(observedKey.contains("org.test.stock2")); + // Check for the package referenced in the return type List<> generic + assertTrue(observedKey.contains("org.test.stock1")); } @@ -178,6 +180,8 @@ public class GorillaDLWProxyTests extend assertTrue(observedKey.contains("org.apache.axis2.jaxws.proxy.gorilla_dlw.data")); // Check for the package referenced only by an @XmlSeeAlso assertTrue(observedKey.contains("org.test.stock2")); + // Check for the package referenced in the return type List<> generic + assertTrue(observedKey.contains("org.test.stock1")); } }catch(Exception e){ e.printStackTrace(); Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/GorillaProxyImpl.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/GorillaProxyImpl.java?rev=963459&r1=963458&r2=963459&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/GorillaProxyImpl.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/GorillaProxyImpl.java Mon Jul 12 20:08:38 2010 @@ -150,5 +150,11 @@ public class GorillaProxyImpl implements } } + + /** + * The following non-doc method is not invoked. It is only present to test the + * generic reflection code. + */ + public List<org.test.stock1.GetPrice> sampleMethod() { return null;} } Modified: axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/sei/GorillaInterface.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/sei/GorillaInterface.java?rev=963459&r1=963458&r2=963459&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/sei/GorillaInterface.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws-integration/test/org/apache/axis2/jaxws/proxy/gorilla_dlw/sei/GorillaInterface.java Mon Jul 12 20:08:38 2010 @@ -331,4 +331,11 @@ public interface GorillaInterface { public void echoPolymorphicDate( @WebParam(name = "request", targetNamespace = "http://org/apache/axis2/jaxws/proxy/gorilla_dlw/data") XMLGregorianCalendar request); + + /** + * The following non-doc method is not invoked. It is only present to test the + * generic reflection code. + */ + @WebMethod + public List<org.test.stock1.GetPrice> sampleMethod(); } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/PackageSetBuilder.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/PackageSetBuilder.java?rev=963459&r1=963458&r2=963459&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/PackageSetBuilder.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/PackageSetBuilder.java Mon Jul 12 20:08:38 2010 @@ -48,20 +48,26 @@ import javax.jws.WebService; import javax.wsdl.Definition; import javax.wsdl.WSDLException; import javax.xml.bind.JAXBElement; +import javax.xml.ws.Holder; +import javax.xml.ws.Response; + import java.io.File; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URL; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.Future; /** * In order to marshal or unmarshal the user data, we need to know the set of packages involved. @@ -336,6 +342,14 @@ public class PackageSetBuilder { set.addAll(packages); } + // See if the Method is available. If so, additional reflection + // can be performed to obtain the generic references + Method m = getMethod(opDesc, msrd); + if (log.isDebugEnabled()) { + log.debug("Method obtained:" + m); + } + + // In most doc/literal cases, the @RequestWrapper or @ResponseWrapper classes are successfully found. // The wrapper classes contain the representation of the parameters, thus the parameters don't need // to be separately processed. @@ -344,7 +358,11 @@ public class PackageSetBuilder { if (log.isDebugEnabled()) { log.debug("Collect the packages of the parameters"); } - addPackagesFromParameters(set, opDesc) ; + addPackagesFromParameters(set, opDesc); + if (m != null) { + addPackagesFromParameters(set, m); + } + } // Finally consider the result type @@ -359,9 +377,123 @@ public class PackageSetBuilder { set.add("@" + pkg); // Indicates a package from an actual class reference (versus namespace) set.add("[" + cls.getCanonicalName() + "]"); // Indicates a actual class reference } + if (m != null) { + addPackagesFromReturn(set, m); + } + } } + /** + * Get Method associated with this OperationDesc + * @param opDesc + * @param msrd + * @return Method or null + */ + private static Method getMethod(OperationDescription opDesc, + MarshalServiceRuntimeDescription msrd) { + Method m = null; + try { + m = msrd.getMethod(opDesc); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Method could not be obtained due to " + t); + } + } + return m; + } + + /** + * add package information by reflecting the parameters on Method m + * @param set + * @param m + */ + private static void addPackagesFromParameters(TreeSet<String> set, Method m) { + if (log.isDebugEnabled()) { + log.debug("enter addPackagesFromParameters for " + m); + } + try { + if (m != null) { + Set<Class> classes = new HashSet<Class>(); + // Build a set of all of the classes referenced in the parameters (including + // generic argument references + for(Type type : m.getGenericParameterTypes()) { + classes = ClassUtils.getClasses(type, classes); + } + addClassesToPackageSet(classes, set); + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Could not reflect the information on method " + m + " due to " + t); + log.debug("Processing continues"); + } + } + if (log.isDebugEnabled()) { + log.debug("exit addPackagesFromParameters"); + } + } + + /** + * add package information by reflecting the return type on Method m + * @param set + * @param m + */ + private static void addPackagesFromReturn(TreeSet<String> set, Method m) { + if (log.isDebugEnabled()) { + log.debug("enter addPackagesFromReturn for " + m); + } + try { + if (m != null) { + Set<Class> classes = new HashSet<Class>(); + // Build a set of all of the classes referenced in the return(including + // generic argument references + classes = ClassUtils.getClasses(m.getGenericReturnType(), classes); + addClassesToPackageSet(classes, set); + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Could not reflect the information on method " + m + " due to " + t); + log.debug("Processing continues"); + } + } + if (log.isDebugEnabled()) { + log.debug("exit addPackagesFromReturn"); + } + } + + /** + * Add all of the packages/names in classSet to our package set collection + * @param classSet + * @param set + */ + private static void addClassesToPackageSet(Set<Class> classSet, TreeSet<String> set) { + if (log.isDebugEnabled()) { + log.debug("enter addClassesToPackageSet"); + } + if (classSet != null) { + for (Class clz : classSet) { + if (clz != null && + clz != Holder.class && + clz != Future.class && + clz != Response.class) { + Package pkg = clz.getPackage(); + //For primitive types there is no package + String pkgText = (pkg != null) ? pkg.getName() : null; + if (pkg != null) { + String name = clz.getCanonicalName(); + if (log.isDebugEnabled()) { + log.debug(" adding class " + name); + } + set.add("@" + pkgText); // Indicates a package from an actual class reference + set.add("[" + name + "]"); // Indicates a actual class referenced + } + } + } + } + if (log.isDebugEnabled()) { + log.debug("exit addClassesToPackageSet"); + } + } /** * addPackagesFromParameters @@ -377,10 +509,7 @@ public class PackageSetBuilder { // Get the actual type of the parameter. // For example if the parameter is Holder<A>, the A.class is // returned. - // TODO Unfortunately the ParameterDescriptor only provides - // the class, not the full generic. So if the parameter - // is List<A>, only List is returned. The ParameterDescriptor - // and this logic will need to be improved to handle that case. + // NOTE Generics are handled by the addPackagesFromParameters(Method..) method Class paramClass = pDesc.getParameterActualType(); String pkg = getPackageFromClass(paramClass); if (log.isDebugEnabled()) { Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/utility/ClassUtils.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/utility/ClassUtils.java?rev=963459&r1=963458&r2=963459&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/utility/ClassUtils.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/utility/ClassUtils.java Mon Jul 12 20:08:38 2010 @@ -19,9 +19,17 @@ package org.apache.axis2.jaxws.utility; -import org.apache.axis2.java.security.AccessController; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; import javax.jws.WebService; import javax.xml.ws.Holder; @@ -29,12 +37,10 @@ import javax.xml.ws.Service; import javax.xml.ws.WebFault; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceProvider; -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.security.PrivilegedAction; -import java.util.HashMap; + +import org.apache.axis2.java.security.AccessController; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** Contains static Class utility methods related to method parameter/argument marshalling. */ public class ClassUtils { @@ -305,5 +311,39 @@ public class ClassUtils { } }); } + + /** + * + */ + public static Set<Class> getClasses(Type type, Set<Class> list) { + if (list == null) { + list = new HashSet<Class>(); + } + try { + if (type instanceof Class) { + list.add( (Class)type); + } + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + getClasses(pt.getRawType(), list); + Type types[] = pt.getActualTypeArguments(); + if (types != null) { + for (int i=0; i<types.length; i++) { + getClasses(types[i], list); + } + } + } + if (type instanceof GenericArrayType) { + GenericArrayType gat = (GenericArrayType) type; + getClasses(gat.getGenericComponentType(), list); + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Problem occurred in getClasses. Processing continues " + t); + } + } + return list; + } + } Added: axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/utility/ClassUtilsTests.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/utility/ClassUtilsTests.java?rev=963459&view=auto ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/utility/ClassUtilsTests.java (added) +++ axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/utility/ClassUtilsTests.java Mon Jul 12 20:08:38 2010 @@ -0,0 +1,90 @@ +/* + * 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.axis2.jaxws.utility; + +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * Test the utility methods in the ClassUtils class + */ +public class ClassUtilsTests extends TestCase { + + + public void test1() throws Exception { + + Method m = Sample.class.getMethod("method1", null); + Set<Class> set = ClassUtils.getClasses(m.getGenericReturnType(), null); + + assertTrue(set.contains(int.class)); + assertTrue(!(set.contains(List.class))); + assertTrue(!(set.contains(BigInteger.class))); + assertTrue(!(set.contains(Float.class))); + assertTrue(!(set.contains(HashMap.class))); + + } + + public void test2() throws Exception { + + Method m = Sample.class.getMethod("method2", null); + Set<Class> set = ClassUtils.getClasses(m.getGenericReturnType(), null); + + assertTrue(!(set.contains(int.class))); + assertTrue((set.contains(List.class))); + assertTrue((set.contains(BigInteger.class))); + assertTrue(!(set.contains(Float.class))); + assertTrue(!(set.contains(HashMap.class))); + } + + public void test3() throws Exception { + + Method m = Sample.class.getMethod("method3", null); + Set<Class> set = ClassUtils.getClasses(m.getGenericReturnType(), null); + assertTrue(!(set.contains(int.class))); + assertTrue((set.contains(List.class))); + assertTrue((set.contains(BigInteger.class))); + assertTrue(!(set.contains(Float.class))); + assertTrue(!(set.contains(HashMap.class))); + } + + public void test4() throws Exception { + + Method m = Sample.class.getMethod("method4", null); + Set<Class> set = ClassUtils.getClasses(m.getGenericReturnType(), null); + assertTrue(!(set.contains(int.class))); + assertTrue((set.contains(List.class))); + assertTrue(!(set.contains(BigInteger.class))); + assertTrue((set.contains(Float.class))); + assertTrue((set.contains(HashMap.class))); + } + + class Sample { + public int method1() { return 0;} + public List<BigInteger> method2() { return null;} + public List<BigInteger[]>[] method3() { return null;} + public List<HashMap<Integer, Float[]>>[] method4() { return null;} + } + +}