KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > model > StringAttributes


1 /*
2 Copyright (c) 2004-2005, 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.model;
30
31 import java.lang.reflect.Constructor JavaDoc;
32 import java.lang.reflect.InvocationTargetException JavaDoc;
33 import java.lang.reflect.Method JavaDoc;
34
35 import org.jibx.binding.util.StringArray;
36
37 /**
38  * Model component for <i>string</i> attribute group in binding definition.
39  *
40  * @author Dennis M. Sosnoski
41  * @version 1.0
42  */

43  
44 public class StringAttributes extends AttributeBase
45 {
46     /** Enumeration of allowed attribute names */
47     public static final StringArray s_allowedAttributes =
48         new StringArray(new String JavaDoc[] { "default", "deserializer",
49         "serializer" });
50     // TODO: add "format" for 2.0
51

52     //
53
// Constants and such related to code generation.
54

55     // signature variants allowed for serializer
56
private static final String JavaDoc[] SERIALIZER_SIGNATURE_VARIANTS =
57     {
58         "Lorg/jibx/runtime/IMarshallingContext;",
59         "Ljava/lang/Object;",
60         ""
61     };
62     
63     // signatures allowed for deserializer
64
private static final String JavaDoc[] DESERIALIZER_SIGNATURES =
65     {
66         "(Ljava/lang/String;Lorg/jibx/runtime/IUnmarshallingContext;)",
67         "(Ljava/lang/String;Ljava/lang/Object;)",
68         "(Ljava/lang/String;)"
69     };
70     
71     // signature required for constructor from string
72
private static final String JavaDoc STRING_CONSTRUCTOR_SIGNATURE =
73         "(Ljava/lang/String;)";
74     
75     // classes of arguments to constructor or deserializer
76
private static final Class JavaDoc[] STRING_CONSTRUCTOR_ARGUMENT_CLASSES =
77     {
78         java.lang.String JavaDoc.class
79     };
80     
81     //
82
// Instance data.
83

84     /** Referenced format name. */
85     private String JavaDoc m_formatName;
86     
87     /** Default value text. */
88     private String JavaDoc m_defaultText;
89     
90     /** Serializer fully qualified class and method name. */
91     private String JavaDoc m_serializerName;
92     
93     /** Deserializer fully qualified class and method name. */
94     private String JavaDoc m_deserializerName;
95     
96     /** Base format for conversions. */
97     private FormatElement m_baseFormat;
98     
99     /** Value type class. */
100     private IClass m_typeClass;
101     
102     /** Default value object. */
103     private Object JavaDoc m_default;
104     
105     /** Serializer method (or toString equivalent) information. */
106     private IClassItem m_serializerItem;
107     
108     /** Deserializer method (or constructor from string) information. */
109     private IClassItem m_deserializerItem;
110     
111     /**
112      * Default constructor.
113      */

114     public StringAttributes() {}
115     
116     /**
117      * Set value type. This needs to be set by the owning element prior to
118      * validation. Even though the type is an important part of the string
119      * information, it's treated as a separate item of information because it
120      * needs to be used as part of the property attributes.
121      *
122      * @param type value type
123      */

124     public void setType(IClass type) {
125         m_typeClass = type;
126     }
127     
128     /**
129      * Get value type.
130      *
131      * @return value type
132      */

133     public IClass getType() {
134         return m_typeClass;
135     }
136     
137     /**
138      * Get base format name.
139      *
140      * @return referenced base format
141      */

142     public String JavaDoc getFormatName() {
143         return m_formatName;
144     }
145     
146     /**
147      * Set base format name.
148      *
149      * @param name referenced base format
150      */

151     public void setFormatName(String JavaDoc name) {
152         m_formatName = name;
153     }
154     
155     /**
156      * Get default value text.
157      *
158      * @return default value text
159      */

160     public String JavaDoc getDefaultText() {
161         return m_defaultText;
162     }
163     
164     /**
165      * Get default value. This method is only usable after a
166      * call to {@link #validate}.
167      *
168      * @return default value object
169      */

170     public Object JavaDoc getDefault() {
171         return m_default;
172     }
173     
174     /**
175      * Set default value text.
176      *
177      * @param value default value text
178      */

179     public void setDefaultText(String JavaDoc value) {
180         m_defaultText = value;
181     }
182     
183     /**
184      * Get serializer name.
185      *
186      * @return fully qualified class and method name for serializer (or
187      * <code>null</code> if none)
188      */

189     public String JavaDoc getSerializerName() {
190         return m_serializerName;
191     }
192     
193     /**
194      * Get serializer method information. This method is only usable after a
195      * call to {@link #validate}.
196      *
197      * @return serializer information (or <code>null</code> if none)
198      */

199     public IClassItem getSerializer() {
200         return m_serializerItem;
201     }
202     
203     /**
204      * Set serializer method name.
205      *
206      * @param fully qualified class and method name for serializer
207      */

208     public void setSerializerName(String JavaDoc name) {
209         m_serializerName = name;
210     }
211     
212     /**
213      * Get deserializer name.
214      *
215      * @return fully qualified class and method name for deserializer (or
216      * <code>null</code> if none)
217      */

218     public String JavaDoc getDeserializerName() {
219         return m_serializerName;
220     }
221     
222     /**
223      * Get deserializer method information. This method is only usable after a
224      * call to {@link #validate}.
225      *
226      * @return deserializer information (or <code>null</code> if none)
227      */

228     public IClassItem getDeserializer() {
229         return m_deserializerItem;
230     }
231     
232     /**
233      * Set deserializer method name.
234      *
235      * @param fully qualified class and method name for deserializer
236      */

237     public void setDeserializerName(String JavaDoc name) {
238         m_deserializerName = name;
239     }
240     
241     /**
242      * Get base format information. This method is only usable after a
243      * call to {@link #validate}.
244      *
245      * @return base format element (or <code>null</code> if none)
246      */

247     public FormatElement getBaseFormat() {
248         return m_baseFormat;
249     }
250     
251     /* (non-Javadoc)
252      * @see org.jibx.binding.model.AttributeBase#prevalidate(org.jibx.binding.model.ValidationContext)
253      */

254     public void prevalidate(ValidationContext vctx) {
255         
256         // make sure the type has been configured
257
if (m_typeClass == null) {
258             vctx.addFatal("Missing type information for conversion to string");
259         } else {
260             
261             // get the base format (if any)
262
DefinitionContext dctx = vctx.getDefinitions();
263             if (m_formatName == null) {
264                 m_baseFormat = dctx.getBestFormat(m_typeClass);
265             } else {
266                 m_baseFormat = dctx.getNamedFormat(m_formatName);
267             }
268             
269             // check specified serializer and deserializer
270
String JavaDoc tname = m_typeClass.getName();
271             if (vctx.isOutBinding()) {
272                 if (m_serializerName != null) {
273                 
274                     // build all possible signature variations
275
String JavaDoc[] tsigs = ClassUtils.
276                         getSignatureVariants(tname, vctx);
277                     int vcnt = SERIALIZER_SIGNATURE_VARIANTS.length;
278                     String JavaDoc[] msigs = new String JavaDoc[tsigs.length * vcnt];
279                     for (int i = 0; i < tsigs.length; i++) {
280                         for (int j = 0; j < vcnt; j++) {
281                             msigs[i*vcnt + j] = "(" + tsigs[i] +
282                                 SERIALIZER_SIGNATURE_VARIANTS[j] +
283                                 ")Ljava/lang/String;";
284                         }
285                     }
286                 
287                     // find a matching static method
288
m_serializerItem = ClassUtils.
289                         findStaticMethod(m_serializerName, msigs, vctx);
290                     if (m_serializerItem == null) {
291                         vctx.addError("Static serializer method " +
292                             m_serializerName + " not found");
293                     }
294                     
295                 } else {
296                     
297                     // try to find an inherited serializer
298
FormatElement ances = m_baseFormat;
299                     while (ances != null) {
300                         m_serializerItem = ances.getSerializer();
301                         if (m_serializerItem == null) {
302                             ances = ances.getBaseFormat();
303                         } else {
304                             break;
305                         }
306                     }
307                     if (m_serializerItem == null) {
308                         m_serializerItem = m_typeClass.getMethod("toString",
309                             "()Ljava/lang/String;");
310                         if (m_serializerItem == null) {
311                             throw new IllegalStateException JavaDoc
312                                 ("Internal error: toString method not found");
313                         }
314                     }
315                 }
316             }
317             if (vctx.isInBinding() || m_defaultText != null) {
318                 if (m_deserializerName != null) {
319                 
320                     // find a matching static method
321
m_deserializerItem = ClassUtils.
322                         findStaticMethod(m_deserializerName,
323                             DESERIALIZER_SIGNATURES, vctx);
324                     if (m_deserializerItem == null) {
325                         vctx.addError("Static deserializer method " +
326                             m_deserializerName + " not found");
327                     } else {
328                         String JavaDoc result = m_deserializerItem.getTypeName();
329                         if (!ClassUtils.isAssignable(result, tname, vctx)) {
330                             vctx.addError("Static deserializer method " +
331                                 m_deserializerName +
332                                 " has incompatible result type");
333                         }
334                     }
335                     
336                 } else {
337                     
338                     // try to find an inherited deserializer
339
FormatElement ances = m_baseFormat;
340                     while (ances != null) {
341                         m_deserializerItem = ances.getDeserializer();
342                         if (m_deserializerItem == null) {
343                             ances = ances.getBaseFormat();
344                         } else {
345                             break;
346                         }
347                     }
348                     if (m_deserializerItem == null &&
349                         !"java.lang.Object".equals(tname)) {
350                         
351                         // try to find a constructor from string as last resort
352
m_deserializerItem = m_typeClass.
353                             getInitializerMethod(STRING_CONSTRUCTOR_SIGNATURE);
354                         if (m_deserializerItem == null) {
355                             StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
356                             buff.append("Need deserializer or constructor ");
357                             buff.append("from string");
358                             if (!vctx.isInBinding()) {
359                                 buff.append(" for default value of type ");
360                                 buff.append(tname);
361                             } else {
362                                 buff.append(" for type ");
363                                 buff.append(tname);
364                             }
365                             vctx.addError(buff.toString());
366                         }
367                     }
368                 }
369             }
370             
371             // check for default value to be converted
372
if (m_defaultText != null && m_deserializerItem != null) {
373                 
374                 // first load the class to handle conversion
375
String JavaDoc cname = m_deserializerItem.getOwningClass().getName();
376                 Class JavaDoc clas = ClassUtils.loadClass(cname);
377                 Exception JavaDoc ex = null;
378                 boolean construct = false;
379                 try {
380                     if (clas == null) {
381                         vctx.addError("Unable to load class " + cname +
382                             " for converting default value of type " + tname);
383                     } else if (m_deserializerItem.isInitializer()) {
384                         
385                         // invoke constructor to process default value
386
construct = true;
387                         Constructor JavaDoc cons = clas.getConstructor
388                             (STRING_CONSTRUCTOR_ARGUMENT_CLASSES);
389                         try {
390                             cons.setAccessible(true);
391                         } catch (Exception JavaDoc e) { /* deliberately left empty */ }
392                         Object JavaDoc[] args = new Object JavaDoc[1];
393                         args[0] = m_defaultText;
394                         m_default = cons.newInstance(args);
395                         
396                     } else {
397                         
398                         // invoke deserializer to convert default value
399
String JavaDoc mname = m_deserializerItem.getName();
400                         Method JavaDoc deser = clas.getDeclaredMethod(mname,
401                             STRING_CONSTRUCTOR_ARGUMENT_CLASSES);
402                         try {
403                             deser.setAccessible(true);
404                         } catch (Exception JavaDoc e) { /* deliberately left empty */ }
405                         Object JavaDoc[] args = new Object JavaDoc[1];
406                         args[0] = m_defaultText;
407                         m_default = deser.invoke(null, args);
408                         
409                     }
410                 } catch (SecurityException JavaDoc e) {
411                     StringBuffer JavaDoc buff = new StringBuffer JavaDoc("Unable to access ");
412                     if (construct) {
413                         buff.append("constructor from string");
414                     } else {
415                         buff.append("deserializer ");
416                         buff.append(m_deserializerName);
417                     }
418                     buff.append(" for converting default value of type ");
419                     buff.append(tname);
420                     vctx.addError(buff.toString());
421                 } catch (NoSuchMethodException JavaDoc e) {
422                     StringBuffer JavaDoc buff = new StringBuffer JavaDoc("Unable to find ");
423                     if (construct) {
424                         buff.append("constructor from string");
425                     } else {
426                         buff.append("deserializer ");
427                         buff.append(m_deserializerName);
428                     }
429                     buff.append(" for converting default value of type ");
430                     buff.append(tname);
431                     vctx.addError(buff.toString());
432                 } catch (IllegalArgumentException JavaDoc e) {
433                     ex = e;
434                 } catch (InstantiationException JavaDoc e) {
435                     ex = e;
436                 } catch (IllegalAccessException JavaDoc e) {
437                     ex = e;
438                 } catch (InvocationTargetException JavaDoc e) {
439                     ex = e;
440                 } finally {
441                     if (ex != null) {
442                         StringBuffer JavaDoc buff = new StringBuffer JavaDoc("Error calling ");
443                         if (construct) {
444                             buff.append("constructor from string");
445                         } else {
446                             buff.append("deserializer ");
447                             buff.append(m_deserializerName);
448                         }
449                         buff.append(" for converting default value of type ");
450                         buff.append(tname);
451                         vctx.addError(buff.toString());
452                     }
453                 }
454             }
455         }
456         super.prevalidate(vctx);
457     }
458 }
Popular Tags