001: /*
002: Copyright (c) 2003-2004, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.binding.def;
030:
031: import org.apache.bcel.Constants;
032: import org.apache.bcel.generic.*;
033:
034: import org.jibx.binding.classes.*;
035: import org.jibx.runtime.JiBXException;
036: import org.jibx.runtime.Utility;
037:
038: /**
039: * Binding modifiers that apply to a class reference. This adds the methods used
040: * for handling binding operations to the object class, then generates calls to
041: * the added methods as this binding definition is used.
042: *
043: * @author Dennis M. Sosnoski
044: * @version 1.0
045: */
046:
047: public class ObjectBinding extends PassThroughComponent implements
048: IComponent, IContextObj {
049: //
050: // Constants and such related to code generation.
051:
052: // recognized marshal hook method (pre-get) signatures.
053: private static final String[] MARSHAL_HOOK_SIGNATURES = {
054: "(Lorg/jibx/runtime/IMarshallingContext;)V",
055: "(Ljava/lang/Object;)V", "()V" };
056:
057: // recognized factory hook method signatures.
058: private static final String[] FACTORY_HOOK_SIGNATURES = {
059: "(Lorg/jibx/runtime/IUnmarshallingContext;)",
060: "(Ljava/lang/Object;)", "()" };
061:
062: // recognized unmarshal hook method (pre-set, post-set) signatures.
063: private static final String[] UNMARSHAL_HOOK_SIGNATURES = {
064: "(Lorg/jibx/runtime/IUnmarshallingContext;)V",
065: "(Ljava/lang/Object;)V", "()V" };
066:
067: // definitions used in generating calls to user defined methods
068: private static final String UNMARSHAL_GETSTACKTOPMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.getStackTop";
069: private static final String MARSHAL_GETSTACKTOPMETHOD = "org.jibx.runtime.impl.MarshallingContext.getStackTop";
070: private static final String GETSTACKTOP_SIGNATURE = "()Ljava/lang/Object;";
071: private static final String MARSHALLING_CONTEXT = "org.jibx.runtime.impl.MarshallingContext";
072: private static final String UNMARSHALLING_CONTEXT = "org.jibx.runtime.impl.UnmarshallingContext";
073: private static final String UNMARSHAL_PARAMETER_SIGNATURE = "(Lorg/jibx/runtime/impl/UnmarshallingContext;)";
074: private static final String UNMARSHAL_PUSHOBJECTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.pushObject";
075: private static final String UNMARSHAL_PUSHTRACKEDOBJECTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.pushTrackedObject";
076: private static final String MARSHAL_PUSHOBJECTMETHOD = "org.jibx.runtime.impl.MarshallingContext.pushObject";
077: private static final String PUSHOBJECT_SIGNATURE = "(Ljava/lang/Object;)V";
078: private static final String UNMARSHAL_POPOBJECTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.popObject";
079: private static final String MARSHAL_POPOBJECTMETHOD = "org.jibx.runtime.impl.MarshallingContext.popObject";
080: private static final String POPOBJECT_SIGNATURE = "()V";
081:
082: // definitions for methods added to mapped class
083: private static final String NEWINSTANCE_SUFFIX = "_newinstance";
084: private static final String UNMARSHAL_ATTR_SUFFIX = "_unmarshalAttr";
085: private static final String MARSHAL_ATTR_SUFFIX = "_marshalAttr";
086: private static final String UNMARSHAL_SUFFIX = "_unmarshal";
087: private static final String MARSHAL_SUFFIX = "_marshal";
088:
089: // definitions for source position tracking
090: private static final String SOURCE_TRACKING_INTERFACE = "org.jibx.runtime.impl.ITrackSourceImpl";
091: private static final String SETSOURCE_METHODNAME = "jibx_setSource";
092: private static final Type[] SETSOURCE_ARGS = { Type.STRING,
093: Type.INT, Type.INT };
094: private static final String SOURCEDOCUMENT_FIELDNAME = "jibx_sourceDocument";
095: private static final String SOURCELINE_FIELDNAME = "jibx_sourceLine";
096: private static final String SOURCECOLUMN_FIELDNAME = "jibx_sourceColumn";
097: private static final String SOURCENAME_METHODNAME = "jibx_getDocumentName";
098: private static final String SOURCELINE_METHODNAME = "jibx_getLineNumber";
099: private static final String SOURCECOLUMN_METHODNAME = "jibx_getColumnNumber";
100: private static final Type[] EMPTY_ARGS = {};
101:
102: //
103: // Actual instance data.
104:
105: /** Containing binding definition structure. */
106: private final IContainer m_container;
107:
108: /** Class linked to mapping. */
109: private BoundClass m_class;
110:
111: /** Object factory method. */
112: private final ClassItem m_factoryMethod;
113:
114: /** Preset method for object. */
115: private final ClassItem m_preSetMethod;
116:
117: /** Postset method for object. */
118: private final ClassItem m_postSetMethod;
119:
120: /** Preget method for object. */
121: private final ClassItem m_preGetMethod;
122:
123: /** Type to be used for creating new instances. */
124: private final ClassFile m_createClass;
125:
126: /** Generated new instance method. */
127: private ClassItem m_newInstanceMethod;
128:
129: /** Flag for recursion while generating attribute unmarshal. */
130: private boolean m_lockAttributeUnmarshal;
131:
132: /** Flag for recursion while generating attribute marshal. */
133: private boolean m_lockAttributeMarshal;
134:
135: /** Flag for recursion while generating attribute unmarshal. */
136: private boolean m_lockContentUnmarshal;
137:
138: /** Flag for recursion while generating attribute marshal. */
139: private boolean m_lockContentMarshal;
140:
141: /** Signature used for unmarshal methods. */
142: private String m_unmarshalSignature;
143:
144: /** Name for unmarshal attribute method (<code>null</code> unless
145: generation started). */
146: private String m_unmarshalAttributeName;
147:
148: /** Name for unmarshal content method (<code>null</code> unless
149: generation started). */
150: private String m_unmarshalContentName;
151:
152: /** Flag for static unmarshal methods. */
153: private boolean m_isStaticUnmarshal;
154:
155: /** Flag for static marshal methods. */
156: private boolean m_isStaticMarshal;
157:
158: /** Signature used for marshal methods. */
159: private String m_marshalSignature;
160:
161: /** Name for marshal attribute method (<code>null</code> unless
162: generation started). */
163: private String m_marshalAttributeName;
164:
165: /** Name for marshal content method (<code>null</code> unless
166: generation istarted). */
167: private String m_marshalContentName;
168:
169: /** Generated unmarshal attribute method. */
170: private ClassItem m_unmarshalAttributeMethod;
171:
172: /** Generated unmarshal content method. */
173: private ClassItem m_unmarshalContentMethod;
174:
175: /** Generated marshal attribute method. */
176: private ClassItem m_marshalAttributeMethod;
177:
178: /** Generated marshal content method. */
179: private ClassItem m_marshalContentMethod;
180:
181: /** Child supplying instance identifier value. */
182: private IComponent m_idChild;
183:
184: /** Flag for "this" reference, meaning that there's no separate object
185: * instance created. */
186: private boolean m_isThisBinding;
187:
188: /**
189: * Constructor. This initializes the definition context to be the same as
190: * the parent's. Subclasses may change this definition context if
191: * appropriate.
192: *
193: * @param contain containing binding definition component
194: * @param objc current object context
195: * @param type fully qualified class name for bound object
196: * @param fact user new instance factory method
197: * @param pres user preset method for unmarshalling
198: * @param posts user postset method for unmarshalling
199: * @param pget user preget method for marshalling
200: * @param ctype type to use for creating new instance (<code>null</code> if
201: * not specified)
202: * @throws JiBXException if method not found
203: */
204: public ObjectBinding(IContainer contain, IContextObj objc,
205: String type, String fact, String pres, String posts,
206: String pget, String ctype) throws JiBXException {
207:
208: // initialize the basics
209: m_container = contain;
210: BoundClass ctxc = (objc == null) ? null : objc.getBoundClass();
211: m_class = BoundClass.getInstance(type, ctxc);
212: ClassFile cf = m_class.getClassFile();
213: if (ctype == null) {
214: m_createClass = cf;
215: } else {
216: m_createClass = ClassCache.getClassFile(ctype);
217: }
218:
219: // check instance creation for unmarshalling
220: if (fact == null) {
221: m_factoryMethod = null;
222: } else {
223:
224: // look up supplied static factory method
225: int split = fact.lastIndexOf('.');
226: if (split >= 0) {
227:
228: // verify the method is defined
229: String cname = fact.substring(0, split);
230: String mname = fact.substring(split + 1);
231: ClassFile mcf = ClassCache.getClassFile(cname);
232: m_factoryMethod = mcf.getMethod(mname,
233: FACTORY_HOOK_SIGNATURES);
234: if (m_factoryMethod == null) {
235: throw new JiBXException("Factory method " + fact
236: + " not found");
237: } else {
238:
239: // force access if necessary
240: m_factoryMethod.makeAccessible(cf);
241:
242: }
243: } else {
244: m_factoryMethod = null;
245: }
246: if (m_factoryMethod == null) {
247: throw new JiBXException("Factory method " + fact
248: + " not found.");
249: }
250: }
251:
252: // look up other method names as members of class
253: if (pres == null) {
254: m_preSetMethod = null;
255: } else {
256: m_preSetMethod = cf.getMethod(pres,
257: UNMARSHAL_HOOK_SIGNATURES);
258: if (m_preSetMethod == null) {
259: throw new JiBXException("User method " + pres
260: + " not found.");
261: }
262: }
263: if (posts == null) {
264: m_postSetMethod = null;
265: } else {
266: m_postSetMethod = cf.getMethod(posts,
267: UNMARSHAL_HOOK_SIGNATURES);
268: if (m_postSetMethod == null) {
269: throw new JiBXException("User method " + posts
270: + " not found.");
271: }
272: }
273: if (pget == null) {
274: m_preGetMethod = null;
275: } else {
276: m_preGetMethod = cf
277: .getMethod(pget, MARSHAL_HOOK_SIGNATURES);
278: if (m_preGetMethod == null) {
279: throw new JiBXException("User method " + pget
280: + " not found.");
281: }
282: }
283: }
284:
285: /**
286: * Abstract binding copy constructor. This is used to create a variation of
287: * the object binding for a mapping which will be used for "this"
288: * references. The "this" reference handling differs only in the code
289: * generation, where it skips adding the source tracking interfaces and
290: * does not push an instance of the object on the marshalling or
291: * unmarshalling stack (since the object will already be there). This method
292: * is only to be used before code generation.
293: *
294: * @param base original object binding
295: */
296: public ObjectBinding(ObjectBinding base) {
297: m_container = base.m_container;
298: m_class = base.m_class;
299: m_factoryMethod = null;
300: m_preSetMethod = base.m_preSetMethod;
301: m_postSetMethod = base.m_postSetMethod;
302: m_preGetMethod = base.m_preGetMethod;
303: m_createClass = base.m_createClass;
304: m_idChild = base.m_idChild;
305: m_component = base.m_component;
306: m_isThisBinding = true;
307: }
308:
309: /**
310: * Copy constructor. This is used in handling abstract mappings, where the
311: * properties of the mapping definition object binding need to be copied for
312: * each use of that binding.
313: *
314: * @param contain binding definition component containing copy
315: */
316: public ObjectBinding(IContainer contain, ObjectBinding base) {
317: m_container = contain;
318: m_class = base.m_class;
319: m_factoryMethod = base.m_factoryMethod;
320: m_preSetMethod = base.m_preSetMethod;
321: m_postSetMethod = base.m_postSetMethod;
322: m_preGetMethod = base.m_preGetMethod;
323: m_newInstanceMethod = base.m_newInstanceMethod;
324: m_unmarshalSignature = base.m_unmarshalSignature;
325: m_unmarshalAttributeName = base.m_unmarshalAttributeName;
326: m_unmarshalContentName = base.m_unmarshalContentName;
327: m_isStaticUnmarshal = base.m_isStaticUnmarshal;
328: m_isStaticMarshal = base.m_isStaticMarshal;
329: m_marshalSignature = base.m_marshalSignature;
330: m_marshalAttributeName = base.m_marshalAttributeName;
331: m_marshalContentName = base.m_marshalAttributeName;
332: m_marshalContentName = base.m_marshalContentName;
333: m_unmarshalAttributeMethod = base.m_unmarshalAttributeMethod;
334: m_unmarshalContentMethod = base.m_unmarshalContentMethod;
335: m_marshalAttributeMethod = base.m_marshalAttributeMethod;
336: m_marshalContentMethod = base.m_marshalContentMethod;
337: m_createClass = base.m_createClass;
338: m_idChild = base.m_idChild;
339: m_component = base.m_component;
340: }
341:
342: /**
343: * Generate code for calling a user supplied method. The object methods
344: * support three signature variations, with no parameters, with the
345: * marshalling or unmarshalling context, or with the owning object.
346: *
347: * @param in flag for unmarshalling method
348: * @param method information for method being called
349: * @param mb method builder for generated code
350: */
351:
352: private void genUserMethodCall(boolean in, ClassItem method,
353: ContextMethodBuilder mb) {
354:
355: // load object reference for virtual call
356: if (!method.isStatic()) {
357: mb.loadObject();
358: }
359:
360: // check if parameter required for call
361: if (method.getArgumentCount() > 0) {
362:
363: // generate code to load context, then get containing object if
364: // needed for call
365: mb.loadContext();
366: String type = method.getArgumentType(0);
367: if ("java.lang.Object".equals(type)) {
368: String name = in ? UNMARSHAL_GETSTACKTOPMETHOD
369: : MARSHAL_GETSTACKTOPMETHOD;
370: mb.appendCallVirtual(name, GETSTACKTOP_SIGNATURE);
371: }
372: }
373:
374: // generate appropriate form of call to user method
375: mb.appendCall(method);
376: mb.addMethodExceptions(method);
377: }
378:
379: /**
380: * Generate code to create an instance of the object for this mapping. This
381: * convenience method generates the actual code for creating an instance of
382: * an object. The generated code leaves the created object reference on the
383: * stack.
384: *
385: * @param mb method builder
386: * @throws JiBXException if error in generating code
387: */
388:
389: private void genNewInstanceCode(ContextMethodBuilder mb)
390: throws JiBXException {
391:
392: // check for factory supplied to create instance
393: if (m_factoryMethod == null) {
394: if (m_createClass.isArray()) {
395:
396: // construct array instance directly with basic size
397: mb.appendLoadConstant(Utility.MINIMUM_GROWN_ARRAY_SIZE);
398: String type = m_createClass.getName();
399: mb.appendCreateArray(type.substring(0,
400: type.length() - 2));
401:
402: } else {
403:
404: // make sure we have a no argument constructor
405: ClassItem cons = m_createClass
406: .getInitializerMethod("()V");
407: if (cons == null) {
408: m_createClass.addDefaultConstructor();
409: } else {
410: cons.makeAccessible(m_class.getMungedFile());
411: }
412:
413: // no factory, so create an instance, duplicate the
414: // reference, and then call the null constructor
415: mb.appendCreateNew(m_createClass.getName());
416: mb.appendDUP();
417: mb.appendCallInit(m_createClass.getName(), "()V");
418:
419: }
420:
421: } else {
422:
423: // generate call to factory method
424: genUserMethodCall(true, m_factoryMethod, mb);
425: mb.appendCreateCast(m_factoryMethod.getTypeName(), m_class
426: .getClassName());
427:
428: }
429: }
430:
431: /**
432: * Generate call to new instance creation method for object. This
433: * convenience method just generates code to call the generated new
434: * instance method added to the class definition.
435: *
436: * @param mb method builder
437: * @throws JiBXException if error in configuration
438: */
439:
440: private void genNewInstanceCall(ContextMethodBuilder mb)
441: throws JiBXException {
442:
443: // check if new instance method needs to be added to class
444: if (m_newInstanceMethod == null) {
445:
446: // set up for constructing new method
447: String name = m_container.getBindingRoot().getPrefix()
448: + NEWINSTANCE_SUFFIX;
449: String sig = UNMARSHAL_PARAMETER_SIGNATURE
450: + m_class.getClassFile().getSignature();
451: ClassFile cf = m_class.getMungedFile();
452: ContextMethodBuilder meth = new ContextMethodBuilder(name,
453: sig, cf, Constants.ACC_PUBLIC
454: | Constants.ACC_STATIC, -1, m_class
455: .getClassName(), 0, UNMARSHALLING_CONTEXT);
456:
457: // generate the code to build a new instance
458: genNewInstanceCode(meth);
459:
460: // finish method code with return of new instance
461: meth.appendReturn(m_class.getClassName());
462: m_newInstanceMethod = m_class.getUniqueMethod(meth)
463: .getItem();
464: }
465:
466: // generate code to call created new instance method
467: mb.loadContext(UNMARSHALLING_CONTEXT);
468: mb.appendCall(m_newInstanceMethod);
469: }
470:
471: /**
472: * Generate code to handle unmarshal source location tracking. This
473: * convenience method generates the member variables and method used to
474: * support setting the source location, the methods used to access the
475: * information, and also adds the appropriate interfaces to the class.
476: *
477: * @throws JiBXException if error in generating code
478: */
479:
480: private void genTrackSourceCode() throws JiBXException {
481: ClassFile cf = m_class.getMungedFile();
482: if (!m_isThisBinding && m_class.isDirectAccess()
483: && !cf.isAbstract()
484: && cf.addInterface(SOURCE_TRACKING_INTERFACE)) {
485:
486: // add position tracking fields to class
487: ClassItem srcname = cf.addPrivateField("java.lang.String;",
488: SOURCEDOCUMENT_FIELDNAME);
489: ClassItem srcline = cf.addPrivateField("int",
490: SOURCELINE_FIELDNAME);
491: ClassItem srccol = cf.addPrivateField("int",
492: SOURCECOLUMN_FIELDNAME);
493:
494: // add method for setting the source information
495: MethodBuilder mb = new ExceptionMethodBuilder(
496: SETSOURCE_METHODNAME, Type.VOID, SETSOURCE_ARGS,
497: cf, Constants.ACC_PUBLIC);
498: mb.appendLoadLocal(0);
499: mb.appendLoadLocal(1);
500: mb.appendPutField(srcname);
501: mb.appendLoadLocal(0);
502: mb.appendLoadLocal(2);
503: mb.appendPutField(srcline);
504: mb.appendLoadLocal(0);
505: mb.appendLoadLocal(3);
506: mb.appendPutField(srccol);
507: mb.appendReturn();
508: mb.codeComplete(false);
509: mb.addMethod();
510:
511: // add methods for getting the source information
512: mb = new ExceptionMethodBuilder(SOURCENAME_METHODNAME,
513: Type.STRING, EMPTY_ARGS, cf, Constants.ACC_PUBLIC);
514: mb.appendLoadLocal(0);
515: mb.appendGetField(srcname);
516: mb.appendReturn(Type.STRING);
517: mb.codeComplete(false);
518: mb.addMethod();
519: mb = new ExceptionMethodBuilder(SOURCELINE_METHODNAME,
520: Type.INT, EMPTY_ARGS, cf, Constants.ACC_PUBLIC);
521: mb.appendLoadLocal(0);
522: mb.appendGetField(srcline);
523: mb.appendReturn("int");
524: mb.codeComplete(false);
525: mb.addMethod();
526: mb = new ExceptionMethodBuilder(SOURCECOLUMN_METHODNAME,
527: Type.INT, EMPTY_ARGS, cf, Constants.ACC_PUBLIC);
528: mb.appendLoadLocal(0);
529: mb.appendGetField(srccol);
530: mb.appendReturn("int");
531: mb.codeComplete(false);
532: mb.addMethod();
533: }
534: }
535:
536: /**
537: * Construct fullly-qualified class and method name for method under
538: * construction.
539: *
540: * @param mb method to be named
541: * @return fully-qualified class and method name
542: */
543: private String fullMethodName(ContextMethodBuilder mb) {
544: return mb.getClassFile().getName() + '.' + mb.getName();
545: }
546:
547: /**
548: * Construct fully-qualified class and method name for constructed method.
549: *
550: * @param item method to be named
551: * @return fully-qualified class and method name
552: */
553: private String fullMethodName(ClassItem item) {
554: return item.getClassFile().getName() + '.' + item.getName();
555: }
556:
557: /**
558: * Generate call to a constructed unmarshal method.
559: *
560: * @param mb
561: */
562: private void genUnmarshalCall(String name, ContextMethodBuilder mb) {
563: if (m_isStaticUnmarshal) {
564: mb.appendCallStatic(name, m_unmarshalSignature);
565: } else {
566: mb.appendCallVirtual(name, m_unmarshalSignature);
567: }
568: }
569:
570: /**
571: * Generate call to a constructed marshal method.
572: *
573: * @param mb
574: */
575: private void genMarshalCall(String name, ContextMethodBuilder mb) {
576: if (m_isStaticMarshal) {
577: mb.appendCallStatic(name, m_marshalSignature);
578: } else {
579: mb.appendCallVirtual(name, m_marshalSignature);
580: }
581: }
582:
583: /**
584: * Generate call to attribute unmarshal method for object. This convenience
585: * method just generates code to call the generated unmarshal method added
586: * to the class definition. The code generated prior to this call must have
587: * loaded a reference to the object to be unmarshalled on the stack, and the
588: * generated code returns the (possibly different, in the case of arrays)
589: * object on the stack.
590: *
591: * @param mb method builder
592: * @throws JiBXException if error in configuration
593: */
594:
595: private void genUnmarshalAttributeCall(ContextMethodBuilder mb)
596: throws JiBXException {
597:
598: // check if unmarshal method needs to be added to class
599: if (m_unmarshalAttributeMethod == null) {
600: if (m_unmarshalAttributeName == null) {
601:
602: // set up for constructing new method
603: String name = m_container.getBindingRoot().getPrefix()
604: + UNMARSHAL_ATTR_SUFFIX;
605: UnmarshalBuilder meth = new UnmarshalBuilder(name,
606: m_class.getClassFile(), m_class.getMungedFile());
607: m_unmarshalAttributeName = fullMethodName(meth);
608: m_unmarshalSignature = meth.getSignature();
609: m_isStaticUnmarshal = meth.isStaticMethod();
610:
611: // if preset method supplied add code to call it
612: if (m_preSetMethod != null) {
613: meth.loadObject();
614: genUserMethodCall(true, m_preSetMethod, meth);
615: }
616:
617: // push object being unmarshalled to unmarshaller stack
618: if (!m_isThisBinding) {
619: meth.loadContext();
620: meth.loadObject();
621: meth.appendCallVirtual(
622: UNMARSHAL_PUSHTRACKEDOBJECTMETHOD,
623: PUSHOBJECT_SIGNATURE);
624: }
625:
626: // generate the actual unmarshalling code in method
627: meth.loadObject();
628: m_component.genAttributeUnmarshal(meth);
629:
630: // pop object from unmarshal stack
631: if (!m_isThisBinding) {
632: meth.loadContext();
633: meth.appendCallVirtual(UNMARSHAL_POPOBJECTMETHOD,
634: POPOBJECT_SIGNATURE);
635: }
636:
637: // if postset method supplied and no content add code to call it
638: if (m_postSetMethod != null && !hasContent()) {
639: genUserMethodCall(true, m_postSetMethod, meth);
640: }
641:
642: // finish by returning object
643: meth.loadObject();
644: meth.appendReturn(m_class.getClassFile().getName());
645:
646: // add method to class
647: if (m_lockAttributeUnmarshal) {
648: m_unmarshalAttributeMethod = m_class
649: .getUniqueNamed(meth).getItem();
650: } else {
651: m_unmarshalAttributeMethod = m_class
652: .getUniqueMethod(meth).getItem();
653: m_unmarshalAttributeName = fullMethodName(m_unmarshalAttributeMethod);
654: }
655:
656: } else {
657: m_lockAttributeUnmarshal = true;
658: }
659: }
660:
661: // generate code to call created unmarshal method
662: mb.loadContext(UNMARSHALLING_CONTEXT);
663: genUnmarshalCall(m_unmarshalAttributeName, mb);
664: }
665:
666: /**
667: * Generate call to attribute marshal method for object. This convenience
668: * method just generates code to call the generated marshal method added to
669: * the class definition. The code generated prior to this call must have
670: * loaded a reference to the object to be marshalled on the stack.
671: *
672: * @param mb method builder
673: * @throws JiBXException if error in configuration
674: */
675:
676: private void genMarshalAttributeCall(ContextMethodBuilder mb)
677: throws JiBXException {
678:
679: // check if marshal method needs to be added to class
680: if (m_marshalAttributeMethod == null) {
681: if (m_marshalAttributeName == null) {
682:
683: // set up for constructing new method
684: String name = m_container.getBindingRoot().getPrefix()
685: + MARSHAL_ATTR_SUFFIX;
686: MarshalBuilder meth = new MarshalBuilder(name, m_class
687: .getClassFile(), m_class.getMungedFile());
688: m_marshalAttributeName = fullMethodName(meth);
689: m_marshalSignature = meth.getSignature();
690: m_isStaticMarshal = meth.isStaticMethod();
691:
692: // if preget method supplied add code to call it
693: if (m_preGetMethod != null) {
694: genUserMethodCall(false, m_preGetMethod, meth);
695: }
696:
697: // push object being marshalled to marshaller stack
698: if (!m_isThisBinding) {
699: meth.loadContext();
700: meth.loadObject();
701: meth.appendCallVirtual(MARSHAL_PUSHOBJECTMETHOD,
702: PUSHOBJECT_SIGNATURE);
703: }
704:
705: // generate actual marshalling code
706: meth.loadContext();
707: m_component.genAttributeMarshal(meth);
708:
709: // pop object from stack
710: if (!m_isThisBinding) {
711: meth.loadContext();
712: meth.appendCallVirtual(MARSHAL_POPOBJECTMETHOD,
713: POPOBJECT_SIGNATURE);
714: }
715:
716: // finish and add constructed method to class
717: meth.appendReturn();
718: if (m_lockAttributeMarshal) {
719: m_marshalAttributeMethod = m_class.getUniqueNamed(
720: meth).getItem();
721: } else {
722: m_marshalAttributeMethod = m_class.getUniqueMethod(
723: meth).getItem();
724: m_marshalAttributeName = fullMethodName(m_marshalAttributeMethod);
725: }
726:
727: } else {
728: m_lockAttributeMarshal = true;
729: }
730: }
731:
732: // generate code to call created marshal method
733: // if (!m_directAccess) {
734: mb.loadContext(MARSHALLING_CONTEXT);
735: // }
736: genMarshalCall(m_marshalAttributeName, mb);
737: }
738:
739: /**
740: * Generate call to content unmarshal method for object. This convenience
741: * method just generates code to call the generated unmarshal method added
742: * to the class definition. The code generated prior to this call must have
743: * loaded a reference to the object to be unmarshalled on the stack, and the
744: * generated code returns the (possibly different, in the case of arrays)
745: * object on the stack.
746: *
747: * @param mb method builder
748: * @throws JiBXException if error in configuration
749: */
750:
751: private void genUnmarshalContentCall(ContextMethodBuilder mb)
752: throws JiBXException {
753:
754: // check if unmarshal method needs to be added to class
755: if (m_unmarshalContentMethod == null) {
756: if (m_unmarshalContentName == null) {
757:
758: // set up for constructing new method
759: String name = m_container.getBindingRoot().getPrefix()
760: + UNMARSHAL_SUFFIX;
761: UnmarshalBuilder meth = new UnmarshalBuilder(name,
762: m_class.getClassFile(), m_class.getMungedFile());
763: m_unmarshalContentName = fullMethodName(meth);
764: m_unmarshalSignature = meth.getSignature();
765: m_isStaticUnmarshal = meth.isStaticMethod();
766:
767: // if preset method supplied add code to call it
768: if (!hasAttribute() && m_preSetMethod != null) {
769: meth.loadObject();
770: genUserMethodCall(true, m_preSetMethod, meth);
771: }
772:
773: // push object being unmarshalled to unmarshaller stack
774: if (!m_isThisBinding) {
775: meth.loadContext();
776: meth.loadObject();
777: String mname = hasAttribute() ? UNMARSHAL_PUSHOBJECTMETHOD
778: : UNMARSHAL_PUSHTRACKEDOBJECTMETHOD;
779: meth.appendCallVirtual(mname, PUSHOBJECT_SIGNATURE);
780: }
781:
782: // generate the actual unmarshalling code in method
783: meth.loadObject();
784: m_component.genContentUnmarshal(meth);
785:
786: // pop object from unmarshal stack
787: if (!m_isThisBinding) {
788: meth.loadContext();
789: meth.appendCallVirtual(UNMARSHAL_POPOBJECTMETHOD,
790: POPOBJECT_SIGNATURE);
791: }
792:
793: // if postset method supplied and no attributes add code to call
794: if (m_postSetMethod != null) {
795: genUserMethodCall(true, m_postSetMethod, meth);
796: }
797:
798: // finish by returning object
799: meth.loadObject();
800: meth.appendReturn(m_class.getClassFile().getName());
801:
802: // add method to class
803: if (m_lockContentUnmarshal) {
804: m_unmarshalContentMethod = m_class.getUniqueNamed(
805: meth).getItem();
806: } else {
807: m_unmarshalContentMethod = m_class.getUniqueMethod(
808: meth).getItem();
809: m_unmarshalContentName = fullMethodName(m_unmarshalContentMethod);
810: }
811:
812: } else {
813: m_lockContentUnmarshal = true;
814: }
815: }
816:
817: // generate code to call created unmarshal method
818: mb.loadContext(UNMARSHALLING_CONTEXT);
819: genUnmarshalCall(m_unmarshalContentName, mb);
820: }
821:
822: /**
823: * Generate call to content marshal method for object. This convenience
824: * method just generates code to call the generated marshal method added to
825: * the class definition. The code generated prior to this call must have
826: * loaded a reference to the object to be marshalled on the stack.
827: *
828: * @param mb method builder
829: * @throws JiBXException if error in configuration
830: */
831:
832: private void genMarshalContentCall(ContextMethodBuilder mb)
833: throws JiBXException {
834:
835: // check if marshal method needs to be added to class
836: if (m_marshalContentMethod == null) {
837: if (m_marshalContentName == null) {
838:
839: // set up for constructing new method
840: String name = m_container.getBindingRoot().getPrefix()
841: + MARSHAL_SUFFIX;
842: MarshalBuilder meth = new MarshalBuilder(name, m_class
843: .getClassFile(), m_class.getMungedFile());
844: m_marshalContentName = fullMethodName(meth);
845: m_marshalSignature = meth.getSignature();
846: m_isStaticMarshal = meth.isStaticMethod();
847:
848: // if preget method supplied and no attributes add code to call it
849: if (m_preGetMethod != null && !hasAttribute()) {
850: genUserMethodCall(false, m_preGetMethod, meth);
851: }
852:
853: // push object being marshalled to marshaller stack
854: if (!m_isThisBinding) {
855: meth.loadContext();
856: meth.loadObject();
857: meth.appendCallVirtual(MARSHAL_PUSHOBJECTMETHOD,
858: PUSHOBJECT_SIGNATURE);
859: }
860:
861: // generate actual marshalling code
862: meth.loadContext();
863: m_component.genContentMarshal(meth);
864:
865: // pop object from stack
866: if (!m_isThisBinding) {
867: meth.loadContext();
868: meth.appendCallVirtual(MARSHAL_POPOBJECTMETHOD,
869: POPOBJECT_SIGNATURE);
870: }
871:
872: // finish and add constructed method to class
873: meth.appendReturn();
874: if (m_lockContentMarshal) {
875: m_marshalContentMethod = m_class.getUniqueNamed(
876: meth).getItem();
877: } else {
878: m_marshalContentMethod = m_class.getUniqueMethod(
879: meth).getItem();
880: m_marshalContentName = fullMethodName(m_marshalContentMethod);
881: }
882:
883: } else {
884: m_lockContentMarshal = true;
885: }
886: }
887:
888: // generate code to call created marshal method
889: mb.loadContext(MARSHALLING_CONTEXT);
890: genMarshalCall(m_marshalContentName, mb);
891: }
892:
893: //
894: // IContextObj interface method definitions
895:
896: public BoundClass getBoundClass() {
897: return m_class;
898: }
899:
900: public boolean setIdChild(IComponent child) {
901: if (m_idChild == null) {
902: m_idChild = child;
903: return true;
904: } else {
905: return false;
906: }
907: }
908:
909: //
910: // IComponent interface method definitions
911:
912: public boolean isOptional() {
913: return false;
914: }
915:
916: public void genAttributeUnmarshal(ContextMethodBuilder mb)
917: throws JiBXException {
918: genUnmarshalAttributeCall(mb);
919: }
920:
921: public void genAttributeMarshal(ContextMethodBuilder mb)
922: throws JiBXException {
923: genMarshalAttributeCall(mb);
924: }
925:
926: public void genContentUnmarshal(ContextMethodBuilder mb)
927: throws JiBXException {
928: genUnmarshalContentCall(mb);
929: }
930:
931: public void genContentMarshal(ContextMethodBuilder mb)
932: throws JiBXException {
933: genMarshalContentCall(mb);
934: }
935:
936: public void genNewInstance(ContextMethodBuilder mb)
937: throws JiBXException {
938: genNewInstanceCall(mb);
939: }
940:
941: public String getType() {
942: return m_class.getClassName();
943: }
944:
945: public boolean hasId() {
946: return m_idChild != null;
947: }
948:
949: public void genLoadId(ContextMethodBuilder mb) throws JiBXException {
950: if (m_idChild == null) {
951: throw new IllegalStateException(
952: "Internal error: no id defined");
953: } else {
954: m_idChild.genLoadId(mb);
955: }
956: }
957:
958: public void setLinkages() throws JiBXException {
959: super .setLinkages();
960: if (m_container.getBindingRoot().isTrackSource()) {
961: genTrackSourceCode();
962: }
963: }
964:
965: // DEBUG
966: public void print(int depth) {
967: BindingDefinition.indent(depth);
968: System.out.print("object binding for "
969: + m_class.getClassFile().getName());
970: if (m_isThisBinding) {
971: System.out.print(" (\"this\" reference)");
972: }
973: if (m_createClass != null) {
974: System.out
975: .print(" create class " + m_createClass.getName());
976: }
977: System.out.println();
978: m_component.print(depth + 1);
979: }
980: }
|