Source code: org/apache/axis/encoding/ser/SimpleListDeserializer.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 java.lang.reflect.Array;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.InvocationTargetException;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.StringTokenizer;
27
28 import javax.xml.namespace.QName;
29
30 import org.apache.axis.description.TypeDesc;
31 import org.apache.axis.encoding.DeserializationContext;
32 import org.apache.axis.encoding.Deserializer;
33 import org.apache.axis.encoding.SimpleType;
34 import org.apache.axis.encoding.TypeMapping;
35 import org.apache.axis.message.SOAPHandler;
36 import org.apache.axis.utils.BeanPropertyDescriptor;
37 import org.apache.axis.utils.Messages;
38 import org.xml.sax.Attributes;
39 import org.xml.sax.SAXException;
40
41 /**
42 * Deserializer for
43 * <xsd:simpleType ...>
44 * <xsd:list itemType="...">
45 * </xsd:simpleType>
46 * based on SimpleDeserializer
47 *
48 * @author Ias (iasandcb@tmax.co.kr)
49 */
50 public class SimpleListDeserializer extends SimpleDeserializer {
51
52 StringBuffer val = new StringBuffer();
53 private Constructor constructor = null;
54 private Map propertyMap = null;
55 private HashMap attributeMap = null;
56 private DeserializationContext context = null;
57
58 public QName xmlType;
59 public Class javaType;
60
61 private TypeDesc typeDesc = null;
62
63 protected SimpleListDeserializer cacheStringDSer = null;
64 protected QName cacheXMLType = null;
65 /**
66 * The Deserializer is constructed with the xmlType and
67 * javaType (which could be a java primitive like int.class)
68 */
69 public SimpleListDeserializer(Class javaType, QName xmlType) {
70 super (javaType, xmlType);
71
72 this.xmlType = xmlType;
73 this.javaType = javaType;
74 }
75 public SimpleListDeserializer(Class javaType, QName xmlType, TypeDesc typeDesc) {
76 super (javaType, xmlType, typeDesc);
77
78 this.xmlType = xmlType;
79 this.javaType = javaType;
80 this.typeDesc = typeDesc;
81 }
82
83
84 /**
85 * Reset deserializer for re-use
86 */
87 public void reset() {
88 val.setLength(0); // Reset string buffer back to zero
89 attributeMap = null; // Remove attribute map
90 isNil = false; // Don't know if nil
91 isEnded = false; // Indicate the end of element not yet called
92 }
93
94 /**
95 * The Factory calls setConstructor.
96 */
97 public void setConstructor(Constructor c)
98 {
99 constructor = c;
100 }
101
102 /**
103 * There should not be nested elements, so thow and exception if this occurs.
104 */
105 public SOAPHandler onStartChild(String namespace,
106 String localName,
107 String prefix,
108 Attributes attributes,
109 DeserializationContext context)
110 throws SAXException
111 {
112 throw new SAXException(
113 Messages.getMessage("cantHandle00", "SimpleDeserializer"));
114 }
115
116 /**
117 * Append any characters received to the value. This method is defined
118 * by Deserializer.
119 */
120 public void characters(char [] chars, int start, int end)
121 throws SAXException
122 {
123 val.append(chars, start, end);
124 }
125
126 /**
127 * Append any characters to the value. This method is defined by
128 * Deserializer.
129 */
130 public void onEndElement(String namespace, String localName,
131 DeserializationContext context)
132 throws SAXException
133 {
134 if (isNil || val == null) {
135 value = null;
136 return;
137 }
138 try {
139 value = makeValue(val.toString());
140 } catch (InvocationTargetException ite) {
141 Throwable realException = ite.getTargetException();
142 if (realException instanceof Exception)
143 throw new SAXException((Exception)realException);
144 else
145 throw new SAXException(ite.getMessage());
146 } catch (Exception e) {
147 throw new SAXException(e);
148 }
149
150 // If this is a SimpleType, set attributes we have stashed away
151 setSimpleTypeAttributes();
152 }
153
154 /**
155 * Convert the string that has been accumulated into an Object. Subclasses
156 * may override this.
157 * @param source the serialized value to be deserialized
158 * @throws Exception any exception thrown by this method will be wrapped
159 */
160 public Object makeValue(String source) throws Exception
161 {
162 // According to XML Schema Spec Part 0: Primer 2.3.1 - white space delimitor
163 StringTokenizer tokenizer = new StringTokenizer(source.trim());
164 int length = tokenizer.countTokens();
165 Object list = Array.newInstance(javaType, length);
166 for (int i = 0; i < length; i++) {
167 String token = tokenizer.nextToken();
168 Array.set(list, i, makeUnitValue(token));
169 }
170 return list;
171 }
172
173 private Object makeUnitValue(String source) throws Exception
174 {
175 // If the javaType is a boolean, except a number of different sources
176 if (javaType == boolean.class || javaType == Boolean.class) {
177 // This is a pretty lame test, but it is what the previous code did.
178 switch (source.charAt(0)) {
179 case '0': case 'f': case 'F':
180 return Boolean.FALSE;
181
182 case '1': case 't': case 'T':
183 return Boolean.TRUE;
184
185 default:
186 throw new NumberFormatException(
187 Messages.getMessage("badBool00"));
188 }
189
190 }
191
192 // If expecting a Float or a Double, need to accept some special cases.
193 if (javaType == float.class ||
194 javaType == java.lang.Float.class) {
195 if (source.equals("NaN")) {
196 return new Float(Float.NaN);
197 } else if (source.equals("INF")) {
198 return new Float(Float.POSITIVE_INFINITY);
199 } else if (source.equals("-INF")) {
200 return new Float(Float.NEGATIVE_INFINITY);
201 }
202 }
203 if (javaType == double.class ||
204 javaType == java.lang.Double.class) {
205 if (source.equals("NaN")) {
206 return new Double(Double.NaN);
207 } else if (source.equals("INF")) {
208 return new Double(Double.POSITIVE_INFINITY);
209 } else if (source.equals("-INF")) {
210 return new Double(Double.NEGATIVE_INFINITY);
211 }
212 }
213 if (javaType == QName.class) {
214 int colon = source.lastIndexOf(":");
215 String namespace = colon < 0 ? "" :
216 context.getNamespaceURI(source.substring(0, colon));
217 String localPart = colon < 0 ? source :
218 source.substring(colon + 1);
219 return new QName(namespace, localPart);
220 }
221
222 return constructor.newInstance(new Object [] { source });
223 }
224 /**
225 * Set the bean properties that correspond to element attributes.
226 *
227 * This method is invoked after startElement when the element requires
228 * deserialization (i.e. the element is not an href and the value is not nil.)
229 * @param namespace is the namespace of the element
230 * @param localName is the name of the element
231 * @param prefix is the prefix of the element
232 * @param attributes are the attributes on the element...used to get the type
233 * @param context is the DeserializationContext
234 */
235 public void onStartElement(String namespace, String localName,
236 String prefix, Attributes attributes,
237 DeserializationContext context)
238 throws SAXException
239 {
240
241 this.context = context;
242
243 // If we have no metadata, we have no attributes. Q.E.D.
244 if (typeDesc == null)
245 return;
246
247 // loop through the attributes and set bean properties that
248 // correspond to attributes
249 for (int i=0; i < attributes.getLength(); i++) {
250 QName attrQName = new QName(attributes.getURI(i),
251 attributes.getLocalName(i));
252 String fieldName = typeDesc.getFieldNameForAttribute(attrQName);
253 if (fieldName == null)
254 continue;
255
256 // look for the attribute property
257 BeanPropertyDescriptor bpd =
258 (BeanPropertyDescriptor) propertyMap.get(fieldName);
259 if (bpd != null) {
260 if (!bpd.isWriteable() || bpd.isIndexed() ) continue ;
261
262 // determine the QName for this child element
263 TypeMapping tm = context.getTypeMapping();
264 Class type = bpd.getType();
265 QName qn = tm.getTypeQName(type);
266 if (qn == null)
267 throw new SAXException(
268 Messages.getMessage("unregistered00", type.toString()));
269
270 // get the deserializer
271 Deserializer dSer = context.getDeserializerForType(qn);
272 if (dSer == null)
273 throw new SAXException(
274 Messages.getMessage("noDeser00", type.toString()));
275 if (! (dSer instanceof SimpleListDeserializer))
276 throw new SAXException(
277 Messages.getMessage("AttrNotSimpleType00",
278 bpd.getName(),
279 type.toString()));
280
281 // Success! Create an object from the string and save
282 // it in our attribute map for later.
283 if (attributeMap == null) {
284 attributeMap = new HashMap();
285 }
286 try {
287 Object val = ((SimpleListDeserializer)dSer).
288 makeValue(attributes.getValue(i));
289 attributeMap.put(fieldName, val);
290 } catch (Exception e) {
291 throw new SAXException(e);
292 }
293 } // if
294 } // attribute loop
295 } // onStartElement
296
297 /**
298 * Process any attributes we may have encountered (in onStartElement)
299 */
300 private void setSimpleTypeAttributes() throws SAXException {
301 // if this isn't a simpleType bean, wont have attributes
302 if (! SimpleType.class.isAssignableFrom(javaType) ||
303 attributeMap == null)
304 return;
305
306 // loop through map
307 Set entries = attributeMap.entrySet();
308 for (Iterator iterator = entries.iterator(); iterator.hasNext();) {
309 Map.Entry entry = (Map.Entry) iterator.next();
310 String name = (String) entry.getKey();
311 Object val = entry.getValue();
312
313 BeanPropertyDescriptor bpd =
314 (BeanPropertyDescriptor) propertyMap.get(name);
315 if (!bpd.isWriteable() || bpd.isIndexed()) continue;
316 try {
317 bpd.set(value, val );
318 } catch (Exception e) {
319 throw new SAXException(e);
320 }
321 }
322 }
323
324 }