Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/axis/encoding/ser/SimpleDeserializer.java


1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.axis.encoding.ser;
18  
19  import org.apache.axis.description.TypeDesc;
20  import org.apache.axis.encoding.DeserializationContext;
21  import org.apache.axis.encoding.Deserializer;
22  import org.apache.axis.encoding.DeserializerImpl;
23  import org.apache.axis.encoding.SimpleType;
24  import org.apache.axis.encoding.TypeMapping;
25  import org.apache.axis.message.SOAPHandler;
26  import org.apache.axis.utils.BeanPropertyDescriptor;
27  import org.apache.axis.utils.BeanUtils;
28  import org.apache.axis.utils.Messages;
29  import org.xml.sax.Attributes;
30  import org.xml.sax.SAXException;
31  
32  import javax.xml.namespace.QName;
33  import java.io.CharArrayWriter;
34  import java.lang.reflect.Constructor;
35  import java.lang.reflect.InvocationTargetException;
36  import java.util.HashMap;
37  import java.util.Iterator;
38  import java.util.Map;
39  import java.util.Set;
40  
41  /**
42   * A deserializer for any simple type with a (String) constructor.  Note:
43   * this class is designed so that subclasses need only override the makeValue 
44   * method in order to construct objects of their own type.
45   *
46   * @author Glen Daniels (gdaniels@apache.org)
47   * @author Sam Ruby (rubys@us.ibm.com)
48   * Modified for JAX-RPC @author Rich Scheuerle (scheu@us.ibm.com)
49   */
50  public class SimpleDeserializer extends DeserializerImpl {
51      
52      private static final Class[] STRING_STRING_CLASS = 
53          new Class [] {String.class, String.class};
54  
55      public static final Class[] STRING_CLASS = 
56          new Class [] {String.class};
57  
58      private final CharArrayWriter val = new CharArrayWriter();
59      private Constructor constructor = null;
60      private Map propertyMap = null;
61      private HashMap attributeMap = null;
62      
63      public QName xmlType;
64      public Class javaType;
65      
66      private TypeDesc typeDesc = null;
67  
68      protected DeserializationContext context = null;
69      protected SimpleDeserializer cacheStringDSer = null;
70      protected QName cacheXMLType = null;
71      /**
72       * The Deserializer is constructed with the xmlType and 
73       * javaType (which could be a java primitive like int.class)
74       */
75      public SimpleDeserializer(Class javaType, QName xmlType) {
76           this.xmlType = xmlType;
77          this.javaType = javaType;
78          
79          init();
80      }
81  
82      public SimpleDeserializer(Class javaType, QName xmlType, TypeDesc typeDesc) {
83          this.xmlType = xmlType;
84          this.javaType = javaType;
85          this.typeDesc = typeDesc;
86          
87          init();
88      }    
89  
90      /**
91       * Initialize the typeDesc, property descriptors and propertyMap.
92       */
93      private void init() {
94          // The typeDesc and map array are only necessary
95          // if this class extends SimpleType.
96          if (SimpleType.class.isAssignableFrom(javaType)) {
97              // Set the typeDesc if not already set
98              if (typeDesc == null) {
99                  typeDesc = TypeDesc.getTypeDescForClass(javaType);
100             }
101         }
102 
103         // Get the cached propertyDescriptor from the type or
104         // generate a fresh one.
105         if (typeDesc != null) {
106             propertyMap = typeDesc.getPropertyDescriptorMap();
107         } else {
108             BeanPropertyDescriptor[] pd = BeanUtils.getPd(javaType, null);
109             propertyMap = new HashMap();
110             for (int i = 0; i < pd.length; i++) {
111                 BeanPropertyDescriptor descriptor = pd[i];
112                 propertyMap.put(descriptor.getName(), descriptor);
113             }
114         }
115     }
116     
117     /**
118      * Reset deserializer for re-use
119      */
120     public void reset() {
121         val.reset();
122         attributeMap = null; // Remove attribute map
123         isNil = false; // Don't know if nil
124         isEnded = false; // Indicate the end of element not yet called
125     }
126     
127     /** 
128      * The Factory calls setConstructor.
129      */
130     public void setConstructor(Constructor c) 
131     {
132         constructor = c;
133     }
134     
135     /**
136      * There should not be nested elements, so thow and exception if this occurs.
137      */
138     public SOAPHandler onStartChild(String namespace,
139                                     String localName,
140                                     String prefix,
141                                     Attributes attributes,
142                                     DeserializationContext context)
143             throws SAXException
144     {
145         throw new SAXException(
146                 Messages.getMessage("cantHandle00", "SimpleDeserializer"));
147     }
148     
149     /**
150      * Append any characters received to the value.  This method is defined 
151      * by Deserializer.
152      */
153     public void characters(char [] chars, int start, int end)
154             throws SAXException
155     {
156         val.write(chars,start,end);
157     }
158     
159     /**
160      * Append any characters to the value.  This method is defined by 
161      * Deserializer.
162      */
163     public void onEndElement(String namespace, String localName,
164                              DeserializationContext context)
165             throws SAXException
166     {
167         if (isNil) {
168             value = null;
169             return;
170         }
171         try {
172             value = makeValue(val.toString());
173         } catch (InvocationTargetException ite) {
174             Throwable realException = ite.getTargetException();
175             if (realException instanceof Exception)
176                 throw new SAXException((Exception)realException);
177             else
178                 throw new SAXException(ite.getMessage());
179         } catch (Exception e) {
180             throw new SAXException(e);
181         }
182         
183         // If this is a SimpleType, set attributes we have stashed away
184         setSimpleTypeAttributes();
185     }
186     
187     /**
188      * Convert the string that has been accumulated into an Object.  Subclasses
189      * may override this.  Note that if the javaType is a primitive, the returned
190      * object is a wrapper class.
191      * @param source the serialized value to be deserialized
192      * @throws Exception any exception thrown by this method will be wrapped
193      */
194     public Object makeValue(String source) throws Exception
195     {
196         if (javaType == java.lang.String.class) {
197             return source;
198         }
199 
200         // Trim whitespace if non-String
201         source = source.trim();
202 
203         if (source.length() == 0 && typeDesc == null) {
204             return null;
205         }
206         
207         // if constructor is set skip all basic java type checks
208         if (this.constructor == null) {
209             Object value = makeBasicValue(source);
210             if (value != null) {
211                 return value;
212             }
213         }
214             
215         Object [] args = null;
216         
217         boolean isQNameSubclass = QName.class.isAssignableFrom(javaType);
218 
219         if (isQNameSubclass) {
220             int colon = source.lastIndexOf(":");
221             String namespace = colon < 0 ? "" :
222                 context.getNamespaceURI(source.substring(0, colon));
223             String localPart = colon < 0 ? source : source.substring(colon + 1);
224             args = new Object [] {namespace, localPart};
225         } 
226 
227         if (constructor == null) {
228             try {
229                 if (isQNameSubclass) {
230                     constructor = 
231                         javaType.getDeclaredConstructor(STRING_STRING_CLASS);
232                 } else {
233                     constructor = 
234                         javaType.getDeclaredConstructor(STRING_CLASS);
235                 }
236             } catch (Exception e) {
237                 return null;
238             }
239         }
240         
241         if(constructor.getParameterTypes().length==0){
242             try {
243                 Object obj = constructor.newInstance(new Object[]{});
244                 obj.getClass().getMethod("set_value", new Class[]{String.class})
245                         .invoke(obj, new Object[]{source});
246                 return obj;
247             } catch (Exception e){
248                 //Ignore exception
249             }
250         }
251         if (args == null) {
252             args = new Object[]{source};
253         }
254         return constructor.newInstance(args);
255     }
256 
257     private Object makeBasicValue(String source) throws Exception {
258         // If the javaType is a boolean, except a number of different sources
259         if (javaType == boolean.class || 
260             javaType == Boolean.class) {
261             // This is a pretty lame test, but it is what the previous code did.
262             switch (source.charAt(0)) {
263                 case '0': case 'f': case 'F':
264                     return Boolean.FALSE;
265                     
266                 case '1': case 't': case 'T': 
267                     return Boolean.TRUE; 
268                     
269                 default:
270                     throw new NumberFormatException(
271                             Messages.getMessage("badBool00"));
272                 }
273             
274         }
275         
276         // If expecting a Float or a Double, need to accept some special cases.
277         if (javaType == float.class ||
278             javaType == java.lang.Float.class) {
279             if (source.equals("NaN")) {
280                 return new Float(Float.NaN);
281             } else if (source.equals("INF")) {
282                 return new Float(Float.POSITIVE_INFINITY);
283             } else if (source.equals("-INF")) {
284                 return new Float(Float.NEGATIVE_INFINITY);
285             } else {
286                 return new Float(source);
287             }
288         }
289         
290         if (javaType == double.class ||
291             javaType == java.lang.Double.class) {
292             if (source.equals("NaN")) {
293                 return new Double(Double.NaN);
294             } else if (source.equals("INF")) {
295                 return new Double(Double.POSITIVE_INFINITY);
296             } else if (source.equals("-INF")) {
297                 return new Double(Double.NEGATIVE_INFINITY);
298             } else {
299                 return new Double(source);
300             }
301         }    
302         
303         if (javaType == int.class ||
304             javaType == java.lang.Integer.class) {
305             return new Integer(source);
306         }
307         
308         if (javaType == short.class ||
309             javaType == java.lang.Short.class) {
310             return new Short(source);
311         }
312         
313         if (javaType == long.class ||
314             javaType == java.lang.Long.class) {
315             return new Long(source);
316         }
317         
318         if (javaType == byte.class ||
319             javaType == java.lang.Byte.class) {
320             return new Byte(source);
321         }
322         
323         if (javaType == org.apache.axis.types.URI.class) {
324             return new org.apache.axis.types.URI(source);
325         }
326 
327         return null;
328     }
329         
330     /**
331      * Set the bean properties that correspond to element attributes.
332      * 
333      * This method is invoked after startElement when the element requires
334      * deserialization (i.e. the element is not an href and the value is not nil.)
335      * @param namespace is the namespace of the element
336      * @param localName is the name of the element
337      * @param prefix is the prefix of the element
338      * @param attributes are the attributes on the element...used to get the type
339      * @param context is the DeserializationContext
340      */
341     public void onStartElement(String namespace, String localName,
342                                String prefix, Attributes attributes,
343                                DeserializationContext context)
344             throws SAXException 
345     {
346         
347         this.context = context;
348 
349         // loop through the attributes and set bean properties that
350         // correspond to attributes
351         for (int i=0; i < attributes.getLength(); i++) {
352             QName attrQName = new QName(attributes.getURI(i),
353                                         attributes.getLocalName(i));
354             
355             String fieldName = attributes.getLocalName(i);
356             
357             if(typeDesc != null) {
358                 fieldName = typeDesc.getFieldNameForAttribute(attrQName);
359                 if (fieldName == null)
360                     continue;
361             }
362 
363             if (propertyMap == null)
364                 continue;
365             
366             // look for the attribute property
367             BeanPropertyDescriptor bpd =
368                     (BeanPropertyDescriptor) propertyMap.get(fieldName);
369             if (bpd != null) {
370                 if (!bpd.isWriteable() || bpd.isIndexed() ) continue ;
371                 
372                 // determine the QName for this child element
373                 TypeMapping tm = context.getTypeMapping();
374                 Class type = bpd.getType();
375                 QName qn = tm.getTypeQName(type);
376                 if (qn == null)
377                     throw new SAXException(
378                             Messages.getMessage("unregistered00", type.toString()));
379                 
380                 // get the deserializer
381                 Deserializer dSer = context.getDeserializerForType(qn);
382                 if (dSer == null)
383                     throw new SAXException(
384                             Messages.getMessage("noDeser00", type.toString()));
385                 if (! (dSer instanceof SimpleDeserializer))
386                     throw new SAXException(
387                             Messages.getMessage("AttrNotSimpleType00",
388                                                 bpd.getName(),
389                                                 type.toString()));
390                 
391                 // Success!  Create an object from the string and save
392                 // it in our attribute map for later.
393                 if (attributeMap == null) {
394                     attributeMap = new HashMap();
395                 }
396                 try {
397                     Object val = ((SimpleDeserializer)dSer).
398                             makeValue(attributes.getValue(i));
399                     attributeMap.put(fieldName, val);
400                 } catch (Exception e) {
401                     throw new SAXException(e);
402                 }
403             } // if
404         } // attribute loop
405     } // onStartElement
406     
407     /**
408      * Process any attributes we may have encountered (in onStartElement)
409      */ 
410     private void setSimpleTypeAttributes() throws SAXException {
411         if (attributeMap == null)
412             return;
413         
414         // loop through map
415         Set entries = attributeMap.entrySet();
416         for (Iterator iterator = entries.iterator(); iterator.hasNext();) {
417             Map.Entry entry = (Map.Entry) iterator.next();
418             String name = (String) entry.getKey();
419             Object val = entry.getValue();
420             
421             BeanPropertyDescriptor bpd =
422                     (BeanPropertyDescriptor) propertyMap.get(name);
423             if (!bpd.isWriteable() || bpd.isIndexed()) continue;
424             try {
425                 bpd.set(value, val );
426             } catch (Exception e) {
427                 throw new SAXException(e);
428             }
429         }
430     }
431     
432 }