001: /*
002: Copyright (c) 2003-2005, 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:
037: /**
038: * Attribute or simple content value definition from binding. This organizes
039: * information for anything that can be converted to and from a simple
040: * <code>String</code>. Content values include both elements with only character
041: * data content and text, as character data content or CDATA sections.
042: *
043: * @author Dennis M. Sosnoski
044: * @version 1.0
045: */
046:
047: public class ValueChild implements IComponent {
048: //
049: // Ident type enumeration.
050:
051: /*package*/static final int DIRECT_IDENT = 0;
052: /*package*/static final int AUTO_IDENT = 1;
053: /*package*/static final int DEF_IDENT = 2;
054: /*package*/static final int REF_IDENT = 3;
055:
056: //
057: // Value style enumeration.
058:
059: /*package*/static final int ATTRIBUTE_STYLE = 0;
060: /*package*/static final int ELEMENT_STYLE = 1;
061: /*package*/static final int TEXT_STYLE = 2;
062: /*package*/static final int CDATA_STYLE = 3;
063:
064: //
065: // Constants for unmarshalling.
066:
067: /** Prefix used for backfill classes. */
068: private static final String BACKFILL_SUFFIX = "_backfill_";
069:
070: private static final String[] BACKFILL_INTERFACES = { "org.jibx.runtime.impl.BackFillReference" };
071: private static final String BACKFILL_METHODNAME = "backfill";
072: private static final Type[] BACKFILL_METHODARGS = { Type.OBJECT };
073: private static final String BOUNDREF_NAME = "m_obj";
074: private static final String CHECK_ELEMENT_NAME = "org.jibx.runtime.impl.UnmarshallingContext.isAt";
075: private static final String CHECK_ATTRIBUTE_NAME = "org.jibx.runtime.impl.UnmarshallingContext.hasAttribute";
076: private static final String CHECK_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)Z";
077: private static final String UNMARSHAL_DEFREF_ATTR_NAME = "org.jibx.runtime.impl.UnmarshallingContext.attributeExistingIDREF";
078: private static final String UNMARSHAL_DEFREF_ELEM_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseElementExistingIDREF";
079: private static final String UNMARSHAL_FWDREF_ATTR_NAME = "org.jibx.runtime.impl.UnmarshallingContext.attributeForwardIDREF";
080: private static final String UNMARSHAL_FWDREF_ELEM_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseElementForwardIDREF";
081: private static final String UNMARSHAL_DEFREF_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/Object;";
082: private static final String REGISTER_BACKFILL_NAME = "org.jibx.runtime.impl.UnmarshallingContext.registerBackFill";
083: private static final String REGISTER_BACKFILL_SIGNATURE = "(ILorg/jibx/runtime/impl/BackFillReference;)V";
084: private static final String DEFINE_ID_NAME = "org.jibx.runtime.impl.UnmarshallingContext.defineID";
085: private static final String DEFINE_ID_SIGNATURE = "(Ljava/lang/String;ILjava/lang/Object;)V";
086: private static final String UNMARSHAL_TEXT_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseContentText";
087: private static final String UNMARSHAL_TEXT_SIGNATURE = "()Ljava/lang/String;";
088: private static final String UNMARSHAL_ELEMENT_TEXT_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseElementText";
089: private static final String UNMARSHAL_ELEMENT_TEXT_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
090: private static final String UNMARSHAL_PARSE_IF_START_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseIfStartTag";
091: private static final String UNMARSHAL_PARSE_IF_START_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)Z";
092: private static final String UNMARSHAL_PARSE_TO_START_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parseToStartTag";
093: private static final String UNMARSHAL_PARSE_TO_START_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)V";
094: private static final String UNMARSHAL_PARSE_PAST_END_NAME = "org.jibx.runtime.impl.UnmarshallingContext.parsePastEndTag";
095: private static final String UNMARSHAL_PARSE_PAST_END_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;)V";
096: private static final String MARSHAL_TEXT_NAME = "org.jibx.runtime.impl.MarshallingContext.writeContent";
097: private static final String MARSHAL_CDATA_NAME = "org.jibx.runtime.impl.MarshallingContext.writeCData";
098: private static final String MARSHAL_TEXT_SIGNATURE = "(Ljava/lang/String;)Lorg/jibx/runtime/impl/MarshallingContext;";
099: private static final String UNMARSHALLING_THROWEXCEPTION_METHOD = "org.jibx.runtime.impl.UnmarshallingContext.throwException";
100: private static final String UNMARSHALLING_THROWEXCEPTION_SIGNATURE = "(Ljava/lang/String;)V";
101: protected static final String MARSHAL_ATTRIBUTE = "org.jibx.runtime.impl.MarshallingContext.attribute";
102: protected static final String MARSHAL_ELEMENT = "org.jibx.runtime.impl.MarshallingContext.element";
103: protected static final String MARSHAL_SIGNATURE = "(ILjava/lang/String;Ljava/lang/String;)"
104: + "Lorg/jibx/runtime/impl/MarshallingContext;";
105: protected static final String MARSHAL_STARTTAG_ATTRIBUTES = "org.jibx.runtime.impl.MarshallingContext.startTagAttributes";
106: protected static final String MARSHAL_STARTTAG_SIGNATURE = "(ILjava/lang/String;)Lorg/jibx/runtime/impl/MarshallingContext;";
107: protected static final String MARSHAL_CLOSESTART_EMPTY = "org.jibx.runtime.impl.MarshallingContext.closeStartEmpty";
108: protected static final String MARSHAL_CLOSESTART_EMPTY_SIGNATURE = "()Lorg/jibx/runtime/impl/MarshallingContext;";
109: protected static final String UNMARSHAL_ATTRIBUTE_BOOLEAN_NAME = "org.jibx.runtime.impl.UnmarshallingContext.attributeBoolean";
110: protected static final String UNMARSHAL_ATTRIBUTE_BOOLEAN_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;Z)Z";
111:
112: //
113: // Actual instance data
114:
115: /** Containing binding definition structure. */
116: private final IContainer m_container;
117:
118: /** Containing object context. */
119: private final IContextObj m_objContext;
120:
121: /** Value style code. */
122: private final int m_valueStyle;
123:
124: /** Constant value. */
125: private final String m_constantValue;
126:
127: /** Ident type code. */
128: private final int m_identType;
129:
130: /** Attribute or element name information. */
131: private final NameDefinition m_name;
132:
133: /** Fully qualified name of type. */
134: private final String m_type;
135:
136: /** Nillable element flag. */
137: private final boolean m_isNillable;
138:
139: /** Linked property information. */
140: private final PropertyDefinition m_property;
141:
142: /** Conversion handling for value. */
143: private final StringConversion m_conversion;
144:
145: /** Mapping definition for object class supplying identifier. */
146: private IMapping m_idRefMap;
147:
148: /**
149: * Constructor. Saves the context information for later use.
150: *
151: * @param contain containing binding definition structure
152: * @param objc containing object context
153: * @param name element or attribute name information (may be
154: * <code>null</code>)
155: * @param prop property reference information
156: * @param conv string conversion handler
157: * @param style value style code
158: * @param ident identifier type code
159: * @param constant value for constant
160: * @param nillable nillable element flag
161: */
162: public ValueChild(IContainer contain, IContextObj objc,
163: NameDefinition name, PropertyDefinition prop,
164: StringConversion conv, int style, int ident,
165: String constant, boolean nillable) {
166: m_container = contain;
167: m_objContext = objc;
168: m_name = name;
169: m_property = prop;
170: m_type = prop.getTypeName();
171: m_conversion = conv;
172: m_valueStyle = style;
173: m_identType = ident;
174: m_constantValue = constant;
175: m_isNillable = nillable;
176: }
177:
178: /**
179: * Create backfill handler class if it does not already exist. This either
180: * looks up the existing backfill handler class or creates a new one
181: * specifically for this value.
182: *
183: * @return backfill handler class for value
184: * @throws JiBXException if error in configuration
185: */
186:
187: private ClassFile createBackfillClass() throws JiBXException {
188:
189: // create the new class
190: BoundClass bc = m_objContext.getBoundClass();
191: BindingDefinition def = m_container.getBindingRoot();
192: String name = bc.getClassFile()
193: .deriveClassName(def.getPrefix(),
194: BACKFILL_SUFFIX + m_property.getName());
195: ClassFile base = ClassCache.getClassFile("java.lang.Object");
196: ClassFile cf = new ClassFile(name, bc.getClassFile().getRoot(),
197: base, Constants.ACC_PUBLIC, BACKFILL_INTERFACES);
198:
199: // add member variable for bound class reference
200: String type = bc.getClassFile().getName();
201: ClassItem ref = cf.addPrivateField(type, BOUNDREF_NAME);
202:
203: // add the constructor taking bound class reference
204: Type[] args = new Type[] { ClassItem.typeFromName(type) };
205: MethodBuilder mb = new ExceptionMethodBuilder("<init>",
206: Type.VOID, args, cf, (short) 0);
207:
208: // call the superclass constructor
209: mb.appendLoadLocal(0);
210: mb.appendCallInit("java.lang.Object", "()V");
211:
212: // store bound class reference to member variable
213: mb.appendLoadLocal(0);
214: mb.appendLoadLocal(1);
215: mb.appendPutField(ref);
216: mb.appendReturn();
217: mb.codeComplete(false);
218: mb.addMethod();
219:
220: // add actual backfill interface implementation method
221: mb = new ExceptionMethodBuilder(BACKFILL_METHODNAME, Type.VOID,
222: BACKFILL_METHODARGS, cf, Constants.ACC_PUBLIC);
223: mb.appendLoadLocal(0);
224: mb.appendGetField(ref);
225: mb.appendLoadLocal(1);
226: mb.appendCreateCast(m_property.getSetValueType());
227: m_property.genStore(mb);
228: mb.appendReturn();
229: mb.codeComplete(false);
230: mb.addMethod();
231:
232: // return unique instance of class
233: return MungedClass.getUniqueSupportClass(cf);
234: }
235:
236: /**
237: * Generate unmarshalling code for object identifier reference. The code
238: * generated by this method assumes the unmarshalling context and name have
239: * already been loaded to the stack, and these are consumed by the code.
240: *
241: * @param mb method builder
242: * @throws JiBXException if error in configuration
243: */
244:
245: private void genParseIdRef(ContextMethodBuilder mb)
246: throws JiBXException {
247:
248: // first part of generated instruction sequence is to check if optional
249: // value is present
250: BranchWrapper ifmiss = null;
251: if (m_property.isOptional()) {
252:
253: // use existing context reference and name information to check for
254: // attribute or element present
255: String name = m_valueStyle == ValueChild.ATTRIBUTE_STYLE ? CHECK_ATTRIBUTE_NAME
256: : CHECK_ELEMENT_NAME;
257: mb.appendCallVirtual(name, CHECK_SIGNATURE);
258: BranchWrapper ifpres = mb.appendIFNE(this );
259:
260: // push a null value to be stored as result for missing case
261: mb.appendACONST_NULL();
262: ifmiss = mb.appendUnconditionalBranch(this );
263:
264: // reload context reference and name information for use by actual
265: // unmarshalling call
266: mb.targetNext(ifpres);
267: mb.loadContext();
268: m_name.genPushUriPair(mb);
269:
270: }
271:
272: // find index of target class ID map
273: int index = m_container.getBindingRoot().getIdClassIndex(
274: m_property.getTypeName());
275:
276: // check if forward references allowed
277: if (m_container.getBindingRoot().isForwards()) {
278:
279: // generate call to unmarshal with forward allowed
280: mb.appendLoadConstant(index);
281: String name = m_valueStyle == ValueChild.ATTRIBUTE_STYLE ? UNMARSHAL_FWDREF_ATTR_NAME
282: : UNMARSHAL_FWDREF_ELEM_NAME;
283: mb.appendCallVirtual(name, UNMARSHAL_DEFREF_SIGNATURE);
284:
285: // check for null result returned
286: mb.appendDUP();
287: BranchWrapper ifdef = mb.appendIFNONNULL(this );
288:
289: // build and register backfill handler; start by loading the
290: // unmarshalling context, then load the index number of the target
291: // class and create an instance of the backfill handler
292: ClassFile backclas = createBackfillClass();
293: mb.loadContext();
294: mb.appendLoadConstant(index);
295: mb.appendCreateNew(backclas.getName());
296:
297: // duplicate the backfill handler reference, then load a reference
298: // to the owning object and call the initializer before calling
299: // the unmarshalling context to register the handler
300: mb.appendDUP();
301: mb.loadObject();
302: mb.appendCallInit(backclas.getName(), "("
303: + m_objContext.getBoundClass().getClassFile()
304: .getSignature() + ")V");
305: mb.appendCallVirtual(REGISTER_BACKFILL_NAME,
306: REGISTER_BACKFILL_SIGNATURE);
307:
308: // set branch target for case where already defined
309: mb.targetNext(ifdef);
310:
311: } else {
312:
313: // generate call to unmarshal with predefined ID required
314: mb.appendLoadConstant(index);
315: String name = m_valueStyle == ValueChild.ATTRIBUTE_STYLE ? UNMARSHAL_DEFREF_ATTR_NAME
316: : UNMARSHAL_DEFREF_ELEM_NAME;
317: mb.appendCallVirtual(name, UNMARSHAL_DEFREF_SIGNATURE);
318: }
319:
320: // handle object type conversion if needed
321: mb.appendCreateCast(m_property.getSetValueType());
322:
323: // store returned reference to property
324: if (ifmiss != null) {
325: mb.targetNext(ifmiss);
326: }
327: m_property.genStore(mb);
328: }
329:
330: /**
331: * Generate test if present code. This generates code that tests if the
332: * child is present, leaving the result of the test (zero if missing,
333: * nonzero if present) on the stack.
334: *
335: * @param mb unmarshal method builder
336: * @throws JiBXException if configuration error
337: */
338:
339: public void genIfPresentTest(UnmarshalBuilder mb)
340: throws JiBXException {
341:
342: // make sure this is an appropriate call
343: if (m_name == null) {
344: throw new JiBXException("Method call on invalid value");
345: }
346:
347: // load the unmarshalling context and name information, then call the
348: // appropriate method to test for item present
349: mb.loadContext();
350: m_name.genPushUriPair(mb);
351: String name = (m_valueStyle == ValueChild.ATTRIBUTE_STYLE) ? CHECK_ATTRIBUTE_NAME
352: : CHECK_ELEMENT_NAME;
353: mb.appendCallVirtual(name, CHECK_SIGNATURE);
354: }
355:
356: /**
357: * Generate unmarshalling code. This internal method generates the
358: * necessary code for handling the unmarshalling operation. The code
359: * generated by this method restores the stack to the original state
360: * when done.
361: *
362: * @param mb method builder
363: * @throws JiBXException if error in configuration
364: */
365:
366: private void genUnmarshal(ContextMethodBuilder mb)
367: throws JiBXException {
368:
369: // first part of generated instruction sequence is to preload object
370: // reference for later use, then load the unmarshalling context and
371: // the name information
372: if (m_constantValue == null && !m_property.isImplicit()) {
373: mb.loadObject();
374: }
375:
376: // prepare for parsing the element name
377: mb.loadContext();
378: if (m_name != null) {
379: m_name.genPushUriPair(mb);
380: }
381:
382: // check if this is an identifier for object
383: boolean isatt = (m_valueStyle == ValueChild.ATTRIBUTE_STYLE);
384: if (m_identType == DEF_IDENT || m_identType == AUTO_IDENT) {
385:
386: // always unmarshal identifier value as text, then duplicate for use
387: // if storing
388: BindingDefinition.s_stringConversion.genParseRequired(
389: isatt, mb);
390: if (m_identType != AUTO_IDENT) {
391: mb.appendDUP();
392: }
393:
394: // load the context and swap to reorder, load the index for the
395: // class, and finally the ID'ed object, then call ID definition
396: // method
397: mb.loadContext();
398: mb.appendSWAP();
399: int index = m_container.getBindingRoot().getIdClassIndex(
400: m_property.getTypeName());
401: mb.appendLoadConstant(index);
402: mb.loadObject();
403: mb.appendCallVirtual(DEFINE_ID_NAME, DEFINE_ID_SIGNATURE);
404:
405: // convert from text and store result using object reference loaded
406: // earlier
407: if (m_identType != AUTO_IDENT) {
408: m_conversion.genFromText(mb);
409: m_property.genStore(mb);
410: }
411:
412: } else if (m_identType == REF_IDENT) {
413:
414: // generate code for unmarshalling object ID
415: genParseIdRef(mb);
416:
417: } else if (m_constantValue == null) {
418:
419: // unmarshal and convert value
420: if (m_isNillable) {
421:
422: // first check for element present at all
423: BranchWrapper ifmiss = null;
424: if (m_property.isOptional()) {
425: mb.appendCallVirtual(UNMARSHAL_PARSE_IF_START_NAME,
426: UNMARSHAL_PARSE_IF_START_SIGNATURE);
427: ifmiss = mb.appendIFEQ(this );
428: } else {
429: mb.appendCallVirtual(UNMARSHAL_PARSE_TO_START_NAME,
430: UNMARSHAL_PARSE_TO_START_SIGNATURE);
431: }
432:
433: // check for xsi:nil="true"
434: mb.loadContext();
435: mb
436: .appendLoadConstant("http://www.w3.org/2001/XMLSchema-instance");
437: mb.appendLoadConstant("nil");
438: mb.appendICONST_0();
439: mb.appendCallVirtual(UNMARSHAL_ATTRIBUTE_BOOLEAN_NAME,
440: UNMARSHAL_ATTRIBUTE_BOOLEAN_SIGNATURE);
441: BranchWrapper notnil = mb.appendIFEQ(this );
442:
443: // code to handle nil case just parses past end
444: mb.loadContext();
445: m_name.genPushUriPair(mb);
446: mb.appendCallVirtual(UNMARSHAL_PARSE_PAST_END_NAME,
447: UNMARSHAL_PARSE_PAST_END_SIGNATURE);
448:
449: // merge path with element not present, which just loads null
450: mb.targetNext(ifmiss);
451: mb.appendACONST_NULL();
452: BranchWrapper ifnil = mb
453: .appendUnconditionalBranch(this );
454:
455: // read element text and process for not-nil case
456: mb.targetNext(notnil);
457: mb.loadContext();
458: m_name.genPushUriPair(mb);
459: mb.appendCallVirtual(UNMARSHAL_ELEMENT_TEXT_NAME,
460: UNMARSHAL_ELEMENT_TEXT_SIGNATURE);
461: m_conversion.genFromText(mb);
462: mb.targetNext(ifnil);
463:
464: } else if (m_valueStyle == ValueChild.TEXT_STYLE
465: || m_valueStyle == ValueChild.CDATA_STYLE) {
466:
467: // unmarshal text value directly and let handler convert
468: mb.appendCallVirtual(UNMARSHAL_TEXT_NAME,
469: UNMARSHAL_TEXT_SIGNATURE);
470: m_conversion.genFromText(mb);
471:
472: } else if (m_property.isOptional()
473: && (isatt || m_container.isContentOrdered())) {
474:
475: // parse value with possible default in ordered container
476: m_conversion.genParseOptional(isatt, mb);
477:
478: } else {
479:
480: // parse required value, or value in unordered container
481: m_conversion.genParseRequired(isatt, mb);
482:
483: }
484:
485: // handle object type conversion if needed
486: if (!m_conversion.isPrimitive() && m_property != null) {
487: String stype = m_conversion.getTypeName();
488: String dtype = m_property.getSetValueType();
489: mb.appendCreateCast(stype, dtype);
490: }
491:
492: // store result using object reference loaded earlier
493: m_property.genStore(mb);
494:
495: } else {
496:
497: // unmarshal and compare value
498: BranchWrapper ifmiss = null;
499: if (m_valueStyle == ValueChild.TEXT_STYLE
500: || m_valueStyle == ValueChild.CDATA_STYLE) {
501:
502: // unmarshal text value directly and let handler convert
503: mb.appendCallVirtual(UNMARSHAL_TEXT_NAME,
504: UNMARSHAL_TEXT_SIGNATURE);
505:
506: } else if (m_property.isOptional()
507: && (isatt || m_container.isContentOrdered())) {
508:
509: // parse optional attribute or element value
510: m_conversion.genParseOptional(isatt, mb);
511: mb.appendDUP();
512: ifmiss = mb.appendIFNULL(this );
513:
514: } else {
515:
516: // parse required attribute or element value
517: m_conversion.genParseRequired(isatt, mb);
518: }
519:
520: // compare unmarshalled value with required constant
521: mb.appendDUP();
522: mb.appendLoadConstant(m_constantValue);
523: mb.appendCallVirtual("java.lang.String.equals",
524: "(Ljava/lang/Object;)Z");
525: BranchWrapper ifmatch = mb.appendIFNE(this );
526:
527: // throw exception on comparison error
528: mb.appendCreateNew("java.lang.StringBuffer");
529: mb.appendDUP();
530: mb.appendLoadConstant("Expected constant value \""
531: + m_constantValue + "\", found \"");
532: mb.appendCallInit("java.lang.StringBuffer",
533: "(Ljava/lang/String;)V");
534: mb.appendSWAP();
535: mb.appendCallVirtual("java.lang.StringBuffer.append",
536: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
537: mb.appendLoadConstant("\"");
538: mb.appendCallVirtual("java.lang.StringBuffer.append",
539: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
540: mb.appendCallVirtual("java.lang.StringBuffer.toString",
541: "()Ljava/lang/String;");
542: mb.loadContext();
543: mb.appendSWAP();
544: mb.appendCallVirtual(UNMARSHALLING_THROWEXCEPTION_METHOD,
545: UNMARSHALLING_THROWEXCEPTION_SIGNATURE);
546: mb.appendACONST_NULL();
547:
548: // finish by setting target for branch
549: mb.targetNext(ifmatch);
550: mb.targetNext(ifmiss);
551: mb.appendPOP();
552: }
553: }
554:
555: /**
556: * Generate marshalling code. This internal method generates the
557: * necessary code for handling the marshalling operation. The code
558: * generated by this method restores the stack to the original state
559: * when done.
560: *
561: * @param mb method builder
562: * @throws JiBXException if error in configuration
563: */
564:
565: private void genMarshal(ContextMethodBuilder mb)
566: throws JiBXException {
567: if (m_constantValue == null) {
568:
569: // first part of generated instruction sequence is to generate a
570: // check for an optional property present, then load the context
571: // and the name information (if present) for later use, then
572: // finally load the actual property value
573: BranchWrapper ifmiss = null;
574: if (m_property.hasTest()) {
575: mb.loadObject();
576: ifmiss = m_property.genTest(mb);
577: } else if (m_isNillable) {
578:
579: // check for null object
580: BranchWrapper ifhit;
581: if (m_property.isImplicit()) {
582: mb.appendDUP();
583: ifhit = mb.appendIFNONNULL(this );
584: mb.appendPOP();
585: } else {
586: mb.loadObject();
587: m_property.genLoad(mb);
588: ifhit = mb.appendIFNONNULL(this );
589: }
590:
591: // generate empty element with xsi:nil="true"
592: mb.loadContext();
593: m_name.genPushIndexPair(mb);
594: mb.appendCallVirtual(MARSHAL_STARTTAG_ATTRIBUTES,
595: MARSHAL_STARTTAG_SIGNATURE);
596: mb.appendLoadConstant(2);
597: mb.appendLoadConstant("nil");
598: mb.appendLoadConstant("true");
599: mb.appendCallVirtual(MARSHAL_ATTRIBUTE,
600: MARSHAL_SIGNATURE);
601: mb.appendCallVirtual(MARSHAL_CLOSESTART_EMPTY,
602: MARSHAL_CLOSESTART_EMPTY_SIGNATURE);
603: mb.appendPOP();
604: ifmiss = mb.appendUnconditionalBranch(this );
605: mb.targetNext(ifhit);
606:
607: }
608: String type = m_property.getTypeName();
609: if (m_name != null) {
610:
611: // handle implicit property by first saving value to local, then
612: // reloading after the name information is on the stack
613: Type tobj = ClassItem.typeFromName(type);
614: if (m_property.isImplicit()) {
615: mb.defineSlot(this , tobj);
616: }
617: m_name.genPushIndexPair(mb);
618: if (m_property.isImplicit()) {
619: mb.appendLoadLocal(mb.getSlot(this ));
620: mb.freeSlot(this );
621: }
622: }
623: if (!m_property.isImplicit()) {
624: mb.loadObject();
625: m_property.genLoad(mb);
626: }
627:
628: // check for object identity definition (accessed through property)
629: StringConversion convert = m_conversion;
630: if (m_identType == REF_IDENT) {
631: m_idRefMap.getImplComponent().genLoadId(mb);
632: convert = BindingDefinition.s_stringConversion;
633: type = "java.lang.String";
634: }
635:
636: // convert to expected type if object
637: if (!ClassItem.isPrimitive(type)) {
638: mb.appendCreateCast(type);
639: }
640:
641: // convert and marshal value
642: boolean isatt = m_valueStyle == ValueChild.ATTRIBUTE_STYLE;
643: if (m_valueStyle == ValueChild.TEXT_STYLE
644: || m_valueStyle == ValueChild.CDATA_STYLE) {
645: convert.genToText(type, mb);
646: String name = (m_valueStyle == ValueChild.TEXT_STYLE) ? MARSHAL_TEXT_NAME
647: : MARSHAL_CDATA_NAME;
648: mb.appendCallVirtual(name, MARSHAL_TEXT_SIGNATURE);
649: } else if (m_property.isOptional()) {
650: convert.genWriteOptional(isatt, type, mb);
651: } else {
652: convert.genWriteRequired(isatt, type, mb);
653: }
654:
655: // finish by setting target for missing optional property test
656: mb.targetNext(ifmiss);
657:
658: } else {
659:
660: // just write constant value directly
661: if (m_name != null) {
662: m_name.genPushIndexPair(mb);
663: }
664: mb.appendLoadConstant(m_constantValue);
665: switch (m_valueStyle) {
666: case ATTRIBUTE_STYLE:
667: mb.appendCallVirtual(MARSHAL_ATTRIBUTE,
668: MARSHAL_SIGNATURE);
669: break;
670: case ELEMENT_STYLE:
671: mb
672: .appendCallVirtual(MARSHAL_ELEMENT,
673: MARSHAL_SIGNATURE);
674: break;
675: case TEXT_STYLE:
676: mb.appendCallVirtual(MARSHAL_TEXT_NAME,
677: MARSHAL_TEXT_SIGNATURE);
678: break;
679: case CDATA_STYLE:
680: mb.appendCallVirtual(MARSHAL_CDATA_NAME,
681: MARSHAL_TEXT_SIGNATURE);
682: break;
683: }
684: }
685: }
686:
687: /**
688: * Get property name. If the child has an associated property this returns
689: * the name of that property.
690: *
691: * @return name for child property
692: */
693:
694: public String getPropertyName() {
695: if (m_property == null) {
696: return null;
697: } else {
698: return m_property.getName();
699: }
700: }
701:
702: /**
703: * Check if implicit.
704: *
705: * @return <code>true</code> if implicit, <code>false</code> if not
706: */
707: public boolean isImplicit() {
708: return m_property.isThis();
709: }
710:
711: /**
712: * Switch property from "this" to "implicit".
713: */
714: public void switchProperty() {
715: m_property.switchProperty();
716: }
717:
718: //
719: // IComponent interface method definitions
720:
721: public boolean isOptional() {
722: return m_property.isOptional();
723: }
724:
725: public boolean hasAttribute() {
726: return m_valueStyle == ATTRIBUTE_STYLE;
727: }
728:
729: public void genAttrPresentTest(ContextMethodBuilder mb)
730: throws JiBXException {
731:
732: // make sure this is an appropriate call
733: if (m_valueStyle != ATTRIBUTE_STYLE || m_name == null) {
734: throw new JiBXException("Method call on invalid structure");
735: }
736:
737: // generate load of the unmarshalling context and the name information,
738: // then just call the attribute check method
739: mb.loadContext();
740: m_name.genPushUriPair(mb);
741: mb.appendCallVirtual(CHECK_ATTRIBUTE_NAME, CHECK_SIGNATURE);
742: }
743:
744: public void genAttributeUnmarshal(ContextMethodBuilder mb)
745: throws JiBXException {
746: if (m_valueStyle == ATTRIBUTE_STYLE) {
747: genUnmarshal(mb);
748: }
749: }
750:
751: public void genAttributeMarshal(ContextMethodBuilder mb)
752: throws JiBXException {
753: if (m_valueStyle == ATTRIBUTE_STYLE) {
754: genMarshal(mb);
755: }
756: }
757:
758: public boolean hasContent() {
759: return m_valueStyle != ATTRIBUTE_STYLE;
760: }
761:
762: public void genContentPresentTest(ContextMethodBuilder mb)
763: throws JiBXException {
764:
765: // make sure this is an appropriate call
766: if (m_valueStyle != ELEMENT_STYLE) {
767: throw new JiBXException("Method call on invalid structure");
768: }
769:
770: // generate load of the unmarshalling context and the name information,
771: // then just call the attribute check method
772: mb.loadContext();
773: m_name.genPushUriPair(mb);
774: mb.appendCallVirtual(CHECK_ELEMENT_NAME, CHECK_SIGNATURE);
775: }
776:
777: public void genContentUnmarshal(ContextMethodBuilder mb)
778: throws JiBXException {
779: if (m_valueStyle != ATTRIBUTE_STYLE) {
780: genUnmarshal(mb);
781: }
782: }
783:
784: public void genContentMarshal(ContextMethodBuilder mb)
785: throws JiBXException {
786: if (m_valueStyle != ATTRIBUTE_STYLE) {
787: genMarshal(mb);
788: }
789: }
790:
791: public void genNewInstance(ContextMethodBuilder mb) {
792: throw new IllegalStateException(
793: "Internal error - no instance creation");
794: }
795:
796: public String getType() {
797: return m_type;
798: }
799:
800: public boolean hasId() {
801: return m_identType == DEF_IDENT;
802: }
803:
804: public void genLoadId(ContextMethodBuilder mub)
805: throws JiBXException {
806: m_property.genLoad(mub);
807: }
808:
809: public NameDefinition getWrapperName() {
810: return (m_valueStyle == ELEMENT_STYLE) ? m_name : null;
811: }
812:
813: public void setLinkages() throws JiBXException {
814: if (m_identType == REF_IDENT) {
815: String type;
816: if (m_property == null) {
817: type = m_objContext.getBoundClass().getClassFile()
818: .getName();
819: } else {
820: type = m_property.getTypeName();
821: }
822: m_idRefMap = m_container.getDefinitionContext()
823: .getClassMapping(type);
824: if (m_idRefMap == null) {
825: throw new JiBXException("No mapping defined for "
826: + type + " used as IDREF target");
827: } else if (!m_idRefMap.getImplComponent().hasId()) {
828: throw new JiBXException("No ID value defined for "
829: + type + " used as IDREF target");
830: }
831: }
832: }
833:
834: // DEBUG
835: public void print(int depth) {
836: BindingDefinition.indent(depth);
837: if (m_valueStyle == ELEMENT_STYLE) {
838: System.out.print("element");
839: } else if (m_valueStyle == ATTRIBUTE_STYLE) {
840: System.out.print("attribute");
841: } else if (m_valueStyle == TEXT_STYLE) {
842: System.out.print("text");
843: } else if (m_valueStyle == CDATA_STYLE) {
844: System.out.print("cdata");
845: }
846: if (m_name != null) {
847: System.out.print(" " + m_name.toString());
848: }
849: if (m_property != null) {
850: System.out.print(" from " + m_property.toString());
851: }
852: System.out.println();
853: }
854: }
|