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}
  +
  
  
  

Reply via email to