001: /*
002: Copyright (c) 2003-2007, 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 java.util.ArrayList;
032:
033: import org.apache.bcel.Constants;
034: import org.apache.bcel.generic.*;
035:
036: import org.jibx.binding.classes.*;
037: import org.jibx.runtime.JiBXException;
038:
039: /**
040: * Normal mapping with defined binding. This is used for a mapping definition
041: * which includes detailed binding information (rather than marshaller and
042: * unmarshaller classes which handle the binding directly).
043: *
044: * @author Dennis M. Sosnoski
045: */
046: public class MappingDefinition extends MappingBase {
047: //
048: // Constants and such related to code generation.
049:
050: // definitions used in generating the adapter class
051: private static final String ADAPTERCLASS_SUFFIX = "_access";
052: private static final String MARSHAL_METHODNAME = "marshal";
053: private static final String BASEMARSHAL_METHODNAME = "baseMarshal";
054: private static final String UNMARSHAL_METHODNAME = "unmarshal";
055: private static final String ISPRESENT_METHODNAME = "isPresent";
056: private static final String UNMARSHALCONTEXT_CLASS = "org.jibx.runtime.impl.UnmarshallingContext";
057: private static final String MARSHALCONTEXT_CLASS = "org.jibx.runtime.impl.MarshallingContext";
058: private static final String UNMARSHAL_ISATMETHOD = "org.jibx.runtime.IUnmarshallingContext.isAt";
059: private static final String UNMARSHAL_ISATSIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)Z";
060: private static final String CHECKEXTENDS_METHOD = "org.jibx.runtime.IMarshaller.isExtension";
061: private static final String GETINDEX_METHOD = "org.jibx.runtime.IMarshallable.JiBX_getIndex";
062: private static final String UNMARSHALLERPRESENT_METHOD = "org.jibx.runtime.IUnmarshaller.isPresent";
063: private static final String UNMARSHALLERPRESENT_SIGNATURE = "(Lorg/jibx/runtime/IUnmarshallingContext;)Z";
064: private static final String UNMARSHALCONTEXT_INTERFACE = "org.jibx.runtime.IUnmarshallingContext";
065: private static final String MARSHALCONTEXT_INTERFACE = "org.jibx.runtime.IMarshallingContext";
066: private static final String CURRENTELEMENT_METHOD = "org.jibx.runtime.impl.UnmarshallingContext.currentNameString";
067: private static final String CURRENTELEMENT_SIGNATURE = "()Ljava/lang/String;";
068: private static final String PARSERNEXT_METHOD = "org.jibx.runtime.impl.UnmarshallingContext.next";
069: private static final String PARSERNEXT_SIGNATURE = "()I";
070: private static final String CLOSESTART_METHOD = "org.jibx.runtime.impl.MarshallingContext.closeStartContent";
071: private static final String CLOSESTART_SIGNATURE = "()Lorg/jibx/runtime/impl/MarshallingContext;";
072: private static final String ADDUNMARSHALLER_METHOD = "org.jibx.runtime.impl.UnmarshallingContext.addUnmarshalling";
073: private static final String ADDUNMARSHALLER_SIGNATURE = "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V";
074: private static final String REMOVEUNMARSHALLER_METHOD = "org.jibx.runtime.impl.UnmarshallingContext.removeUnmarshalling";
075: private static final String REMOVEUNMARSHALLER_SIGNATURE = "(I)V";
076: private static final String ADDMARSHALLER_METHOD = "org.jibx.runtime.impl.MarshallingContext.addMarshalling";
077: private static final String ADDMARSHALLER_SIGNATURE = "(ILjava/lang/String;)V";
078: private static final String REMOVEMARSHALLER_METHOD = "org.jibx.runtime.impl.MarshallingContext.removeMarshalling";
079: private static final String REMOVEMARSHALLER_SIGNATURE = "(I)V";
080:
081: // argument list for the unmarshaller methods
082: private static final Type[] ISPRESENT_METHOD_ARGS = { ClassItem
083: .typeFromName("org.jibx.runtime.IUnmarshallingContext") };
084: private static final Type[] UNMARSHAL_METHOD_ARGS = {
085: Type.OBJECT,
086: ClassItem
087: .typeFromName("org.jibx.runtime.IUnmarshallingContext") };
088:
089: // argument list for the marshaller methods
090: private static final Type[] MARSHAL_METHOD_ARGS = {
091: Type.OBJECT,
092: ClassItem
093: .typeFromName("org.jibx.runtime.IMarshallingContext") };
094:
095: //
096: // Data shared with other classes within package
097:
098: // interface list for adapter with unmarshaller only
099: /*package*/static final String[] UNMARSHALLER_INTERFACES = { UNMARSHALLER_INTERFACE };
100:
101: // interface list for adapter with marshaller only
102: /*package*/static final String[] MARSHALLER_INTERFACES = { MARSHALLER_INTERFACE };
103:
104: // interface list for adapter with both unmarshaller and marshaller
105: /*package*/static final String[] BOTH_INTERFACES = {
106: UNMARSHALLER_INTERFACE, MARSHALLER_INTERFACE };
107:
108: //
109: // Actual instance data.
110:
111: /** Containing binding definition structure. */
112: private final IContainer m_container;
113:
114: /** Definition context for mapping. */
115: private final DefinitionContext m_defContext;
116:
117: /** Class linked to mapping. */
118: private final BoundClass m_class;
119:
120: /** Mapped element name (may be <code>null</code> if element(s) defined
121: by marshaller and unmarshaller, or if abstract mapping). */
122: private final NameDefinition m_name;
123:
124: /** Abstract mapping flag. */
125: private final boolean m_isAbstract;
126:
127: /** Name of abstract base type. */
128: private final String m_baseType;
129:
130: /** Abstract binding this one is based on (<code>null</code> if not an
131: extension. */
132: private IMapping m_baseMapping;
133:
134: /** Duplicate of component structure for use as "this" reference
135: * (<code>null</code> if not yet defined). */
136: private IComponent m_this Binding;
137:
138: /** Constructed marshaller class. */
139: private ClassFile m_marshaller;
140:
141: /** Constructed unmarshaller class. */
142: private ClassFile m_unmarshaller;
143:
144: /** Mapping which extend this one (<code>null</code> if none). */
145: private ArrayList m_extensions;
146:
147: /** Reference type of mapping, as fully qualifed class name. */
148: private String m_referenceType;
149:
150: /**
151: * Constructor. This initializes the new definition context.
152: *
153: * @param contain containing binding definition structure
154: * @param defc definition context for this mapping
155: * @param type bound class name
156: * @param name mapped element name information (<code>null</code> if defined
157: * by marshaller and unmarshaller)
158: * @param tname qualified type name for abstract mapping (<code>null</code>
159: * if none)
160: * @param abs abstract mapping flag
161: * @param base abstract mapping extended by this one
162: * @param bind binding definition component
163: * @param nillable flag for nillable element
164: * @throws JiBXException if class definition not found
165: */
166: public MappingDefinition(IContainer contain,
167: DefinitionContext defc, String type, NameDefinition name,
168: String tname, boolean abs, String base, ObjectBinding bind,
169: boolean nillable) throws JiBXException {
170: super (contain, type, tname);
171: IComponent tref = new ObjectBinding(bind);
172: if (name == null) {
173: setWrappedComponent(bind);
174: } else {
175: setWrappedComponent(new ElementWrapper(defc, name, bind,
176: nillable));
177: tref = new ElementWrapper(defc, name, tref, nillable);
178: }
179: m_this Binding = tref;
180: m_container = contain;
181: m_defContext = defc;
182: m_class = BoundClass.getInstance(type, null);
183: m_referenceType = type == null ? "java.lang.Object" : type;
184: m_name = name;
185: m_isAbstract = abs;
186: m_baseType = base;
187: }
188:
189: /**
190: * Check if one or more namespaces are defined for element.
191: *
192: * @return <code>true</code> if namespaces are defined, <code>false</code>
193: * if not
194: */
195: /*package*/boolean hasNamespace() {
196: return m_defContext.hasNamespace();
197: }
198:
199: /**
200: * Generate code for loading namespace index and URI arrays.
201: *
202: * @param mb method builder for generated code
203: */
204: /*package*/void genLoadNamespaces(MethodBuilder mb) {
205: m_defContext.genLoadNamespaces(mb);
206: }
207:
208: /**
209: * Get the mapped class information. This implements the method used by the
210: * base class.
211: *
212: * @return information for mapped class
213: */
214: public BoundClass getBoundClass() {
215: return m_class;
216: }
217:
218: /**
219: * Links extension mappings to their base mappings. This must be done before
220: * the more general linking step in order to determine which abstract
221: * mappings are standalone and which are extended by other mappings
222: *
223: * @throws JiBXException if error in linking
224: */
225: public void linkMappings() throws JiBXException {
226: if (m_baseType != null) {
227: m_baseMapping = m_defContext.getClassMapping(m_baseType);
228: if (m_baseMapping == null) {
229: throw new JiBXException("Mapping for base class "
230: + m_baseType + " not defined");
231: }
232: m_baseMapping.addExtension(this );
233: }
234: m_defContext.linkMappings();
235: }
236:
237: //
238: // IMapping interface method definitions
239:
240: public String getBoundType() {
241: return m_class.getClassName();
242: }
243:
244: public String getReferenceType() {
245: return m_referenceType;
246: }
247:
248: public IComponent getImplComponent() {
249: return m_component;
250: }
251:
252: public ClassFile getMarshaller() {
253: return m_marshaller;
254: }
255:
256: public ClassFile getUnmarshaller() {
257: return m_unmarshaller;
258: }
259:
260: public NameDefinition getName() {
261: return m_name;
262: }
263:
264: public void addNamespace(NamespaceDefinition ns)
265: throws JiBXException {
266: m_defContext.addNamespace(ns);
267: }
268:
269: public boolean isAbstract() {
270: return m_isAbstract;
271: }
272:
273: public boolean isBase() {
274: return m_extensions != null && m_extensions.size() > 0;
275: }
276:
277: public void addExtension(MappingDefinition mdef)
278: throws JiBXException {
279: if (m_extensions == null) {
280: m_extensions = new ArrayList();
281: }
282: if (!m_extensions.contains(mdef)) {
283: m_extensions.add(mdef);
284: }
285: ClassFile cf = mdef.getBoundClass().getClassFile();
286: if (!cf.isSuperclass(m_referenceType)
287: && !cf.isImplements(m_referenceType)) {
288: m_referenceType = "java.lang.Object";
289: }
290: }
291:
292: public IComponent buildRef(IContainer parent, IContextObj objc,
293: String type, PropertyDefinition prop) throws JiBXException {
294: if (prop.isThis()) {
295:
296: // directly incorporate base mapping definition
297: return new BaseMappingWrapper(m_this Binding);
298:
299: } else if (m_isAbstract && m_extensions == null) {
300:
301: // create reference to use mapping definition directly
302: ComponentProperty comp = new ComponentProperty(prop,
303: m_component, false);
304: if (!hasAttribute() && !hasContent()) {
305: comp.setForceUnmarshal(true);
306: }
307: return comp;
308:
309: } else {
310:
311: // create link to mapping definition
312: DirectObject dobj = new DirectObject(m_container, null,
313: m_class.getClassFile(), m_isAbstract
314: || m_extensions != null, m_marshaller,
315: m_unmarshaller, getIndex(), null);
316: return new DirectProperty(prop, dobj);
317:
318: }
319: }
320:
321: public ArrayList getNamespaces() {
322: return m_defContext.getNamespaces();
323: }
324:
325: /**
326: * Add abstract marshaller interface to handler class. This adds the
327: * interface and generates the {@link
328: * org.jibx.runtime.IAbstractMarshaller#baseMarshal(Object,
329: * org.jibx.runtime.IMarshallingContext)} method responsible for passing
330: * handling on to the appropriate extension class.
331: *
332: * @param cf hanlder class
333: * @throws JiBXException
334: */
335: private void generateAbstractMarshaller(ClassFile cf)
336: throws JiBXException {
337:
338: // build the implementation method
339: ContextMethodBuilder mb = new ContextMethodBuilder(
340: BASEMARSHAL_METHODNAME, Type.VOID, MARSHAL_METHOD_ARGS,
341: cf, Constants.ACC_PUBLIC | Constants.ACC_FINAL, 1,
342: "java.lang.Object", 2, MARSHALCONTEXT_INTERFACE);
343: mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
344: // TODO: optionally check for null value on object
345: mb.loadContext();
346: mb.loadObject(IMARSHALLABLE_INTERFACE);
347: mb.appendCallInterface(GETINDEX_METHOD, GETINDEX_SIGNATURE);
348: mb.loadObject();
349: mb.appendCallVirtual("java.lang.Object.getClass",
350: "()Ljava/lang/Class;");
351: mb.appendCallVirtual("java.lang.Class.getName",
352: "()Ljava/lang/String;");
353: mb.appendCallInterface(GETMARSHALLER_METHOD,
354: GETMARSHALLER_SIGNATURE);
355: mb.appendDUP();
356: mb.appendLoadConstant(getIndex());
357: mb.appendCallInterface(CHECKEXTENDS_METHOD,
358: CHECKEXTENDS_SIGNATURE);
359: BranchWrapper ifvalid = mb.appendIFNE(this );
360:
361: // generate and throw exception describing the problem
362: mb.appendCreateNew("java.lang.StringBuffer");
363: mb.appendDUP();
364: mb.appendLoadConstant("Mapping for type ");
365: mb.appendCallInit("java.lang.StringBuffer",
366: "(Ljava/lang/String;)V");
367: mb.appendDUP();
368: mb.loadObject();
369: mb.appendCallVirtual("java.lang.Object.getClass",
370: "()Ljava/lang/Class;");
371: mb.appendCallVirtual("java.lang.Class.getName",
372: "()Ljava/lang/String;");
373: mb.appendCallVirtual("java.lang.StringBuffer.append",
374: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
375: mb.appendDUP();
376: mb.appendLoadConstant(" must extend abstract mapping for "
377: + "type " + m_class.getClassName());
378: mb.appendCallVirtual("java.lang.StringBuffer.append",
379: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
380: mb.appendCallVirtual("java.lang.StringBuffer.toString",
381: "()Ljava/lang/String;");
382: mb.appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
383: mb.appendDUP_X1();
384: mb.appendSWAP();
385: mb.appendCallInit(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS,
386: MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
387: mb.appendThrow();
388:
389: // for valid extension mapping, just call the marshaller
390: mb.targetNext(ifvalid);
391: mb.loadObject();
392: mb.loadContext();
393: mb.appendCallInterface(MARSHALLERMARSHAL_METHOD,
394: MARSHALLERMARSHAL_SIGNATURE);
395: mb.appendReturn();
396: mb.codeComplete(false);
397: mb.addMethod();
398:
399: // add extended interface to constructed class
400: cf.addInterface(ABSTRACTMARSHALLER_INTERFACE);
401: }
402:
403: /**
404: * Generate the {@link org.jibx.runtime.IMarshaller#isExtension(int)}
405: * method to check if this mapping is extending a particular abstract
406: * mapping.
407: *
408: * @param cf
409: * @param hasname
410: * @throws JiBXException
411: */
412: private void generateIfExtendingCheck(ClassFile cf, boolean hasname)
413: throws JiBXException {
414:
415: // build the method
416: ExceptionMethodBuilder xb = new ExceptionMethodBuilder(
417: CHECKEXTENDS_METHODNAME, CHECKEXTENDS_SIGNATURE, cf,
418: Constants.ACC_PUBLIC | Constants.ACC_FINAL);
419: xb.appendLoadLocal(1);
420: xb.appendLoadConstant(getIndex());
421: xb.appendISUB();
422: ArrayList ifeqs = new ArrayList();
423: ifeqs.add(xb.appendIFEQ(this ));
424: IMapping base = m_baseMapping;
425: while (base != null) {
426: xb.appendLoadLocal(1);
427: xb.appendLoadConstant(base.getIndex());
428: xb.appendISUB();
429: ifeqs.add(xb.appendIFEQ(this ));
430: if (base instanceof MappingDefinition) {
431: base = ((MappingDefinition) base).m_baseMapping;
432: } else {
433: break;
434: }
435: }
436: xb.appendICONST_0();
437: xb.appendReturn("int");
438: for (int i = 0; i < ifeqs.size(); i++) {
439: xb.targetNext((BranchWrapper) ifeqs.get(i));
440: }
441: xb.appendICONST_1();
442: xb.appendReturn("int");
443: xb.codeComplete(false);
444: xb.addMethod();
445: }
446:
447: /**
448: * Generate the {@link org.jibx.runtime.IUnmarshaller#unmarshal(Object,
449: * org.jibx.runtime.IUnmarshallingContext)} method implementation.
450: *
451: * @param cf class to receive method
452: * @param hasattr attribute definition present flag
453: * @param hascont content definition present flag
454: * @param hasname element name defined by this mapping flag
455: * @throws JiBXException
456: */
457: private void generateUnmarshalImplementation(ClassFile cf,
458: boolean hasattr, boolean hascont, boolean hasname)
459: throws JiBXException {
460:
461: // build the unmarshal method for item; this just generates code
462: // to unmarshal attributes and content, first creating an
463: // instance of the class if one was not passed in, then
464: // returning the unmarshalled instance as the value of the call
465: String type = m_class.getClassName();
466: ContextMethodBuilder mb = new ContextMethodBuilder(
467: UNMARSHAL_METHODNAME, Type.OBJECT,
468: UNMARSHAL_METHOD_ARGS, cf, Constants.ACC_PUBLIC
469: | Constants.ACC_FINAL, 1, type, 2,
470: UNMARSHALCONTEXT_INTERFACE);
471: mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
472:
473: // first part of generated code just checks if an object has
474: // been supplied; if it has, this can just go direct to
475: // unmarshalling
476: mb.loadObject();
477: BranchWrapper ifnnull = mb.appendIFNONNULL(this );
478:
479: // check for extension mapping handling required
480: if (m_extensions != null) {
481:
482: // generate name comparison unless an abstract mapping
483: BranchWrapper ifthis = null;
484: if (hasname) {
485:
486: // test if at defined element name
487: mb
488: .addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
489: mb.loadContext();
490: m_name.genPushUriPair(mb);
491: mb.appendCallInterface(UNMARSHAL_ISATMETHOD,
492: UNMARSHAL_ISATSIGNATURE);
493: ifthis = mb.appendIFNE(this );
494: }
495:
496: // build code to check each extension mapping in turn,
497: // keeping an instance of the unmarshaller for the matching
498: // extension
499: BranchWrapper[] iffounds = new BranchWrapper[m_extensions
500: .size()];
501: for (int i = 0; i < iffounds.length; i++) {
502: IMapping map = (IMapping) m_extensions.get(i);
503: mb.loadContext();
504: mb.appendLoadConstant(map.getIndex());
505: mb.appendCallInterface(GETUNMARSHALLER_METHOD,
506: GETUNMARSHALLER_SIGNATURE);
507: mb.appendDUP();
508: mb.loadContext();
509: mb.appendCallInterface(UNMARSHALLERPRESENT_METHOD,
510: UNMARSHALLERPRESENT_SIGNATURE);
511: iffounds[i] = mb.appendIFNE(this );
512: mb.appendPOP();
513: }
514:
515: // generate code to throw exception if no matching extension
516: // found
517: mb.appendCreateNew("java.lang.StringBuffer");
518: mb.appendDUP();
519: mb.appendLoadConstant("Element ");
520: mb.appendCallInit("java.lang.StringBuffer",
521: "(Ljava/lang/String;)V");
522: mb.appendDUP();
523: mb.loadContext(UNMARSHALCONTEXT_CLASS);
524: mb.appendCallVirtual(CURRENTELEMENT_METHOD,
525: CURRENTELEMENT_SIGNATURE);
526: mb.appendCallVirtual("java.lang.StringBuffer.append",
527: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
528: mb.appendDUP();
529: mb.appendLoadConstant(" has no mapping that extends "
530: + m_class.getClassName());
531: mb.appendCallVirtual("java.lang.StringBuffer.append",
532: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
533: mb.appendCallVirtual("java.lang.StringBuffer.toString",
534: "()Ljava/lang/String;");
535: mb.appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
536: mb.appendDUP_X1();
537: mb.appendSWAP();
538: mb.appendCallInit(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS,
539: MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
540: mb.appendThrow();
541: if (iffounds.length > 0) {
542:
543: // finish by calling unmarshaller for extension mapping
544: // found and returning the result with no further
545: // processing
546: mb.initStackState(iffounds[0]);
547: BranchTarget found = mb.appendTargetACONST_NULL();
548: for (int i = 0; i < iffounds.length; i++) {
549: iffounds[i].setTarget(found, mb);
550: }
551: mb.loadContext();
552: mb.appendCallInterface(UNMARSHALLERUNMARSHAL_METHOD,
553: UNMARSHALLERUNMARSHAL_SIGNATURE);
554: mb.appendReturn("java.lang.Object");
555: }
556:
557: // fall into instance creation if this mapping reference
558: if (ifthis != null) {
559: mb.targetNext(ifthis );
560: }
561:
562: } else if (m_isAbstract) {
563:
564: // throw an exception when no instance supplied
565: mb.appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
566: mb.appendDUP();
567: mb
568: .appendLoadConstant("Abstract mapping requires instance to "
569: + "be supplied for class "
570: + m_class.getClassName());
571: mb.appendCallInit(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS,
572: MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
573: mb.appendThrow();
574:
575: }
576: if (hasname) {
577:
578: // just create an instance of the (non-abstract) mapped class
579: genNewInstance(mb);
580: mb.storeObject();
581:
582: }
583:
584: // define unmarshallings for child mappings of this mapping
585: mb.targetNext(ifnnull);
586: ArrayList maps = m_defContext.getMappings();
587: if (maps != null && maps.size() > 0) {
588: for (int i = 0; i < maps.size(); i++) {
589: IMapping map = (IMapping) maps.get(i);
590: if (!map.isAbstract() || map.isBase()) {
591: mb.loadContext(UNMARSHALCONTEXT_CLASS);
592: mb.appendLoadConstant(map.getIndex());
593: NameDefinition mname = map.getName();
594: if (mname == null) {
595: mb.appendACONST_NULL();
596: mb.appendACONST_NULL();
597: } else {
598: map.getName().genPushUriPair(mb);
599: }
600: mb.appendLoadConstant(map.getUnmarshaller()
601: .getName());
602: mb.appendCallVirtual(ADDUNMARSHALLER_METHOD,
603: ADDUNMARSHALLER_SIGNATURE);
604: }
605: }
606: }
607:
608: // load object and cast to type
609: mb.loadObject();
610: mb.appendCreateCast(type);
611:
612: // handle the actual unmarshalling
613: if (hasattr) {
614: m_component.genAttributeUnmarshal(mb);
615: }
616: if (hasattr || !hasname) {
617: mb.loadContext(UNMARSHALCONTEXT_CLASS);
618: mb.appendCallVirtual(PARSERNEXT_METHOD,
619: PARSERNEXT_SIGNATURE);
620: mb.appendPOP();
621: }
622: if (hascont) {
623: m_component.genContentUnmarshal(mb);
624: }
625:
626: // undefine unmarshallings for child mappings of this mapping
627: if (maps != null && maps.size() > 0) {
628: for (int i = 0; i < maps.size(); i++) {
629: IMapping map = (IMapping) maps.get(i);
630: if (!map.isAbstract() || map.isBase()) {
631: mb.loadContext(UNMARSHALCONTEXT_CLASS);
632: mb.appendLoadConstant(map.getIndex());
633: mb.appendCallVirtual(REMOVEUNMARSHALLER_METHOD,
634: REMOVEUNMARSHALLER_SIGNATURE);
635: }
636: }
637: }
638:
639: // finish by returning unmarshalled object reference
640: mb.appendReturn("java.lang.Object");
641: mb.codeComplete(false);
642: mb.addMethod();
643:
644: // add interface if mapped class is directly unmarshallable
645: if (hasname
646: && m_class.getClassFile() == m_class.getMungedFile()) {
647: addIUnmarshallableMethod();
648: }
649: }
650:
651: /**
652: * Generate the {@link
653: * org.jibx.runtime.IUnmarshaller#isPresent(org.jibx.runtime.IUnmarshallingContext)}
654: * method implementation.
655: *
656: * @param cf class to receive method
657: * @param hasname element name defined by this mapping flag
658: * @throws JiBXException
659: */
660: private void generateIsPresent(ClassFile cf, boolean hasname)
661: throws JiBXException {
662:
663: // create the method builder
664: ContextMethodBuilder mb = new ContextMethodBuilder(
665: ISPRESENT_METHODNAME, Type.BOOLEAN,
666: ISPRESENT_METHOD_ARGS, cf, Constants.ACC_PUBLIC
667: | Constants.ACC_FINAL, -1, null, 1,
668: UNMARSHALCONTEXT_INTERFACE);
669:
670: // generate name comparison unless an abstract mapping
671: if (hasname) {
672:
673: // test if at defined element name
674: mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
675: mb.loadContext();
676: m_name.genPushUriPair(mb);
677: mb.appendCallInterface(UNMARSHAL_ISATMETHOD,
678: UNMARSHAL_ISATSIGNATURE);
679: }
680:
681: // check for extension mapping handling required
682: if (m_extensions != null) {
683:
684: // return immediately if this mapping name check successful
685: BranchWrapper ifthis = null;
686: if (hasname) {
687: ifthis = mb.appendIFNE(this );
688: }
689:
690: // build code to check each extension mapping in turn;
691: // return "true" if one matches, or "false" if none do
692: mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
693: BranchWrapper[] iffounds = new BranchWrapper[m_extensions
694: .size()];
695: for (int i = 0; i < iffounds.length; i++) {
696: IMapping map = (IMapping) m_extensions.get(i);
697: mb.loadContext();
698: mb.appendLoadConstant(map.getIndex());
699: mb.appendCallInterface(GETUNMARSHALLER_METHOD,
700: GETUNMARSHALLER_SIGNATURE);
701: mb.loadContext();
702: mb.appendCallInterface(UNMARSHALLERPRESENT_METHOD,
703: UNMARSHALLERPRESENT_SIGNATURE);
704: iffounds[i] = mb.appendIFNE(this );
705: }
706: mb.appendICONST_0();
707: mb.appendReturn("int");
708: mb.initStackState(iffounds[0]);
709: BranchTarget found = mb.appendTargetLoadConstant(1);
710: if (ifthis != null) {
711: ifthis .setTarget(found, mb);
712: }
713: for (int i = 0; i < iffounds.length; i++) {
714: iffounds[i].setTarget(found, mb);
715: }
716:
717: } else if (!hasname) {
718:
719: // mapping with no separate element name, just return "true"
720: mb.appendICONST_1();
721:
722: }
723: mb.appendReturn("int");
724: mb.codeComplete(false);
725: mb.addMethod();
726: }
727:
728: /**
729: * Generate the {@link org.jibx.runtime.IMarshaller#marshal(Object,
730: * org.jibx.runtime.IMarshallingContext)} method implementation.
731: *
732: * @param cf class to receive method
733: * @param hasattr attribute definition present flag
734: * @param hascont content definition present flag
735: * @throws JiBXException
736: */
737: private void generateMarshalImplementation(ClassFile cf,
738: boolean hasattr, boolean hascont) throws JiBXException {
739:
740: // build the marshal implementation method; this loads the
741: // passed object and casts it to the target type, then handles
742: // marshalling first attributes and followed by content for the
743: // item
744: ContextMethodBuilder mb = new ContextMethodBuilder(
745: MARSHAL_METHODNAME, Type.VOID, MARSHAL_METHOD_ARGS, cf,
746: Constants.ACC_PUBLIC | Constants.ACC_FINAL, 1,
747: "java.lang.Object", 2, MARSHALCONTEXT_INTERFACE);
748: mb.addException(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS);
749: // TODO: optionally check for null value on object
750:
751: // define marshallings for child mappings of this mapping
752: ArrayList maps = m_defContext.getMappings();
753: if (maps != null && maps.size() > 0) {
754: for (int i = 0; i < maps.size(); i++) {
755: IMapping map = (IMapping) maps.get(i);
756: if (!map.isAbstract() || map.isBase()) {
757: mb.loadContext(MARSHALCONTEXT_CLASS);
758: mb.appendLoadConstant(map.getIndex());
759: mb
760: .appendLoadConstant(map.getMarshaller()
761: .getName());
762: mb.appendCallVirtual(ADDMARSHALLER_METHOD,
763: ADDMARSHALLER_SIGNATURE);
764: }
765: }
766: }
767:
768: // handle the actual marshalling
769: if (hasattr || hascont) {
770: mb.loadObject(m_class.getClassName());
771: if (hasattr) {
772: if (hascont) {
773: mb.appendDUP();
774: }
775: m_component.genAttributeMarshal(mb);
776: }
777: if (hasattr || m_isAbstract) {
778: mb.loadContext(MARSHALCONTEXT_CLASS);
779: mb.appendCallVirtual(CLOSESTART_METHOD,
780: CLOSESTART_SIGNATURE);
781: mb.appendPOP();
782: }
783: if (hascont) {
784: m_component.genContentMarshal(mb);
785: }
786: }
787:
788: // undefine marshallings for child mappings of this mapping
789: if (maps != null && maps.size() > 0) {
790: for (int i = 0; i < maps.size(); i++) {
791: IMapping map = (IMapping) maps.get(i);
792: if (!map.isAbstract() || map.isBase()) {
793: mb.loadContext(MARSHALCONTEXT_CLASS);
794: mb.appendLoadConstant(map.getIndex());
795: mb.appendCallVirtual(REMOVEMARSHALLER_METHOD,
796: REMOVEMARSHALLER_SIGNATURE);
797: }
798: }
799: }
800:
801: // finish with plain return
802: mb.appendReturn();
803: mb.codeComplete(false);
804: mb.addMethod();
805: }
806:
807: public void generateCode(boolean force) throws JiBXException {
808:
809: // first call code generation for child mappings
810: m_defContext.generateCode(false, false);
811: if (!force && m_isAbstract && m_extensions == null) {
812: return;
813: }
814:
815: // create the helper class
816: BindingDefinition def = m_container.getBindingRoot();
817: String init = m_class.deriveClassName(def.getPrefix(),
818: ADAPTERCLASS_SUFFIX);
819: String name = init;
820: int loop = 0;
821: while (ClassCache.hasClassFile(name)) {
822: name = init + ++loop;
823: }
824: ClassFile base = ClassCache.getClassFile("java.lang.Object");
825: String[] intfs = def.isInput() ? (def.isOutput() ? BOTH_INTERFACES
826: : UNMARSHALLER_INTERFACES)
827: : MARSHALLER_INTERFACES;
828: ClassFile cf = new ClassFile(name, m_class.getMungedFile()
829: .getRoot(), base, Constants.ACC_PUBLIC, intfs);
830: cf.addDefaultConstructor();
831:
832: // add marshaller/unmarshaller implementation methods
833: boolean hasattr = m_component.hasAttribute();
834: boolean hascont = m_component.hasContent();
835: boolean hasname = !m_isAbstract && m_name != null;
836: if (def.isInput()) {
837: generateIsPresent(cf, hasname);
838: generateUnmarshalImplementation(cf, hasattr, hascont,
839: hasname);
840: }
841: if (def.isOutput()) {
842:
843: // generate the basic method
844: generateMarshalImplementation(cf, hasattr, hascont);
845: generateIfExtendingCheck(cf, hasname);
846:
847: // add interface if mapped class is directly marshallable
848: if (hasname
849: && m_class.getClassFile() == m_class
850: .getMungedFile()) {
851: addIMarshallableMethod();
852: }
853:
854: // check for mapping with extensions to add extra method and
855: // interface
856: if (m_extensions != null) {
857: generateAbstractMarshaller(cf);
858: }
859: }
860:
861: // add as generated class
862: m_marshaller = m_unmarshaller = MungedClass
863: .getUniqueSupportClass(cf);
864: }
865:
866: public NameDefinition getWrapperName() {
867: return m_name;
868: }
869:
870: public void setLinkages() throws JiBXException {
871: m_component.setLinkages();
872: m_defContext.setLinkages();
873: if (m_name != null) {
874: m_name.fixNamespace(m_defContext);
875: }
876: }
877:
878: // DEBUG
879: public void print(int depth) {
880: BindingDefinition.indent(depth);
881: System.out.print("mapping class "
882: + m_class.getClassFile().getName());
883: if (m_name != null) {
884: System.out.print(" to element " + m_name.toString());
885: }
886: System.out.print(" (#" + getIndex() + ')');
887: if (m_baseMapping != null) {
888: System.out
889: .print(" extends " + m_baseMapping.getBoundType());
890: }
891: if (m_isAbstract) {
892: if (m_extensions != null) {
893: System.out.print(" (abstract, " + m_extensions.size()
894: + " extensions)");
895: } else {
896: System.out.print(" (abstract)");
897: }
898: }
899: System.out.println();
900: m_defContext.print(depth + 1);
901: m_component.print(depth + 1);
902: }
903: }
|