Author: jason.greene(a)jboss.com
Date: 2007-01-11 03:28:06 -0500 (Thu, 11 Jan 2007)
New Revision: 1918
Added:
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/acessor/ReflectiveFieldAccessor.java
Modified:
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/builder/jaxws/JAXWSWebServiceMetaDataBuilder.java
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/umdm/FaultMetaData.java
Log:
Refactor fault handling to no long need element names
Introduce field accessor
Fix CTS regression
Added:
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/acessor/ReflectiveFieldAccessor.java
===================================================================
---
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/acessor/ReflectiveFieldAccessor.java 2007-01-10
23:14:18 UTC (rev 1917)
+++
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/acessor/ReflectiveFieldAccessor.java 2007-01-11
08:28:06 UTC (rev 1918)
@@ -0,0 +1,128 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.ws.metadata.acessor;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.jboss.ws.WSException;
+import org.jboss.ws.metadata.umdm.Accessor;
+import org.jboss.ws.metadata.umdm.AccessorFactory;
+import org.jboss.ws.metadata.umdm.AccessorFactoryCreator;
+import org.jboss.ws.metadata.umdm.FaultMetaData;
+import org.jboss.ws.metadata.umdm.ParameterMetaData;
+import org.jboss.ws.metadata.umdm.WrappedParameter;
+
+/**
+ * A simple Java field accessor that uses ordinary reflection.
+ *
+ * @author <a href="jason.greene(a)jboss.com">Jason T. Greene</a>
+ * @version $Revision: 1760 $
+ */
+@SuppressWarnings("unchecked")
+public class ReflectiveFieldAccessor implements Accessor
+{
+ private Field field;
+
+ public static AccessorFactoryCreator FACTORY_CREATOR = new AccessorFactoryCreator()
+ {
+ public AccessorFactory create(ParameterMetaData parameter)
+ {
+ return create(parameter.getJavaType());
+ }
+
+ public AccessorFactory create(FaultMetaData fault)
+ {
+ return create(fault.getFaultBean());
+ }
+
+ private AccessorFactory create(final Class clazz)
+ {
+ return new AccessorFactory()
+ {
+ public Accessor create(WrappedParameter parameter)
+ {
+ String fieldName = parameter.getVariable();
+ try
+ {
+ Field field;
+
+ try
+ {
+ field = clazz.getField(fieldName);
+ }
+ catch (NoSuchFieldException e)
+ {
+ // Search for a private field
+ field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ }
+
+ if (Modifier.isStatic(field.getModifiers()))
+ throw new WSException("Field can not be static: " +
fieldName);
+
+ return new ReflectiveFieldAccessor(field);
+ }
+ catch (Throwable t)
+ {
+ WSException ex = new WSException("Error accessing field: " +
fieldName + t.getClass().getSimpleName() + ": " + t.getMessage());
+ ex.setStackTrace(t.getStackTrace());
+ throw ex;
+ }
+ }
+ };
+ }
+ };
+
+ private ReflectiveFieldAccessor(Field field)
+ {
+ this.field = field;
+ }
+
+ public Object get(Object bean)
+ {
+ try
+ {
+ return field.get(bean);
+ }
+ catch (Throwable e)
+ {
+ WSException ex = new WSException(e.getMessage());
+ ex.setStackTrace(ex.getStackTrace());
+ throw ex;
+ }
+ }
+
+ public void set(Object bean, Object value)
+ {
+ try
+ {
+ field.set(bean, value);
+ }
+ catch (Throwable e)
+ {
+ WSException ex = new WSException(e.getMessage());
+ ex.setStackTrace(ex.getStackTrace());
+ throw ex;
+ }
+ }
+}
\ No newline at end of file
Property changes on:
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/acessor/ReflectiveFieldAccessor.java
___________________________________________________________________
Name: svn:executable
+ *
Modified:
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/builder/jaxws/JAXWSWebServiceMetaDataBuilder.java
===================================================================
---
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/builder/jaxws/JAXWSWebServiceMetaDataBuilder.java 2007-01-10
23:14:18 UTC (rev 1917)
+++
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/builder/jaxws/JAXWSWebServiceMetaDataBuilder.java 2007-01-11
08:28:06 UTC (rev 1918)
@@ -94,7 +94,7 @@
* @author Thomas.Diesler(a)jboss.org
* @author <a href="mailto:jason.greene@jboss.com">Jason T.
Greene</a>
* @author Heiko.Braun(a)jboss.org
- *
+ *
* @since 15-Oct-2005
*/
@SuppressWarnings("deprecation")
@@ -167,7 +167,6 @@
FaultMetaData fmd = new FaultMetaData(omd, xmlName, xmlType, exception.getName());
fmd.setFaultBeanName(faultBeanName);
- fmd.setAccessorFactoryCreator(JAXBAccessor.FACTORY_CREATOR);
if (generate)
wrapperGenerator.generate(fmd);
@@ -670,7 +669,7 @@
throw new
WSException("@WebService[portName,serviceName,endpointInterface] MUST NOT be defined
on: " + seiName);
// @WebService[name] is allowed, but what should we do with it?
-
+
interfaceNS = anWebService.targetNamespace();
if (interfaceNS.length() == 0)
interfaceNS = wsdlUtils.getTypeNamespace(seiClass);
Modified: trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/umdm/FaultMetaData.java
===================================================================
---
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/umdm/FaultMetaData.java 2007-01-10
23:14:18 UTC (rev 1917)
+++
trunk/jbossws-core/src/main/java/org/jboss/ws/metadata/umdm/FaultMetaData.java 2007-01-11
08:28:06 UTC (rev 1918)
@@ -26,13 +26,12 @@
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
-import javax.xml.bind.annotation.XmlAttribute;
-import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceException;
@@ -41,6 +40,7 @@
import org.jboss.ws.WSException;
import org.jboss.ws.core.jaxws.DynamicWrapperGenerator;
import org.jboss.ws.core.utils.JavaUtils;
+import org.jboss.ws.metadata.acessor.ReflectiveFieldAccessor;
import org.jboss.ws.metadata.acessor.ReflectiveMethodAccessor;
/**
@@ -67,11 +67,12 @@
private Method getFaultInfoMethod;
private Constructor<? extends Exception> serviceExceptionConstructor;
- private PropertyDescriptor[] serviceExceptionProperties;
+ private Method[] serviceExceptionGetters;
private WrappedParameter[] faultBeanProperties;
- private AccessorFactoryCreator accessorFactoryCreator =
ReflectiveMethodAccessor.FACTORY_CREATOR;
+ private Class<?>[] propertyTypes;
+
public FaultMetaData(OperationMetaData operation, QName xmlName, QName xmlType, String
javaTypeName)
{
this(operation, xmlName, javaTypeName);
@@ -202,8 +203,8 @@
{
/* JAX-WS 2.5: A wsdl:fault element refers to a wsdl:message that contains
* a single part. The global element declaration referred to by that part
- * is mapped to a Java bean. A wrapper exception class contains the
- * following methods:
+ * is mapped to a Java bean. A wrapper exception class contains the
+ * following methods:
* . WrapperException(String message, FaultBean faultInfo)
* . WrapperException(String message, FaultBean faultInfo, Throwable cause)
* . FaultBean getFaultInfo() */
@@ -221,14 +222,13 @@
if (xmlType == null)
throw new WebServiceException("@XmlType missing from fault bean: "
+ faultBeanName);
- AccessorFactory accessorFactory = accessorFactoryCreator.create(this);
+ AccessorFactory accessorFactory = getAccessorFactory(faultBean);
String[] propertyNames = xmlType.propOrder();
int propertyCount = propertyNames.length;
- Class<?>[] propertyTypes = new Class<?>[propertyCount];
-
+ propertyTypes = new Class<?>[propertyCount];
faultBeanProperties = new WrappedParameter[propertyCount];
- serviceExceptionProperties = new PropertyDescriptor[propertyCount];
+ serviceExceptionGetters = new Method[propertyCount];
for (int i = 0; i < propertyCount; i++)
{
@@ -237,10 +237,9 @@
try
{
PropertyDescriptor propertyDescriptor = new
PropertyDescriptor(propertyName, faultBean);
- QName propertyXmlName = getPropertyXmlName(propertyDescriptor);
Class<?> propertyType = propertyDescriptor.getPropertyType();
- WrappedParameter faultBeanProperty = new WrappedParameter(propertyXmlName,
propertyType.getName(), propertyName, i);
+ WrappedParameter faultBeanProperty = new WrappedParameter(null,
propertyType.getName(), propertyName, i);
faultBeanProperty.setAccessor(accessorFactory.create(faultBeanProperty));
faultBeanProperties[i] = faultBeanProperty;
@@ -258,7 +257,7 @@
* of PropertyDescriptor(String, Class) because the latter fails
* with an IntrospectionException: Method not found: setXXX */
PropertyDescriptor propertyDescriptor = new
PropertyDescriptor(propertyName, javaType, "is" +
JavaUtils.capitalize(propertyName), null);
- serviceExceptionProperties[i] = propertyDescriptor;
+ serviceExceptionGetters[i] = propertyDescriptor.getReadMethod();
}
catch (IntrospectionException ie)
{
@@ -268,92 +267,34 @@
try
{
+ // Attempt to locate a usable constructor
serviceExceptionConstructor =
javaType.asSubclass(Exception.class).getConstructor(propertyTypes);
}
catch (NoSuchMethodException e)
{
- throw new WSException("Service exception has no constructor for
parameter types: " + Arrays.toString(propertyTypes));
+ // Only needed for client side. The spec does not clarify this, and the TCK
makes use of non matching constructors,
+ // so we allow them for server side usage and only fail when used by the
client.
}
}
}
- private QName getPropertyXmlName(PropertyDescriptor propertyDescriptor)
+ private AccessorFactory getAccessorFactory(Class<?> faultBean)
{
- QName propertyXmlName;
+ // This should catch all cases due to the constraints that JAX-WS puts on the fault
bean
+ // However, if issues arrise then switch this to a full jaxb reflection library
+ XmlAccessorType type = faultBean.getAnnotation(XmlAccessorType.class);
+ if (type != null && type.value() == XmlAccessType.FIELD)
+ return ReflectiveFieldAccessor.FACTORY_CREATOR.create(this);
- // examine the underlying field, if any
- try
- {
- Field propertyField = faultBean.getDeclaredField(propertyDescriptor.getName());
- propertyXmlName = getPropertyXmlName(propertyField);
- if (propertyXmlName != null)
- return propertyXmlName;
- }
- catch (NoSuchFieldException e)
- {
- // proceed to examine the accessor methods
- }
-
- // examine the getter
- Method propertyGetter = propertyDescriptor.getReadMethod();
- propertyXmlName = getPropertyXmlName(propertyGetter);
- if (propertyXmlName != null)
- return propertyXmlName;
-
- // examine the setter
- Method propertySetter = propertyDescriptor.getWriteMethod();
- return getPropertyXmlName(propertySetter);
+ return ReflectiveMethodAccessor.FACTORY_CREATOR.create(this);
}
- // [JBBUILD-330] Add support for java.lang.reflect.AnnotatedElement
- // private QName getPropertyXmlName(AnnotatedElement propertyMember)
- private QName getPropertyXmlName(Field propertyMember)
- {
- QName propertyXmlName = null;
-
- XmlElement xmlElement = propertyMember.getAnnotation(XmlElement.class);
- if (xmlElement != null)
- propertyXmlName = new QName(xmlElement.namespace(), xmlElement.name());
- else
- {
- XmlAttribute xmlAttribute = propertyMember.getAnnotation(XmlAttribute.class);
- if (xmlAttribute != null)
- propertyXmlName = new QName(xmlAttribute.namespace(), xmlAttribute.name());
- // TODO should any other annotation be examined?
- }
- return propertyXmlName;
- }
-
- // [JBBUILD-330] Add support for java.lang.reflect.AnnotatedElement
- // private QName getPropertyXmlName(AnnotatedElement propertyMember)
- private QName getPropertyXmlName(Method propertyMember)
- {
- QName propertyXmlName = null;
-
- XmlElement xmlElement = propertyMember.getAnnotation(XmlElement.class);
- if (xmlElement != null)
- propertyXmlName = new QName(xmlElement.namespace(), xmlElement.name());
- else
- {
- XmlAttribute xmlAttribute = propertyMember.getAnnotation(XmlAttribute.class);
- if (xmlAttribute != null)
- propertyXmlName = new QName(xmlAttribute.namespace(), xmlAttribute.name());
- // TODO should any other annotation be examined?
- }
- return propertyXmlName;
- }
-
- public void setAccessorFactoryCreator(AccessorFactoryCreator accessorFactoryCreator)
- {
- this.accessorFactoryCreator = accessorFactoryCreator;
- }
-
public Object toFaultBean(Exception serviceException)
{
Object faultBeanInstance;
try
{
- /* is the service exception a wrapper
+ /* is the service exception a wrapper
* (i.e. does it match the pattern in JAX-WS 2.5)? */
if (getFaultInfoMethod != null)
{
@@ -373,13 +314,13 @@
}
// copy the properties from the service exception to the fault bean
- for (int i = 0, n = serviceExceptionProperties.length; i < n; i++)
+ for (int i = 0; i < serviceExceptionGetters.length; i++)
{
- PropertyDescriptor serviceExceptionProperty =
serviceExceptionProperties[i];
- Object propertyValue =
serviceExceptionProperty.getReadMethod().invoke(serviceException);
+ Object propertyValue =
serviceExceptionGetters[i].invoke(serviceException);
WrappedParameter faultBeanProperty = faultBeanProperties[i];
- log.debug("copying from " + javaType.getSimpleName() +
'.' + serviceExceptionProperty.getName()
+ if (log.isTraceEnabled())
+ log.trace("copying from " + javaType.getSimpleName() +
'.' + serviceExceptionGetters[i].getName()
+ " to " + faultBean.getSimpleName() + '.' +
faultBeanProperty.getVariable() + "<->" + faultBeanProperty.getName()
+ ": " + propertyValue);
faultBeanProperty.accessor().set(faultBeanInstance, propertyValue);
@@ -403,7 +344,7 @@
try
{
- /* is the service exception a wrapper
+ /* is the service exception a wrapper
* (i.e. does it match the pattern in JAX-WS 2.5)? */
if (getFaultInfoMethod != null)
{
@@ -411,6 +352,9 @@
}
else
{
+ if (serviceExceptionConstructor == null)
+ throw new WSException("Could not instantiate service exception
(" + javaType.getSimpleName() +"), since neither a faultInfo nor sorted
constructor is present: " + Arrays.toString(propertyTypes));
+
// extract the properties from the fault bean
int propertyCount = faultBeanProperties.length;
Object[] propertyValues = new Object[propertyCount];