dims 2005/02/04 16:14:32
Modified: java/src/org/apache/axis/encoding/ser BeanDeserializer.java java/test/faults PackageTests.java java/src/org/apache/axis/i18n resource.properties Added: java/test/faults BeanFault.java BeanFault2.java TestBeans.java java/src/org/apache/axis/encoding ConstructorTarget.java Log: Support and test case for JSR 109 style exceptions: JSR 109 Section 7.3.2 says: Faults must map to an exception such that it: • Directly or indirectly inherits from java.lang.Exception, but must not inherit from RuntimeException nor RemoteException. • Has at most a single property called “message” of type java.lang.String Notes: - I don't like this, but checking it in for Glen/Tom's review and comment. - Any alternate solution should not break the test(s) added in this check-in. Revision Changes Path 1.71 +45 -7 ws-axis/java/src/org/apache/axis/encoding/ser/BeanDeserializer.java Index: BeanDeserializer.java =================================================================== RCS file: /home/cvs/ws-axis/java/src/org/apache/axis/encoding/ser/BeanDeserializer.java,v retrieving revision 1.70 retrieving revision 1.71 diff -u -r1.70 -r1.71 --- BeanDeserializer.java 1 Nov 2004 14:07:35 -0000 1.70 +++ BeanDeserializer.java 5 Feb 2005 00:14:32 -0000 1.71 @@ -24,6 +24,8 @@ import org.apache.axis.encoding.Deserializer; import org.apache.axis.encoding.DeserializerImpl; import org.apache.axis.encoding.TypeMapping; +import org.apache.axis.encoding.Target; +import org.apache.axis.encoding.ConstructorTarget; import org.apache.axis.message.MessageElement; import org.apache.axis.message.SOAPHandler; import org.apache.axis.utils.BeanPropertyDescriptor; @@ -37,6 +39,7 @@ import java.io.Serializable; import java.io.CharArrayWriter; import java.util.Map; +import java.lang.reflect.Constructor; /** * General purpose deserializer for an arbitrary java bean. @@ -57,6 +60,16 @@ protected Map propertyMap = null; protected QName prevQName; + /** + * Constructor if no default constructor + */ + protected Constructor constructorToUse = null; + + /** + * Constructor Target object to use (if constructorToUse != null) + */ + protected Target constructorTarget = null; + /** Type metadata about this class for XML deserialization */ protected TypeDesc typeDesc = null; @@ -120,10 +133,20 @@ try { value=javaType.newInstance(); } catch (Exception e) { - // Failed to create an object. - throw new SAXException(Messages.getMessage("cantCreateBean00", + // Use first found constructor. + // Note : the right way is to use XML mapping information + // for example JSR 109's constructor-parameter-order + Constructor[] constructors = javaType.getConstructors(); + if (constructors.length > 0) { + constructorToUse = constructors[0]; + } + + // Failed to create an object if no constructor + if (constructorToUse == null) { + throw new SAXException(Messages.getMessage("cantCreateBean00", javaType.getName(), e.toString())); + } } } // Invoke super.startElement to do the href/id processing. @@ -270,8 +293,12 @@ childXMLType.toString())); } - // Register value target - if (propDesc.isWriteable()) { + if (constructorToUse != null) { + if (constructorTarget == null) { + constructorTarget = new ConstructorTarget(constructorToUse, this); + } + dSer.registerValueTarget(constructorTarget); + } else if (propDesc.isWriteable()) { // Register value target // If this is an indexed property, and the deserializer we found // was NOT the ArrayDeserializer, this is a non-SOAP array: // <bean> @@ -338,7 +365,7 @@ // The value should have been created or assigned already. // This code may no longer be needed. - if (value == null) { + if (value == null && constructorToUse == null) { // create a value try { value=javaType.newInstance(); @@ -369,7 +396,10 @@ BeanPropertyDescriptor bpd = (BeanPropertyDescriptor) propertyMap.get(fieldName); if (bpd != null) { - if (!bpd.isWriteable() || bpd.isIndexed() ) continue ; + if (constructorToUse == null) { + // check only if default constructor + if (!bpd.isWriteable() || bpd.isIndexed()) continue ; + } // Get the Deserializer for the attribute Deserializer dSer = getDeserializer(fieldDesc.getXmlType(), @@ -397,7 +427,15 @@ attributes, context); Object val = ((SimpleDeserializer)dSer). makeValue(attributes.getValue(i)); - bpd.set(value, val); + if (constructorToUse == null) { + bpd.set(value, val); + } else { + // add value for our constructor + if (constructorTarget == null) { + constructorTarget = new ConstructorTarget(constructorToUse, this); + } + constructorTarget.set(val); + } } catch (Exception e) { throw new SAXException(e); } 1.7 +1 -0 ws-axis/java/test/faults/PackageTests.java Index: PackageTests.java =================================================================== RCS file: /home/cvs/ws-axis/java/test/faults/PackageTests.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- PackageTests.java 25 Feb 2004 14:02:55 -0000 1.6 +++ PackageTests.java 5 Feb 2005 00:14:32 -0000 1.7 @@ -37,6 +37,7 @@ suite.addTestSuite(FaultDecode.class); suite.addTestSuite(FaultEncode.class); suite.addTestSuite(TestSOAPFaultException.class); + suite.addTestSuite(TestBeans.class); suite.addTest(TestAxisFault.suite()); 1.1 ws-axis/java/test/faults/BeanFault.java Index: BeanFault.java =================================================================== package test.faults; public class BeanFault extends Exception { private String message; public BeanFault() { } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } 1.1 ws-axis/java/test/faults/BeanFault2.java Index: BeanFault2.java =================================================================== package test.faults; public class BeanFault2 extends Exception { public BeanFault2(String s) { super(s); message = s; } public String getMessage() { return message; } private String message; } 1.1 ws-axis/java/test/faults/TestBeans.java Index: TestBeans.java =================================================================== /* * Copyright 2002-2004 The Apache Software Foundation. * * Licensed 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 test.faults; import org.apache.axis.client.Call; import org.apache.axis.encoding.TypeMapping; import org.apache.axis.encoding.ser.BeanDeserializerFactory; import org.apache.axis.encoding.ser.BeanSerializerFactory; import org.apache.axis.enum.Style; import org.apache.axis.Constants; import org.apache.axis.AxisFault; import test.GenericLocalTest; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; /** * Confirm that faults using beans work */ public class TestBeans extends GenericLocalTest { private QName TYPE_QNAME = new QName("ns", "dataType"); public TestBeans() { super("service"); } public TestBeans(String s) { super(s); } protected void setUp() throws Exception { super.setUp(false); // don't deploy here TypeMapping tm = (TypeMapping)config.getTypeMappingRegistry(). getDefaultTypeMapping(); tm.register(BeanFault.class, TYPE_QNAME, new BeanSerializerFactory(BeanFault.class, TYPE_QNAME), new BeanDeserializerFactory(BeanFault.class, TYPE_QNAME)); deploy("service", this.getClass(), Style.WRAPPED); //tm.register(BeanFault2.class, TYPE_QNAME, // new BeanSerializerFactory(BeanFault2.class, TYPE_QNAME), // new BeanDeserializerFactory(BeanFault2.class, TYPE_QNAME)); } public void testBeanFault() throws Exception { Call call = getCall(); call.setOperationStyle("wrapped"); call.setOperationUse("literal"); call.setEncodingStyle(""); call.registerTypeMapping(BeanFault.class, TYPE_QNAME, new BeanSerializerFactory(BeanFault.class, TYPE_QNAME), new BeanDeserializerFactory(BeanFault.class, TYPE_QNAME)); call.setReturnClass(BeanFault.class); call.addParameter("arg0", Constants.XSD_STRING, ParameterMode.IN); String data = "bean fault test - 1"; try { call.invoke("echoString", new Object [] { data }); } catch (AxisFault af){ assertNotNull(af.detail); assertEquals(BeanFault.class,af.detail.getClass()); assertEquals(data,((BeanFault)af.detail).getMessage()); return; } fail("did not catch fault"); } public void testBeanFault2() throws Exception { Call call = getCall(); call.setOperationStyle("wrapped"); call.setOperationUse("literal"); call.setEncodingStyle(""); call.registerTypeMapping(BeanFault2.class, TYPE_QNAME, new BeanSerializerFactory(BeanFault2.class, TYPE_QNAME), new BeanDeserializerFactory(BeanFault2.class, TYPE_QNAME)); call.setReturnClass(BeanFault2.class); call.addParameter("arg0", Constants.XSD_STRING, ParameterMode.IN); String data = "bean fault test - 2"; try { call.invoke("echoString2", new Object [] { data }); } catch (AxisFault af){ assertNotNull(af.detail); assertEquals(BeanFault2.class,af.detail.getClass()); assertEquals(data,((BeanFault2)af.detail).getMessage()); return; } fail("did not catch fault"); } public String echoString(String data) throws BeanFault { BeanFault f = new BeanFault(); f.setMessage(data); throw f; } public String echoString2(String data) throws BeanFault2 { BeanFault2 f = new BeanFault2(data); throw f; } } 1.1 ws-axis/java/src/org/apache/axis/encoding/ConstructorTarget.java Index: ConstructorTarget.java =================================================================== /* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed 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.axis.encoding; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import org.xml.sax.SAXException; import org.apache.axis.i18n.Messages; /** * Used when the class need a specific Constructor (not default one) * @author Florent Benoit */ public class ConstructorTarget implements Target { /** * Constructor to use */ private Constructor constructor = null; /** * Deserializer on which set value */ private Deserializer deSerializer = null; /** * List of values */ private List values = null; public ConstructorTarget(Constructor constructor, Deserializer deSerializer) { this.deSerializer = deSerializer; this.constructor = constructor; values = new ArrayList(); } /** * Instantiate a new class with right constructor * @param value value to use on Constructor * @throws SAXException on error */ public void set(Object value) throws SAXException { try { // store received value values.add(value); // got right parameter length if (constructor.getParameterTypes().length == values.size()) { // type of parameters Class[] classes = constructor.getParameterTypes(); // args array Object[] args = new Object[constructor.getParameterTypes().length]; // Get arg for the type of the class for (int c = 0; c < classes.length; c++) { boolean found = false; int i = 0; while (!found && i < values.size()) { // got right class arg if (values.get(i).getClass().getName().toLowerCase().indexOf(classes[c].getName().toLowerCase()) != -1) { found = true; args[c] = values.get(i); } i++; } // no suitable object for class required if (!found) { throw new SAXException(Messages.getMessage("cannotFindObjectForClass00", classes[c].toString())); } } // then build object Object o = constructor.newInstance(args); deSerializer.setValue(o); } } catch (Exception e) { throw new SAXException(e); } } } 1.111 +3 -1 ws-axis/java/src/org/apache/axis/i18n/resource.properties Index: resource.properties =================================================================== RCS file: /home/cvs/ws-axis/java/src/org/apache/axis/i18n/resource.properties,v retrieving revision 1.110 retrieving revision 1.111 diff -u -r1.110 -r1.111 --- resource.properties 4 Feb 2005 03:42:45 -0000 1.110 +++ resource.properties 5 Feb 2005 00:14:32 -0000 1.111 @@ -1266,4 +1266,6 @@ noDefaultTypeMapping00=Default TypeMapping has not been specified noOverloadedOperations=WS-I Basic Profile disallows overloaded operations. Multiple definitions for operation ''{0}''! invocationArgumentsModified00=Invocation arguments were modified -cannotCreateTextNode00=Exception creating text node \ No newline at end of file +cannotCreateTextNode00=Exception creating text node +cannotFindObjectForClass00=No object was found for class type {0} +