KickJava   Java API By Example, From Geeks To Geeks.

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


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.Constants;
32 import org.apache.bcel.generic.*;
33
34 import org.jibx.binding.classes.*;
35 import org.jibx.runtime.JiBXException;
36
37 /**
38  * Binding modifiers that apply to a class reference. This adds the methods used
39  * for handling binding operations to the object class, then generates calls to
40  * the added methods as this binding definition is used.
41  *
42  * @author Dennis M. Sosnoski
43  * @version 1.0
44  */

45
46 public class ObjectBinding extends PassThroughComponent
47 implements IComponent, IContextObj
48 {
49     //
50
// Constants and such related to code generation.
51

52     // recognized marshal hook method (pre-get) signatures.
53
private static final String JavaDoc[] MARSHAL_HOOK_SIGNATURES =
54     {
55         "(Lorg/jibx/runtime/IMarshallingContext;)V",
56         "(Ljava/lang/Object;)V",
57         "()V"
58     };
59     
60     // recognized factory hook method signatures.
61
private static final String JavaDoc[] FACTORY_HOOK_SIGNATURES =
62     {
63         "(Lorg/jibx/runtime/IUnmarshallingContext;)",
64         "(Ljava/lang/Object;)",
65         "()"
66     };
67     
68     // recognized unmarshal hook method (pre-set, post-set) signatures.
69
private static final String JavaDoc[] UNMARSHAL_HOOK_SIGNATURES =
70     {
71         "(Lorg/jibx/runtime/IUnmarshallingContext;)V",
72         "(Ljava/lang/Object;)V",
73         "()V"
74     };
75     
76     // definitions used in generating calls to user defined methods
77
private static final String JavaDoc UNMARSHAL_GETSTACKTOPMETHOD =
78         "org.jibx.runtime.impl.UnmarshallingContext.getStackTop";
79     private static final String JavaDoc MARSHAL_GETSTACKTOPMETHOD =
80         "org.jibx.runtime.impl.MarshallingContext.getStackTop";
81     private static final String JavaDoc GETSTACKTOP_SIGNATURE =
82         "()Ljava/lang/Object;";
83     private static final String JavaDoc MARSHALLING_CONTEXT =
84         "org.jibx.runtime.impl.MarshallingContext";
85     private static final String JavaDoc UNMARSHALLING_CONTEXT =
86         "org.jibx.runtime.impl.UnmarshallingContext";
87     private static final String JavaDoc UNMARSHAL_PARAMETER_SIGNATURE =
88         "(Lorg/jibx/runtime/impl/UnmarshallingContext;)";
89     private static final String JavaDoc UNMARSHAL_PUSHOBJECTMETHOD =
90         "org.jibx.runtime.impl.UnmarshallingContext.pushObject";
91     private static final String JavaDoc MARSHAL_PUSHOBJECTMETHOD =
92         "org.jibx.runtime.impl.MarshallingContext.pushObject";
93     private static final String JavaDoc PUSHOBJECT_SIGNATURE =
94         "(Ljava/lang/Object;)V";
95     private static final String JavaDoc UNMARSHAL_POPOBJECTMETHOD =
96         "org.jibx.runtime.impl.UnmarshallingContext.popObject";
97     private static final String JavaDoc MARSHAL_POPOBJECTMETHOD =
98         "org.jibx.runtime.impl.MarshallingContext.popObject";
99     private static final String JavaDoc POPOBJECT_SIGNATURE = "()V";
100     
101     // definitions for methods added to mapped class
102
private static final String JavaDoc NEWINSTANCE_SUFFIX = "_newinstance";
103     private static final String JavaDoc UNMARSHAL_ATTR_SUFFIX = "_unmarshalAttr";
104     private static final String JavaDoc MARSHAL_ATTR_SUFFIX = "_marshalAttr";
105     private static final String JavaDoc UNMARSHAL_SUFFIX = "_unmarshal";
106     private static final String JavaDoc MARSHAL_SUFFIX = "_marshal";
107     
108     // definitions for source position tracking
109
private static final String JavaDoc SOURCE_TRACKING_INTERFACE =
110         "org.jibx.runtime.impl.ITrackSourceImpl";
111     private static final String JavaDoc SOURCE_TRACKING_SIGNATURE =
112         "Lorg/jibx/runtime/impl/ITrackSourceImpl;";
113     private static final String JavaDoc SETSOURCE_METHODNAME = "jibx_setSource";
114     private static final Type[] SETSOURCE_ARGS =
115     {
116         Type.STRING, Type.INT, Type.INT
117     };
118     private static final String JavaDoc SOURCEDOCUMENT_FIELDNAME ="jibx_sourceDocument";
119     private static final String JavaDoc SOURCELINE_FIELDNAME = "jibx_sourceLine";
120     private static final String JavaDoc SOURCECOLUMN_FIELDNAME = "jibx_sourceColumn";
121     private static final String JavaDoc SOURCENAME_METHODNAME = "jibx_getDocumentName";
122     private static final String JavaDoc SOURCELINE_METHODNAME = "jibx_getLineNumber";
123     private static final String JavaDoc SOURCECOLUMN_METHODNAME =
124         "jibx_getColumnNumber";
125     private static final String JavaDoc SOURCENUMBER_SIGNATURE = "()I";
126     private static final Type[] EMPTY_ARGS = {};
127
128     //
129
// Actual instance data.
130

131     /** Containing binding definition structure. */
132     private final IContainer m_container;
133     
134     /** Class linked to mapping. */
135     private BoundClass m_class;
136
137     /** Default style for value expression. */
138     private int m_styleDefault;
139
140     /** Object factory method. */
141     private final ClassItem m_factoryMethod;
142
143     /** Preset method for object. */
144     private final ClassItem m_preSetMethod;
145
146     /** Postset method for object. */
147     private final ClassItem m_postSetMethod;
148
149     /** Preget method for object. */
150     private final ClassItem m_preGetMethod;
151     
152     /** Generated new instance method. */
153     private ClassItem m_newInstanceMethod;
154     
155     /** Flag for recursion while generating attribute unmarshal. */
156     private boolean m_lockAttributeUnmarshal;
157     
158     /** Flag for recursion while generating attribute marshal. */
159     private boolean m_lockAttributeMarshal;
160     
161     /** Flag for recursion while generating attribute unmarshal. */
162     private boolean m_lockContentUnmarshal;
163     
164     /** Flag for recursion while generating attribute marshal. */
165     private boolean m_lockContentMarshal;
166     
167     /** Signature used for unmarshal methods. */
168     private String JavaDoc m_unmarshalSignature;
169     
170     /** Name for unmarshal attribute method (<code>null</code> unless
171      generation started). */

172     private String JavaDoc m_unmarshalAttributeName;
173     
174     /** Name for unmarshal content method (<code>null</code> unless
175      generation started). */

176     private String JavaDoc m_unmarshalContentName;
177     
178     /** Flag for static unmarshal methods. */
179     private boolean m_isStaticUnmarshal;
180     
181     /** Flag for static marshal methods. */
182     private boolean m_isStaticMarshal;
183     
184     /** Signature used for marshal methods. */
185     private String JavaDoc m_marshalSignature;
186     
187     /** Name for marshal attribute method (<code>null</code> unless
188      generation started). */

189     private String JavaDoc m_marshalAttributeName;
190     
191     /** Name for marshal content method (<code>null</code> unless
192      generation istarted). */

193     private String JavaDoc m_marshalContentName;
194     
195     /** Generated unmarshal attribute method. */
196     private ClassItem m_unmarshalAttributeMethod;
197     
198     /** Generated unmarshal content method. */
199     private ClassItem m_unmarshalContentMethod;
200     
201     /** Generated marshal attribute method. */
202     private ClassItem m_marshalAttributeMethod;
203     
204     /** Generated marshal content method. */
205     private ClassItem m_marshalContentMethod;
206     
207     /** Child supplying instance identifier value. */
208     private IComponent m_idChild;
209     
210     /** Flag for value from collection (TODO: fix this in update). */
211     private boolean m_directAccess;
212     
213     /** Flag for abstract mapping. */
214     private boolean m_isAbstract;
215
216     /**
217      * Constructor. This initializes the definition context to be the same as
218      * the parent's. Subclasses may change this definition context if
219      * appropriate.
220      *
221      * @param contain containing binding definition component
222      * @param objc current object context
223      * @param type fully qualified class name for bound object
224      * @param fact user new instance factory method
225      * @param pres user preset method for unmarshalling
226      * @param posts user postset method for unmarshalling
227      * @param pget user preget method for marshalling
228      * @throws JiBXException if method not found
229      */

230
231     public ObjectBinding(IContainer contain, IContextObj objc, String JavaDoc type,
232         String JavaDoc fact, String JavaDoc pres, String JavaDoc posts, String JavaDoc pget)
233         throws JiBXException {
234         
235         // initialize the basics
236
m_container = contain;
237         BoundClass ctxc = (objc == null) ? null : objc.getBoundClass();
238         m_class = BoundClass.getInstance(type, ctxc);
239         ClassFile cf = m_class.getClassFile();
240         
241         // check instance creation for unmarshalling
242
if (fact == null) {
243             m_factoryMethod = null;
244         } else {
245             
246             // look up supplied static factory method
247
int split = fact.lastIndexOf('.');
248             if (split >= 0) {
249                 
250                 // verify the method is defined
251
String JavaDoc cname = fact.substring(0, split);
252                 String JavaDoc mname = fact.substring(split+1);
253                 ClassFile mcf = ClassCache.getClassFile(cname);
254                 m_factoryMethod = mcf.getMethod(mname,
255                     FACTORY_HOOK_SIGNATURES);
256                 if (m_factoryMethod == null) {
257                     throw new JiBXException("Factory method " + fact +
258                         " not found");
259                 } else if (m_factoryMethod.getTypeName().equals(type)) {
260                     
261                     // force access if necessary
262
m_factoryMethod.makeAccessible(cf);
263                     
264                 } else {
265                     throw new JiBXException("Factory method " + fact +
266                         " return type is not " + type);
267                 }
268             } else {
269                 m_factoryMethod = null;
270             }
271             if (m_factoryMethod == null) {
272                 throw new JiBXException("Factory method " + fact +
273                     " not found.");
274             }
275         }
276         
277         // look up other method names as members of class
278
if (pres == null) {
279             m_preSetMethod = null;
280         } else {
281             m_preSetMethod = cf.getMethod(pres, UNMARSHAL_HOOK_SIGNATURES);
282             if (m_preSetMethod == null) {
283                 throw new JiBXException("User method " + pres + " not found.");
284             }
285         }
286         if (posts == null) {
287             m_postSetMethod = null;
288         } else {
289             m_postSetMethod = cf.getMethod(posts, UNMARSHAL_HOOK_SIGNATURES);
290             if (m_postSetMethod == null) {
291                 throw new JiBXException("User method " + posts + " not found.");
292             }
293         }
294         if (pget == null) {
295             m_preGetMethod = null;
296         } else {
297             m_preGetMethod = cf.getMethod(pget, MARSHAL_HOOK_SIGNATURES);
298             if (m_preGetMethod == null) {
299                 throw new JiBXException("User method " + pget + " not found.");
300             }
301         }
302     }
303
304     /**
305      * Set the direct access flag. This controls a variation in the code
306      * generation to handle values loaded from a collection.
307      *
308      * @param direct <code>true</code> if direct access from collection,
309      * <code>false</code> if not
310      */

311     
312     public void setDirect(boolean direct) {
313         m_directAccess = direct;
314     }
315
316     /**
317      * Set the abstract mapping flag. This disables source tracking for abstract
318      * base mappings.
319      *
320      * @param abs <code>true</code> if abstract mapping, <code>false</code> if
321      * not
322      */

323     
324     public void setAbstract(boolean abs) {
325         m_isAbstract = abs;
326     }
327
328     /**
329      * Generate code for calling a user supplied method. The object methods
330      * support three signature variations, with no parameters, with the
331      * marshalling or unmarshalling context, or with the owning object.
332      *
333      * @param in flag for unmarshalling method
334      * @param method information for method being called
335      * @param mb method builder for generated code
336      * @throws JiBXException if error in generating code
337      */

338     
339     private void genUserMethodCall(boolean in, ClassItem method,
340         ContextMethodBuilder mb) {
341         
342         // load object reference for virtual call
343
if (!method.isStatic()) {
344             mb.loadObject();
345         }
346         
347         // check if parameter required for call
348
if (method.getArgumentCount() > 0) {
349             
350             // generate code to load context, then get containing object if
351
// needed for call
352
mb.loadContext();
353             String JavaDoc type = method.getArgumentType(0);
354             if ("java.lang.Object".equals(type)) {
355                 String JavaDoc name = in ? UNMARSHAL_GETSTACKTOPMETHOD :
356                     MARSHAL_GETSTACKTOPMETHOD;
357                 mb.appendCallVirtual(name, GETSTACKTOP_SIGNATURE);
358             }
359         }
360         
361         // generate appropriate form of call to user method
362
mb.appendCall(method);
363         mb.addMethodExceptions(method);
364     }
365
366     /**
367      * Generate code to create an instance of the object for this mapping. This
368      * convenience method generates the actual code for creating an instance of
369      * an object. The generated code leaves the created object reference on the
370      * stack.
371      *
372      * @param mb method builder
373      * @throws JiBXException if error in generating code
374      */

375
376     private void genNewInstanceCode(ContextMethodBuilder mb)
377         throws JiBXException {
378         
379         // check for factory supplied to create instance
380
if (m_factoryMethod == null) {
381             
382             // make sure we have a no argument constructor
383
ClassFile cf = m_class.getClassFile();
384             if (cf.getInitializerMethod("()V") != null) {
385             
386                 // no factory, so create an instance, duplicate the reference,
387
// and then call the null constructor
388
mb.appendCreateNew(cf.getName());
389                 mb.appendDUP();
390                 mb.appendCallInit(cf.getName(),"()V");
391                 
392             } else {
393                 throw new JiBXException
394                     ("Need no-argument constructor or factory for " +
395                     cf.getName());
396             }
397             
398         } else {
399             
400             // generate call to factory method
401
genUserMethodCall(true, m_factoryMethod, mb);
402             
403         }
404     }
405
406     /**
407      * Generate call to new instance creation method for object. This
408      * convenience method just generates code to call the generated new
409      * instance method added to the class definition.
410      *
411      * @param mb method builder
412      * @throws JiBXException if error in configuration
413      */

414
415     private void genNewInstanceCall(ContextMethodBuilder mb)
416         throws JiBXException {
417         
418         // check if new instance method needs to be added to class
419
if (m_newInstanceMethod == null) {
420             
421             // set up for constructing new method
422
String JavaDoc name = m_container.getBindingRoot().getPrefix() +
423                 NEWINSTANCE_SUFFIX;
424             String JavaDoc sig = UNMARSHAL_PARAMETER_SIGNATURE +
425                 m_class.getClassFile().getSignature();
426             ClassFile cf = m_class.getMungedFile();
427             ContextMethodBuilder meth = new ContextMethodBuilder(name, sig,
428                 cf, Constants.ACC_PUBLIC|Constants.ACC_STATIC, -1,
429                 m_class.getClassName(), 0, UNMARSHALLING_CONTEXT);
430             
431             // generate the code to build a new instance
432
genNewInstanceCode(meth);
433             
434             // if preset method supplied add code to call it
435
if (m_preSetMethod != null) {
436                 
437                 // save object as local in case used by method call
438
meth.storeObject();
439                 genUserMethodCall(true, m_preSetMethod, meth);
440                 meth.loadObject();
441             }
442             
443             // finish method code with return of new instance
444
meth.appendReturn(m_class.getClassName());
445             m_newInstanceMethod = m_class.getUniqueMethod(meth).getItem();
446         }
447         
448         // generate code to call created new instance method
449
mb.loadContext(UNMARSHALLING_CONTEXT);
450         mb.appendCall(m_newInstanceMethod);
451     }
452
453     /**
454      * Generate code to handle unmarshal source location tracking. This
455      * convenience method generates the member variables and method used to
456      * support setting the source location, the methods used to access the
457      * information, and also adds the appropriate interfaces to the class.
458      *
459      * @throws JiBXException if error in generating code
460      */

461
462     private void genTrackSourceCode()
463         throws JiBXException {
464         ClassFile cf = m_class.getMungedFile();
465         if (!m_isAbstract && m_class.isDirectAccess() &&
466             cf.addInterface(SOURCE_TRACKING_INTERFACE)) {
467         
468             // add position tracking fields to class
469
ClassItem srcname = cf.addPrivateField("java.lang.String;",
470                 SOURCEDOCUMENT_FIELDNAME);
471             ClassItem srcline = cf.addPrivateField("int", SOURCELINE_FIELDNAME);
472             ClassItem srccol = cf.addPrivateField("int",
473                 SOURCECOLUMN_FIELDNAME);
474         
475             // add method for setting the source information
476
InstructionBuilder ib = cf.getInstructionBuilder();
477             MethodBuilder mb = new ExceptionMethodBuilder(SETSOURCE_METHODNAME,
478                 Type.VOID, SETSOURCE_ARGS, cf, Constants.ACC_PUBLIC);
479             mb.appendLoadLocal(0);
480             mb.appendLoadLocal(1);
481             mb.appendPutField(srcname);
482             mb.appendLoadLocal(0);
483             mb.appendLoadLocal(2);
484             mb.appendPutField(srcline);
485             mb.appendLoadLocal(0);
486             mb.appendLoadLocal(3);
487             mb.appendPutField(srccol);
488             mb.appendReturn();
489             mb.codeComplete(false);
490             mb.addMethod();
491         
492             // add methods for getting the source information
493
mb = new ExceptionMethodBuilder(SOURCENAME_METHODNAME,
494                 Type.STRING, EMPTY_ARGS, cf, Constants.ACC_PUBLIC);
495             mb.appendLoadLocal(0);
496             mb.appendGetField(srcname);
497             mb.appendReturn(Type.STRING);
498             mb.codeComplete(false);
499             mb.addMethod();
500             mb = new ExceptionMethodBuilder(SOURCELINE_METHODNAME,
501                 Type.INT, EMPTY_ARGS, cf, Constants.ACC_PUBLIC);
502             mb.appendLoadLocal(0);
503             mb.appendGetField(srcline);
504             mb.appendReturn("int");
505             mb.codeComplete(false);
506             mb.addMethod();
507             mb = new ExceptionMethodBuilder(SOURCECOLUMN_METHODNAME,
508                 Type.INT, EMPTY_ARGS, cf, Constants.ACC_PUBLIC);
509             mb.appendLoadLocal(0);
510             mb.appendGetField(srccol);
511             mb.appendReturn("int");
512             mb.codeComplete(false);
513             mb.addMethod();
514         }
515     }
516     
517     /**
518      * Construct fullly-qualified class and method name for method under
519      * construction.
520      *
521      * @param mb method to be named
522      * @return
523      */

524     private String JavaDoc fullMethodName(ContextMethodBuilder mb) {
525         return mb.getClassFile().getName() + '.' + mb.getName();
526     }
527     
528     /**
529      * Construct fullly-qualified class and method name for constructed method.
530      *
531      * @param item method to be named
532      * @return
533      */

534     private String JavaDoc fullMethodName(ClassItem item) {
535         return item.getClassFile().getName() + '.' + item.getName();
536     }
537     
538     /**
539      * Generate call to a constructed unmarshal method.
540      *
541      * @param mb
542      */

543     private void genUnmarshalCall(String JavaDoc name, ContextMethodBuilder mb) {
544         if (m_isStaticUnmarshal) {
545             mb.appendCallStatic(name, m_unmarshalSignature);
546         } else {
547             mb.appendCallVirtual(name, m_unmarshalSignature);
548         }
549     }
550     
551     /**
552      * Generate call to a constructed marshal method.
553      *
554      * @param mb
555      */

556     private void genMarshalCall(String JavaDoc name, ContextMethodBuilder mb) {
557         if (m_isStaticMarshal) {
558             mb.appendCallStatic(name, m_marshalSignature);
559         } else {
560             mb.appendCallVirtual(name, m_marshalSignature);
561         }
562     }
563
564     /**
565      * Generate call to attribute unmarshal method for object. This convenience
566      * method just generates code to call the generated unmarshal method added
567      * to the class definition. The code generated prior to this call must have
568      * loaded a reference to the object to be unmarshalled on the stack.
569      *
570      * @param mb method builder
571      * @throws JiBXException if error in configuration
572      */

573
574     private void genUnmarshalAttributeCall(ContextMethodBuilder mb)
575         throws JiBXException {
576         
577         // check if unmarshal method needs to be added to class
578
if (m_unmarshalAttributeMethod == null) {
579             if (m_unmarshalAttributeName == null) {
580                 
581                 // set up for constructing new method
582
String JavaDoc name = m_container.getBindingRoot().getPrefix() +
583                     UNMARSHAL_ATTR_SUFFIX;
584                 UnmarshalBuilder meth = new UnmarshalBuilder(name,
585                     m_class.getClassFile(), m_class.getMungedFile());
586                 m_unmarshalAttributeName = fullMethodName(meth);
587                 m_unmarshalSignature = meth.getSignature();
588                 m_isStaticUnmarshal = meth.isStaticMethod();
589                 
590                 // push object being unmarshalled to unmarshaller stack
591
meth.loadContext();
592                 meth.loadObject();
593                 meth.appendCallVirtual(UNMARSHAL_PUSHOBJECTMETHOD,
594                     PUSHOBJECT_SIGNATURE);
595                 
596                 // generate the actual unmarshalling code in method
597
meth.loadObject();
598                 m_component.genAttributeUnmarshal(meth);
599                 
600                 // pop object from unmarshal stack
601
meth.loadContext();
602                 meth.appendCallVirtual(UNMARSHAL_POPOBJECTMETHOD,
603                     POPOBJECT_SIGNATURE);
604                 
605                 // if postset method supplied and no content add code to call it
606
if (m_postSetMethod != null && !hasContent()) {
607                     genUserMethodCall(true, m_postSetMethod, meth);
608                 }
609                 
610                 // finish method code and add to class
611
meth.appendReturn();
612                 if (m_lockAttributeUnmarshal) {
613                     m_unmarshalAttributeMethod =
614                         m_class.getUniqueNamed(meth).getItem();
615                 } else {
616                     m_unmarshalAttributeMethod =
617                         m_class.getUniqueMethod(meth).getItem();
618                     m_unmarshalAttributeName =
619                         fullMethodName(m_unmarshalAttributeMethod);
620                 }
621                 
622             } else {
623                 m_lockAttributeUnmarshal = true;
624             }
625         }
626         
627         // generate code to call created unmarshal method
628
mb.loadContext(UNMARSHALLING_CONTEXT);
629         genUnmarshalCall(m_unmarshalAttributeName, mb);
630     }
631
632     /**
633      * Generate call to attribute marshal method for object. This convenience
634      * method just generates code to call the generated marshal method added to
635      * the class definition. The code generated prior to this call must have
636      * loaded a reference to the object to be marshalled on the stack.
637      *
638      * @param mb method builder
639      * @throws JiBXException if error in configuration
640      */

641
642     private void genMarshalAttributeCall(ContextMethodBuilder mb)
643         throws JiBXException {
644         
645         // check if marshal method needs to be added to class
646
if (m_marshalAttributeMethod == null) {
647             if (m_marshalAttributeName == null) {
648                 
649                 // set up for constructing new method
650
String JavaDoc name = m_container.getBindingRoot().getPrefix() +
651                     MARSHAL_ATTR_SUFFIX;
652                 MarshalBuilder meth = new MarshalBuilder(name,
653                     m_class.getClassFile(), m_class.getMungedFile());
654                 m_marshalAttributeName = fullMethodName(meth);
655                 m_marshalSignature = meth.getSignature();
656                 m_isStaticMarshal = meth.isStaticMethod();
657                 
658                 // if preget method supplied add code to call it
659
if (m_preGetMethod != null) {
660                     genUserMethodCall(false, m_preGetMethod, meth);
661                 }
662                 
663                 // push object being marshalled to marshaller stack
664
meth.loadContext();
665                 meth.loadObject();
666                 meth.appendCallVirtual(MARSHAL_PUSHOBJECTMETHOD,
667                     PUSHOBJECT_SIGNATURE);
668                 
669                 // generate actual marshalling code
670
meth.loadContext();
671                 m_component.genAttributeMarshal(meth);
672                 
673                 // pop object from stack
674
meth.loadContext();
675                 meth.appendCallVirtual(MARSHAL_POPOBJECTMETHOD,
676                     POPOBJECT_SIGNATURE);
677                 
678                 // finish and add constructed method to class
679
meth.appendReturn();
680                 if (m_lockAttributeUnmarshal) {
681                     m_marshalAttributeMethod =
682                         m_class.getUniqueNamed(meth).getItem();
683                 } else {
684                     m_marshalAttributeMethod =
685                         m_class.getUniqueMethod(meth).getItem();
686                     m_marshalAttributeName =
687                         fullMethodName(m_marshalAttributeMethod);
688                 }
689                 
690             } else {
691                 m_lockAttributeMarshal = true;
692             }
693         }
694         
695         // generate code to call created marshal method
696
if (!m_directAccess) {
697             mb.loadContext(MARSHALLING_CONTEXT);
698         }
699         genMarshalCall(m_marshalAttributeName, mb);
700     }
701
702     /**
703      * Generate call to content unmarshal method for object. This convenience
704      * method just generates code to call the generated unmarshal method added
705      * to the class definition. The code generated prior to this call must have
706      * loaded a reference to the object to be unmarshalled on the stack.
707      *
708      * @param mb method builder
709      * @throws JiBXException if error in configuration
710      */

711
712     private void genUnmarshalContentCall(ContextMethodBuilder mb)
713         throws JiBXException {
714         
715         // check if unmarshal method needs to be added to class
716
if (m_unmarshalContentMethod == null) {
717             if (m_unmarshalContentName == null) {
718                 
719                 // set up for constructing new method
720
String JavaDoc name = m_container.getBindingRoot().getPrefix() +
721                     UNMARSHAL_SUFFIX;
722                 UnmarshalBuilder meth = new UnmarshalBuilder(name,
723                     m_class.getClassFile(), m_class.getMungedFile());
724                 m_unmarshalContentName = fullMethodName(meth);
725                 m_unmarshalSignature = meth.getSignature();
726                 m_isStaticUnmarshal = meth.isStaticMethod();
727                 
728                 // push object being unmarshalled to unmarshaller stack
729
meth.loadContext();
730                 meth.loadObject();
731                 meth.appendCallVirtual(UNMARSHAL_PUSHOBJECTMETHOD,
732                     PUSHOBJECT_SIGNATURE);
733                 
734                 // generate the actual unmarshalling code in method
735
meth.loadObject();
736                 m_component.genContentUnmarshal(meth);
737                 
738                 // pop object from unmarshal stack
739
meth.loadContext();
740                 meth.appendCallVirtual(UNMARSHAL_POPOBJECTMETHOD,
741                     POPOBJECT_SIGNATURE);
742                 
743                 // if postset method supplied and no attributes add code to call
744
if (m_postSetMethod != null) {
745                     genUserMethodCall(true, m_postSetMethod, meth);
746                 }
747                 
748                 // finish method code and add to class
749
meth.appendReturn();
750                 if (m_lockContentUnmarshal) {
751                     m_unmarshalContentMethod =
752                         m_class.getUniqueNamed(meth).getItem();
753                 } else {
754                     m_unmarshalContentMethod =
755                         m_class.getUniqueMethod(meth).getItem();
756                     m_unmarshalContentName =
757                         fullMethodName(m_unmarshalContentMethod);
758                 }
759                 
760             } else {
761                 m_lockContentUnmarshal = true;
762             }
763         }
764         
765         // generate code to call created unmarshal method
766
mb.loadContext(UNMARSHALLING_CONTEXT);
767         genUnmarshalCall(m_unmarshalContentName, mb);
768     }
769
770     /**
771      * Generate call to content marshal method for object. This convenience
772      * method just generates code to call the generated marshal method added to
773      * the class definition. The code generated prior to this call must have
774      * loaded a reference to the object to be marshalled on the stack.
775      *
776      * @param mb method builder
777      * @throws JiBXException if error in configuration
778      */

779
780     private void genMarshalContentCall(ContextMethodBuilder mb)
781         throws JiBXException {
782         
783         // check if marshal method needs to be added to class
784
if (m_marshalContentMethod == null) {
785             if (m_marshalContentName == null) {
786                 
787                 // set up for constructing new method
788
String JavaDoc name =
789                     m_container.getBindingRoot().getPrefix() + MARSHAL_SUFFIX;
790                 MarshalBuilder meth = new MarshalBuilder(name,
791                     m_class.getClassFile(), m_class.getMungedFile());
792                 m_marshalContentName = fullMethodName(meth);
793                 m_marshalSignature = meth.getSignature();
794                 m_isStaticMarshal = meth.isStaticMethod();
795                 
796                 // if preget method supplied and no attributes add code to call it
797
if (m_preGetMethod != null && !hasAttribute()) {
798                     genUserMethodCall(false, m_preGetMethod, meth);
799                 }
800                 
801                 // push object being marshalled to marshaller stack
802
meth.loadContext();
803                 meth.loadObject();
804                 meth.appendCallVirtual(MARSHAL_PUSHOBJECTMETHOD,
805                     PUSHOBJECT_SIGNATURE);
806                 
807                 // generate actual marshalling code
808
meth.loadContext();
809                 m_component.genContentMarshal(meth);
810                 
811                 // pop object from stack
812
meth.loadContext();
813                 meth.appendCallVirtual(MARSHAL_POPOBJECTMETHOD,
814                     POPOBJECT_SIGNATURE);
815                 
816                 // finish and add constructed method to class
817
meth.appendReturn();
818                 if (m_lockContentMarshal) {
819                     m_marshalContentMethod =
820                         m_class.getUniqueNamed(meth).getItem();
821                 } else {
822                     m_marshalContentMethod =
823                         m_class.getUniqueMethod(meth).getItem();
824                     m_marshalContentName = fullMethodName(m_marshalContentMethod);
825                 }
826                 
827             } else {
828                 m_lockContentMarshal = true;
829             }
830         }
831         
832         // generate code to call created marshal method
833
if (!m_directAccess) {
834             mb.loadContext(MARSHALLING_CONTEXT);
835         }
836         genMarshalCall(m_marshalContentName, mb);
837     }
838     
839     //
840
// IContextObj interface method definitions
841

842     public BoundClass getBoundClass() {
843         return m_class;
844     }
845
846     public boolean setIdChild(IComponent child) {
847         if (m_idChild == null) {
848             m_idChild = child;
849             return true;
850         } else {
851             return false;
852         }
853     }
854     
855     //
856
// IComponent interface method definitions
857

858     public boolean isOptional() {
859         return false;
860     }
861
862     public void genAttributeUnmarshal(ContextMethodBuilder mb)
863         throws JiBXException {
864         genUnmarshalAttributeCall(mb);
865     }
866
867     public void genAttributeMarshal(ContextMethodBuilder mb)
868         throws JiBXException {
869         genMarshalAttributeCall(mb);
870     }
871
872     public void genContentUnmarshal(ContextMethodBuilder mb)
873         throws JiBXException {
874         // TODO: load reference from local if already defined in method
875
genUnmarshalContentCall(mb);
876     }
877
878     public void genContentMarshal(ContextMethodBuilder mb)
879         throws JiBXException {
880         genMarshalContentCall(mb);
881     }
882     
883     public void genNewInstance(ContextMethodBuilder mb) throws JiBXException {
884         genNewInstanceCall(mb);
885     }
886
887     public String JavaDoc getType() {
888         return m_class.getClassName();
889     }
890
891     public boolean hasId() {
892         return m_idChild != null;
893     }
894
895     public void genLoadId(ContextMethodBuilder mb) throws JiBXException {
896         if (m_idChild == null) {
897             throw new IllegalStateException JavaDoc("Internal error: no id defined");
898         } else {
899             m_idChild.genLoadId(mb);
900         }
901     }
902     
903     public void setLinkages() throws JiBXException {
904         super.setLinkages();
905         if (m_container.getBindingRoot().isTrackSource()) {
906             genTrackSourceCode();
907         }
908     }
909     
910     // DEBUG
911
public void print(int depth) {
912         BindingDefinition.indent(depth);
913         System.out.print("object binding for " +
914             m_class.getClassFile().getName());
915         if (m_directAccess) {
916             System.out.print(" direct");
917         }
918         System.out.println();
919         m_component.print(depth+1);
920     }
921 }
Popular Tags