KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2 Copyright (c) 2003-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.def;
30
31 import java.util.ArrayList JavaDoc;
32
33 import org.apache.bcel.Constants;
34 import org.apache.bcel.generic.*;
35
36 import org.jibx.binding.classes.*;
37 import org.jibx.runtime.JiBXException;
38
39 /**
40  * Normal mapping with defined binding. This is used for a mapping definition
41  * which includes detailed binding information (rather than marshaller and
42  * unmarshaller classes which handle the binding directly).
43  *
44  * @author Dennis M. Sosnoski
45  * @version 1.0
46  */

47
48 public class MappingDefinition extends MappingBase
49 {
50     //
51
// Constants and such related to code generation.
52

53     // definitions used in generating the adapter class
54
private static final String JavaDoc ADAPTERCLASS_SUFFIX = "_access";
55     private static final String JavaDoc MARSHAL_METHODNAME = "marshal";
56     private static final String JavaDoc BASEMARSHAL_METHODNAME = "baseMarshal";
57     private static final String JavaDoc UNMARSHAL_METHODNAME = "unmarshal";
58     private static final String JavaDoc ISPRESENT_METHODNAME = "isPresent";
59     private static final String JavaDoc UNMARSHALCONTEXT_CLASS =
60         "org.jibx.runtime.impl.UnmarshallingContext";
61     private static final String JavaDoc MARSHALCONTEXT_CLASS =
62         "org.jibx.runtime.impl.MarshallingContext";
63     private static final String JavaDoc UNMARSHAL_ISATMETHOD =
64         "org.jibx.runtime.IUnmarshallingContext.isAt";
65     private static final String JavaDoc UNMARSHAL_ISATSIGNATURE =
66         "(Ljava/lang/String;Ljava/lang/String;)Z";
67     private static final String JavaDoc CHECKEXTENDS_METHOD =
68         "org.jibx.runtime.IMarshaller.isExtension";
69     private static final String JavaDoc GETINDEX_METHOD =
70         "org.jibx.runtime.IMarshallable.JiBX_getIndex";
71     private static final String JavaDoc UNMARSHALLERPRESENT_METHOD =
72         "org.jibx.runtime.IUnmarshaller.isPresent";
73     private static final String JavaDoc UNMARSHALLERPRESENT_SIGNATURE =
74         "(Lorg/jibx/runtime/IUnmarshallingContext;)Z";
75     private static final String JavaDoc UNMARSHALCONTEXT_INTERFACE =
76         "org.jibx.runtime.IUnmarshallingContext";
77     private static final String JavaDoc MARSHALCONTEXT_INTERFACE =
78         "org.jibx.runtime.IMarshallingContext";
79     private static final String JavaDoc CURRENTELEMENT_METHOD =
80         "org.jibx.runtime.impl.UnmarshallingContext.currentNameString";
81     private static final String JavaDoc CURRENTELEMENT_SIGNATURE =
82         "()Ljava/lang/String;";
83     private static final String JavaDoc ADDUNMARSHALLER_METHOD =
84         "org.jibx.runtime.impl.UnmarshallingContext.addUnmarshalling";
85     private static final String JavaDoc ADDUNMARSHALLER_SIGNATURE =
86         "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V";
87     private static final String JavaDoc REMOVEUNMARSHALLER_METHOD =
88         "org.jibx.runtime.impl.UnmarshallingContext.removeUnmarshalling";
89     private static final String JavaDoc REMOVEUNMARSHALLER_SIGNATURE = "(I)V";
90     private static final String JavaDoc ADDMARSHALLER_METHOD =
91         "org.jibx.runtime.impl.MarshallingContext.addMarshalling";
92     private static final String JavaDoc ADDMARSHALLER_SIGNATURE =
93         "(ILjava/lang/String;)V";
94     private static final String JavaDoc REMOVEMARSHALLER_METHOD =
95         "org.jibx.runtime.impl.MarshallingContext.removeMarshalling";
96     private static final String JavaDoc REMOVEMARSHALLER_SIGNATURE = "(I)V";
97     
98     // argument list for the unmarshaller methods
99
private static final Type[] ISPRESENT_METHOD_ARGS =
100     {
101         ClassItem.typeFromName("org.jibx.runtime.IUnmarshallingContext")
102     };
103     private static final Type[] UNMARSHAL_METHOD_ARGS =
104     {
105         Type.OBJECT,
106         ClassItem.typeFromName("org.jibx.runtime.IUnmarshallingContext")
107     };
108     
109     // argument list for the marshaller methods
110
private static final Type[] MARSHAL_METHOD_ARGS =
111     {
112         Type.OBJECT,
113         ClassItem.typeFromName("org.jibx.runtime.IMarshallingContext")
114     };
115     
116     //
117
// Data shared with other classes within package
118

119     // interface list for adapter with unmarshaller only
120
/*package*/ static final String JavaDoc[] UNMARSHALLER_INTERFACES =
121     {
122         UNMARSHALLER_INTERFACE
123     };
124     
125     // interface list for adapter with marshaller only
126
/*package*/ static final String JavaDoc[] MARSHALLER_INTERFACES =
127     {
128         MARSHALLER_INTERFACE
129     };
130     
131     // interface list for adapter with both unmarshaller and marshaller
132
/*package*/ static final String JavaDoc[] BOTH_INTERFACES =
133     {
134         UNMARSHALLER_INTERFACE, MARSHALLER_INTERFACE
135     };
136     
137     //
138
// Actual instance data.
139

140     /** Containing binding definition structure. */
141     private final IContainer m_container;
142     
143     /** Definition context for mapping. */
144     private final DefinitionContext m_defContext;
145     
146     /** Class linked to mapping. */
147     private final BoundClass m_class;
148
149     /** Mapped element name (may be <code>null</code> if element(s) defined
150      by marshaller and unmarshaller, or if abstract mapping). */

151     private final NameDefinition m_name;
152     
153     /** Abstract mapping flag. */
154     private final boolean m_isAbstract;
155     
156     /** Name of abstract base type. */
157     private final String JavaDoc m_baseType;
158     
159     /** Abstract binding this one is based on (<code>null</code> if not an
160      extension. */

161     private IMapping m_baseMapping;
162     
163     /** Constructed marshaller class. */
164     private ClassFile m_marshaller;
165
166     /** Constructed unmarshaller class. */
167     private ClassFile m_unmarshaller;
168     
169     /** Mapping which extend this one (only for abstract mapping). */
170     private ArrayList JavaDoc m_extensions;
171
172     /**
173      * Constructor. This initializes the new definition context.
174      *
175      * @param contain containing binding definition structure
176      * @param defc definition context for this mapping
177      * @param type bound class name
178      * @param name mapped element name information (<code>null</code> if defined
179      * by marshaller and unmarshaller)
180      * @param abs abstract mapping flag
181      * @param base abstract mapping extended by this one
182      * @param bind binding definition component
183      * @throws JiBXException if class definition not found
184      */

185     public MappingDefinition(IContainer contain, DefinitionContext defc,
186         String JavaDoc type, NameDefinition name, boolean abs, String JavaDoc base,
187         IComponent bind) throws JiBXException {
188         super(contain, type);
189         if (name == null) {
190             setWrappedComponent(bind);
191         } else {
192             setWrappedComponent(new ElementWrapper(defc, name, bind));
193         }
194         m_container = contain;
195         m_defContext = defc;
196         m_class = BoundClass.getInstance(type, null);
197         m_name = name;
198         m_isAbstract = abs;
199         if (abs) {
200             m_extensions = new ArrayList JavaDoc();
201         }
202         m_baseType = base;
203     }
204
205     /**
206      * Check if one or more namespaces are defined for element.
207      *
208      * @return <code>true</code> if namespaces are defined, <code>false</code>
209      * if not
210      */

211     /*package*/ boolean hasNamespace() {
212         return m_defContext.hasNamespace();
213     }
214
215     /**
216      * Generate code for loading namespace index and URI arrays. This default
217      * implementation assumes no namespaces are present and does nothing. It
218      * must be overridden by subclasses that support namespace declarations.
219      *
220      * @param mb method builder for generated code
221      * @throws JiBXException if error in generating code
222      */

223     /*package*/ void genLoadNamespaces(MethodBuilder mb) throws JiBXException {
224         m_defContext.genLoadNamespaces(mb);
225     }
226
227     /**
228      * Get the mapped class information. This implements the method used by the
229      * base class.
230      *
231      * @return information for mapped class
232      */

233     public BoundClass getBoundClass() {
234         return m_class;
235     }
236     
237     /**
238      * Links extension mappings to their base mappings. This must be done before
239      * the more general linking step in order to determine which abstract
240      * mappings are standalone and which are extended by other mappings
241      *
242      * @throws JiBXException if error in linking
243      */

244     public void linkMappings() throws JiBXException {
245         if (m_isAbstract && m_component instanceof ObjectBinding) {
246             ((ObjectBinding)m_component).setAbstract(true);
247         }
248         if (m_baseType != null) {
249             m_baseMapping = m_defContext.getClassMapping(m_baseType);
250             if (m_baseMapping == null) {
251                 throw new JiBXException("Mapping for base class " + m_baseType +
252                     " not defined");
253             }
254             m_baseMapping.addExtension(this);
255         }
256         m_defContext.linkMappings();
257     }
258     
259     //
260
// IMapping interface method definitions
261

262     public String JavaDoc getBoundType() {
263         return m_class.getClassName();
264     }
265     
266     public IComponent getImplComponent() {
267         return m_component;
268     }
269     
270     public ClassFile getMarshaller() {
271         return m_marshaller;
272     }
273     
274     public ClassFile getUnmarshaller() {
275         return m_unmarshaller;
276     }
277     
278     public NameDefinition getName() {
279         return m_name;
280     }
281
282     public void addNamespace(NamespaceDefinition ns) throws JiBXException {
283         m_defContext.addNamespace(ns);
284     }
285
286     public boolean isAbstract() {
287         return m_isAbstract;
288     }
289
290     public void addExtension(MappingDefinition mdef) {
291         if (!m_extensions.contains(mdef)) {
292             m_extensions.add(mdef);
293         }
294     }
295     
296     public IComponent buildRef(IContainer parent, IContextObj objc, String JavaDoc type,
297         PropertyDefinition prop) throws JiBXException {
298         if (m_isAbstract && prop.isThis()) {
299             
300             // directly incorporate base mapping definition
301
if (m_component instanceof ObjectBinding) {
302                 ((ObjectBinding)m_component).setAbstract(true);
303             }
304             return new BaseMappingWrapper(m_component);
305             
306         } else if (m_isAbstract && m_extensions.size() == 0) {
307             
308             // create structure to use mapping definition directly
309
if (m_component instanceof ObjectBinding) {
310                 ((ObjectBinding)m_component).setAbstract(true);
311             }
312             ObjectBinding bind = new ObjectBinding(parent, objc, type, null,
313                 null, null, null);
314             NestedStructure nest = new NestedStructure(parent, bind, true,
315                 false, true);
316             nest.addComponent(new BaseMappingWrapper(m_component));
317             bind.setWrappedComponent(nest);
318             return new ComponentProperty(prop, bind, false);
319             
320         } else {
321             
322             // create link to mapping definition
323
DirectObject dobj = new DirectObject(m_container, null,
324                 m_class.getClassFile(), m_isAbstract, m_marshaller,
325                 m_unmarshaller, getIndex(), null);
326             return new DirectProperty(prop, dobj);
327             
328         }
329     }
330     
331     public void generateCode() throws JiBXException {
332         
333         // TODO: Split this sucker up!
334

335         // first call code generation for child mappings
336
m_defContext.generateCode(false);
337         if (m_isAbstract && m_extensions.size() == 0) {
338             return;
339         }
340     
341         // create the helper class
342
ClassFile target = m_class.getMungedFile();
343         BindingDefinition def = m_container.getBindingRoot();
344         String JavaDoc name = target.deriveClassName(def.getPrefix(),
345             ADAPTERCLASS_SUFFIX);
346         ClassFile base = ClassCache.getClassFile("java.lang.Object");
347         String JavaDoc[] intfs = def.isInput() ?
348             (def.isOutput() ? BOTH_INTERFACES : UNMARSHALLER_INTERFACES) :
349             MARSHALLER_INTERFACES;
350         ClassFile cf = new ClassFile(name, target.getRoot(), base,
351             Constants.ACC_PUBLIC, intfs);
352         cf.addDefaultConstructor();
353         
354         // add unmarshaller access methods
355
boolean hasattr = !m_isAbstract && m_component.hasAttribute();
356         boolean hascont = m_component.hasContent();
357         boolean genfull = !m_isAbstract || m_extensions.size() > 0;
358         if (def.isInput()) {
359             
360             // build the is present test method for item
361
ContextMethodBuilder mb = new ContextMethodBuilder
362                 (ISPRESENT_METHODNAME, Type.BOOLEAN, ISPRESENT_METHOD_ARGS,
363                 cf, Constants.ACC_PUBLIC|Constants.ACC_FINAL, -1, null,
364                 1, UNMARSHALCONTEXT_INTERFACE);
365             
366             // check for an abstract mapping
367
if (m_isAbstract) {
368                 
369                 // build code to check each extension mapping in turn;
370
// return "true" if one matches, or "false" if none do
371
mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
372                 BranchWrapper[] iffounds =
373                     new BranchWrapper[m_extensions.size()];
374                 if (iffounds.length > 0) {
375                     for (int i = 0; i < iffounds.length; i++) {
376                         IMapping map = (IMapping)m_extensions.get(i);
377                         mb.loadContext();
378                         mb.appendLoadConstant(map.getIndex());
379                         mb.appendCallInterface(GETUNMARSHALLER_METHOD,
380                             GETUNMARSHALLER_SIGNATURE);
381                         mb.loadContext();
382                         mb.appendCallInterface(UNMARSHALLERPRESENT_METHOD,
383                             UNMARSHALLERPRESENT_SIGNATURE);
384                         iffounds[i] = mb.appendIFNE(this);
385                     }
386                     mb.appendICONST_0();
387                     mb.appendReturn("int");
388                     mb.initStackState(iffounds[0]);
389                     BranchTarget found = mb.appendTargetLoadConstant(1);
390                     for (int i = 0; i < iffounds.length; i++) {
391                         iffounds[i].setTarget(found, mb);
392                     }
393                 } else {
394                     mb.appendLoadConstant(1);
395                 }
396                 
397             } else if (m_name == null) {
398                 
399                 // concrete mapping with no separate element name, just
400
// return "true" always
401
mb.appendICONST_1();
402                 
403             } else {
404                 
405                 // concrete mapping with element name, test for at that
406
// element and return result as value
407
mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
408                 mb.loadContext();
409                 m_name.genPushUriPair(mb);
410                 mb.appendCallInterface(UNMARSHAL_ISATMETHOD,
411                     UNMARSHAL_ISATSIGNATURE);
412                     
413             }
414             mb.appendReturn("int");
415             mb.codeComplete(false);
416             mb.addMethod();
417             
418             // build the unmarshal method for item; this just generates code
419
// to unmarshal attributes and content, first creating an
420
// instance of the class if one was not passed in, then
421
// returning the unmarshalled instance as the value of the call
422
String JavaDoc type = m_class.getClassName();
423             mb = new ContextMethodBuilder(UNMARSHAL_METHODNAME,
424                 Type.OBJECT, UNMARSHAL_METHOD_ARGS, cf,
425                 Constants.ACC_PUBLIC|Constants.ACC_FINAL, 1, type,
426                 2, UNMARSHALCONTEXT_INTERFACE);
427             mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
428             
429             // first part of generated code just checks if an object has
430
// been supplied; if it has, this can just go direct to
431
// unmarshalling on the assumption that the unmarshaller for an
432
// abstract mapping will only be passed an object when used by
433
// an extension mapping
434
mb.loadObject();
435             BranchWrapper ifnnull = mb.appendIFNONNULL(this);
436             
437             // check for an abstract mapping
438
if (m_isAbstract) {
439                 
440                 // build code to check each extension mapping in turn,
441
// keeping an instance of the unmarshaller for the matching
442
// extension
443
BranchWrapper[] iffounds =
444                     new BranchWrapper[m_extensions.size()];
445                 for (int i = 0; i < iffounds.length; i++) {
446                     IMapping map = (IMapping)m_extensions.get(i);
447                     mb.loadContext();
448                     mb.appendLoadConstant(map.getIndex());
449                     mb.appendCallInterface(GETUNMARSHALLER_METHOD,
450                         GETUNMARSHALLER_SIGNATURE);
451                     mb.appendDUP();
452                     mb.loadContext();
453                     mb.appendCallInterface(UNMARSHALLERPRESENT_METHOD,
454                         UNMARSHALLERPRESENT_SIGNATURE);
455                     iffounds[i] = mb.appendIFNE(this);
456                     mb.appendPOP();
457                 }
458                 
459                 // generate code to throw exception if no matching extension
460
// found
461
mb.appendCreateNew("java.lang.StringBuffer");
462                 mb.appendDUP();
463                 mb.appendLoadConstant("Element ");
464                 mb.appendCallInit("java.lang.StringBuffer",
465                     "(Ljava/lang/String;)V");
466                 mb.appendDUP();
467                 mb.loadContext(UNMARSHALCONTEXT_CLASS);
468                 mb.appendCallVirtual(CURRENTELEMENT_METHOD,
469                     CURRENTELEMENT_SIGNATURE);
470                 mb.appendCallVirtual("java.lang.StringBuffer.append",
471                     "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
472                 mb.appendDUP();
473                 mb.appendLoadConstant(" has no mapping that extends " +
474                     m_class.getClassName());
475                 mb.appendCallVirtual("java.lang.StringBuffer.append",
476                     "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
477                 mb.appendCallVirtual("java.lang.StringBuffer.toString",
478                     "()Ljava/lang/String;");
479                 mb.appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
480                 mb.appendDUP_X1();
481                 mb.appendSWAP();
482                 mb.appendCallInit(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS,
483                     MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
484                 mb.appendThrow();
485                 if (iffounds.length > 0) {
486                 
487                     // finish by calling unmarshaller for extension mapping
488
// found and returning the result with no further
489
// processing
490
mb.initStackState(iffounds[0]);
491                     BranchTarget found = mb.appendTargetACONST_NULL();
492                     for (int i = 0; i < iffounds.length; i++) {
493                         iffounds[i].setTarget(found, mb);
494                     }
495                     mb.loadContext();
496                     mb.appendCallInterface(UNMARSHALLERUNMARSHAL_METHOD,
497                         UNMARSHALLERUNMARSHAL_SIGNATURE);
498                     mb.appendReturn("java.lang.Object");
499                 }
500                 
501             } else {
502                 
503                 // just create an instance of the (non-abstract) mapped class
504
genNewInstance(mb);
505                 mb.storeObject();
506                 
507             }
508             
509             // define unmarshallings for child mappings of this mapping
510
ArrayList JavaDoc maps = m_defContext.getMappings();
511             if (maps != null && maps.size() > 0) {
512                 for (int i = 0; i < maps.size(); i++) {
513                     mb.loadContext(UNMARSHALCONTEXT_CLASS);
514                     IMapping map = (IMapping)maps.get(i);
515                     mb.appendLoadConstant(map.getIndex());
516                     NameDefinition mname = map.getName();
517                     if (mname == null) {
518                         mb.appendACONST_NULL();
519                         mb.appendACONST_NULL();
520                     } else {
521                         map.getName().genPushUriPair(mb);
522                     }
523                     mb.appendLoadConstant(map.getUnmarshaller().getName());
524                     mb.appendCallVirtual(ADDUNMARSHALLER_METHOD,
525                         ADDUNMARSHALLER_SIGNATURE);
526                 }
527             }
528             
529             // load object and cast to type
530
mb.targetNext(ifnnull);
531             mb.loadObject();
532             mb.appendCreateCast(type);
533             
534             // handle the actual unmarshalling
535
if (hasattr) {
536                 mb.appendDUP();
537                 m_component.genAttributeUnmarshal(mb);
538             }
539             if (hascont) {
540                 mb.appendDUP();
541                 m_component.genContentUnmarshal(mb);
542             }
543             
544             // undefine unmarshallings for child mappings of this mapping
545
if (maps != null && maps.size() > 0) {
546                 for (int i = 0; i < maps.size(); i++) {
547                     mb.loadContext(UNMARSHALCONTEXT_CLASS);
548                     IMapping map = (IMapping)maps.get(i);
549                     mb.appendLoadConstant(map.getIndex());
550                     mb.appendCallVirtual(REMOVEUNMARSHALLER_METHOD,
551                         REMOVEUNMARSHALLER_SIGNATURE);
552                 }
553             }
554             
555             // finish by returning unmarshalled object reference
556
mb.appendReturn("java.lang.Object");
557             mb.codeComplete(false);
558             mb.addMethod();
559         
560             // add interface if mapped class is directly unmarshallable
561
if (m_name != null && !m_isAbstract &&
562                 m_class.getClassFile() == m_class.getMungedFile()) {
563                 addIUnmarshallableMethod();
564             }
565         }
566     
567         // add marshaller access method
568
if (def.isOutput()) {
569             
570             // build the marshal implementation method; this loads the
571
// passed object and casts it to the target type, then handles
572
// marshalling first attributes and followed by content for the
573
// item
574
ContextMethodBuilder mb = new ContextMethodBuilder
575                 (MARSHAL_METHODNAME, Type.VOID, MARSHAL_METHOD_ARGS, cf,
576                 Constants.ACC_PUBLIC|Constants.ACC_FINAL,
577                 1, "java.lang.Object", 2, MARSHALCONTEXT_INTERFACE);
578             mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
579             // TODO: optionally check for null value on object
580

581             // define marshallings for child mappings of this mapping
582
ArrayList JavaDoc maps = m_defContext.getMappings();
583             if (maps != null && maps.size() > 0) {
584                 for (int i = 0; i < maps.size(); i++) {
585                     mb.loadContext(MARSHALCONTEXT_CLASS);
586                     IMapping map = (IMapping)maps.get(i);
587                     mb.appendLoadConstant(map.getIndex());
588                     mb.appendLoadConstant(map.getMarshaller().getName());
589                     mb.appendCallVirtual(ADDMARSHALLER_METHOD,
590                         ADDMARSHALLER_SIGNATURE);
591                 }
592             }
593             
594             // handle the actual marshalling
595
if (hasattr || hascont) {
596                 mb.loadObject(m_class.getClassName());
597                 if (hasattr) {
598                     if (hascont) {
599                         mb.appendDUP();
600                     }
601                     m_component.genAttributeMarshal(mb);
602                 }
603                 if (hascont) {
604                     m_component.genContentMarshal(mb);
605                 }
606             }
607             
608             // undefine marshallings for child mappings of this mapping
609
if (maps != null && maps.size() > 0) {
610                 for (int i = 0; i < maps.size(); i++) {
611                     mb.loadContext(MARSHALCONTEXT_CLASS);
612                     IMapping map = (IMapping)maps.get(i);
613                     mb.appendLoadConstant(map.getIndex());
614                     mb.appendCallVirtual(REMOVEMARSHALLER_METHOD,
615                         REMOVEMARSHALLER_SIGNATURE);
616                 }
617             }
618             
619             // finish with plain return
620
mb.appendReturn();
621             mb.codeComplete(false);
622             mb.addMethod();
623             
624             // build method to check if extending a particular abstract
625
// mapping
626
ExceptionMethodBuilder xb = new ExceptionMethodBuilder
627                 (CHECKEXTENDS_METHODNAME, CHECKEXTENDS_SIGNATURE, cf,
628                 Constants.ACC_PUBLIC|Constants.ACC_FINAL);
629             if (m_baseMapping == null) {
630                 xb.appendICONST_0();
631             } else {
632                 xb.appendLoadLocal(1);
633                 xb.appendLoadConstant(m_baseMapping.getIndex());
634                 xb.appendISUB();
635                 BranchWrapper iftrue = xb.appendIFEQ(this);
636                 xb.appendICONST_0();
637                 xb.appendReturn("int");
638                 xb.targetNext(iftrue);
639                 xb.appendICONST_1();
640             }
641             xb.appendReturn("int");
642             xb.codeComplete(false);
643             xb.addMethod();
644         
645             // add interface if mapped class is directly marshallable
646
if (m_name != null && !m_isAbstract &&
647                 m_class.getClassFile() == m_class.getMungedFile()) {
648                 addIMarshallableMethod();
649             }
650             
651             // check for an abstract mapping to add extra method and
652
// interface
653
if (m_isAbstract) {
654                 
655                 // for an abstract mapping, add base marshal implementation
656
// that just passes handling on to the appropriate
657
// extension class, and add corresponding interface to
658
// class.
659
mb = new ContextMethodBuilder(BASEMARSHAL_METHODNAME,
660                     Type.VOID, MARSHAL_METHOD_ARGS, cf,
661                     Constants.ACC_PUBLIC|Constants.ACC_FINAL,
662                     1, "java.lang.Object", 2, MARSHALCONTEXT_INTERFACE);
663                 mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
664                 // TODO: optionally check for null value on object
665
mb.loadContext();
666                 mb.loadObject(IMARSHALLABLE_INTERFACE);
667                 mb.appendCallInterface(GETINDEX_METHOD, GETINDEX_SIGNATURE);
668                 mb.loadObject();
669                 mb.appendCallVirtual("java.lang.Object.getClass",
670                     "()Ljava/lang/Class;");
671                 mb.appendCallVirtual("java.lang.Class.getName",
672                     "()Ljava/lang/String;");
673                 mb.appendCallInterface(GETMARSHALLER_METHOD,
674                     GETMARSHALLER_SIGNATURE);
675                 mb.appendDUP();
676                 mb.appendLoadConstant(getIndex());
677                 mb.appendCallInterface(CHECKEXTENDS_METHOD,
678                     CHECKEXTENDS_SIGNATURE);
679                 BranchWrapper ifvalid = mb.appendIFNE(this);
680             
681                 // generate and throw exception describing the problem
682
mb.appendCreateNew("java.lang.StringBuffer");
683                 mb.appendDUP();
684                 mb.appendLoadConstant("Mapping for type ");
685                 mb.appendCallInit("java.lang.StringBuffer",
686                     "(Ljava/lang/String;)V");
687                 mb.appendDUP();
688                 mb.loadObject();
689                 mb.appendCallVirtual("java.lang.Object.getClass",
690                     "()Ljava/lang/Class;");
691                 mb.appendCallVirtual("java.lang.Class.getName",
692                     "()Ljava/lang/String;");
693                 mb.appendCallVirtual("java.lang.StringBuffer.append",
694                     "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
695                 mb.appendDUP();
696                 mb.appendLoadConstant(" must extend abstract mapping for " +
697                     "type " + m_class.getClassName());
698                 mb.appendCallVirtual("java.lang.StringBuffer.append",
699                     "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
700                 mb.appendCallVirtual("java.lang.StringBuffer.toString",
701                     "()Ljava/lang/String;");
702                 mb.appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
703                 mb.appendDUP_X1();
704                 mb.appendSWAP();
705                 mb.appendCallInit(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS,
706                     MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
707                 mb.appendThrow();
708             
709                 // for valid extension mapping, just call the marshaller
710
mb.targetNext(ifvalid);
711                 mb.loadObject();
712                 mb.loadContext();
713                 mb.appendCallInterface(MARSHALLERMARSHAL_METHOD,
714                     MARSHALLERMARSHAL_SIGNATURE);
715                 mb.appendReturn();
716                 mb.codeComplete(false);
717                 mb.addMethod();
718                 
719                 // add extended interface to constructed class
720
cf.addInterface(ABSTRACTMARSHALLER_INTERFACE);
721             }
722         }
723     
724         // add as generated class
725
m_marshaller = m_unmarshaller = MungedClass.getUniqueSupportClass(cf);
726     }
727     
728     //
729
// IComponent interface method definitions
730

731     public void setLinkages() throws JiBXException {
732         m_component.setLinkages();
733         if (!m_isAbstract) {
734             m_component.checkContentSequence(true);
735         }
736         m_defContext.setLinkages();
737     }
738     
739     // DEBUG
740
public void print(int depth) {
741         BindingDefinition.indent(depth);
742         System.out.print("mapping class " + m_class.getClassFile().getName());
743         if (m_name != null) {
744             System.out.print(" to element " + m_name.toString());
745         }
746         System.out.println();
747         m_component.print(depth+1);
748     }
749 }
Popular Tags