KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > def > StringConversion


1 /*
2 Copyright (c) 2003-2004, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.binding.def;
30
31 import org.apache.bcel.classfile.Utility;
32
33 import org.jibx.binding.classes.*;
34 import org.jibx.runtime.JiBXException;
35
36 /**
37  * String conversion handling. Defines serialization handling for converting
38  * to and from a <code>String</code> value. This uses an inheritance approach,
39  * where each serialization definition is initialized based on the handling
40  * set for the containing definition of the same (or parent class) type.
41  *
42  * @author Dennis M. Sosnoski
43  * @version 1.0
44  */

45
46 public abstract class StringConversion
47 {
48     //
49
// Constants for code generation.
50

51     protected static final String JavaDoc UNMARSHAL_OPT_ATTRIBUTE =
52         "org.jibx.runtime.impl.UnmarshallingContext.attributeText";
53     protected static final String JavaDoc UNMARSHAL_OPT_ELEMENT =
54         "org.jibx.runtime.impl.UnmarshallingContext.parseElementText";
55     protected static final String JavaDoc UNMARSHAL_OPT_SIGNATURE =
56         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)" +
57         "Ljava/lang/String;";
58     protected static final String JavaDoc UNMARSHAL_REQ_ATTRIBUTE =
59         "org.jibx.runtime.impl.UnmarshallingContext.attributeText";
60     protected static final String JavaDoc UNMARSHAL_REQ_ELEMENT =
61         "org.jibx.runtime.impl.UnmarshallingContext.parseElementText";
62     protected static final String JavaDoc UNMARSHAL_REQ_SIGNATURE =
63         "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
64     protected static final String JavaDoc MARSHAL_ATTRIBUTE =
65         "org.jibx.runtime.impl.MarshallingContext.attribute";
66     protected static final String JavaDoc MARSHAL_ELEMENT =
67         "org.jibx.runtime.impl.MarshallingContext.element";
68     protected static final String JavaDoc MARSHAL_SIGNATURE =
69         "(ILjava/lang/String;Ljava/lang/String;)" +
70         "Lorg/jibx/runtime/impl/MarshallingContext;";
71     protected static final String JavaDoc COMPARE_OBJECTS_METHOD =
72         "org.jibx.runtime.Utility.isEqual";
73     protected static final String JavaDoc COMPARE_OBJECTS_SIGNATURE =
74         "(Ljava/lang/Object;Ljava/lang/Object;)Z";
75     
76     // values used for name in marshalling; must be 1 or 2
77
public static final int MARSHAL_NAME_VALUES = 2;
78
79     //
80
// Actual instance data
81

82     /** Name of format. */
83     protected String JavaDoc m_formatName;
84
85     /** Default value used for this type (wrapper for primitives, otherwise
86      <code>String</code> or <code>null</code>). */

87     protected Object JavaDoc m_default;
88
89     /** Serializer method information. */
90     protected ClassItem m_serializer;
91
92     /** Deserializer method information. */
93     protected ClassItem m_deserializer;
94     
95     /** Fully qualified name of class handled by conversion. */
96     protected String JavaDoc m_typeName;
97     
98     /** Signature of class handled by conversion. */
99     protected String JavaDoc m_typeSignature;
100
101     /**
102      * Constructor. This internal form only initializes the type information.
103      *
104      * @param type fully qualified name of class handled by conversion
105      */

106
107     private StringConversion(String JavaDoc type) {
108         m_typeName = type;
109         m_typeSignature = Utility.getSignature(type);
110     }
111
112     /**
113      * Constructor. Initializes conversion handling based on the supplied
114      * inherited handling.
115      *
116      * @param type fully qualified name of class handled by conversion
117      * @param inherit conversion information inherited by this conversion
118      */

119
120     protected StringConversion(String JavaDoc type, StringConversion inherit) {
121         this(type);
122         m_default = inherit.m_default;
123         m_serializer = inherit.m_serializer;
124         m_deserializer = inherit.m_deserializer;
125     }
126
127     /**
128      * Constructor. Initializes conversion handling based on argument values.
129      * This form is only used for constructing the default set of conversions.
130      * Because of this, it throws an unchecked exception on error.
131      *
132      * @param dflt default value object (wrapped value for primitive types,
133      * otherwise <code>String</code>)
134      * @param ser fully qualified name of serialization method
135      * @param deser fully qualified name of deserialization method
136      * @param type fully qualified name of class handled by conversion
137      */

138
139     /*package*/ StringConversion(Object JavaDoc dflt, String JavaDoc ser, String JavaDoc deser,
140         String JavaDoc type) {
141         this(type);
142         m_default = dflt;
143         try {
144             if (ser != null) {
145                 setSerializer(ser);
146             }
147             if (deser != null) {
148                 setDeserializer(deser);
149             }
150         } catch (JiBXException ex) {
151             throw new IllegalArgumentException JavaDoc(ex.getMessage());
152         }
153     }
154
155     /**
156      * Get name of type handled by this conversion.
157      *
158      * @return fully qualified class name of type handled by conversion
159      */

160
161     public String JavaDoc getTypeName() {
162         return m_typeName;
163     }
164
165     /**
166      * Generate code to convert <code>String</code> representation. The
167      * code generated by this method assumes that the <code>String</code>
168      * value has already been pushed on the stack. It consumes this and
169      * leaves the converted value on the stack.
170      *
171      * @param mb method builder
172      * @throws JiBXException if error in configuration
173      */

174
175     public abstract void genFromText(MethodBuilder mb) throws JiBXException;
176
177     /**
178      * Generate code to parse and convert optional attribute or element. This
179      * abstract base class method must be implemented by every subclass. The
180      * code generated by this method assumes that the unmarshalling context
181      * and name information for the attribute or element have already
182      * been pushed on the stack. It consumes these and leaves the converted
183      * value (or converted default value, if the item itself is missing) on
184      * the stack.
185      *
186      * @param attr item is an attribute (vs element) flag
187      * @param mb method builder
188      * @throws JiBXException if error in configuration
189      */

190     
191     public abstract void genParseOptional(boolean attr, MethodBuilder mb)
192         throws JiBXException;
193
194     /**
195      * Generate code to parse and convert required attribute or element. This
196      * abstract base class method must be implemented by every subclass. The
197      * code generated by this method assumes that the unmarshalling context and
198      * name information for the attribute or element have already been pushed
199      * on the stack. It consumes these and leaves the converted value on the
200      * stack.
201      *
202      * @param attr item is an attribute (vs element) flag
203      * @param mb method builder
204      * @throws JiBXException if error in configuration
205      */

206
207     public abstract void genParseRequired(boolean attr, MethodBuilder ub)
208         throws JiBXException;
209
210     /**
211      * Generate code to write <code>String</code> value to generated document.
212      * The code generated by this method assumes that the marshalling context,
213      * the name information, and the actual value to be converted have already
214      * been pushed on the stack. It consumes these, leaving the marshalling
215      * context on the stack.
216      *
217      * @param attr item is an attribute (vs element) flag
218      * @param mb method builder
219      * @throws JiBXException if error in configuration
220      */

221
222     public void genWriteText(boolean attr, MethodBuilder mb)
223         throws JiBXException {
224         
225         // append code to call the appropriate generic marshalling context
226
// String method
227
String JavaDoc name = attr ? MARSHAL_ATTRIBUTE : MARSHAL_ELEMENT;
228         mb.appendCallVirtual(name, MARSHAL_SIGNATURE);
229     }
230
231     /**
232      * Generate code to pop values from stack.
233      *
234      * @param count number of values to be popped
235      * @param mb method builder
236      */

237
238     public void genPopValues(int count, MethodBuilder mb) {
239         while (--count >= 0) {
240             if (mb.isStackTopLong()) {
241                 mb.appendPOP2();
242             } else {
243                 mb.appendPOP();
244             }
245         }
246     }
247
248     /**
249      * Generate code to check if an optional value is not equal to the default.
250      * This abstract base class method must be implemented by every subclass.
251      * The code generated by this method assumes that the actual value to be
252      * converted has already been pushed on the stack. It consumes this,
253      * leaving the converted text reference on the stack if it's not equal to
254      * the default value.
255      *
256      * @param type fully qualified class name for value on stack
257      * @param mb method builder
258      * @param extra count of extra words to be popped from stack if missing
259      * @return handle for branch taken when value is equal to the default
260      * (target must be set by caller)
261      * @throws JiBXException if error in configuration
262      */

263
264     protected abstract BranchWrapper genToOptionalText(String JavaDoc type,
265         MethodBuilder mb, int extra) throws JiBXException;
266
267     /**
268      * Generate code to convert value to a <code>String</code>. The code
269      * generated by this method assumes that the actual value to be converted
270      * has already been pushed on the stack. It consumes this, leaving the
271      * converted text reference on the stack.
272      *
273      * @param type fully qualified class name for value on stack
274      * @param mb method builder
275      * @throws JiBXException if error in configuration
276      */

277
278     public void genToText(String JavaDoc type, MethodBuilder mb) throws JiBXException {
279         
280         // check if a serializer is used for this type
281
if (m_serializer != null) {
282             
283             // just generate call to the serializer (adding any checked
284
// exceptions thrown by the serializer to the list needing
285
// handling)
286
if (!isPrimitive()) {
287                 mb.appendCreateCast(type, m_serializer.getArgumentType(0));
288             }
289             mb.addMethodExceptions(m_serializer);
290             mb.appendCall(m_serializer);
291             
292         } else {
293             
294             // make sure this is a string
295
mb.appendCreateCast(type, "java.lang.String");
296         }
297     }
298
299     /**
300      * Generate code to convert and write optional value to generated document.
301      * The generated code first tests if the value is the same as the supplied
302      * default, and if so skips writing. The code assumes that the marshalling
303      * context, the name information, and the actual value to be converted have
304      * already been pushed on the stack. It consumes these, leaving only the
305      * marshalling context on the stack.
306      *
307      * @param attr item is an attribute (vs element) flag
308      * @param type fully qualified class name for value on stack
309      * @param mb method builder
310      * @throws JiBXException if error in configuration
311      */

312
313     public void genWriteOptional(boolean attr, String JavaDoc type, MethodBuilder mb)
314         throws JiBXException {
315         
316         // start with code to convert value to String, if it's not equal to the
317
// default value
318
BranchWrapper toend = genToOptionalText(type, mb, MARSHAL_NAME_VALUES);
319         
320         // next use standard write code, followed by targeting branch
321
genWriteText(attr, mb);
322         if (toend != null) {
323             mb.targetNext(toend);
324         }
325     }
326
327     /**
328      * Generate code to convert and write required value to generated document.
329      * The code generated by this method assumes that the marshalling context,
330      * the name information, and the actual value to be converted have already
331      * been pushed on the stack. It consumes these, leaving the returned
332      * marshalling context on the stack.
333      *
334      * @param attr item is an attribute (vs element) flag
335      * @param type fully qualified class name for value on stack
336      * @param mb method builder
337      * @throws JiBXException if error in configuration
338      */

339     
340     public void genWriteRequired(boolean attr, String JavaDoc type, MethodBuilder mb)
341         throws JiBXException {
342         
343         // generate code to convert to text, followed by code to marshal text
344
genToText(type, mb);
345         genWriteText(attr, mb);
346     }
347
348     /**
349      * Check if the type handled by this conversion is of a primitive type.
350      *
351      * @return <code>true</code> if a primitive type, <code>false</code> if an
352      * object type
353      */

354
355     public abstract boolean isPrimitive();
356
357     /**
358      * Set serializer for conversion. This finds the named static method and
359      * sets it as the serializer to be used for this conversion. The serializer
360      * method is expected to take a single argument of either the handled
361      * type or a superclass or interface of the handled type, and to return a
362      * <code>String</code> result.
363      *
364      * @param ser fully qualified class and method name of serializer
365      * @throws JiBXException if serializer not found or not usable
366      */

367
368     protected void setSerializer(String JavaDoc ser) throws JiBXException {
369         
370         // build all possible signature variations
371
String JavaDoc[] tsigs = ClassItem.getSignatureVariants(m_typeName);
372         String JavaDoc[] msigs = new String JavaDoc[tsigs.length];
373         for (int i = 0; i < tsigs.length; i++) {
374             msigs[i] = "(" + tsigs[i] + ")Ljava/lang/String;";
375         }
376         
377         // find a matching static method
378
ClassItem method = ClassItem.findStaticMethod(ser, msigs);
379         
380         // report error if method not found
381
if (method == null) {
382             throw new JiBXException("Serializer " + ser + " not found");
383         } else {
384             m_serializer = method;
385         }
386     }
387
388     /**
389      * Set deserializer for conversion. This finds the named static method and
390      * sets it as the deserializer to be used for this conversion. The
391      * deserializer method is expected to take a single argument of type
392      * <code>String</code>, and to return a value of the handled type or a
393      * subtype of that type.
394      *
395      * @param deser fully qualified class and method name of deserializer
396      * @throws JiBXException if deserializer not found or not usable
397      */

398
399     protected void setDeserializer(String JavaDoc deser) throws JiBXException {
400         
401         // find a matching static method
402
String JavaDoc[] msigs = new String JavaDoc[] { "(Ljava/lang/String;)" };
403         ClassItem method = ClassItem.findStaticMethod(deser, msigs);
404         
405         // report error if method not found or incompatible
406
if (method == null) {
407             throw new JiBXException("Deserializer " + deser + " not found");
408         } else if (ClassItem.isAssignable(method.getTypeName(), m_typeName)) {
409             m_deserializer = method;
410         } else {
411             throw new JiBXException("Deserializer " + deser +
412                 " returns wrong type");
413         }
414     }
415     
416     /**
417      * Convert text representation into default value object. Each subclass
418      * must implement this with the appropriate conversion handling.
419      *
420      * @param text value representation to be converted
421      * @return converted default value object
422      * @throws JiBXException on conversion error
423      */

424
425     protected abstract Object JavaDoc convertDefault(String JavaDoc text) throws JiBXException;
426
427     /**
428      * Derive from existing formatting information. This abstract base class
429      * method must be implemented by every subclass. It allows constructing
430      * a new instance from an existing format of the same or an ancestor
431      * type, with the properties of the existing format copied to the new
432      * instance except where overridden by the supplied values.
433      *
434      * @param type fully qualified name of class handled by conversion
435      * @param ser fully qualified name of serialization method
436      * (<code>null</code> if inherited)
437      * @param deser fully qualified name of deserialization method
438      * (<code>null</code> if inherited)
439      * @param dflt default value text (<code>null</code> if inherited)
440      * @return new instance initialized from existing one
441      * @throws JiBXException if error in configuration information
442      */

443
444     public abstract StringConversion derive(String JavaDoc type, String JavaDoc ser,
445         String JavaDoc dser, String JavaDoc dlft) throws JiBXException;
446 }
Popular Tags