/* Copyright (c) 2003-2007, Dennis M. Sosnoski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of JiBX nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jibx.binding.def; import org.apache.bcel.Constants; import org.apache.bcel.generic.*; import org.jibx.binding.classes.*; import org.jibx.runtime.JiBXException; import org.jibx.runtime.Utility; /** * Binding modifiers that apply to a class reference. This adds the methods used * for handling binding operations to the object class, then generates calls to * the added methods as this binding definition is used. * * @author Dennis M. Sosnoski */ public class ObjectBinding extends PassThroughComponent implements IComponent, IContextObj { // // Constants and such related to code generation. // recognized marshal hook method (pre-get) signatures. private static final String[] MARSHAL_HOOK_SIGNATURES = { "(Lorg/jibx/runtime/IMarshallingContext;)V", "(Ljava/lang/Object;)V", "()V" }; // recognized factory hook method signatures. private static final String[] FACTORY_HOOK_SIGNATURES = { "(Lorg/jibx/runtime/IUnmarshallingContext;)", "(Ljava/lang/Object;)", "()" }; // recognized unmarshal hook method (pre-set, post-set) signatures. private static final String[] UNMARSHAL_HOOK_SIGNATURES = { "(Lorg/jibx/runtime/IUnmarshallingContext;)V", "(Ljava/lang/Object;)V", "()V" }; // definitions used in generating calls to user defined methods private static final String UNMARSHAL_GETSTACKTOPMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.getStackTop"; private static final String MARSHAL_GETSTACKTOPMETHOD = "org.jibx.runtime.impl.MarshallingContext.getStackTop"; private static final String GETSTACKTOP_SIGNATURE = "()Ljava/lang/Object;"; private static final String MARSHALLING_CONTEXT = "org.jibx.runtime.impl.MarshallingContext"; private static final String UNMARSHALLING_CONTEXT = "org.jibx.runtime.impl.UnmarshallingContext"; private static final String UNMARSHAL_PARAMETER_SIGNATURE = "(Lorg/jibx/runtime/impl/UnmarshallingContext;)"; private static final String UNMARSHAL_PUSHOBJECTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.pushObject"; private static final String UNMARSHAL_PUSHTRACKEDOBJECTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.pushTrackedObject"; private static final String MARSHAL_PUSHOBJECTMETHOD = "org.jibx.runtime.impl.MarshallingContext.pushObject"; private static final String PUSHOBJECT_SIGNATURE = "(Ljava/lang/Object;)V"; private static final String UNMARSHAL_POPOBJECTMETHOD = "org.jibx.runtime.impl.UnmarshallingContext.popObject"; private static final String MARSHAL_POPOBJECTMETHOD = "org.jibx.runtime.impl.MarshallingContext.popObject"; private static final String POPOBJECT_SIGNATURE = "()V"; // definitions for methods added to mapped class private static final String NEWINSTANCE_SUFFIX = "_newinstance"; private static final String UNMARSHAL_ATTR_SUFFIX = "_unmarshalAttr"; private static final String MARSHAL_ATTR_SUFFIX = "_marshalAttr"; private static final String UNMARSHAL_SUFFIX = "_unmarshal"; private static final String MARSHAL_SUFFIX = "_marshal"; // definitions for source position tracking private static final String SOURCE_TRACKING_INTERFACE = "org.jibx.runtime.impl.ITrackSourceImpl"; private static final String SETSOURCE_METHODNAME = "jibx_setSource"; private static final Type[] SETSOURCE_ARGS = { Type.STRING, Type.INT, Type.INT }; private static final String SOURCEDOCUMENT_FIELDNAME ="jibx_sourceDocument"; private static final String SOURCELINE_FIELDNAME = "jibx_sourceLine"; private static final String SOURCECOLUMN_FIELDNAME = "jibx_sourceColumn"; private static final String SOURCENAME_METHODNAME = "jibx_getDocumentName"; private static final String SOURCELINE_METHODNAME = "jibx_getLineNumber"; private static final String SOURCECOLUMN_METHODNAME = "jibx_getColumnNumber"; private static final Type[] EMPTY_ARGS = {}; // // Actual instance data. /** Containing binding definition structure. */ private final IContainer m_container; /** Class linked to mapping. */ private BoundClass m_class; /** Object factory method. */ private final ClassItem m_factoryMethod; /** Preset method for object. */ private final ClassItem m_preSetMethod; /** Postset method for object. */ private final ClassItem m_postSetMethod; /** Preget method for object. */ private final ClassItem m_preGetMethod; /** Type to be used for creating new instances. */ private final ClassFile m_createClass; /** Generated new instance method. */ private ClassItem m_newInstanceMethod; /** Flag for recursion while generating attribute unmarshal. */ private boolean m_lockAttributeUnmarshal; /** Flag for recursion while generating attribute marshal. */ private boolean m_lockAttributeMarshal; /** Flag for recursion while generating attribute unmarshal. */ private boolean m_lockContentUnmarshal; /** Flag for recursion while generating attribute marshal. */ private boolean m_lockContentMarshal; /** Signature used for unmarshal methods. */ private String m_unmarshalSignature; /** Name for unmarshal attribute method (null unless generation started). */ private String m_unmarshalAttributeName; /** Name for unmarshal content method (null unless generation started). */ private String m_unmarshalContentName; /** Flag for static unmarshal methods. */ private boolean m_isStaticUnmarshal; /** Flag for static marshal methods. */ private boolean m_isStaticMarshal; /** Signature used for marshal methods. */ private String m_marshalSignature; /** Name for marshal attribute method (null unless generation started). */ private String m_marshalAttributeName; /** Name for marshal content method (null unless generation istarted). */ private String m_marshalContentName; /** Generated unmarshal attribute method. */ private ClassItem m_unmarshalAttributeMethod; /** Generated unmarshal content method. */ private ClassItem m_unmarshalContentMethod; /** Generated marshal attribute method. */ private ClassItem m_marshalAttributeMethod; /** Generated marshal content method. */ private ClassItem m_marshalContentMethod; /** Child supplying instance identifier value. */ private IComponent m_idChild; /** Flag for "this" reference, meaning that there's no separate object * instance created. */ private boolean m_isThisBinding; /** * Constructor. This initializes the definition context to be the same as * the parent's. Subclasses may change this definition context if * appropriate. * * @param contain containing binding definition component * @param objc current object context * @param type fully qualified class name for bound object * @param fact user new instance factory method * @param pres user preset method for unmarshalling * @param posts user postset method for unmarshalling * @param pget user preget method for marshalling * @param ctype type to use for creating new instance (null if * not specified) * @throws JiBXException if method not found */ public ObjectBinding(IContainer contain, IContextObj objc, String type, String fact, String pres, String posts, String pget, String ctype) throws JiBXException { // initialize the basics m_container = contain; BoundClass ctxc = (objc == null) ? null : objc.getBoundClass(); m_class = BoundClass.getInstance(type, ctxc); ClassFile cf = m_class.getClassFile(); if (ctype == null) { m_createClass = cf; } else { m_createClass = ClassCache.getClassFile(ctype); } // check instance creation for unmarshalling if (fact == null) { m_factoryMethod = null; } else { // look up supplied static factory method int split = fact.lastIndexOf('.'); if (split >= 0) { // verify the method is defined String cname = fact.substring(0, split); String mname = fact.substring(split+1); ClassFile mcf = ClassCache.getClassFile(cname); m_factoryMethod = mcf.getMethod(mname, FACTORY_HOOK_SIGNATURES); if (m_factoryMethod == null) { throw new JiBXException("Factory method " + fact + " not found"); } else { // force access if necessary m_factoryMethod.makeAccessible(cf); } } else { m_factoryMethod = null; } if (m_factoryMethod == null) { throw new JiBXException("Factory method " + fact + " not found."); } } // look up other method names as members of class if (pres == null) { m_preSetMethod = null; } else { m_preSetMethod = cf.getMethod(pres, UNMARSHAL_HOOK_SIGNATURES); if (m_preSetMethod == null) { throw new JiBXException("User method " + pres + " not found."); } } if (posts == null) { m_postSetMethod = null; } else { m_postSetMethod = cf.getMethod(posts, UNMARSHAL_HOOK_SIGNATURES); if (m_postSetMethod == null) { throw new JiBXException("User method " + posts + " not found."); } } if (pget == null) { m_preGetMethod = null; } else { m_preGetMethod = cf.getMethod(pget, MARSHAL_HOOK_SIGNATURES); if (m_preGetMethod == null) { throw new JiBXException("User method " + pget + " not found."); } } } /** * Abstract binding copy constructor. This is used to create a variation of * the object binding for a mapping which will be used for "this" * references. The "this" reference handling differs only in the code * generation, where it skips adding the source tracking interfaces and * does not push an instance of the object on the marshalling or * unmarshalling stack (since the object will already be there). This method * is only to be used before code generation. * * @param base original object binding */ public ObjectBinding(ObjectBinding base) { m_container = base.m_container; m_class = base.m_class; m_factoryMethod = null; m_preSetMethod = base.m_preSetMethod; m_postSetMethod = base.m_postSetMethod; m_preGetMethod = base.m_preGetMethod; m_createClass = base.m_createClass; m_idChild = base.m_idChild; m_component = base.m_component; m_isThisBinding = true; } /** * Copy constructor. This is used in handling abstract mappings, where the * properties of the mapping definition object binding need to be copied for * each use of that binding. * * @param contain binding definition component for constructed copy * @param base instance to be copied */ public ObjectBinding(IContainer contain, ObjectBinding base) { m_container = contain; m_class = base.m_class; m_factoryMethod = base.m_factoryMethod; m_preSetMethod = base.m_preSetMethod; m_postSetMethod = base.m_postSetMethod; m_preGetMethod = base.m_preGetMethod; m_newInstanceMethod = base.m_newInstanceMethod; m_unmarshalSignature = base.m_unmarshalSignature; m_unmarshalAttributeName = base.m_unmarshalAttributeName; m_unmarshalContentName = base.m_unmarshalContentName; m_isStaticUnmarshal = base.m_isStaticUnmarshal; m_isStaticMarshal = base.m_isStaticMarshal; m_marshalSignature = base.m_marshalSignature; m_marshalAttributeName = base.m_marshalAttributeName; m_marshalContentName = base.m_marshalAttributeName; m_marshalContentName = base.m_marshalContentName; m_unmarshalAttributeMethod = base.m_unmarshalAttributeMethod; m_unmarshalContentMethod = base.m_unmarshalContentMethod; m_marshalAttributeMethod = base.m_marshalAttributeMethod; m_marshalContentMethod = base.m_marshalContentMethod; m_createClass = base.m_createClass; m_idChild = base.m_idChild; m_component = base.m_component; } /** * Generate code for calling a user supplied method. The object methods * support three signature variations, with no parameters, with the * marshalling or unmarshalling context, or with the owning object. * * @param in flag for unmarshalling method * @param method information for method being called * @param mb method builder for generated code */ private void genUserMethodCall(boolean in, ClassItem method, ContextMethodBuilder mb) { // load object reference for virtual call if (!method.isStatic()) { mb.loadObject(); } // check if parameter required for call if (method.getArgumentCount() > 0) { // generate code to load context, then get containing object if // needed for call mb.loadContext(); String type = method.getArgumentType(0); if ("java.lang.Object".equals(type)) { String name = in ? UNMARSHAL_GETSTACKTOPMETHOD : MARSHAL_GETSTACKTOPMETHOD; mb.appendCallVirtual(name, GETSTACKTOP_SIGNATURE); } } // generate appropriate form of call to user method mb.appendCall(method); mb.addMethodExceptions(method); } /** * Generate code to create an instance of the object for this mapping. This * convenience method generates the actual code for creating an instance of * an object. The generated code leaves the created object reference on the * stack. * * @param mb method builder * @return true if able to create instance, false * if not * @throws JiBXException if error in generating code */ private boolean genNewInstanceCode(ContextMethodBuilder mb) throws JiBXException { // check for factory supplied to create instance if (m_factoryMethod == null) { if (m_createClass.isArray()) { // construct array instance directly with basic size mb.appendLoadConstant(Utility.MINIMUM_GROWN_ARRAY_SIZE); String type = m_createClass.getName(); mb.appendCreateArray(type.substring(0, type.length()-2)); return true; } else if (m_createClass.isInterface()) { // cannot create instance, throw exception mb.appendCreateNew(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS); mb.appendDUP(); mb.appendLoadConstant("Cannot create instance of interface " + m_createClass.getName()); mb.appendCallInit(MethodBuilder.FRAMEWORK_EXCEPTION_CLASS, MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1); mb.appendThrow(); return false; } else { // make sure we have a no argument constructor ClassItem cons = m_createClass.getInitializerMethod("()V"); if (cons == null) { m_createClass.addDefaultConstructor(); } else { cons.makeAccessible(m_class.getMungedFile()); } // no factory, so create an instance, duplicate the // reference, and then call the null constructor mb.appendCreateNew(m_createClass.getName()); mb.appendDUP(); mb.appendCallInit(m_createClass.getName(),"()V"); return true; } } else { // generate call to factory method genUserMethodCall(true, m_factoryMethod, mb); mb.appendCreateCast(m_factoryMethod.getTypeName(), m_class.getClassName()); return true; } } /** * Generate call to new instance creation method for object. This * convenience method just generates code to call the generated new * instance method added to the class definition. * * @param mb method builder * @throws JiBXException if error in configuration */ private void genNewInstanceCall(ContextMethodBuilder mb) throws JiBXException { // check if new instance method needs to be added to class if (m_newInstanceMethod == null) { // set up for constructing new method String name = m_container.getBindingRoot().getPrefix() + NEWINSTANCE_SUFFIX; String sig = UNMARSHAL_PARAMETER_SIGNATURE + m_class.getClassFile().getSignature(); ClassFile cf = m_class.getMungedFile(); ContextMethodBuilder meth = new ContextMethodBuilder(name, sig, cf, Constants.ACC_PUBLIC|Constants.ACC_STATIC, -1, m_class.getClassName(), 0, UNMARSHALLING_CONTEXT); // generate the code to build a new instance if (genNewInstanceCode(meth)) { // finish method code with return of new instance meth.appendReturn(m_class.getClassName()); } m_newInstanceMethod = m_class.getUniqueMethod(meth).getItem(); } // generate code to call created new instance method mb.loadContext(UNMARSHALLING_CONTEXT); mb.appendCall(m_newInstanceMethod); } /** * Generate code to handle unmarshal source location tracking. This * convenience method generates the member variables and method used to * support setting the source location, the methods used to access the * information, and also adds the appropriate interfaces to the class. * * @throws JiBXException if error in generating code */ private void genTrackSourceCode() throws JiBXException { ClassFile cf = m_class.getMungedFile(); if (!m_isThisBinding && m_class.isDirectAccess() && !cf.isAbstract() && cf.addInterface(SOURCE_TRACKING_INTERFACE)) { // add position tracking fields to class ClassItem srcname = cf.addPrivateField("java.lang.String;", SOURCEDOCUMENT_FIELDNAME); ClassItem srcline = cf.addPrivateField("int", SOURCELINE_FIELDNAME); ClassItem srccol = cf.addPrivateField("int", SOURCECOLUMN_FIELDNAME); // add method for setting the source information MethodBuilder mb = new ExceptionMethodBuilder(SETSOURCE_METHODNAME, Type.VOID, SETSOURCE_ARGS, cf, Constants.ACC_PUBLIC); mb.appendLoadLocal(0); mb.appendLoadLocal(1); mb.appendPutField(srcname); mb.appendLoadLocal(0); mb.appendLoadLocal(2); mb.appendPutField(srcline); mb.appendLoadLocal(0); mb.appendLoadLocal(3); mb.appendPutField(srccol); mb.appendReturn(); mb.codeComplete(false); mb.addMethod(); // add methods for getting the source information mb = new ExceptionMethodBuilder(SOURCENAME_METHODNAME, Type.STRING, EMPTY_ARGS, cf, Constants.ACC_PUBLIC); mb.appendLoadLocal(0); mb.appendGetField(srcname); mb.appendReturn(Type.STRING); mb.codeComplete(false); mb.addMethod(); mb = new ExceptionMethodBuilder(SOURCELINE_METHODNAME, Type.INT, EMPTY_ARGS, cf, Constants.ACC_PUBLIC); mb.appendLoadLocal(0); mb.appendGetField(srcline); mb.appendReturn("int"); mb.codeComplete(false); mb.addMethod(); mb = new ExceptionMethodBuilder(SOURCECOLUMN_METHODNAME, Type.INT, EMPTY_ARGS, cf, Constants.ACC_PUBLIC); mb.appendLoadLocal(0); mb.appendGetField(srccol); mb.appendReturn("int"); mb.codeComplete(false); mb.addMethod(); } } /** * Construct fullly-qualified class and method name for method under * construction. * * @param mb method to be named * @return fully-qualified class and method name */ private String fullMethodName(ContextMethodBuilder mb) { return mb.getClassFile().getName() + '.' + mb.getName(); } /** * Construct fully-qualified class and method name for constructed method. * * @param item method to be named * @return fully-qualified class and method name */ private String fullMethodName(ClassItem item) { return item.getClassFile().getName() + '.' + item.getName(); } /** * Generate call to a constructed unmarshal method. * * @param name * @param mb */ private void genUnmarshalCall(String name, ContextMethodBuilder mb) { if (m_isStaticUnmarshal) { mb.appendCallStatic(name, m_unmarshalSignature); } else { mb.appendCallVirtual(name, m_unmarshalSignature); } } /** * Generate call to a constructed marshal method. * * @param name * @param mb */ private void genMarshalCall(String name, ContextMethodBuilder mb) { if (m_isStaticMarshal) { mb.appendCallStatic(name, m_marshalSignature); } else { mb.appendCallVirtual(name, m_marshalSignature); } } /** * Generate call to attribute unmarshal method for object. This convenience * method just generates code to call the generated unmarshal method added * to the class definition. The code generated prior to this call must have * loaded a reference to the object to be unmarshalled on the stack, and the * generated code returns the (possibly different, in the case of arrays) * object on the stack. * * @param mb method builder * @throws JiBXException if error in configuration */ private void genUnmarshalAttributeCall(ContextMethodBuilder mb) throws JiBXException { // check if unmarshal method needs to be added to class if (m_unmarshalAttributeMethod == null) { if (m_unmarshalAttributeName == null) { // set up for constructing new method String name = m_container.getBindingRoot().getPrefix() + UNMARSHAL_ATTR_SUFFIX; UnmarshalBuilder meth = new UnmarshalBuilder(name, m_class.getClassFile(), m_class.getMungedFile()); m_unmarshalAttributeName = fullMethodName(meth); m_unmarshalSignature = meth.getSignature(); m_isStaticUnmarshal = meth.isStaticMethod(); // if preset method supplied add code to call it if (m_preSetMethod != null) { meth.loadObject(); genUserMethodCall(true, m_preSetMethod, meth); } // push object being unmarshalled to unmarshaller stack if (!m_isThisBinding) { meth.loadContext(); meth.loadObject(); meth.appendCallVirtual(UNMARSHAL_PUSHTRACKEDOBJECTMETHOD, PUSHOBJECT_SIGNATURE); } // generate the actual unmarshalling code in method meth.loadObject(); m_component.genAttributeUnmarshal(meth); // pop object from unmarshal stack if (!m_isThisBinding) { meth.loadContext(); meth.appendCallVirtual(UNMARSHAL_POPOBJECTMETHOD, POPOBJECT_SIGNATURE); } // if postset method supplied and no content add code to call it if (m_postSetMethod != null && !hasContent()) { genUserMethodCall(true, m_postSetMethod, meth); } // finish by returning object meth.loadObject(); meth.appendReturn(m_class.getClassFile().getName()); // add method to class if (m_lockAttributeUnmarshal) { m_unmarshalAttributeMethod = m_class.getUniqueNamed(meth).getItem(); } else { m_unmarshalAttributeMethod = m_class.getUniqueMethod(meth).getItem(); m_unmarshalAttributeName = fullMethodName(m_unmarshalAttributeMethod); } } else { m_lockAttributeUnmarshal = true; } } // generate code to call created unmarshal method mb.loadContext(UNMARSHALLING_CONTEXT); genUnmarshalCall(m_unmarshalAttributeName, mb); } /** * Generate call to attribute marshal method for object. This convenience * method just generates code to call the generated marshal method added to * the class definition. The code generated prior to this call must have * loaded a reference to the object to be marshalled on the stack. * * @param mb method builder * @throws JiBXException if error in configuration */ private void genMarshalAttributeCall(ContextMethodBuilder mb) throws JiBXException { // check if marshal method needs to be added to class if (m_marshalAttributeMethod == null) { if (m_marshalAttributeName == null) { // set up for constructing new method String name = m_container.getBindingRoot().getPrefix() + MARSHAL_ATTR_SUFFIX; MarshalBuilder meth = new MarshalBuilder(name, m_class.getClassFile(), m_class.getMungedFile()); m_marshalAttributeName = fullMethodName(meth); m_marshalSignature = meth.getSignature(); m_isStaticMarshal = meth.isStaticMethod(); // if preget method supplied add code to call it if (m_preGetMethod != null) { genUserMethodCall(false, m_preGetMethod, meth); } // push object being marshalled to marshaller stack if (!m_isThisBinding) { meth.loadContext(); meth.loadObject(); meth.appendCallVirtual(MARSHAL_PUSHOBJECTMETHOD, PUSHOBJECT_SIGNATURE); } // generate actual marshalling code meth.loadContext(); m_component.genAttributeMarshal(meth); // pop object from stack if (!m_isThisBinding) { meth.loadContext(); meth.appendCallVirtual(MARSHAL_POPOBJECTMETHOD, POPOBJECT_SIGNATURE); } // finish and add constructed method to class meth.appendReturn(); if (m_lockAttributeMarshal) { m_marshalAttributeMethod = m_class.getUniqueNamed(meth).getItem(); } else { m_marshalAttributeMethod = m_class.getUniqueMethod(meth).getItem(); m_marshalAttributeName = fullMethodName(m_marshalAttributeMethod); } } else { m_lockAttributeMarshal = true; } } // generate code to call created marshal method // if (!m_directAccess) { mb.loadContext(MARSHALLING_CONTEXT); // } genMarshalCall(m_marshalAttributeName, mb); } /** * Generate call to content unmarshal method for object. This convenience * method just generates code to call the generated unmarshal method added * to the class definition. The code generated prior to this call must have * loaded a reference to the object to be unmarshalled on the stack, and the * generated code returns the (possibly different, in the case of arrays) * object on the stack. * * @param mb method builder * @throws JiBXException if error in configuration */ private void genUnmarshalContentCall(ContextMethodBuilder mb) throws JiBXException { // check if unmarshal method needs to be added to class if (m_unmarshalContentMethod == null) { if (m_unmarshalContentName == null) { // set up for constructing new method String name = m_container.getBindingRoot().getPrefix() + UNMARSHAL_SUFFIX; UnmarshalBuilder meth = new UnmarshalBuilder(name, m_class.getClassFile(), m_class.getMungedFile()); m_unmarshalContentName = fullMethodName(meth); m_unmarshalSignature = meth.getSignature(); m_isStaticUnmarshal = meth.isStaticMethod(); // if preset method supplied add code to call it if (!hasAttribute() && m_preSetMethod != null) { meth.loadObject(); genUserMethodCall(true, m_preSetMethod, meth); } // push object being unmarshalled to unmarshaller stack if (!m_isThisBinding) { meth.loadContext(); meth.loadObject(); String mname = hasAttribute() ? UNMARSHAL_PUSHOBJECTMETHOD : UNMARSHAL_PUSHTRACKEDOBJECTMETHOD; meth.appendCallVirtual(mname, PUSHOBJECT_SIGNATURE); } // generate the actual unmarshalling code in method meth.loadObject(); m_component.genContentUnmarshal(meth); // pop object from unmarshal stack if (!m_isThisBinding) { meth.loadContext(); meth.appendCallVirtual(UNMARSHAL_POPOBJECTMETHOD, POPOBJECT_SIGNATURE); } // if postset method supplied and no attributes add code to call if (m_postSetMethod != null) { genUserMethodCall(true, m_postSetMethod, meth); } // finish by returning object meth.loadObject(); meth.appendReturn(m_class.getClassFile().getName()); // add method to class if (m_lockContentUnmarshal) { m_unmarshalContentMethod = m_class.getUniqueNamed(meth).getItem(); } else { m_unmarshalContentMethod = m_class.getUniqueMethod(meth).getItem(); m_unmarshalContentName = fullMethodName(m_unmarshalContentMethod); } } else { m_lockContentUnmarshal = true; } } // generate code to call created unmarshal method mb.loadContext(UNMARSHALLING_CONTEXT); genUnmarshalCall(m_unmarshalContentName, mb); } /** * Generate call to content marshal method for object. This convenience * method just generates code to call the generated marshal method added to * the class definition. The code generated prior to this call must have * loaded a reference to the object to be marshalled on the stack. * * @param mb method builder * @throws JiBXException if error in configuration */ private void genMarshalContentCall(ContextMethodBuilder mb) throws JiBXException { // check if marshal method needs to be added to class if (m_marshalContentMethod == null) { if (m_marshalContentName == null) { // set up for constructing new method String name = m_container.getBindingRoot().getPrefix() + MARSHAL_SUFFIX; MarshalBuilder meth = new MarshalBuilder(name, m_class.getClassFile(), m_class.getMungedFile()); m_marshalContentName = fullMethodName(meth); m_marshalSignature = meth.getSignature(); m_isStaticMarshal = meth.isStaticMethod(); // if preget method supplied and no attributes add code to call it if (m_preGetMethod != null && !hasAttribute()) { genUserMethodCall(false, m_preGetMethod, meth); } // push object being marshalled to marshaller stack if (!m_isThisBinding) { meth.loadContext(); meth.loadObject(); meth.appendCallVirtual(MARSHAL_PUSHOBJECTMETHOD, PUSHOBJECT_SIGNATURE); } // generate actual marshalling code meth.loadContext(); m_component.genContentMarshal(meth); // pop object from stack if (!m_isThisBinding) { meth.loadContext(); meth.appendCallVirtual(MARSHAL_POPOBJECTMETHOD, POPOBJECT_SIGNATURE); } // finish and add constructed method to class meth.appendReturn(); if (m_lockContentMarshal) { m_marshalContentMethod = m_class.getUniqueNamed(meth).getItem(); } else { m_marshalContentMethod = m_class.getUniqueMethod(meth).getItem(); m_marshalContentName = fullMethodName(m_marshalContentMethod); } } else { m_lockContentMarshal = true; } } // generate code to call created marshal method mb.loadContext(MARSHALLING_CONTEXT); genMarshalCall(m_marshalContentName, mb); } // // IContextObj interface method definitions public BoundClass getBoundClass() { return m_class; } public boolean setIdChild(IComponent child) { if (m_idChild == null) { m_idChild = child; return true; } else { return false; } } // // IComponent interface method definitions public boolean isOptional() { return false; } public void genAttributeUnmarshal(ContextMethodBuilder mb) throws JiBXException { genUnmarshalAttributeCall(mb); } public void genAttributeMarshal(ContextMethodBuilder mb) throws JiBXException { genMarshalAttributeCall(mb); } public void genContentUnmarshal(ContextMethodBuilder mb) throws JiBXException { genUnmarshalContentCall(mb); } public void genContentMarshal(ContextMethodBuilder mb) throws JiBXException { genMarshalContentCall(mb); } public void genNewInstance(ContextMethodBuilder mb) throws JiBXException { genNewInstanceCall(mb); } public String getType() { return m_class.getClassName(); } public boolean hasId() { return m_idChild != null; } public void genLoadId(ContextMethodBuilder mb) throws JiBXException { if (m_idChild == null) { throw new IllegalStateException("Internal error: no id defined"); } else { m_idChild.genLoadId(mb); } } public void setLinkages() throws JiBXException { super.setLinkages(); if (m_container.getBindingRoot().isTrackSource()) { genTrackSourceCode(); } } // DEBUG public void print(int depth) { BindingDefinition.indent(depth); System.out.print("object binding for " + m_class.getClassFile().getName()); if (m_isThisBinding) { System.out.print(" (\"this\" reference)"); } if (m_createClass != null) { System.out.print(" create class " + m_createClass.getName()); } System.out.println(); m_component.print(depth+1); } }