/*******************************************************************************
 * Copyright (c) 1998, 2016 Oracle and/or its affiliates. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
 * which accompanies this distribution.
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     Oracle - initial API and implementation from Oracle TopLink
 ******************************************************************************/
package org.eclipse.persistence.jaxb.compiler;

import java.awt.Image;
import java.beans.Introspector;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableSet;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;

import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.core.descriptors.CoreDescriptor;
import org.eclipse.persistence.core.mappings.CoreMapping;
import org.eclipse.persistence.core.mappings.converters.CoreConverter;
import org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.core.sessions.CoreProject;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.exceptions.JAXBException;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor;
import org.eclipse.persistence.internal.descriptors.InstantiationPolicy;
import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor;
import org.eclipse.persistence.internal.descriptors.VirtualAttributeAccessor;
import org.eclipse.persistence.internal.jaxb.AccessorFactoryWrapper;
import org.eclipse.persistence.internal.jaxb.CustomAccessorAttributeAccessor;
import org.eclipse.persistence.internal.jaxb.DefaultElementConverter;
import org.eclipse.persistence.internal.jaxb.DomHandlerConverter;
import org.eclipse.persistence.internal.jaxb.JAXBElementConverter;
import org.eclipse.persistence.internal.jaxb.JAXBElementRootConverter;
import org.eclipse.persistence.internal.jaxb.JAXBSetMethodAttributeAccessor;
import org.eclipse.persistence.internal.jaxb.JaxbClassLoader;
import org.eclipse.persistence.internal.jaxb.MultiArgInstantiationPolicy;
import org.eclipse.persistence.internal.jaxb.WrappedValue;
import org.eclipse.persistence.internal.jaxb.XMLJavaTypeConverter;
import org.eclipse.persistence.internal.jaxb.many.JAXBArrayAttributeAccessor;
import org.eclipse.persistence.internal.jaxb.many.ManyValue;
import org.eclipse.persistence.internal.jaxb.many.MapValue;
import org.eclipse.persistence.internal.jaxb.many.MapValueAttributeAccessor;
import org.eclipse.persistence.internal.libraries.asm.ClassWriter;
import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
import org.eclipse.persistence.internal.libraries.asm.Opcodes;
import org.eclipse.persistence.internal.libraries.asm.Type;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.NamespaceResolver;
import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.internal.oxm.mappings.AnyAttributeMapping;
import org.eclipse.persistence.internal.oxm.mappings.AnyCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.AnyObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.BinaryDataCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.BinaryDataMapping;
import org.eclipse.persistence.internal.oxm.mappings.ChoiceCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.ChoiceObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.CollectionReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.CompositeCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.CompositeObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.DirectCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.DirectMapping;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.mappings.InverseReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.oxm.mappings.ObjectReferenceMapping;
import org.eclipse.persistence.internal.oxm.mappings.TransformationMapping;
import org.eclipse.persistence.internal.oxm.mappings.VariableXPathCollectionMapping;
import org.eclipse.persistence.internal.oxm.mappings.VariableXPathObjectMapping;
import org.eclipse.persistence.internal.oxm.mappings.XMLContainerMapping;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedClassForName;
import org.eclipse.persistence.jaxb.JAXBEnumTypeConverter;
import org.eclipse.persistence.jaxb.TypeMappingInfo;
import org.eclipse.persistence.jaxb.javamodel.Helper;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.javamodel.JavaField;
import org.eclipse.persistence.jaxb.javamodel.JavaMethod;
import org.eclipse.persistence.jaxb.xmlmodel.XmlAbstractNullPolicy;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper;
import org.eclipse.persistence.jaxb.xmlmodel.XmlIsSetNullPolicy;
import org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter;
import org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNamedObjectGraph;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNamedSubgraph;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNullPolicy;
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation;
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlReadTransformer;
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlWriteTransformer;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.converters.Converter;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.XMLField;
import org.eclipse.persistence.oxm.mappings.FixedMimeTypePolicy;
import org.eclipse.persistence.oxm.mappings.UnmarshalKeepAsElementPolicy;
import org.eclipse.persistence.oxm.mappings.XMLAnyAttributeMapping;
import org.eclipse.persistence.oxm.mappings.XMLAnyCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLAnyObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLBinaryDataCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLBinaryDataMapping;
import org.eclipse.persistence.oxm.mappings.XMLChoiceCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLChoiceObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLCollectionReferenceMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.oxm.mappings.XMLInverseReferenceMapping;
import org.eclipse.persistence.oxm.mappings.XMLMapping;
import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping;
import org.eclipse.persistence.oxm.mappings.XMLTransformationMapping;
import org.eclipse.persistence.oxm.mappings.XMLVariableXPathCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLVariableXPathObjectMapping;
import org.eclipse.persistence.oxm.mappings.converters.XMLListConverter;
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy;
import org.eclipse.persistence.oxm.mappings.nullpolicy.IsSetNullPolicy;
import org.eclipse.persistence.oxm.mappings.nullpolicy.NullPolicy;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
import org.eclipse.persistence.oxm.schema.XMLSchemaClassPathReference;
import org.eclipse.persistence.oxm.schema.XMLSchemaReference;
import org.eclipse.persistence.queries.AttributeGroup;
import org.eclipse.persistence.sessions.Project;

/**
 * INTERNAL:
 * <p><b>Purpose:</b>To generate a TopLink OXM Project based on Java Class and TypeInfo information
 * <p><b>Responsibilities:</b><ul>
 * <li>Generate a XMLDescriptor for each TypeInfo object</li>
 * <li>Generate a mapping for each TypeProperty object</li>
 * <li>Determine the correct mapping type based on the type of each property</li>
 * <li>Set up Converters on mappings for XmlAdapters or JDK 1.5 Enumeration types.</li>
 * </ul>
 * <p>This class is invoked by a Generator in order to create a TopLink Project.
 * This is generally used by JAXBContextFactory to create the runtime project. A Descriptor will
 * be generated for each TypeInfo and Mappings generated for each Property. In the case that a
 * non-transient property's type is a user defined class, a Descriptor and Mappings will be generated
 * for that class as well.
 * @see org.eclipse.persistence.jaxb.compiler.Generator
 * @see org.eclipse.persistence.jaxb.compiler.TypeInfo
 * @see org.eclipse.persistence.jaxb.compiler.Property
 * @author mmacivor
 * @since Oracle TopLink 11.1.1.0.0
 *
 */
public class MappingsGenerator {
    private static final String ATT = "@";
    private static final String TXT = "/text()";
    private static String OBJECT_CLASS_NAME = "java.lang.Object";
    public static final QName RESERVED_QNAME = new QName("urn:ECLIPSELINK_RESERVEDURI", "RESERVEDNAME");

    String outputDir = ".";
    private Map<String, QName> userDefinedSchemaTypes;
    private Helper helper;
    private JavaClass jotArrayList;
    private JavaClass jotHashSet;
    private JavaClass jotHashMap;
    private JavaClass jotLinkedList;
    private JavaClass jotTreeSet;
    private Map<String, PackageInfo> packageToPackageInfoMappings;
    private Map<String, TypeInfo> typeInfo;
    private Map<QName, Class> qNamesToGeneratedClasses;
    private Map<String, Class> classToGeneratedClasses;
    private Map<QName, Class> qNamesToDeclaredClasses;
    private Map<QName, ElementDeclaration> globalElements;
    private List<ElementDeclaration> localElements;
    private Map<TypeMappingInfo, Class> typeMappingInfoToGeneratedClasses;
    private Map<MapEntryGeneratedKey, Class> generatedMapEntryClasses;
    private CoreProject project;
    private org.eclipse.persistence.oxm.NamespaceResolver globalNamespaceResolver;
    private boolean isDefaultNamespaceAllowed;
    private Map<TypeMappingInfo, Class>typeMappingInfoToAdapterClasses;

    public MappingsGenerator(Helper helper) {
        this.helper = helper;
        jotArrayList = helper.getJavaClass(ArrayList.class);
        jotHashSet = helper.getJavaClass(HashSet.class);
        jotHashMap = helper.getJavaClass(HashMap.class);
        jotLinkedList = helper.getJavaClass(LinkedList.class);
        jotTreeSet = helper.getJavaClass(TreeSet.class);
        qNamesToGeneratedClasses = new HashMap<QName, Class>();
        qNamesToDeclaredClasses = new HashMap<QName, Class>();
        classToGeneratedClasses = new HashMap<String, Class>();
        globalNamespaceResolver = new org.eclipse.persistence.oxm.NamespaceResolver();
        isDefaultNamespaceAllowed = true;
    }

    public CoreProject generateProject(List<JavaClass> typeInfoClasses, Map<String, TypeInfo> typeInfo, Map<String, QName> userDefinedSchemaTypes, Map<String, PackageInfo> packageToPackageInfoMappings, Map<QName, ElementDeclaration> globalElements, List<ElementDeclaration> localElements, Map<TypeMappingInfo, Class> typeMappingInfoToGeneratedClass, Map<TypeMappingInfo, Class> typeMappingInfoToAdapterClasses,  boolean isDefaultNamespaceAllowed) throws Exception {
        this.typeInfo = typeInfo;
        this.userDefinedSchemaTypes = userDefinedSchemaTypes;
        this.packageToPackageInfoMappings = packageToPackageInfoMappings;
        this.isDefaultNamespaceAllowed = isDefaultNamespaceAllowed;
        this.globalElements = globalElements;
        this.localElements = localElements;
        this.typeMappingInfoToGeneratedClasses = typeMappingInfoToGeneratedClass;
        this.typeMappingInfoToAdapterClasses = typeMappingInfoToAdapterClasses;
        project = new Project();

        processDefaultNamespacePreferences(packageToPackageInfoMappings.values());

        // Generate descriptors
        for (JavaClass next : typeInfoClasses) {
            if (!next.isEnum()) {
                generateDescriptor(next, project);
            }
        }
        // Setup inheritance
        for (JavaClass next : typeInfoClasses) {
            if (!next.isEnum()) {
                setupInheritance(next);
            }
        }
        
        // Now create mappings
        generateMappings();
        
        // Setup AttributeGroups
        for(JavaClass next : typeInfoClasses) {
            setupAttributeGroups(next);
        }
        
        // apply customizers if necessary
        Set<Entry<String, TypeInfo>> entrySet = this.typeInfo.entrySet();
        for (Entry<String, TypeInfo> entry : entrySet) {
            TypeInfo tInfo = entry.getValue();
            if (tInfo.getXmlCustomizer() != null) {
                String customizerClassName = tInfo.getXmlCustomizer();
                try {
                    Class customizerClass = PrivilegedAccessHelper.getClassForName(customizerClassName, true, helper.getClassLoader());
                    DescriptorCustomizer descriptorCustomizer = (DescriptorCustomizer) PrivilegedAccessHelper.newInstanceFromClass(customizerClass);
                    descriptorCustomizer.customize((XMLDescriptor)tInfo.getDescriptor());
                } catch (IllegalAccessException iae) {
                    throw JAXBException.couldNotCreateCustomizerInstance(iae, customizerClassName);
                } catch (InstantiationException ie) {
                    throw JAXBException.couldNotCreateCustomizerInstance(ie, customizerClassName);
                } catch (ClassCastException cce) {
                    throw JAXBException.invalidCustomizerClass(cce, customizerClassName);
                } catch (ClassNotFoundException cnfe) {
                    throw JAXBException.couldNotCreateCustomizerInstance(cnfe, customizerClassName);
                }
            }
        }

        processGlobalElements(project);
        return project;
    }

    private void setupAttributeGroups(JavaClass javaClass) {
        TypeInfo info = this.typeInfo.get(javaClass.getQualifiedName());
        XMLDescriptor descriptor = (XMLDescriptor)info.getDescriptor();
        
        if(!info.getObjectGraphs().isEmpty()) {
            for(XmlNamedObjectGraph next:info.getObjectGraphs()) {
                AttributeGroup group = descriptor.getAttributeGroup(next.getName());
                Map<String, List<CoreAttributeGroup>> subgraphs = processSubgraphs(next.getXmlNamedSubgraph());
                for(XmlNamedAttributeNode nextAttributeNode:next.getXmlNamedAttributeNode()) {
                    if(nextAttributeNode.getSubgraph() == null || nextAttributeNode.getSubgraph().length() == 0) {
                        group.addAttribute(nextAttributeNode.getName());
                    } else {
                        List<CoreAttributeGroup> nestedGroups = subgraphs.get(nextAttributeNode.getSubgraph());
                        if(nestedGroups == null || nestedGroups.isEmpty()) {
                            Property property = info.getProperties().get(nextAttributeNode.getName());
                            if(property == null) {
                                //if there's no property associated with the attributeNode, just ignore it
                                continue;
                            }
                            JavaClass cls = property.getActualType();
                            TypeInfo referenceType = typeInfo.get(cls.getQualifiedName());
                            if(referenceType != null) {
                                AttributeGroup targetGroup = (AttributeGroup)referenceType.getDescriptor().getAttributeGroup(nextAttributeNode.getSubgraph());
                                group.addAttribute(nextAttributeNode.getName(), targetGroup);
                            } else {
                                //TODO: Exception
                            }
                        } else {
                            if(nestedGroups.size() == 1) {
                                group.addAttribute(nextAttributeNode.getName(), nestedGroups.get(0));
                            } else {
                                group.addAttribute(nextAttributeNode.getName(), nestedGroups);
                            }
                        }
                    }
                }


                for(XmlNamedSubgraph nextSubclass:next.getXmlNamedSubclassGraph()) {
                    AttributeGroup subclassGroup = new AttributeGroup(next.getName(), nextSubclass.getType(), true);
                    group.getSubClassGroups().put(nextSubclass.getType(), subclassGroup);
                    for(XmlNamedAttributeNode nextAttributeNode:nextSubclass.getXmlNamedAttributeNode()) {
                        if(nextAttributeNode.getSubgraph() == null || nextAttributeNode.getSubgraph().length() == 0) {
                            subclassGroup.addAttribute(nextAttributeNode.getName());
                        } else {
                            List<CoreAttributeGroup> nestedGroups = subgraphs.get(nextAttributeNode.getSubgraph());
                            if(nestedGroups == null || nestedGroups.isEmpty()) {
                                Property property = info.getProperties().get(nextAttributeNode.getName());
                                JavaClass cls = property.getActualType();
                                TypeInfo referenceType = typeInfo.get(cls.getQualifiedName());
                                if(referenceType != null) {
                                    AttributeGroup targetGroup = (AttributeGroup)referenceType.getDescriptor().getAttributeGroup(nextAttributeNode.getSubgraph());
                                    subclassGroup.addAttribute(nextAttributeNode.getName(), targetGroup);
                                } else {
                                    //TODO: Exception
                                }
                            } else {
                                if(nestedGroups.size() == 1) {
                                    subclassGroup.addAttribute(nextAttributeNode.getName(), nestedGroups.get(0));
                                } else {
                                    subclassGroup.addAttribute(nextAttributeNode.getName(), nestedGroups);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    
    private Map<String, List<CoreAttributeGroup>> processSubgraphs(List<XmlNamedSubgraph> subgraphs) {
        Map<String, List<CoreAttributeGroup>> subgroups = new HashMap<String, List<CoreAttributeGroup>>();
        //Iterate through once and create all the AttributeGroups
        for(XmlNamedSubgraph next: subgraphs) {
            String type = next.getType();
            if(type == null) {
                type = "java.lang.Object";
            }
            AttributeGroup group = new AttributeGroup(next.getName(), type, false);
            if(subgroups.containsKey(group.getName())) {
                List<CoreAttributeGroup> groups = subgroups.get(group.getName());
                groups.add(group);
            } else {
                List<CoreAttributeGroup> groups = new ArrayList<CoreAttributeGroup>(1);
                groups.add(group);
                subgroups.put(group.getName(), groups);
            }
        }
        
        //Iterate through a second time to populate the groups and set up links.
        for(XmlNamedSubgraph next:subgraphs) {
            List<XmlNamedAttributeNode> attributeNodes = next.getXmlNamedAttributeNode();
            List<CoreAttributeGroup> attributeGroups = subgroups.get(next.getName());
            if(attributeGroups != null) {
                for(CoreAttributeGroup group:attributeGroups) {
                    String typeName = next.getType();
                    if(typeName == null) {
                        typeName = "java.lang.Object";
                    }
                    if(group.getTypeName().equals(typeName)) {
                        for(XmlNamedAttributeNode attributeNode:attributeNodes) {
                            if(attributeNode.getSubgraph() == null || attributeNode.getSubgraph().length() == 0) {
                                group.addAttribute(attributeNode.getName());
                            } else {
                                List<CoreAttributeGroup> nestedGroups = subgroups.get(attributeNode.getSubgraph());
                                if(nestedGroups == null || nestedGroups.size() == 0) {
                                    //TODO: Exception or check for root level ones on target class
                                } else {
                                    group.addAttribute(attributeNode.getName(), nestedGroups.get(0));
                                }

                            }
                        }
                    }
                }
            }
        }
        return subgroups;
    }

    public void generateDescriptor(JavaClass javaClass, CoreProject project) {
        String jClassName = javaClass.getQualifiedName();
        TypeInfo info = typeInfo.get(jClassName);
        if (info.isTransient()){
            return;
        }
        NamespaceInfo namespaceInfo = this.packageToPackageInfoMappings.get(javaClass.getPackageName()).getNamespaceInfo();
        String packageNamespace = namespaceInfo.getNamespace();
        String elementName;
        String namespace;

        if (javaClass.getSuperclass() != null && javaClass.getSuperclass().getName().equals("javax.xml.bind.JAXBElement")) {
            generateDescriptorForJAXBElementSubclass(javaClass, project, getNamespaceResolverForDescriptor(namespaceInfo));
            return;
        }

        Descriptor descriptor = new XMLDescriptor();
        org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement rootElem = info.getXmlRootElement();
        if (rootElem == null) {
        	 try{                
        		 elementName = info.getXmlNameTransformer().transformRootElementName(javaClass.getName());
             }catch (Exception ex){
              	throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex);
             }  
            
            namespace = packageNamespace;
        } else {
            elementName = rootElem.getName();
            if (elementName.equals(XMLProcessor.DEFAULT)) {
                try{                
                    elementName = info.getXmlNameTransformer().transformRootElementName(javaClass.getName());
                }catch (Exception ex){
                 	throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex);
                }  
            }
            namespace = rootElem.getNamespace();
        }

        descriptor.setJavaClassName(jClassName);

        if (info.getFactoryMethodName() != null) {
            descriptor.getInstantiationPolicy().useFactoryInstantiationPolicy(info.getObjectFactoryClassName(), info.getFactoryMethodName());
        }

        if (namespace.equals(XMLProcessor.DEFAULT)) {
            namespace = namespaceInfo.getNamespace();
        }

        NamespaceResolver resolverForDescriptor = getNamespaceResolverForDescriptor(namespaceInfo);
        JavaClass manyValueJavaClass = helper.getJavaClass(ManyValue.class);
        if (!manyValueJavaClass.isAssignableFrom(javaClass)){
            if(isDefaultNamespaceAllowed
                    && namespace.length() != 0
                    && globalNamespaceResolver.getDefaultNamespaceURI() == null
                    && !resolverForDescriptor.getPrefixesToNamespaces().containsValue(namespace)) {
                globalNamespaceResolver.setDefaultNamespaceURI(namespace);
                resolverForDescriptor.setDefaultNamespaceURI(namespace);
            }
            if (rootElem == null) {
                descriptor.setDefaultRootElement("");
            } else {
                if (namespace.length() == 0) {
                    descriptor.setDefaultRootElement(elementName);
                } else {
                    descriptor.setDefaultRootElement(getQualifiedString(getPrefixForNamespace(namespace, resolverForDescriptor), elementName));
    	        }
            }
        }

        descriptor.setNamespaceResolver(resolverForDescriptor);
        
        setSchemaContext(descriptor, info);
        // set the ClassExtractor class name if necessary
        if (info.isSetClassExtractorName()) {
            descriptor.getInheritancePolicy().setClassExtractorName(info.getClassExtractorName());
        }
        // set any user-defined properties
        if (info.getUserProperties() != null) {
            descriptor.setProperties(info.getUserProperties());
        }

        if (info.isLocationAware()) {
            Property locProp = null;
            Iterator<Property> i = info.getPropertyList().iterator();
            while (i.hasNext()) {
                Property p = i.next();
                if (p.getType().getName().equals(Constants.LOCATOR_CLASS_NAME)) {
                    locProp = p;
                }
            }
            if (locProp != null && locProp.isTransient()) {
                // build accessor
                // don't make a mapping
                if (locProp.isMethodProperty()) {
                    MethodAttributeAccessor aa = new MethodAttributeAccessor();
                    aa.setAttributeName(locProp.getPropertyName());
                    aa.setSetMethodName(locProp.getSetMethodName());
                    aa.setGetMethodName(locProp.getGetMethodName());
                    descriptor.setLocationAccessor(aa);
                } else {
                    // instance variable property
                    InstanceVariableAttributeAccessor aa = new InstanceVariableAttributeAccessor();
                    aa.setAttributeName(locProp.getPropertyName());
                    descriptor.setLocationAccessor(aa);
                }
            }
        }
        
        if(!info.getObjectGraphs().isEmpty()) {
            //create attribute groups for each object graph. 
            //these will be populated later to allow for linking
            for(XmlNamedObjectGraph next:info.getObjectGraphs()) {
                AttributeGroup attributeGroup = new AttributeGroup(next.getName(), info.getJavaClassName(), false);
                ((XMLDescriptor)descriptor).addAttributeGroup(attributeGroup);
                
                //process subclass graphs for inheritance
                //for(NamedSubgraph nextSubclass:next.getNamedSubclassGraph()) {
                    //attributeGroup.insertSubClass(new AttributeGroup(next.getName(), nextSubclass.getType()));
                //}
            }
        }

        project.addDescriptor((CoreDescriptor)descriptor);
        info.setDescriptor(descriptor);
    }

    public void generateDescriptorForJAXBElementSubclass(JavaClass javaClass, CoreProject project, NamespaceResolver nsr) {
        String jClassName = javaClass.getQualifiedName();
        TypeInfo info = typeInfo.get(jClassName);

        Descriptor xmlDescriptor = new XMLDescriptor();
        xmlDescriptor.setJavaClassName(jClassName);

        String[] factoryMethodParamTypes = info.getFactoryMethodParamTypes();

        MultiArgInstantiationPolicy policy = new MultiArgInstantiationPolicy();
        policy.useFactoryInstantiationPolicy(info.getObjectFactoryClassName(), info.getFactoryMethodName());
        policy.setParameterTypeNames(factoryMethodParamTypes);
        policy.setDefaultValues(new String[]{null});

        xmlDescriptor.setInstantiationPolicy(policy);
        JavaClass paramClass = helper.getJavaClass(factoryMethodParamTypes[0]);
        boolean isObject = paramClass.getName().equals("java.lang.Object");        
        if(helper.isBuiltInJavaType(paramClass) && !isObject ){
            if(isBinaryData(paramClass)){
                BinaryDataMapping mapping = new XMLBinaryDataMapping();
                mapping.setAttributeName("value");
                mapping.setXPath(".");
                ((Field)mapping.getField()).setSchemaType(Constants.BASE_64_BINARY_QNAME);
                mapping.setSetMethodName("setValue");
                mapping.setGetMethodName("getValue");

                Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(factoryMethodParamTypes[0], helper.getClassLoader());
                mapping.setAttributeClassification(attributeClassification);
                mapping.getNullPolicy().setNullRepresentedByEmptyNode(false);

                mapping.setShouldInlineBinaryData(false);
                if(mapping.getMimeType() == null) {
                    if(areEquals(paramClass, javax.xml.transform.Source.class)) {
                        mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/xml"));
                    } else {
                        mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/octet-stream"));
                    }                       
                }
                xmlDescriptor.addMapping((CoreMapping)mapping); 
            } else {
                DirectMapping mapping = new XMLDirectMapping();
                mapping.setNullValueMarshalled(true);
                mapping.setAttributeName("value");
                mapping.setGetMethodName("getValue");
                mapping.setSetMethodName("setValue");
                mapping.setXPath("text()");
                Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(factoryMethodParamTypes[0], helper.getClassLoader());
                mapping.setAttributeClassification(attributeClassification);
                xmlDescriptor.addMapping((CoreMapping)mapping);
            }
        }else if(paramClass.isEnum()){
             EnumTypeInfo enumInfo = (EnumTypeInfo)typeInfo.get(paramClass.getQualifiedName());
        	
             DirectMapping mapping = new XMLDirectMapping();
             mapping.setConverter(buildJAXBEnumTypeConverter(mapping, enumInfo));
             mapping.setNullValueMarshalled(true);
             mapping.setAttributeName("value");
             mapping.setGetMethodName("getValue");
             mapping.setSetMethodName("setValue");
             mapping.setXPath("text()");
             Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(factoryMethodParamTypes[0], helper.getClassLoader());
             mapping.setAttributeClassification(attributeClassification);
             xmlDescriptor.addMapping((CoreMapping)mapping);
             
        }else{
        
            CompositeObjectMapping mapping = new XMLCompositeObjectMapping();
            mapping.setAttributeName("value");
            mapping.setGetMethodName("getValue");
            mapping.setSetMethodName("setValue");
            mapping.setXPath(".");
            if(isObject){
            	mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);                
            }else{
            	mapping.setReferenceClassName(factoryMethodParamTypes[0]);
            }
            xmlDescriptor.addMapping((CoreMapping)mapping);
        }
        xmlDescriptor.setNamespaceResolver(nsr);
        setSchemaContext(xmlDescriptor, info);
        project.addDescriptor((CoreDescriptor)xmlDescriptor);
        info.setDescriptor(xmlDescriptor);
    }
    
    private void setSchemaContext(Descriptor desc, TypeInfo info) {
        XMLSchemaClassPathReference schemaRef = new XMLSchemaClassPathReference();
        if (info.getClassNamespace() == null || info.getClassNamespace().equals("")) {
            schemaRef.setSchemaContext("/" + info.getSchemaTypeName());
            schemaRef.setSchemaContextAsQName(new QName(info.getSchemaTypeName()));
        } else {
            String prefix = desc.getNonNullNamespaceResolver().resolveNamespaceURI(info.getClassNamespace());
            if (prefix != null && !prefix.equals("")) {
                schemaRef.setSchemaContext("/" + prefix + ":" + info.getSchemaTypeName());
                schemaRef.setSchemaContextAsQName(new QName(info.getClassNamespace(), info.getSchemaTypeName(), prefix));
            } else {
            	String generatedPrefix =getPrefixForNamespace(info.getClassNamespace(), desc.getNonNullNamespaceResolver(), false);
            	schemaRef.setSchemaContext("/" + getQualifiedString(generatedPrefix, info.getSchemaTypeName()));            	
            	if(generatedPrefix == null || generatedPrefix.equals(Constants.EMPTY_STRING)){
                    schemaRef.setSchemaContextAsQName(new QName(info.getClassNamespace(), info.getSchemaTypeName()));            		
            	}else{
                    schemaRef.setSchemaContextAsQName(new QName(info.getClassNamespace(), info.getSchemaTypeName(), generatedPrefix));
            	}
            }     
        }
        // the default type is complex; need to check for simple type case
        if (info.isEnumerationType() || (info.getPropertyNames().size() == 1 && helper.isAnnotationPresent(info.getProperties().get(info.getPropertyNames().get(0)).getElement(), XmlValue.class))) {
            schemaRef.setType(XMLSchemaReference.SIMPLE_TYPE);
        }
        desc.setSchemaReference(schemaRef);

    }

    /**
     * Generate a mapping for a given Property.
     * 
     * @param property
     * @param descriptor
     * @param namespaceInfo
     * @return newly created mapping
     */
    public Mapping generateMapping(Property property, Descriptor descriptor, JavaClass descriptorJavaClass, NamespaceInfo namespaceInfo) {
        if (property.isSetXmlJavaTypeAdapter()) {
            // if we are dealing with a reference, generate mapping and return 
            if (property.isReference()) {
                return generateMappingForReferenceProperty(property, descriptor, namespaceInfo);
            }
            
            XmlJavaTypeAdapter xja = property.getXmlJavaTypeAdapter();
            JavaClass adapterClass = helper.getJavaClass(xja.getValue());

            JavaClass valueType = null;
            String sValType = xja.getValueType();
            if (sValType.equals("javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT")) {
                valueType = property.getActualType();
            } else {
                valueType = helper.getJavaClass(xja.getValueType());
            }

            Mapping mapping;
            boolean isArray = property.getType().isArray() && !property.getType().getRawName().equals("byte[]");
            
            // if the value type is something we have a descriptor for, create
            // a composite mapping
            if(property.isChoice()) {
                if(helper.isCollectionType(property.getType()) || property.getType().isArray()) {
                    mapping = generateChoiceCollectionMapping(property, descriptor, namespaceInfo);
                    ((ChoiceCollectionMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                } else {
                    mapping = generateChoiceMapping(property, descriptor, namespaceInfo);
                    ((ChoiceObjectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                }
            } else if (typeInfo.containsKey(valueType.getQualifiedName())) {
                TypeInfo reference = typeInfo.get(valueType.getQualifiedName());
                if (helper.isCollectionType(property.getType())) {
                    if (reference.isEnumerationType()) {
                        mapping = generateEnumCollectionMapping(property, descriptor, namespaceInfo, (EnumTypeInfo) reference);
                        XMLJavaTypeConverter converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName());
                        converter.setNestedConverter(((DirectCollectionMapping)mapping).getValueConverter());
                        ((DirectCollectionMapping)mapping).setValueConverter(converter);
                    } else {   
                    	if(property.getVariableAttributeName() !=null){
                    		mapping = generateVariableXPathCollectionMapping(property, descriptor, namespaceInfo, valueType);
                            ((VariableXPathCollectionMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    	}else{
                            mapping = generateCompositeCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo, valueType.getQualifiedName());
                            ((CompositeCollectionMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    	}
                    }
                } else {
                    if (reference.isEnumerationType()) {
                        mapping = generateDirectEnumerationMapping(property, descriptor, namespaceInfo, (EnumTypeInfo) reference);
                        XMLJavaTypeConverter converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName());
                        converter.setNestedConverter(((DirectMapping)mapping).getConverter());
                        ((DirectMapping)mapping).setConverter(converter);
                    } else if (property.isInverseReference()) {
                        mapping = generateInverseReferenceMapping(property, descriptor, namespaceInfo);
                    } else {                    
                    	if(property.getVariableAttributeName() !=null){
                    		mapping = generateVariableXPathObjectMapping(property, descriptor, namespaceInfo, valueType);
                            ((VariableXPathObjectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    	}else{
                            mapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, valueType.getQualifiedName());
                            ((CompositeObjectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    	}
                    }
                }
            } else {
                // no descriptor for value type
                if (property.isAny()) {
                    if (helper.isCollectionType(property.getType())){
                        mapping = generateAnyCollectionMapping(property, descriptor, namespaceInfo, property.isMixedContent());
                        ((AnyCollectionMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    } else {
                        mapping = generateAnyObjectMapping(property, descriptor, namespaceInfo);
                        ((AnyObjectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    }
                } else if (helper.isCollectionType(property.getType()) || isArray) {
                    if (property.isSwaAttachmentRef() || property.isMtomAttachment()) {
                    	mapping = generateBinaryDataCollectionMapping(property, descriptor, namespaceInfo);
                    	((BinaryDataCollectionMapping) mapping).setValueConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    } else{
                	    mapping = generateDirectCollectionMapping(property, descriptor, namespaceInfo);
                        if(adapterClass.getQualifiedName().equals(CollapsedStringAdapter.class.getName())) {
                            ((DirectCollectionMapping)mapping).setCollapsingStringValues(true);
                        } else if(adapterClass.getQualifiedName().equals(NormalizedStringAdapter.class.getName())) {
                            ((DirectCollectionMapping)mapping).setNormalizingStringValues(true);
                        } else {
                            ((DirectCollectionMapping) mapping).setValueConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                        }
                	}
                } else if (property.isSwaAttachmentRef() || property.isMtomAttachment()) {
                    mapping = generateBinaryMapping(property, descriptor, namespaceInfo);
                    ((BinaryDataMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                } else {
                    if (!property.isAttribute() && areEquals(valueType, Object.class) || property.isTyped()){
                        mapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, null);
                        ((CompositeObjectMapping)mapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
                        ((CompositeObjectMapping)mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                        return mapping;
                    }
                    mapping = generateDirectMapping(property, descriptor, namespaceInfo);
                    if(adapterClass.getQualifiedName().equals(CollapsedStringAdapter.class.getName())) {
                        ((DirectMapping)mapping).setCollapsingStringValues(true);
                    } else if(adapterClass.getQualifiedName().equals(NormalizedStringAdapter.class.getName())) {
                        ((DirectMapping)mapping).setNormalizingStringValues(true);
                    } else {
                        ((DirectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
                    }
                }
            }
            return mapping;
        }
        if (property.getVariableAttributeName() != null){
        	if (helper.isCollectionType(property.getType()) || property.getType().isArray() || property.isMap()){
                return generateVariableXPathCollectionMapping(property, descriptor, namespaceInfo, property.getActualType());
        	}else{
        		return generateVariableXPathObjectMapping(property, descriptor, namespaceInfo, property.getActualType());
        	}
        }
        if (property.isSetXmlJoinNodes()) {
            if (helper.isCollectionType(property.getType())) {
                return generateXMLCollectionReferenceMapping(property, descriptor, namespaceInfo, property.getActualType());
            }
            return generateXMLObjectReferenceMapping(property, descriptor, namespaceInfo, property.getType());
        }
        if (property.isXmlTransformation()) {
            return generateTransformationMapping(property, descriptor, namespaceInfo);
        }
        if (property.isChoice()) {
            if (helper.isCollectionType(property.getType()) || property.getType().isArray()) {
                return generateChoiceCollectionMapping(property, descriptor, namespaceInfo);
            } 
            return generateChoiceMapping(property, descriptor, namespaceInfo);
        }
        if (property.isInverseReference()) {
            return generateInverseReferenceMapping(property, descriptor, namespaceInfo);
        } 
        if (property.isReference()) {
            return generateMappingForReferenceProperty(property, descriptor, namespaceInfo);
        }
        if (property.isAny()) {
            if (helper.isCollectionType(property.getType()) || property.getType().isArray()){
                return generateAnyCollectionMapping(property, descriptor, namespaceInfo, property.isMixedContent());
            }
            return generateAnyObjectMapping(property, descriptor, namespaceInfo);
        }

        if (property.isMap()){
        	if (property.isAnyAttribute()) {
        		return generateAnyAttributeMapping(property, descriptor, namespaceInfo);
        	}
        	return generateCompositeCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo, null);
        }
        if (helper.isCollectionType(property.getType())) {
            return generateCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo);
        }
        
        JavaClass referenceClass = property.getType();
        String referenceClassName = referenceClass.getRawName();
        if (referenceClass.isArray()  && !referenceClassName.equals("byte[]")){
            JavaClass componentType = referenceClass.getComponentType();
            TypeInfo reference = typeInfo.get(componentType.getName());
                        
            if (reference != null && reference.isEnumerationType()) {
                return generateEnumCollectionMapping(property,  descriptor, namespaceInfo,(EnumTypeInfo) reference);
            }            
            if (areEquals(componentType, Object.class)){
                CompositeCollectionMapping mapping = generateCompositeCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo, null);
                mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
                return mapping;
            }
            
            if (reference != null ||  componentType.isArray()){
            	  if (property.isXmlIdRef() || property.isSetXmlJoinNodes()) {
                      return generateXMLCollectionReferenceMapping(property, descriptor, namespaceInfo, componentType);
                  }
            	
                return generateCompositeCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo, componentType.getQualifiedName());
            }
            return generateDirectCollectionMapping(property, descriptor, namespaceInfo);
        }
        if (property.isXmlIdRef()) {
            return generateXMLObjectReferenceMapping(property, descriptor, namespaceInfo, referenceClass);
        }
        TypeInfo reference = typeInfo.get(referenceClass.getQualifiedName());
        if (reference != null) {
            if (reference.isEnumerationType()) {
                return generateDirectEnumerationMapping(property, descriptor, namespaceInfo, (EnumTypeInfo) reference);
            }
            if (property.isXmlLocation()) {
                CompositeObjectMapping locationMapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, referenceClass.getQualifiedName());
                reference.getDescriptor().setInstantiationPolicy(new NullInstantiationPolicy());
                descriptor.setLocationAccessor(locationMapping.getAttributeAccessor());
                return locationMapping;
            } else {
                return generateCompositeObjectMapping(property, descriptor, namespaceInfo, referenceClass.getQualifiedName());
            }
        }
        if (property.isSwaAttachmentRef() || property.isMtomAttachment()) {
            return generateBinaryMapping(property, descriptor, namespaceInfo);
        }
        if (referenceClass.getQualifiedName().equals(OBJECT_CLASS_NAME) && !property.isAttribute() || property.isTyped() ) {
            CompositeObjectMapping coMapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, null);
            coMapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
            return coMapping;
        }
        if (property.isXmlLocation()) {
            return null;
        }
        return generateDirectMapping(property, descriptor, namespaceInfo);
    }

    private Mapping generateVariableXPathCollectionMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, JavaClass actualType) {    	
        XMLVariableXPathCollectionMapping mapping = new XMLVariableXPathCollectionMapping();        
        mapping.setAttributeName(property.getPropertyName());
        
        if(property.isMap()){
        	actualType = property.getValueType();
        }
        
        initializeXMLContainerMapping(mapping, property.getType().isArray());
        initializeXMLMapping(mapping, property);
        initializeVariableXPathMapping(mapping, property, actualType);
        
        if (property.getXmlPath() != null) {
            mapping.setField(new XMLField(property.getXmlPath()));
        } else {
            if (property.isSetXmlElementWrapper()) {
                mapping.setField((XMLField)getXPathForField(property, namespaceInfo, false, true));
            }
        }
                
        if (property.isSetXmlElementWrapper()) {
            mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
        }
        JavaClass collectionType = property.getType();
        if (collectionType.isArray()){
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            JavaClass componentType = collectionType.getComponentType();
            if(componentType.isArray()) {
                JavaClass baseComponentType = getBaseComponentType(componentType);
                if (baseComponentType.isPrimitive()){
                    Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName());
                    accessor.setComponentClass(primitiveClass);
                } else {
                    accessor.setComponentClassName(baseComponentType.getQualifiedName());
                }
            } else {
                accessor.setComponentClassName(componentType.getQualifiedName());
            }
            mapping.setAttributeAccessor(accessor);
        }
        

        
        if(property.isMap()){
        	JavaClass mapType = property.getType(); 
        	if(mapType.isInterface()){        		
        		mapping.useMapClass("java.util.HashMap");
        	}else{
        	    mapping.useMapClass(property.getType().getName());
        	}
        	
        }else{
        	collectionType = containerClassImpl(collectionType);
            mapping.useCollectionClass(helper.getClassForJavaClass(collectionType));
        }
       
        
        return mapping;
    }

    private Mapping generateVariableXPathObjectMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, JavaClass actualType) {    	
        XMLVariableXPathObjectMapping mapping = new XMLVariableXPathObjectMapping();        
        initializeXMLMapping(mapping, property);
        initializeVariableXPathMapping(mapping, property, actualType);

        // handle null policy set via xml metadata
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else {
            NullPolicy nullPolicy = (NullPolicy) mapping.getNullPolicy();
            nullPolicy.setSetPerformedForAbsentNode(false);
            if(property.isNillable()) {
                nullPolicy.setNullRepresentedByXsiNil(true);
                nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
            }
        }
    
        if (property.getXmlPath() != null) {
            mapping.setField(new XMLField(property.getXmlPath()));
        } else {
            if (property.isSetXmlElementWrapper()) {
                mapping.setField((XMLField)getXPathForField(property, namespaceInfo, false, true));
            }
        }
                
        return mapping;
    }
    
    private void initializeVariableXPathMapping(VariableXPathObjectMapping mapping, Property property, JavaClass actualType){
        String variableAttributeName = property.getVariableAttributeName();
        
        TypeInfo refInfo = typeInfo.get(actualType.getName());
        
        if(refInfo == null){
        	throw JAXBException.unknownTypeForVariableNode(actualType.getName());
        }
        
        Property refProperty = refInfo.getProperties().get(variableAttributeName);
                
        
        while(refProperty == null){
         	JavaClass superClass = CompilerHelper.getNextMappedSuperClass(actualType, typeInfo, helper);
	        if (superClass != null){
	        	refInfo = typeInfo.get(superClass.getName());
	            refProperty = refInfo.getProperties().get(variableAttributeName);	           
	        }else{
	        	break;
	        }
        }
        
        
        if(refProperty == null){
        	throw JAXBException.unknownPropertyForVariableNode(variableAttributeName, actualType.getName());
        }
       
        String refPropertyType = refProperty.getActualType().getQualifiedName();
        
        if(!(refPropertyType.equals("java.lang.String") || refPropertyType.equals("javax.xml.namespace.QName"))){
        	throw JAXBException.invalidTypeForVariableNode(variableAttributeName, refPropertyType, actualType.getName());
        }
        if (refProperty.isMethodProperty()) {
            if (refProperty.getGetMethodName() == null) {
                // handle case of set with no get method
                String paramTypeAsString = refProperty.getType().getName();
                JAXBSetMethodAttributeAccessor accessor = new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader());
                accessor.setIsReadOnly(true);
                accessor.setSetMethodName(refProperty.getSetMethodName());
                mapping.setIsReadOnly(true);
                accessor.setAttributeName("thingBLAH");
                mapping.setVariableAttributeAccessor(accessor);
            } else if (refProperty.getSetMethodName() == null) {
            	mapping.setVariableGetMethodName(refProperty.getGetMethodName());
            } else {
            	mapping.setVariableGetMethodName(refProperty.getGetMethodName());
            	mapping.setVariableSetMethodName(refProperty.getSetMethodName());
            }
        }else{
        	mapping.setVariableAttributeName(property.getVariableAttributeName());
        }
        
    
        if(property.getVariableClassName() != null){
        	mapping.setReferenceClassName(property.getVariableClassName());		
        }else{
            mapping.setReferenceClassName(actualType.getQualifiedName());
        } 
        	
        mapping.setAttribute(property.isVariableNodeAttribute());
        
    }
    
    private InverseReferenceMapping generateInverseReferenceMapping(Property property, Descriptor descriptor, NamespaceInfo namespace) {
        InverseReferenceMapping invMapping = new XMLInverseReferenceMapping();
        boolean isCollection = helper.isCollectionType(property.getType());
        
        if (isCollection) {
            invMapping.setReferenceClassName(property.getGenericType().getQualifiedName());
        } else {
            invMapping.setReferenceClassName(property.getType().getQualifiedName());
        }

        invMapping.setAttributeName(property.getPropertyName());

        String setMethodName = property.getInverseReferencePropertySetMethodName();
        String getMethodName = property.getInverseReferencePropertyGetMethodName();

        if (setMethodName != null && !setMethodName.equals(Constants.EMPTY_STRING)) {
            invMapping.setSetMethodName(setMethodName);
        }
        if (getMethodName != null && !getMethodName.equals(Constants.EMPTY_STRING)) {
            invMapping.setGetMethodName(getMethodName);
        }
        invMapping.setMappedBy(property.getInverseReferencePropertyName());

        if (isCollection) {
            JavaClass collectionType = property.getType();
            collectionType = containerClassImpl(collectionType);
            invMapping.useCollectionClass(org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(collectionType.getQualifiedName(), helper.getClassLoader()));
        }
        
        if(property.isWriteableInverseReference()){
   	        if(isCollection){           	
   	            JavaClass descriptorClass = helper.getJavaClass(descriptor.getJavaClassName());
   	        	invMapping.setInlineMapping((XMLCompositeCollectionMapping)generateCompositeCollectionMapping(property, descriptor, descriptorClass, namespace, invMapping.getReferenceClassName()));
   	        }else{
   	        	invMapping.setInlineMapping((XMLCompositeObjectMapping)generateCompositeObjectMapping(property, descriptor, namespace, invMapping.getReferenceClassName()));   	        	
   	        }
        }                  

        return invMapping;
    }

    /**
     * Generate an XMLTransformationMapping based on a given Property.  
     * 
     * @param property
     * @param descriptor
     * @param namespace
     * @return
     */
    public TransformationMapping generateTransformationMapping(Property property, Descriptor descriptor, NamespaceInfo namespace) {
        TransformationMapping mapping = new XMLTransformationMapping();
        if (property.isMethodProperty()) {
            if (property.getGetMethodName() == null) {
                // handle case of set with no get method
                String paramTypeAsString = property.getType().getName();
                mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader()));
                mapping.setSetMethodName(property.getSetMethodName());
            } else if (property.getSetMethodName() == null) {
                mapping.setGetMethodName(property.getGetMethodName());
            } else {
                mapping.setSetMethodName(property.getSetMethodName());
                mapping.setGetMethodName(property.getGetMethodName());
            }
        }
        // handle transformation
        if (property.isSetXmlTransformation()) {
            XmlTransformation xmlTransformation = property.getXmlTransformation();
            mapping.setIsOptional(xmlTransformation.isOptional());
            // handle transformer(s)
            if (xmlTransformation.isSetXmlReadTransformer()) {
                // handle read transformer
                mapping.setAttributeName(property.getPropertyName());
                XmlReadTransformer readTransformer = xmlTransformation.getXmlReadTransformer();
                if (readTransformer.isSetTransformerClass()) {
                    mapping.setAttributeTransformerClassName(xmlTransformation.getXmlReadTransformer().getTransformerClass());
                } else {
                    mapping.setAttributeTransformation(xmlTransformation.getXmlReadTransformer().getMethod());
                }
            }
            if (xmlTransformation.isSetXmlWriteTransformers()) {
                // handle write transformer(s)
                for (XmlWriteTransformer writeTransformer : xmlTransformation.getXmlWriteTransformer()) {
                    if (writeTransformer.isSetTransformerClass()) {
                        mapping.addFieldTransformerClassName(writeTransformer.getXmlPath(), writeTransformer.getTransformerClass());
                    } else {
                        mapping.addFieldTransformation(writeTransformer.getXmlPath(), writeTransformer.getMethod());
                    }
                }
            }
        }
        return mapping;
    }
    
    public ChoiceObjectMapping generateChoiceMapping(Property property, Descriptor descriptor, NamespaceInfo namespace) {
        ChoiceObjectMapping mapping = new XMLChoiceObjectMapping();
        initializeXMLMapping((XMLChoiceObjectMapping)mapping, property);
      
        boolean isIdRef = property.isXmlIdRef();
        Iterator<Property> choiceProperties = property.getChoiceProperties().iterator();
        while (choiceProperties.hasNext()) {
            Property next = choiceProperties.next();
            JavaClass type = next.getType();
            JavaClass originalType = next.getType();
            Converter converter = null;
            TypeInfo info = typeInfo.get(type.getName());
            if(info != null){
                XmlJavaTypeAdapter adapter = info.getXmlJavaTypeAdapter();
                if(adapter != null){
                    String adapterValue = adapter.getValue();
                    JavaClass adapterClass = helper.getJavaClass(adapterValue);
                    JavaClass theClass = CompilerHelper.getTypeFromAdapterClass(adapterClass, helper);
                    type = theClass;
                    converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName());
                }
            }            
            if (next.getXmlJoinNodes() != null) {
                // handle XmlJoinNodes
                List<Field> srcFlds = new ArrayList<Field>();
                List<Field> tgtFlds = new ArrayList<Field>();
                for (XmlJoinNode xmlJoinNode: next.getXmlJoinNodes().getXmlJoinNode()) {
                    srcFlds.add(new XMLField(xmlJoinNode.getXmlPath()));
                    tgtFlds.add(new XMLField(xmlJoinNode.getReferencedXmlPath()));
                }
                mapping.addChoiceElement(srcFlds, type.getQualifiedName(), tgtFlds);
            } else if (isIdRef) {
                // handle IDREF
                String tgtXPath = null;
                TypeInfo referenceType = typeInfo.get(type.getQualifiedName());
                if (null != referenceType && referenceType.isIDSet()) {
                    Property prop = referenceType.getIDProperty();
                    tgtXPath = getXPathForField(prop, namespace, !prop.isAttribute(), false).getXPath();
                }
                // if the XPath is set (via xml-path) use it, otherwise figure it out
                Field srcXPath;
                if (next.getXmlPath() != null) {
                    srcXPath = new XMLField(next.getXmlPath());
                } else {
                    srcXPath = getXPathForField(next, namespace, true, false);
                }
                mapping.addChoiceElement(srcXPath.getXPath(), type.getQualifiedName(), tgtXPath);
            } else {
            	Field xpath;
                if (next.getXmlPath() != null) {
                    xpath = new XMLField(next.getXmlPath());
                } else {
                    xpath = getXPathForField(next, namespace, (!(this.typeInfo.containsKey(type.getQualifiedName()))) || next.isMtomAttachment() || type.isEnum(), false);
                }
                mapping.addChoiceElement(xpath, type.getQualifiedName());
                if(!originalType.getQualifiedName().equals(type.getQualifiedName())) {
                    if(mapping.getClassNameToFieldMappings().get(originalType.getQualifiedName()) == null) {
                        mapping.getClassNameToFieldMappings().put(originalType.getQualifiedName(), xpath);
                    }
                    mapping.addConverter(xpath, converter);
                }
                Mapping nestedMapping = (Mapping) mapping.getChoiceElementMappings().get(xpath);
                if(nestedMapping instanceof BinaryDataMapping){
                	((BinaryDataMapping)nestedMapping).getNullPolicy().setNullRepresentedByEmptyNode(false);
                }
                if (type.isEnum()) {
                    if(nestedMapping.isAbstractDirectMapping()) {
                        ((DirectMapping)nestedMapping).setConverter(buildJAXBEnumTypeConverter(nestedMapping, (EnumTypeInfo)info));
                    }
                }                
            }
        }
        return mapping;
    }

    public ChoiceCollectionMapping generateChoiceCollectionMapping(Property property, Descriptor descriptor, NamespaceInfo namespace) {
        ChoiceCollectionMapping mapping = new XMLChoiceCollectionMapping();
        initializeXMLContainerMapping(mapping, property.getType().isArray());
        initializeXMLMapping((XMLChoiceCollectionMapping)mapping, property);
       
        JavaClass collectionType = property.getType();
        if (collectionType.isArray()){
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            JavaClass componentType = collectionType.getComponentType();
            if(componentType.isArray()) {
                JavaClass baseComponentType = getBaseComponentType(componentType);
                if (baseComponentType.isPrimitive()){
                    Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName());
                    accessor.setComponentClass(primitiveClass);
                } else {
                    accessor.setComponentClassName(baseComponentType.getQualifiedName());
                }
            } else {
                accessor.setComponentClassName(componentType.getQualifiedName());
            }
         
            mapping.setAttributeAccessor(accessor);
        }
        
        
        collectionType = containerClassImpl(collectionType);
        mapping.useCollectionClassName(collectionType.getRawName());

        if (property.isSetXmlElementWrapper()) {
            mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
        }

        boolean isIdRef = property.isXmlIdRef();
        Iterator<Property> choiceProperties = property.getChoiceProperties().iterator();
        while (choiceProperties.hasNext()) {
            Property next = choiceProperties.next();
            JavaClass type = next.getType();
            JavaClass originalType = next.getType();
            Converter converter = null;
            Field xmlField = null;
            TypeInfo info = typeInfo.get(type.getName());
            if(info != null){
                XmlJavaTypeAdapter adapter = info.getXmlJavaTypeAdapter();
                if(adapter != null){
                    String adapterValue = adapter.getValue();
                    JavaClass adapterClass = helper.getJavaClass(adapterValue);
                    JavaClass theClass = CompilerHelper.getTypeFromAdapterClass(adapterClass, helper);
                    type = theClass;
                    converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName());
                }
            }
            
            if (next.getXmlJoinNodes() != null) {
                // handle XmlJoinNodes
                List<Field> srcFlds = new ArrayList<Field>();
                List<Field> tgtFlds = new ArrayList<Field>();
                for (XmlJoinNode xmlJoinNode: next.getXmlJoinNodes().getXmlJoinNode()) {
                    srcFlds.add(new XMLField(xmlJoinNode.getXmlPath()));
                    tgtFlds.add(new XMLField(xmlJoinNode.getReferencedXmlPath()));
                }
                mapping.addChoiceElement(srcFlds, type.getQualifiedName(), tgtFlds);
            } else if (isIdRef) {
                // handle IDREF
                String tgtXPath = null;
                TypeInfo referenceType = typeInfo.get(type.getQualifiedName());
                if (null != referenceType && referenceType.isIDSet()) {
                    Property prop = referenceType.getIDProperty();
                    tgtXPath = getXPathForField(prop, namespace, !prop.isAttribute(), false).getXPath();
                }
                // if the XPath is set (via xml-path) use it, otherwise figure it out
                Field srcXPath;
                if (next.getXmlPath() != null) {
                    srcXPath = new XMLField(next.getXmlPath());
                } else {
                    srcXPath = getXPathForField(next, namespace, true, false);
                }
                mapping.addChoiceElement(srcXPath.getXPath(), type.getQualifiedName(), tgtXPath);
            } else {
            	Field xpath;
                if (next.getXmlPath() != null) {
                    xpath = new XMLField(next.getXmlPath());
                } else {
                    xpath = getXPathForField(next, namespace, (!(this.typeInfo.containsKey(type.getQualifiedName()))) || type.isEnum(), false);
                }
                xmlField = xpath;
                mapping.addChoiceElement(xpath.getName(), type.getQualifiedName());
                if(!originalType.getQualifiedName().equals(type.getQualifiedName())) {
                    if(mapping.getClassNameToFieldMappings().get(originalType.getQualifiedName()) == null) {
                        mapping.getClassNameToFieldMappings().put(originalType.getQualifiedName(), xpath);
                    }
                    mapping.addConverter(xpath, converter);
                }
                
            }
                        
            if(xmlField !=null){
                Mapping nestedMapping = (Mapping) mapping.getChoiceElementMappings().get(xmlField);
                if(nestedMapping.isAbstractCompositeCollectionMapping()){ 
                   //handle null policy set via xml metadata
                   if (property.isSetNullPolicy()) {
                	   ((CompositeCollectionMapping)nestedMapping).setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespace)));
                   } else if (next.isNillable() && property.isNillable()){
                	   ((CompositeCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByXsiNil(true);
                	   ((CompositeCollectionMapping)nestedMapping).getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
                   }
                } else if(nestedMapping.isAbstractCompositeDirectCollectionMapping()){   
                	 if (next.isSetNullPolicy()) {
                		 ((DirectCollectionMapping)nestedMapping).setNullPolicy(getNullPolicyFromProperty(next, getNamespaceResolverForDescriptor(namespace)));
                     } else if (next.isNillable() && property.isNillable()){
                    	 ((DirectCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByXsiNil(true);
                    	 ((DirectCollectionMapping)nestedMapping).getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
                     }
                	 ((DirectCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByEmptyNode(false);
                	 
                     if (type.isEnum()) {
                         ((DirectCollectionMapping)nestedMapping).setValueConverter(buildJAXBEnumTypeConverter(nestedMapping, (EnumTypeInfo)info));
                     }
                } else if(nestedMapping instanceof BinaryDataCollectionMapping){   
               	    if (next.isSetNullPolicy()) {
            		    ((BinaryDataCollectionMapping)nestedMapping).setNullPolicy(getNullPolicyFromProperty(next, getNamespaceResolverForDescriptor(namespace)));
                    } else if (next.isNillable() && property.isNillable()){
                	    ((BinaryDataCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByXsiNil(true);
                	    ((BinaryDataCollectionMapping)nestedMapping).getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
                    }
                }
            }
        }
        return mapping;
    }

    public Mapping generateMappingForReferenceProperty(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo)  {
        boolean isCollection = helper.isCollectionType(property.getType()) || property.getType().isArray();

        Mapping mapping;
        if (isCollection) {
            mapping = new XMLChoiceCollectionMapping();
            initializeXMLContainerMapping((ChoiceCollectionMapping) mapping, property.getType().isArray());
            JavaClass collectionType = property.getType();
            collectionType = containerClassImpl(collectionType);
            ((ChoiceCollectionMapping) mapping).useCollectionClassName(collectionType.getRawName());
            JAXBElementRootConverter jaxbERConverter = new JAXBElementRootConverter(Object.class);
            if (property.isSetXmlJavaTypeAdapter()) {
                JavaClass adapterClass = helper.getJavaClass(property.getXmlJavaTypeAdapter().getValue());
                jaxbERConverter.setNestedConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
            }
            ((ChoiceCollectionMapping) mapping).setConverter(jaxbERConverter);
            if (property.isSetWriteOnly()) {
                ((ChoiceCollectionMapping) mapping).setIsWriteOnly(property.isWriteOnly());
            }
            if (property.isSetXmlElementWrapper()) {
                ((ChoiceCollectionMapping) mapping).setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
            }
        } else {
            mapping = new XMLChoiceObjectMapping();
            JAXBElementRootConverter jaxbERConverter = new JAXBElementRootConverter(Object.class);
            if (property.isSetXmlJavaTypeAdapter()) {
                JavaClass adapterClass = helper.getJavaClass(property.getXmlJavaTypeAdapter().getValue());
                jaxbERConverter.setNestedConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName()));
            }
            ((ChoiceObjectMapping) mapping).setConverter(jaxbERConverter);
            if (property.isSetWriteOnly()) {
                ((ChoiceObjectMapping) mapping).setIsWriteOnly(property.isWriteOnly());
            }
        }
      
        initializeXMLMapping((XMLMapping)mapping, property);

        List<ElementDeclaration> referencedElements = property.getReferencedElements();
        JavaClass propertyType = property.getType();
        if (propertyType.isArray()) {
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            accessor.setComponentClassName(property.getType().getComponentType().getQualifiedName());
            JavaClass componentType = propertyType.getComponentType();
            if(componentType.isArray()) {
                Class adaptedClass = classToGeneratedClasses.get(componentType.getQualifiedName());
                accessor.setAdaptedClassName(adaptedClass.getName());
            }
            mapping.setAttributeAccessor(accessor);
        }
        String wrapperXPath = "";
        // handle XmlElementWrapper
        if (property.isSetXmlElementWrapper()) {
            XmlElementWrapper wrapper = property.getXmlElementWrapper();
            String namespace = wrapper.getNamespace();
            if (namespace.equals(XMLProcessor.DEFAULT)) {
                if (namespaceInfo.isElementFormQualified()) {
                    namespace = namespaceInfo.getNamespace();
                } else {
                    namespace = "";
                }
            }
            if (namespace.equals("")) {
                wrapperXPath += (wrapper.getName() + "/");
            } else {
                String prefix = getPrefixForNamespace(namespace, getNamespaceResolverForDescriptor(namespaceInfo));
                wrapperXPath += getQualifiedString(prefix, wrapper.getName() + "/");
            }
        }        
        if(property.isMixedContent() && isCollection) {
            if(wrapperXPath.length() == 0) {
                ((ChoiceCollectionMapping)mapping).setMixedContent(true);
            } else {
                ((ChoiceCollectionMapping)mapping).setMixedContent(wrapperXPath.substring(0, wrapperXPath.length() - 1));
            }
        }  
        for (ElementDeclaration element:referencedElements) {
            QName elementName = element.getElementName();
            JavaClass	pType = element.getJavaType();
            String	pTypeName = element.getJavaTypeName();
            boolean isBinaryType = (areEquals(pType, AnnotationsProcessor.JAVAX_ACTIVATION_DATAHANDLER) || areEquals(pType, byte[].class) || areEquals(pType, Image.class) || areEquals(pType, Source.class) || areEquals(pType, AnnotationsProcessor.JAVAX_MAIL_INTERNET_MIMEMULTIPART));        
            boolean isText = pType.isEnum() || (!isBinaryType && !(this.typeInfo.containsKey(element.getJavaTypeName())) && !(element.getJavaTypeName().equals(OBJECT_CLASS_NAME)));
            String xPath = wrapperXPath;

            Field xmlField = this.getXPathForElement(xPath, elementName, namespaceInfo, isText);
            //ensure byte[] goes to base64 instead of the default hex.
            if(helper.getXMLToJavaTypeMap().get(pType.getRawName()) == Constants.BASE_64_BINARY_QNAME) {
                xmlField.setSchemaType(Constants.BASE_64_BINARY_QNAME);
            }
            if(areEquals(pType, Object.class)) {
            	setTypedTextField(xmlField);
            }
            Mapping nestedMapping;
            AbstractNullPolicy nullPolicy = null;
            if(isCollection){
                ChoiceCollectionMapping xmlChoiceCollectionMapping = (ChoiceCollectionMapping) mapping;
                xmlChoiceCollectionMapping.addChoiceElement(xmlField, pTypeName);
                nestedMapping = (Mapping) xmlChoiceCollectionMapping.getChoiceElementMappings().get(xmlField);
                if(nestedMapping.isAbstractCompositeCollectionMapping()){
                    ((CompositeCollectionMapping)nestedMapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
                    nullPolicy = ((CompositeCollectionMapping)nestedMapping).getNullPolicy();
                }

                if (nestedMapping.isAbstractCompositeDirectCollectionMapping()) {
                    DirectCollectionMapping nestedCompositeDirectCollectionMapping = (DirectCollectionMapping) nestedMapping;
                    nullPolicy = nestedCompositeDirectCollectionMapping.getNullPolicy();
                    if(pType.isEnum()) {
                        TypeInfo enumTypeInfo = typeInfo.get(pType.getQualifiedName());
                        nestedCompositeDirectCollectionMapping.setValueConverter(buildJAXBEnumTypeConverter(nestedCompositeDirectCollectionMapping, (EnumTypeInfo) enumTypeInfo));
                    }
                    if(element.isList()){
                        XMLListConverter listConverter = new XMLListConverter();
                        listConverter.setObjectClassName(pType.getQualifiedName());
                        ((DirectCollectionMapping)nestedMapping).setValueConverter(listConverter); 
                    }
                }else if(nestedMapping instanceof BinaryDataCollectionMapping){
                    nullPolicy =  ((BinaryDataCollectionMapping)nestedMapping).getNullPolicy();
                    if(element.isList()){
                    	((XMLField)((BinaryDataCollectionMapping)nestedMapping).getField()).setUsesSingleNode(true);
                    }
                }

              
            } else {
                ChoiceObjectMapping xmlChoiceObjectMapping = (ChoiceObjectMapping) mapping;
                xmlChoiceObjectMapping.addChoiceElement(xmlField, pTypeName);
                nestedMapping = (Mapping) xmlChoiceObjectMapping.getChoiceElementMappings().get(xmlField);
                if(pType.isEnum()) {
                    TypeInfo enumTypeInfo = typeInfo.get(pType.getQualifiedName());
                    ((DirectMapping)nestedMapping).setConverter(buildJAXBEnumTypeConverter(nestedMapping, (EnumTypeInfo) enumTypeInfo));
                }
                if(nestedMapping.isAbstractCompositeObjectMapping()){
                    ((CompositeObjectMapping)nestedMapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
                    nullPolicy = ((CompositeObjectMapping)nestedMapping).getNullPolicy();

                }else if(nestedMapping instanceof BinaryDataMapping){
                    nullPolicy = ((BinaryDataMapping)nestedMapping).getNullPolicy();
                }else if(nestedMapping instanceof DirectMapping){
                    nullPolicy = ((DirectMapping)nestedMapping).getNullPolicy();
                }
                
            }
            if(nullPolicy != null){
                nullPolicy.setNullRepresentedByEmptyNode(false);
                nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
                nullPolicy.setNullRepresentedByXsiNil(true);
                nullPolicy.setIgnoreAttributesForNil(false);
            }
            if (!element.isXmlRootElement()) {
                Class scopeClass = element.getScopeClass();
                if (scopeClass == javax.xml.bind.annotation.XmlElementDecl.GLOBAL.class){
                    scopeClass = JAXBElement.GlobalScope.class;
                }
                
                Class declaredType = null;
                if(element.getAdaptedJavaType() != null){
                	declaredType =  org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(element.getAdaptedJavaType().getQualifiedName(), helper.getClassLoader());
                }else{
                	declaredType =  org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(pType.getQualifiedName(), helper.getClassLoader());
                }
                
                JAXBElementConverter converter = new JAXBElementConverter(xmlField, declaredType, scopeClass);
                if (isCollection){
                    ChoiceCollectionMapping xmlChoiceCollectionMapping = (ChoiceCollectionMapping) mapping;
                    if(element.getJavaTypeAdapterClass() != null){                	                	
                    	converter.setNestedConverter(new XMLJavaTypeConverter(element.getJavaTypeAdapterClass().getName()));
                    }else{
                    	CoreConverter originalConverter = xmlChoiceCollectionMapping.getConverter(xmlField);
                        converter.setNestedConverter(originalConverter);	
                    }                    
                    xmlChoiceCollectionMapping.addConverter(xmlField, converter);
                } else {
                    ChoiceObjectMapping xmlChoiceObjectMapping = (ChoiceObjectMapping) mapping;
                    if(element.getJavaTypeAdapterClass() != null){                	                	
                    	converter.setNestedConverter(new XMLJavaTypeConverter(element.getJavaTypeAdapterClass().getName()));
                    }else{
                    	CoreConverter originalConverter = xmlChoiceObjectMapping.getConverter(xmlField);
                        converter.setNestedConverter(originalConverter);	
                    }  
                    xmlChoiceObjectMapping.addConverter(xmlField, converter);
                }
            }
        }
        if(property.isAny()){
        	if(isCollection){
                XMLChoiceCollectionMapping xmlChoiceCollectionMapping = (XMLChoiceCollectionMapping) mapping;
                xmlChoiceCollectionMapping.setIsAny(true);
        	}
        }
        
        return mapping;
    }

    private void setTypedTextField(Field field){
    	
    	field.setIsTypedTextField(true);
    	if(field.getSchemaType() == null){
    	    field.setSchemaType(Constants.ANY_TYPE_QNAME);
    	}
     	((XMLField)field).addXMLConversion(Constants.DATE_TIME_QNAME, CoreClassConstants.XML_GREGORIAN_CALENDAR);
    	((XMLField)field).addXMLConversion(Constants.DATE_QNAME, CoreClassConstants.XML_GREGORIAN_CALENDAR);
    	((XMLField)field).addXMLConversion(Constants.TIME_QNAME, CoreClassConstants.XML_GREGORIAN_CALENDAR);
    	((XMLField)field).addJavaConversion(CoreClassConstants.APBYTE, Constants.BASE_64_BINARY_QNAME);
    	((XMLField)field).addJavaConversion(CoreClassConstants.ABYTE, Constants.BASE_64_BINARY_QNAME);
       	
    }
    
    public AnyCollectionMapping generateAnyCollectionMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, boolean isMixed) {
        AnyCollectionMapping  mapping = new XMLAnyCollectionMapping();
        initializeXMLContainerMapping(mapping, property.getType().isArray());
        initializeXMLMapping((XMLMapping)mapping, property);

        // if the XPath is set (via xml-path) use it
        if (property.getXmlPath() != null) {
            mapping.setField(new XMLField(property.getXmlPath()));
        } else {
            if (property.isSetXmlElementWrapper()) {
                mapping.setField(getXPathForField(property, namespaceInfo, false, true));
            }
        }

        if (property.isSetXmlElementWrapper()) {
            mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
        }

        Class declaredType = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(property.getActualType().getQualifiedName(), helper.getClassLoader());
        JAXBElementRootConverter jaxbElementRootConverter = new JAXBElementRootConverter(declaredType);
        mapping.setConverter(jaxbElementRootConverter);
        if (property.getDomHandlerClassName() != null) {
            jaxbElementRootConverter.setNestedConverter(new DomHandlerConverter(property.getDomHandlerClassName()));
        }

        if (property.isLax() || property.isReference()) {
            mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
        } else {
            if (property.isAny()) {
                mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT);
            } else {
                mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_NONE_AS_ELEMENT);
            }
        }

        mapping.setMixedContent(isMixed);
        if (isMixed) {
            mapping.setPreserveWhitespaceForMixedContent(true);
        }
        if (property.isAny()) {
            mapping.setUseXMLRoot(true);
        }

        JavaClass collectionType = property.getType();
        if (collectionType.isArray()){
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            JavaClass componentType = collectionType.getComponentType();
            if(componentType.isArray()) {
                JavaClass baseComponentType = getBaseComponentType(componentType);
                if (baseComponentType.isPrimitive()){
                    Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName());
                    accessor.setComponentClass(primitiveClass);
                } else {
                    accessor.setComponentClassName(baseComponentType.getQualifiedName());
                }
            } else {
                accessor.setComponentClassName(componentType.getQualifiedName());
            }
            mapping.setAttributeAccessor(accessor);
        }
        collectionType = containerClassImpl(collectionType);
        mapping.useCollectionClass(helper.getClassForJavaClass(collectionType));
        
        return mapping;
    }

    public CompositeObjectMapping generateCompositeObjectMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, String referenceClassName) {
        CompositeObjectMapping mapping = new XMLCompositeObjectMapping();
      
        initializeXMLMapping((XMLMapping)mapping, property);

        // if the XPath is set (via xml-path) use it; otherwise figure it out
        mapping.setField((XMLField)getXPathForField(property, namespaceInfo, false, false));
        // handle null policy set via xml metadata
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else {
            NullPolicy nullPolicy = (NullPolicy) mapping.getNullPolicy();
            nullPolicy.setSetPerformedForAbsentNode(false);
            if(property.isNillable()) {
                nullPolicy.setNullRepresentedByXsiNil(true);
                nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
            }
        }

        if (referenceClassName == null){
        	setTypedTextField((Field)mapping.getField());
        	String defaultValue = property.getDefaultValue();
        	if (null != defaultValue) {
        	    mapping.setConverter(new DefaultElementConverter(defaultValue));
        	}
        } else {
        	mapping.setReferenceClassName(referenceClassName);
        }
            if(property.isTransientType()){
                mapping.setReferenceClassName(Constants.UNKNOWN_OR_TRANSIENT_CLASS);
            }
        
        if (property.isRequired()) {
            ((Field) mapping.getField()).setRequired(true);
        }
        return mapping;

    }

    public DirectMapping generateDirectMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo) {
    	DirectMapping mapping = new XMLDirectMapping();
        mapping.setNullValueMarshalled(true);
        
        String fixedValue = property.getFixedValue();
        if (fixedValue != null) {
            mapping.setIsWriteOnly(true);
        }
        initializeXMLMapping((XMLMapping)mapping, property);
   
        // if the XPath is set (via xml-path) use it; otherwise figure it out
        Field xmlField = getXPathForField(property, namespaceInfo, true, false);
        mapping.setField(xmlField);

        if (property.getDefaultValue() != null) {
            mapping.setNullValue(property.getDefaultValue());
        }

        if (property.isXmlId()) {
            mapping.setCollapsingStringValues(true);
        }

        // handle null policy set via xml metadata
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else {
            if (property.isNillable()){
                mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
                mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
            } 
            mapping.getNullPolicy().setNullRepresentedByEmptyNode(false);

            if (!mapping.getXPath().equals("text()")) {
                ((NullPolicy) mapping.getNullPolicy()).setSetPerformedForAbsentNode(false);
            }
        }

        if (property.isRequired()) {
            ((Field) mapping.getField()).setRequired(true);
        }

        if (property.getType() != null) {
            String theClass = null;
            String targetClass = null;
            if (property.isSetXmlJavaTypeAdapter()) {
                theClass = property.getOriginalType().getQualifiedName();
                targetClass = property.getType().getQualifiedName();                
            } else {
                theClass = property.getType().getQualifiedName();
                
            }
            // Try to get the actual Class
            try {
                JavaClass actualJavaClass = helper.getJavaClass(theClass);
                Class actualClass =  org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(actualJavaClass.getQualifiedName(), helper.getClassLoader());
                mapping.setAttributeClassification(actualClass);
                if(targetClass != null) {
                    Class fieldClass = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(targetClass, helper.getClassLoader());
                    mapping.getField().setType(fieldClass);
                }  
                
            } catch (Exception e) {
                // Couldn't find Class (Dynamic?), so set class name instead.
                mapping.setAttributeClassificationName(theClass);
            }
        }

        if (Constants.QNAME_QNAME.equals(property.getSchemaType())){
            ((Field) mapping.getField()).setSchemaType(Constants.QNAME_QNAME);
        }
        // handle cdata set via metadata
        if (property.isSetCdata()) {
            mapping.setIsCDATA(property.isCdata());
        }
        return mapping;
    }

    public BinaryDataMapping generateBinaryMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo) {
        BinaryDataMapping mapping = new XMLBinaryDataMapping();
      
        initializeXMLMapping((XMLMapping)mapping, property);

        // if the XPath is set (via xml-path) use it
        mapping.setField(getXPathForField(property, namespaceInfo, false, false));
        if (property.isSwaAttachmentRef()) {
            ((Field) mapping.getField()).setSchemaType(Constants.SWA_REF_QNAME);
            mapping.setSwaRef(true);
        } else if (property.isMtomAttachment()) {
            Field f = ((Field) mapping.getField());
            if (!f.getSchemaType().equals(Constants.HEX_BINARY_QNAME)) {
                f.setSchemaType(Constants.BASE_64_BINARY_QNAME);
            }
        }
         
        if (property.isInlineBinaryData()) {
            mapping.setShouldInlineBinaryData(true);
        }
        // use a non-dynamic implementation of MimeTypePolicy to wrap the MIME string
        if (property.getMimeType() != null) {
            mapping.setMimeTypePolicy(new FixedMimeTypePolicy(property.getMimeType(),(DatabaseMapping) mapping));
        } else {
            if(areEquals(property.getType(), javax.xml.transform.Source.class)) {
                mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/xml", (DatabaseMapping)mapping));
            } else if(areEquals(property.getType(), java.awt.Image.class)) {
                mapping.setMimeTypePolicy(new FixedMimeTypePolicy("image/png", (DatabaseMapping)mapping));
            } else {
                mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/octet-stream", (DatabaseMapping)mapping));
            }
        }
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else {
            if (property.isNillable()){
                mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
                mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
            } 
            mapping.getNullPolicy().setNullRepresentedByEmptyNode(false);

            if (!mapping.getXPath().equals("text()")) {
                ((NullPolicy) mapping.getNullPolicy()).setSetPerformedForAbsentNode(false);
            }
        }
        mapping.setAttributeClassificationName(property.getActualType().getQualifiedName());
        return mapping;
    }

    public BinaryDataCollectionMapping generateBinaryDataCollectionMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo) {
        BinaryDataCollectionMapping mapping = new XMLBinaryDataCollectionMapping();
        initializeXMLMapping((XMLMapping)mapping, property);

        initializeXMLContainerMapping(mapping, property.getType().isArray());
    
        if (property.isSetXmlElementWrapper()) {
            mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
        }
     
        // handle null policy set via xml metadata
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else if (property.isNillable()){
            mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
            mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
        }
        
        // if the XPath is set (via xml-path) use it
        mapping.setField(getXPathForField(property, namespaceInfo, false, false));
        if (property.isSwaAttachmentRef()) {
            ((Field) mapping.getField()).setSchemaType(Constants.SWA_REF_QNAME);
            mapping.setSwaRef(true);
        } else if (property.isMtomAttachment()) {
            Field f = (Field) mapping.getField();
            if (!f.getSchemaType().equals(Constants.HEX_BINARY_QNAME)) {
                f.setSchemaType(Constants.BASE_64_BINARY_QNAME);
            }            
        }
        if (property.isInlineBinaryData()) {
            mapping.setShouldInlineBinaryData(true);
        }
        // use a non-dynamic implementation of MimeTypePolicy to wrap the MIME string
        if (property.getMimeType() != null) {
            mapping.setMimeTypePolicy(new FixedMimeTypePolicy(property.getMimeType()));
        } else {
        	if(areEquals(property.getType(), javax.xml.transform.Source.class)) {
                mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/xml"));
        	} else {
        		mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/octet-stream"));
        	}
        }

        JavaClass collectionType = property.getType();
        JavaClass itemType = property.getActualType();
        if(collectionType != null && helper.isCollectionType(collectionType)){
            try{
                Class declaredClass = PrivilegedAccessHelper.getClassForName(itemType.getQualifiedName(), false, helper.getClassLoader());
                mapping.setAttributeElementClass(declaredClass);
            }catch (Exception e) {
            }
        }
        collectionType = containerClassImpl(collectionType);
        mapping.useCollectionClassName(collectionType.getRawName());
        return mapping;
    }
    
    public DirectMapping generateDirectEnumerationMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, EnumTypeInfo enumInfo) {
    	DirectMapping mapping = new XMLDirectMapping();
    	initializeXMLMapping((XMLMapping)mapping, property);
        mapping.setNullValueMarshalled(true);
        mapping.setConverter(buildJAXBEnumTypeConverter(mapping, enumInfo));
        mapping.setField(getXPathForField(property, namespaceInfo, true, false));
        if (!mapping.getXPath().equals("text()")) {
            ((NullPolicy) mapping.getNullPolicy()).setSetPerformedForAbsentNode(false);
        }
        return mapping;
    }

    private JAXBEnumTypeConverter buildJAXBEnumTypeConverter(Mapping mapping, EnumTypeInfo enumInfo){
        JAXBEnumTypeConverter converter = new JAXBEnumTypeConverter(mapping, enumInfo.getClassName(), false);
        List<String> fieldNames = enumInfo.getFieldNames();
        List<Object> xmlEnumValues = enumInfo.getXmlEnumValues();
        for (int i=0; i< fieldNames.size(); i++) {
            converter.addConversionValue(xmlEnumValues.get(i), fieldNames.get(i));
        }
        return converter;
    }

    public Mapping generateCollectionMapping(Property property, Descriptor descriptor, JavaClass descriptorJavaClass, NamespaceInfo namespaceInfo) {
        // check to see if this should be a composite or direct mapping
        JavaClass javaClass = property.getActualType();

        if (property.isMixedContent()) {
            return generateAnyCollectionMapping(property, descriptor, namespaceInfo, true);
        }
        if (property.isXmlIdRef() || property.isSetXmlJoinNodes()) {
            return generateXMLCollectionReferenceMapping(property, descriptor, namespaceInfo, javaClass);
        }
        
        if (javaClass != null && typeInfo.get(javaClass.getQualifiedName()) != null) {
            TypeInfo referenceInfo = typeInfo.get(javaClass.getQualifiedName());
            if (referenceInfo.isEnumerationType()) {
                return generateEnumCollectionMapping(property,  descriptor, namespaceInfo,(EnumTypeInfo) referenceInfo);
            }
            return generateCompositeCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo, javaClass.getQualifiedName());
        }
        if (!property.isAttribute() && javaClass != null && javaClass.getQualifiedName().equals(OBJECT_CLASS_NAME)){
            CompositeCollectionMapping ccMapping = generateCompositeCollectionMapping(property, descriptor, descriptorJavaClass, namespaceInfo, null);
            ccMapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
            return ccMapping;
        }
        if(isBinaryData(javaClass)){
        	return generateBinaryDataCollectionMapping(property, descriptor, namespaceInfo);
        }
        return generateDirectCollectionMapping(property, descriptor, namespaceInfo);
    }

    public DirectCollectionMapping generateEnumCollectionMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, EnumTypeInfo info) {
    	
    	DirectCollectionMapping mapping = generateDirectCollectionMapping(property, descriptor, namespaceInfo);
    	mapping.setValueConverter(buildJAXBEnumTypeConverter(mapping, info));
    	return mapping;
    }
    public AnyAttributeMapping generateAnyAttributeMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo) {
        AnyAttributeMapping mapping = new XMLAnyAttributeMapping();
        initializeXMLMapping((XMLAnyAttributeMapping)mapping, property);
        initializeXMLContainerMapping(mapping, property.getType().isArray());
     
        // if the XPath is set (via xml-path) use it
        if (property.getXmlPath() != null) {
            mapping.setField(new XMLField(property.getXmlPath()));
        }
        mapping.setSchemaInstanceIncluded(false);
        mapping.setNamespaceDeclarationIncluded(false);

        JavaClass mapType = property.getType();
        if (areEquals(mapType, Map.class)) {
            mapType = jotHashMap;
        }
        mapping.useMapClassName(mapType.getRawName());
        
        return mapping;
    }

    public AnyObjectMapping generateAnyObjectMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo)  {
        AnyObjectMapping mapping = new XMLAnyObjectMapping();
        initializeXMLMapping((XMLMapping)mapping, property);

        // if the XPath is set (via xml-path) use it
        if (property.getXmlPath() != null) {
            mapping.setField(new XMLField(property.getXmlPath()));
        }

        Class declaredType = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(property.getActualType().getQualifiedName(), helper.getClassLoader());
        JAXBElementRootConverter jaxbElementRootConverter = new JAXBElementRootConverter(declaredType);
        mapping.setConverter(jaxbElementRootConverter);
        if (property.getDomHandlerClassName() != null) {
            jaxbElementRootConverter.setNestedConverter(new DomHandlerConverter(property.getDomHandlerClassName()));
        }

        if (property.isLax()) {
            mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
        } else {
            mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT);
        }

        if (property.isMixedContent()) {
            mapping.setMixedContent(true);
        } else {
            mapping.setUseXMLRoot(true);
        }
        
        return mapping;
    }

    protected boolean areEquals(JavaClass src, Class tgt) {
        if (src == null || tgt == null) {
            return false;
        }
        return src.getRawName().equals(tgt.getCanonicalName());
    }

    /**
     * Compares a JavaModel JavaClass to a Class.  Equality is based on
     * the raw name of the JavaClass compared to the canonical
     * name of the Class.
     *
     * @param src
     * @param tgtCanonicalName
     * @return
     */
    protected boolean areEquals(JavaClass src, String tgtCanonicalName) {
        if (src == null || tgtCanonicalName == null) {
            return false;
        }
        return src.getRawName().equals(tgtCanonicalName);
    }


    private Class generateMapEntryClassAndDescriptor(Property property, NamespaceResolver nr){
    	JavaClass keyType = property.getKeyType();
        JavaClass valueType = property.getValueType();
        if(keyType == null){
        	keyType = helper.getJavaClass("java.lang.Object");
        }
        if(valueType == null){
        	valueType = helper.getJavaClass("java.lang.Object");
        }
        
        String mapEntryClassName = getJaxbClassLoader().nextAvailableGeneratedClassName();

        MapEntryGeneratedKey mapKey = new MapEntryGeneratedKey(keyType.getQualifiedName(),valueType.getQualifiedName());
    	Class generatedClass = getGeneratedMapEntryClasses().get(mapKey);

        if(generatedClass == null){
            generatedClass = generateMapEntryClass(mapEntryClassName, keyType.getQualifiedName(), valueType.getQualifiedName());
            getGeneratedMapEntryClasses().put(mapKey, generatedClass);
            Descriptor desc = new XMLDescriptor();
            desc.setJavaClass(generatedClass);

            desc.addMapping((CoreMapping)generateMappingForType(keyType, Property.DEFAULT_KEY_NAME));
            desc.addMapping((CoreMapping)generateMappingForType(valueType, Property.DEFAULT_VALUE_NAME));
            desc.setNamespaceResolver(nr);
            project.addDescriptor((CoreDescriptor)desc);
        }
        return generatedClass;
    }

    private Class generateMapEntryClass(String className, String keyType, String valueType){

        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

        String qualifiedInternalClassName = className.replace('.', '/');
        String qualifiedInternalKeyClassName = keyType.replace('.', '/');
        String qualifiedInternalValueClassName = valueType.replace('.', '/');

        String valuePrefix = "L"; // non-array type
        if (qualifiedInternalValueClassName.startsWith("[L") && qualifiedInternalValueClassName.endsWith(";")) {
            valuePrefix = "[L"; // array type
            qualifiedInternalValueClassName = qualifiedInternalValueClassName.substring(2, qualifiedInternalValueClassName.length() - 1);
        }

        String sig = "Ljava/lang/Object;Lorg/eclipse/persistence/internal/jaxb/many/MapEntry<L"+qualifiedInternalKeyClassName+";" + valuePrefix + qualifiedInternalValueClassName+";>;";
        cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, qualifiedInternalClassName, sig, "java/lang/Object", new String[] { "org/eclipse/persistence/internal/jaxb/many/MapEntry" });

        cw.visitField(Opcodes.ACC_PRIVATE, "key", "L"+qualifiedInternalKeyClassName+";", null, null);

        cw.visitField(Opcodes.ACC_PRIVATE, "value", valuePrefix + qualifiedInternalValueClassName+";", null, null);

        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
        
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getKey", "()L"+qualifiedInternalKeyClassName+";", null, null);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitFieldInsn(Opcodes.GETFIELD, qualifiedInternalClassName, "key", "L"+qualifiedInternalKeyClassName+";");
        mv.visitInsn(Opcodes.ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
        
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setKey", "(L"+qualifiedInternalKeyClassName+";)V", null, null);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitFieldInsn(Opcodes.PUTFIELD, qualifiedInternalClassName, "key", "L"+qualifiedInternalKeyClassName+";");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(2, 2);
        mv.visitEnd();

        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getValue", "()" + valuePrefix + qualifiedInternalValueClassName+";", null, null);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitFieldInsn(Opcodes.GETFIELD, qualifiedInternalClassName, "value", valuePrefix + qualifiedInternalValueClassName+";");
        mv.visitInsn(Opcodes.ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();

        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setValue", "(" + valuePrefix + qualifiedInternalValueClassName+";)V", null, null);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 1);
        mv.visitFieldInsn(Opcodes.PUTFIELD, qualifiedInternalClassName, "value", valuePrefix + qualifiedInternalValueClassName+";");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(2, 2);
        mv.visitEnd();
        
        if(!qualifiedInternalValueClassName.equals("java/lang/Object")){
	        mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "getValue", "()Ljava/lang/Object;", null, null);
	        mv.visitVarInsn(Opcodes.ALOAD, 0);
	        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "getValue", "()" + valuePrefix + qualifiedInternalValueClassName+";", false);
	        mv.visitInsn(Opcodes.ARETURN);
	        mv.visitMaxs(1, 1);
	        mv.visitEnd();
	        
	        mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "setValue", "(Ljava/lang/Object;)V", null, null);
	        mv.visitVarInsn(Opcodes.ALOAD, 0);
	        mv.visitVarInsn(Opcodes.ALOAD, 1);
	        // CHECKCAST is slightly different for array types
	        if (valuePrefix.equals("[L")) {
	            mv.visitTypeInsn(Opcodes.CHECKCAST, valuePrefix + qualifiedInternalValueClassName + ";");
	        } else {
	            mv.visitTypeInsn(Opcodes.CHECKCAST, qualifiedInternalValueClassName);
	        }
	        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "setValue", "(" + valuePrefix + qualifiedInternalValueClassName+";)V", false);
	        mv.visitInsn(Opcodes.RETURN);
	        mv.visitMaxs(2, 2);
	        mv.visitEnd();
        }

        if(!qualifiedInternalKeyClassName.equals("java/lang/Object")){
            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "getKey", "()Ljava/lang/Object;", null, null);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,qualifiedInternalClassName, "getKey", "()L"+qualifiedInternalKeyClassName+";", false);
            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
            
            mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "setKey", "(Ljava/lang/Object;)V", null, null);
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitVarInsn(Opcodes.ALOAD, 1);
            mv.visitTypeInsn(Opcodes.CHECKCAST, qualifiedInternalKeyClassName);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "setKey", "(L"+qualifiedInternalKeyClassName+";)V", false);
            mv.visitInsn(Opcodes.RETURN);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }

        cw.visitEnd();

        byte[] classBytes =cw.toByteArray();
        Class generatedClass = getJaxbClassLoader().generateClass(className, classBytes);
        return generatedClass;
    }

    private Mapping generateMappingForType(JavaClass theType, String attributeName){
    	Mapping mapping;
        boolean typeIsObject =  theType.getRawName().equals(OBJECT_CLASS_NAME);
        TypeInfo info = typeInfo.get(theType.getQualifiedName());
        if ((info != null && !(info.isEnumerationType())) || typeIsObject) {
            mapping = new XMLCompositeObjectMapping();
            mapping.setAttributeName(attributeName);
            ((CompositeObjectMapping)mapping).setXPath(attributeName);
            if(typeIsObject){
            	((CompositeObjectMapping)mapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
            	setTypedTextField((Field)((CompositeObjectMapping)mapping).getField());
            }else{
		((CompositeObjectMapping)mapping).setReferenceClassName(theType.getQualifiedName());
            }
        } else if (theType.isArray() || helper.isCollectionType(theType)) {
            DirectCollectionMapping directCollectionMapping;
            mapping = directCollectionMapping = new XMLCompositeDirectCollectionMapping();
            initializeXMLContainerMapping(directCollectionMapping, theType.isArray());
            directCollectionMapping.setAttributeName(attributeName);
            if (theType.isArray()) {
                JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(directCollectionMapping.getAttributeAccessor(),
                        directCollectionMapping.getContainerPolicy(), helper.getClassLoader());
                String componentClassName = theType.getComponentType().getQualifiedName();
                if (theType.getComponentType().isPrimitive()){
                    Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(componentClassName);
                    accessor.setComponentClass(primitiveClass);
                    directCollectionMapping.setAttributeAccessor(accessor);

                    Class declaredClass = XMLConversionManager.getDefaultManager().getObjectClass(primitiveClass);
                    directCollectionMapping.setAttributeElementClass(declaredClass);
                } else {
                    accessor.setComponentClassName(componentClassName);
                    directCollectionMapping.setAttributeAccessor(accessor);

                    JavaClass componentType = theType.getComponentType();
                    try {
                        Class declaredClass;
                        if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
                                try {
                                    declaredClass = AccessController.doPrivileged(new PrivilegedClassForName(componentType.getRawName(), false, helper.getClassLoader()));
                                } catch (PrivilegedActionException exception) {
                                    throw JAXBException.classNotFoundException(componentType.getRawName());
                                }
                        } else {
                            declaredClass = PrivilegedAccessHelper.getClassForName(componentType.getRawName(), false, helper.getClassLoader());
                        }
                        directCollectionMapping.setAttributeElementClass(declaredClass);
                    } catch (ClassNotFoundException e) {
                        throw JAXBException.classNotFoundException(componentType.getRawName());
                    }
                }
            } else if (helper.isCollectionType(theType)) {
                Collection args = theType.getActualTypeArguments();
                if (args.size() > 0) {
                    JavaClass itemType = (JavaClass)args.iterator().next();
                    try {
                        Class declaredClass;
                        if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) {
                                try {
                                    declaredClass = AccessController.doPrivileged(new PrivilegedClassForName(itemType.getRawName(), false, helper.getClassLoader()));
                                } catch (PrivilegedActionException exception) {
                                    throw JAXBException.classNotFoundException(itemType.getRawName());
                                }
                        } else {
                            declaredClass = PrivilegedAccessHelper.getClassForName(itemType.getRawName(), false, helper.getClassLoader());
                        }
                        if(declaredClass != String.class){
                            directCollectionMapping.setAttributeElementClass(declaredClass);
                        }
                    } catch (ClassNotFoundException e) {
                        throw JAXBException.classNotFoundException(itemType.getRawName());
                    }
                }
            }
            theType = containerClassImpl(theType);
            directCollectionMapping.useCollectionClassName(theType.getRawName());
            directCollectionMapping.setXPath(attributeName + TXT);
        } else {
            mapping = new XMLDirectMapping();
            mapping.setAttributeName(attributeName);
            ((DirectMapping)mapping).setNullValueMarshalled(true);
            ((DirectMapping)mapping).setXPath(attributeName + TXT);

            QName schemaType = userDefinedSchemaTypes.get(theType.getQualifiedName());

            if (schemaType == null) {
                schemaType = (QName) helper.getXMLToJavaTypeMap().get(theType);
            }
            ((Field)((DirectMapping)mapping).getField()).setSchemaType(schemaType);
            if(info != null && info.isEnumerationType()) {
                ((DirectMapping)mapping).setConverter(buildJAXBEnumTypeConverter(mapping, (EnumTypeInfo)info));
            }
        }
        return mapping;
    }

    public CompositeCollectionMapping generateCompositeCollectionMapping(Property property, Descriptor descriptor, JavaClass javaClass, NamespaceInfo namespaceInfo, String referenceClassName) {
        CompositeCollectionMapping mapping = new XMLCompositeCollectionMapping();
        initializeXMLMapping((XMLMapping)mapping, property);
        initializeXMLContainerMapping(mapping, property.getType().isArray());
        
        JavaClass manyValueJavaClass = helper.getJavaClass(ManyValue.class);        
        if (manyValueJavaClass.isAssignableFrom(javaClass)){
            mapping.setReuseContainer(false);
        }
     
        // handle null policy set via xml metadata
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else if (property.isNillable()){
            mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
            mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
        }
        
        if (property.isSetXmlElementWrapper()) {
            mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
        }

        JavaClass collectionType = property.getType();

        if (collectionType.isArray()){
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            JavaClass componentType = collectionType.getComponentType();
            if(componentType.isArray()) {
                Class adaptedClass = classToGeneratedClasses.get(componentType.getName());
                referenceClassName = adaptedClass.getName();
                accessor.setAdaptedClassName(referenceClassName);
                JavaClass baseComponentType = getBaseComponentType(componentType);
                if (baseComponentType.isPrimitive()){
                    Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName());
                    accessor.setComponentClass(primitiveClass);
                } else {
                    accessor.setComponentClassName(baseComponentType.getQualifiedName());
                }
            } else {
                accessor.setComponentClassName(componentType.getQualifiedName());
            }
            mapping.setAttributeAccessor(accessor);
        }else if (helper.isMapType(property.getType())){
            Class generatedClass = generateMapEntryClassAndDescriptor(property, descriptor.getNonNullNamespaceResolver());
            referenceClassName = generatedClass.getName();
            String mapClassName = property.getType().getRawName();
            mapping.setAttributeAccessor(new MapValueAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), generatedClass, mapClassName, helper.getClassLoader()));
        }
        collectionType = containerClassImpl(collectionType);
        mapping.useCollectionClassName(collectionType.getRawName());

        // if the XPath is set (via xml-path) use it; otherwise figure it out
        Field xmlField = getXPathForField(property, namespaceInfo, false, false);
        if(helper.isMapType(property.getType())){
    	    JavaClass mapValueClass = helper.getJavaClass(MapValue.class);
	        if(mapValueClass.isAssignableFrom(javaClass)){
	        	mapping.setXPath("entry");
	        }else{
	        	mapping.setXPath(xmlField.getXPath() + "/entry");
	        }
        }else{
        	mapping.setXPath(xmlField.getXPath());
        }

        if (referenceClassName == null){                   
        	setTypedTextField((Field)mapping.getField());
        } else {
        	mapping.setReferenceClassName(referenceClassName);
        }
        if(property.isTransientType()){
            mapping.setReferenceClassName(Constants.UNKNOWN_OR_TRANSIENT_CLASS);   
        }    

        if (property.isRequired()) {
            ((Field) mapping.getField()).setRequired(true);
        }
           
        return mapping;
    }

    public DirectCollectionMapping generateDirectCollectionMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo) {
        DirectCollectionMapping mapping = new XMLCompositeDirectCollectionMapping();
        initializeXMLMapping((XMLMapping)mapping, property);

        initializeXMLContainerMapping(mapping, property.getType().isArray());
     
        JavaClass collectionType = property.getType();

        if (collectionType.isArray()){
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            String componentClassName = collectionType.getComponentType().getQualifiedName();
            if (collectionType.getComponentType().isPrimitive()){
                Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(componentClassName);
                accessor.setComponentClass(primitiveClass);
                mapping.setAttributeAccessor(accessor);

                Class declaredClass = XMLConversionManager.getDefaultManager().getObjectClass(primitiveClass);
                mapping.setAttributeElementClass(declaredClass);
            } else {
                accessor.setComponentClassName(componentClassName);
                mapping.setAttributeAccessor(accessor);

                JavaClass componentType = collectionType.getComponentType();
                try{
                    Class declaredClass = PrivilegedAccessHelper.getClassForName(componentType.getRawName(), false, helper.getClassLoader());
                    mapping.setAttributeElementClass(declaredClass);
                }catch (Exception e) {}
            }
        } else if (helper.isCollectionType(collectionType)){
            Collection args = collectionType.getActualTypeArguments();
        	if (args.size() >0){
        		JavaClass itemType = (JavaClass)args.iterator().next();
        		try {
        			Class declaredClass = PrivilegedAccessHelper.getClassForName(itemType.getRawName(), false, helper.getClassLoader());
        			if(declaredClass != String.class){
        			    mapping.setAttributeElementClass(declaredClass);
        			}
        		} catch (Exception e) {}
        	}
        }
        collectionType = containerClassImpl(collectionType);
        mapping.useCollectionClassName(collectionType.getRawName());

        if (property.getDefaultValue() != null) {
            mapping.setNullValue(property.getDefaultValue());
        }
        
        // if the XPath is set (via xml-path) use it; otherwise figure it out
        Field xmlField = getXPathForField(property, namespaceInfo, true, false);
        mapping.setField(xmlField);

        if (helper.isAnnotationPresent(property.getElement(), XmlMixed.class)) {
            xmlField.setXPath("text()");
        }

        if (Constants.QNAME_QNAME.equals(property.getSchemaType())){
            ((Field) mapping.getField()).setSchemaType(Constants.QNAME_QNAME);
        }

        // handle null policy set via xml metadata
        if (property.isSetNullPolicy()) {
            mapping.setNullPolicy(getNullPolicyFromProperty(property, getNamespaceResolverForDescriptor(namespaceInfo)));
        } else if (property.isNillable()){
            mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
            mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
        }
        mapping.getNullPolicy().setNullRepresentedByEmptyNode(false);

        if (property.isSetXmlElementWrapper()) {
            mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property));
        }

        if (property.isRequired()) {
            ((Field) mapping.getField()).setRequired(true);
        }

        if (property.isXmlElementType() && property.getGenericType()!=null ){
        	Class theClass = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(property.getGenericType().getQualifiedName(), helper.getClassLoader());
        	mapping.setAttributeElementClass(theClass);
        }

        if (xmlField.getXPathFragment().isAttribute() || property.isXmlList() || xmlField.getXPathFragment().nameIsText()){
            mapping.setUsesSingleNode(true);
        }
        // handle cdata set via metadata
        if (property.isSetCdata()) {
            mapping.setIsCDATA(property.isCdata());
        }
        return mapping;
    }


    public String getPrefixForNamespace(String URI, NamespaceResolver namespaceResolver) {
    	return getPrefixForNamespace(URI, namespaceResolver, true);
    }
    
    public String getPrefixForNamespace(String URI, NamespaceResolver namespaceResolver, boolean addPrefixToNR) {
    	String defaultNS = namespaceResolver.getDefaultNamespaceURI();
    	if(defaultNS != null && URI.equals(defaultNS)){
    		return null;
    	}
        String prefix = namespaceResolver.resolveNamespaceURI(URI);
        if (prefix != null) {
            return prefix;
        }
        prefix = globalNamespaceResolver.resolveNamespaceURI(URI);
        if(prefix == null){
            if(URI.equals(globalNamespaceResolver.getDefaultNamespaceURI())) { 
                namespaceResolver.setDefaultNamespaceURI(URI);
                return null;
            } else {            	
            	//Bug 400536 before generating a new one check other resolvers
            	String suggestedPrefix = null;
                NamespaceInfo refInfo = getNamespaceInfoForURI(URI);
            	if(refInfo != null && refInfo.getNamespaceResolver() !=null){
            		suggestedPrefix = refInfo.getNamespaceResolver().resolveNamespaceURI(URI);
            	}            	
            	if(suggestedPrefix != null){
            	    prefix = globalNamespaceResolver.generatePrefix(suggestedPrefix);
                } else{
            	    prefix = globalNamespaceResolver.generatePrefix();
                }
            }
        }
       
        String nrUri = namespaceResolver.resolveNamespacePrefix(prefix);
    	while(null != nrUri && !URI.equals(nrUri)){
        	prefix = globalNamespaceResolver.generatePrefix();
        	nrUri = namespaceResolver.resolveNamespacePrefix(prefix);
        }
        if(addPrefixToNR){
        	namespaceResolver.put(prefix, URI);        	
        }
        globalNamespaceResolver.put(prefix, URI);
        return prefix;
    }

    /**
     * Setup inheritance for abstract superclass.
     *
     * NOTE: We currently only handle one level of inheritance in this case.
     * For multiple levels the code will need to be modified. The logic in
     * generateMappings() that determines when to copy down inherited
     * methods from the parent class will need to be changed as well.
     *
     * @param jClass
     */
    private void setupInheritance(JavaClass jClass) {
        TypeInfo tInfo = typeInfo.get(jClass.getName());
        Descriptor descriptor = tInfo.getDescriptor();
        if (descriptor == null) {
            return;
        }

        JavaClass superClass = CompilerHelper.getNextMappedSuperClass(jClass, typeInfo, helper);
        if (superClass == null){
            return;
        }

        TypeInfo superTypeInfo =  typeInfo.get(superClass.getName());
        if (superTypeInfo == null){
        	return;
        }
        Descriptor superDescriptor = superTypeInfo.getDescriptor();
        if (superDescriptor != null) {
            XMLSchemaReference sRef = descriptor.getSchemaReference();
            if (sRef == null || sRef.getSchemaContext() == null) {
                return;
            }

            JavaClass rootMappedSuperClass = getRootMappedSuperClass(superClass);
            TypeInfo rootTypeInfo =  typeInfo.get(rootMappedSuperClass.getName());
            Descriptor rootDescriptor = rootTypeInfo.getDescriptor();
            if (rootDescriptor.getNamespaceResolver() == null) {
                rootDescriptor.setNamespaceResolver(new org.eclipse.persistence.oxm.NamespaceResolver());
            }

            if (rootDescriptor.getInheritancePolicy().getClassIndicatorField() == null) {
                Field classIndicatorField;
                if (rootTypeInfo.isSetXmlDiscriminatorNode()) {
                    classIndicatorField = new XMLField(rootTypeInfo.getXmlDiscriminatorNode());
                } else {
                    classIndicatorField = new XMLField(ATT + "type");
                    classIndicatorField.getXPathFragment().setNamespaceURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
                }
            	rootDescriptor.getInheritancePolicy().setClassIndicatorField(classIndicatorField);
            }

            Object sCtx = null;
            //TypeInfo tInfo = typeInfo.get(jClass.getName());
            if (tInfo.isSetXmlDiscriminatorValue()) {
                sCtx = tInfo.getXmlDiscriminatorValue();
            } else if(!tInfo.isAnonymousComplexType()){
            	sCtx = sRef.getSchemaContextAsQName();
            }
            if(sCtx != null) {
                descriptor.getInheritancePolicy().setParentClassName(superClass.getName());
                rootDescriptor.getInheritancePolicy().addClassNameIndicator(jClass.getName(), sCtx);
            }
            Object value = rootDescriptor.getInheritancePolicy().getClassNameIndicatorMapping().get(rootDescriptor.getJavaClassName());
            if (value == null){
                if (rootTypeInfo.isSetXmlDiscriminatorValue()) {
                    rootDescriptor.getInheritancePolicy().addClassNameIndicator(rootDescriptor.getJavaClassName(), rootTypeInfo.getXmlDiscriminatorValue());
                } else {
                    XMLSchemaReference rootSRef = rootDescriptor.getSchemaReference();
                    if (rootSRef != null && rootSRef.getSchemaContext() != null) {
                    	QName rootSCtx = rootSRef.getSchemaContextAsQName();
                        rootDescriptor.getInheritancePolicy().addClassNameIndicator(rootDescriptor.getJavaClassName(), rootSCtx);
                    }
                }
            }
            rootDescriptor.getInheritancePolicy().setShouldReadSubclasses(true);
            //Check for attributeGroups
            Map<String, AttributeGroup> childGroups = ((XMLDescriptor)descriptor).getAttributeGroups();
            Map<String, AttributeGroup> parentGroups = ((XMLDescriptor)rootDescriptor).getAttributeGroups();
            if(childGroups != null && !(childGroups.isEmpty()) && parentGroups != null && !(parentGroups.isEmpty())) {
                for(String nextKey:childGroups.keySet()) {
                    AttributeGroup parentGroup = parentGroups.get(nextKey);
                    if(parentGroup != null) {
                        AttributeGroup childGroup = childGroups.get(nextKey);
                        parentGroup.getSubClassGroups().put(descriptor.getJavaClassName(), childGroup);
                    }
                }
            }
        }
    }

    private JavaClass getRootMappedSuperClass(JavaClass javaClass){
        JavaClass rootMappedSuperClass = javaClass;

        JavaClass nextMappedSuperClass = rootMappedSuperClass;
        while(nextMappedSuperClass != null){
            nextMappedSuperClass = CompilerHelper.getNextMappedSuperClass(nextMappedSuperClass, this.typeInfo, helper);
            if(nextMappedSuperClass == null){
                return rootMappedSuperClass;
            }
            rootMappedSuperClass = nextMappedSuperClass;
        }

        return rootMappedSuperClass;
    }

    public void generateMappings() {
        Iterator javaClasses = this.typeInfo.keySet().iterator();
        while (javaClasses.hasNext()) {
            String next = (String)javaClasses.next();
            JavaClass javaClass = helper.getJavaClass(next);
            TypeInfo info = (TypeInfo) this.typeInfo.get(next);            
            if (info.isEnumerationType()) {
                continue;
            }
            NamespaceInfo namespaceInfo = this.packageToPackageInfoMappings.get(javaClass.getPackageName()).getNamespaceInfo();

            Descriptor descriptor = info.getDescriptor();
            if (descriptor != null) {
                generateMappings(info, descriptor, javaClass, namespaceInfo);
                // set primary key fields (if necessary)
                CoreMapping mapping;
                // handle XmlID
                if (info.isIDSet()) {
                    mapping = descriptor.getMappingForAttributeName(info.getIDProperty().getPropertyName());
                    if (mapping != null) {
                        descriptor.addPrimaryKeyField(mapping.getField());
                    }
                }
                // handle XmlKey
                if (info.hasXmlKeyProperties()) {
                    for (Property keyProp : info.getXmlKeyProperties()) {
                        mapping = descriptor.getMappingForAttributeName(keyProp.getPropertyName());
                        if (mapping != null) {
                            descriptor.addPrimaryKeyField(mapping.getField());
                        }                    
                    }
                }
            }
            info.postInitialize();
        }
    }

    /**
     * Generate mappings for a given TypeInfo.
     *
     * @param info
     * @param descriptor
     * @param namespaceInfo
     */
    public void generateMappings(TypeInfo info, Descriptor descriptor, JavaClass descriptorJavaClass, NamespaceInfo namespaceInfo) {
        if(info.isAnonymousComplexType()) {
            //may need to generate inherited mappings
            generateInheritedMappingsForAnonymousType(info, descriptor, descriptorJavaClass, namespaceInfo);
        }
        List<Property> propertiesInOrder = info.getNonTransientPropertiesInPropOrder();
        for (int i = 0; i < propertiesInOrder.size(); i++) {
            Property next = propertiesInOrder.get(i);
            if (next != null && (!next.isTransient() || (next.isTransient() && next.isXmlLocation()))) {
                Mapping mapping = generateMapping(next, descriptor, descriptorJavaClass, namespaceInfo);
                if (next.isVirtual()) {
                    VirtualAttributeAccessor accessor = new VirtualAttributeAccessor();
                    accessor.setAttributeName(mapping.getAttributeName());

                    String getMethod = info.getXmlVirtualAccessMethods().getGetMethod();
                    String setMethod = info.getXmlVirtualAccessMethods().getSetMethod();

                    // Check to see if get/set were overridden in the mapping
                    if (mapping.getAttributeAccessor().isMethodAttributeAccessor()) {
                        getMethod = ((MethodAttributeAccessor) mapping.getAttributeAccessor()).getGetMethodName();
                        setMethod = ((MethodAttributeAccessor) mapping.getAttributeAccessor()).getSetMethodName();
                        accessor.setValueType(mapping.getAttributeClassification());
                    }

                    accessor.setGetMethodName(getMethod);
                    accessor.setSetMethodName(setMethod);

                    if (mapping.getAttributeAccessor() instanceof JAXBArrayAttributeAccessor) {
                        JAXBArrayAttributeAccessor jaa = (JAXBArrayAttributeAccessor) mapping.getAttributeAccessor();
                        jaa.setNestedAccessor(accessor);
                    } else {
                        mapping.setAttributeAccessor(accessor);
                    }
                }
                if (mapping != null) {
                    descriptor.addMapping((CoreMapping)mapping);
                }
                // set user-defined properties if necessary
                if (next.isSetUserProperties()) {
                    mapping.setProperties(next.getUserProperties());
                }
                //get package info
                AccessorFactoryWrapper accessorFactory = info.getXmlAccessorFactory();
                if(accessorFactory == null) {
                    accessorFactory = info.getPackageLevelXmlAccessorFactory();
                }
                if(accessorFactory != null) {
                    try {
                        Object accessor = CompilerHelper.createAccessorFor(descriptorJavaClass, next, helper, accessorFactory);
                        
                        if(accessor != null) {
                            CustomAccessorAttributeAccessor attributeAccessor = new CustomAccessorAttributeAccessor(accessor);
                            mapping.setAttributeAccessor(attributeAccessor);
                        }
                    } catch(Exception ex) {}
                }
            }
            next.postInitialize();
        }
    }

    private void generateInheritedMappingsForAnonymousType(TypeInfo info, Descriptor descriptor, JavaClass descriptorJavaClass, NamespaceInfo namespaceInfo) {
        List<TypeInfo> mappedParents = new ArrayList<TypeInfo>();
        JavaClass next = CompilerHelper.getNextMappedSuperClass(descriptorJavaClass, typeInfo, helper);
        while(next != null) {
            TypeInfo nextInfo = this.typeInfo.get(next.getName());
            mappedParents.add(0, nextInfo);
            next = CompilerHelper.getNextMappedSuperClass(helper.getJavaClass(nextInfo.getJavaClassName()), typeInfo, helper);
        }
        for(TypeInfo nextInfo:mappedParents) {
            List<Property> propertiesInOrder = nextInfo.getNonTransientPropertiesInPropOrder();
            for (int i = 0; i < propertiesInOrder.size(); i++) {
                Property nextProp = propertiesInOrder.get(i);
                if (nextProp != null){
                    Mapping mapping = generateMapping(nextProp, descriptor, descriptorJavaClass, namespaceInfo);
                    descriptor.addMapping((CoreMapping)mapping);
                    // set user-defined properties if necessary
                    if (nextProp.isSetUserProperties()) {
                        mapping.setProperties(nextProp.getUserProperties());
                    }
                }
            }            
        }
        
    }

    /**
     * Create an XMLCollectionReferenceMapping and add it to the descriptor.
     *
     * @param property
     * @param descriptor
     * @param namespaceInfo
     * @param referenceClass
     */
    public CollectionReferenceMapping generateXMLCollectionReferenceMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, JavaClass referenceClass) {
        CollectionReferenceMapping mapping = new XMLCollectionReferenceMapping();
        initializeXMLMapping((XMLMapping)mapping, property);

        initializeXMLContainerMapping(mapping, property.getType().isArray());
        mapping.setUsesSingleNode(property.isXmlList() || (property.isAttribute() && (property.getXmlPath() == null || !property.getXmlPath().contains("/"))));
       
        String referenceClassName = referenceClass.getQualifiedName();      
        JavaClass collectionType = property.getType();

        if (collectionType.isArray()){
            JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader());
            JavaClass componentType = collectionType.getComponentType();
            if(componentType.isArray()) {
                Class adaptedClass = classToGeneratedClasses.get(componentType.getName());
                referenceClassName = adaptedClass.getName();
                accessor.setAdaptedClassName(referenceClassName);
                JavaClass baseComponentType = getBaseComponentType(componentType);
                if (baseComponentType.isPrimitive()){
                    Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName());
                    accessor.setComponentClass(primitiveClass);
                } else {
                    accessor.setComponentClassName(baseComponentType.getQualifiedName());
                }
            } else {
                accessor.setComponentClassName(componentType.getQualifiedName());
            }
            mapping.setAttributeAccessor(accessor);
        }
        collectionType = containerClassImpl(collectionType);
        mapping.useCollectionClassName(collectionType.getRawName());
        mapping.setReferenceClassName(referenceClassName);
        
        // here we need to setup source/target key field associations
        if (property.isSetXmlJoinNodes()) {
            for (XmlJoinNode xmlJoinNode: property.getXmlJoinNodes().getXmlJoinNode()) {
               validateJoinNode(descriptor.getJavaClassName(), property, xmlJoinNode.getReferencedXmlPath(), referenceClass);
               mapping.addSourceToTargetKeyFieldAssociation(xmlJoinNode.getXmlPath(), xmlJoinNode.getReferencedXmlPath());
            }
        } else {
            // here we need to setup source/target key field associations
            TypeInfo referenceType = typeInfo.get(referenceClass.getQualifiedName());
            String tgtXPath = null;
            if (null != referenceType && referenceType.isIDSet()) {
                Property prop = referenceType.getIDProperty();
                tgtXPath = getXPathForField(prop, namespaceInfo, !prop.isAttribute(), false).getXPath();
            }
            // if the XPath is set (via xml-path) use it
            Field srcXPath;
            if (property.getXmlPath() != null) {
                srcXPath = new XMLField(property.getXmlPath());
            } else {
                srcXPath = getXPathForField(property, namespaceInfo, true, false);
            }
            mapping.addSourceToTargetKeyFieldAssociation(srcXPath.getXPath(), tgtXPath);
        }
        if (property.getInverseReferencePropertyName() != null) {
            mapping.getInverseReferenceMapping().setAttributeName(property.getInverseReferencePropertyName());
            JavaClass backPointerPropertyType = null;
            if (property.getInverseReferencePropertyGetMethodName() != null && property.getInverseReferencePropertySetMethodName() != null && !property.getInverseReferencePropertyGetMethodName().equals("") && !property.getInverseReferencePropertySetMethodName().equals("")) {
                mapping.getInverseReferenceMapping().setGetMethodName(property.getInverseReferencePropertySetMethodName());
                mapping.getInverseReferenceMapping().setSetMethodName(property.getInverseReferencePropertySetMethodName());
                JavaMethod getMethod = referenceClass.getDeclaredMethod(mapping.getInverseReferenceMapping().getGetMethodName(), new JavaClass[]{});
                if (getMethod != null) {
                    backPointerPropertyType = getMethod.getReturnType();
                }
            } else {
                JavaField backpointerField = referenceClass.getDeclaredField(property.getInverseReferencePropertyName());
                if (backpointerField != null) {
                    backPointerPropertyType = backpointerField.getResolvedType();
                }
            }
            if (helper.isCollectionType(backPointerPropertyType)) {
                mapping.getInverseReferenceMapping().setContainerPolicy(ContainerPolicy.buildDefaultPolicy());
            }
        }
        return mapping;
    }
    /**
     * Create an XMLObjectReferenceMapping and add it to the descriptor.
     *
     * @param property
     * @param descriptor
     * @param namespaceInfo
     * @param referenceClass
     */
    public ObjectReferenceMapping generateXMLObjectReferenceMapping(Property property, Descriptor descriptor, NamespaceInfo namespaceInfo, JavaClass referenceClass) {
        ObjectReferenceMapping mapping = new XMLObjectReferenceMapping();
        initializeXMLMapping((XMLMapping)mapping, property);
        mapping.setReferenceClassName(referenceClass.getQualifiedName());

        // here we need to setup source/target key field associations
        if (property.isSetXmlJoinNodes()) {
            for (XmlJoinNode xmlJoinNode: property.getXmlJoinNodes().getXmlJoinNode()) {
                validateJoinNode(descriptor.getJavaClassName(), property, xmlJoinNode.getReferencedXmlPath(), referenceClass);
                mapping.addSourceToTargetKeyFieldAssociation(xmlJoinNode.getXmlPath(), xmlJoinNode.getReferencedXmlPath());
            }
        } else {
            String tgtXPath = null;
            TypeInfo referenceType = typeInfo.get(referenceClass.getQualifiedName());
            if (null != referenceType && referenceType.isIDSet()) {
                Property prop = referenceType.getIDProperty();
                tgtXPath = getXPathForField(prop, namespaceInfo, !prop.isAttribute(), false).getXPath();
            }
            // if the XPath is set (via xml-path) use it, otherwise figure it out
            Field srcXPath;
            if (property.getXmlPath() != null) {
                srcXPath = new XMLField(property.getXmlPath());
            } else {
                srcXPath = getXPathForField(property, namespaceInfo, true, false);
            }
            mapping.addSourceToTargetKeyFieldAssociation(srcXPath.getXPath(), tgtXPath);
        }        
        if (property.getInverseReferencePropertyName() != null) {
            mapping.getInverseReferenceMapping().setAttributeName(property.getInverseReferencePropertyName());
            JavaClass backPointerPropertyType = null;
            if (property.getInverseReferencePropertyGetMethodName() != null && property.getInverseReferencePropertySetMethodName() != null && !property.getInverseReferencePropertyGetMethodName().equals("") && !property.getInverseReferencePropertySetMethodName().equals("")) {
                mapping.getInverseReferenceMapping().setGetMethodName(property.getInverseReferencePropertySetMethodName());
                mapping.getInverseReferenceMapping().setSetMethodName(property.getInverseReferencePropertySetMethodName());
                JavaMethod getMethod = referenceClass.getDeclaredMethod(mapping.getInverseReferenceMapping().getGetMethodName(), new JavaClass[]{});
                if (getMethod != null) {
                    backPointerPropertyType = getMethod.getReturnType();
                }
            } else {
                JavaField backpointerField = referenceClass.getDeclaredField(property.getInverseReferencePropertyName());
                if (backpointerField != null) {
                    backPointerPropertyType = backpointerField.getResolvedType();
                }
            }
            if (helper.isCollectionType(backPointerPropertyType)) {
                mapping.getInverseReferenceMapping().setContainerPolicy(ContainerPolicy.buildDefaultPolicy());
            }
        }
        return mapping;
    }

    private void validateJoinNode(String className, Property property, String referencedXmlPath, JavaClass referenceClass) {
        TypeInfo targetInfo = this.typeInfo.get(referenceClass.getQualifiedName());
        NamespaceInfo namespaceInfo = this.packageToPackageInfoMappings.get(referenceClass.getPackageName()).getNamespaceInfo();        
        Property idProp = targetInfo.getIDProperty();
        if(idProp != null) {
            String idXpath = idProp.getXmlPath();
            if(idXpath == null) {
                idXpath = this.getXPathForField(idProp, namespaceInfo, !idProp.isAttribute(), false).getXPath();
            }
            if (referencedXmlPath.equals(idXpath)) {
                return;
            }
        }
        boolean matched = false;
        if (targetInfo.getXmlKeyProperties() != null) {
            for (Property xmlkeyProperty : targetInfo.getXmlKeyProperties()) {
                String keyXpath = xmlkeyProperty.getXmlPath();
                if(keyXpath == null) {
                    keyXpath = this.getXPathForField(xmlkeyProperty, namespaceInfo, !xmlkeyProperty.isAttribute(), false).getXPath();
                }
                if (referencedXmlPath.equals(keyXpath)) {
                    matched = true;
                    break;
                }
            }
        }
        if (!matched) {
            throw JAXBException.invalidReferencedXmlPathOnJoin(className, property.getPropertyName(), referenceClass.getQualifiedName(), referencedXmlPath);
        }
    }


    private String prefixCustomXPath(String unprefixedXPath, Property property, NamespaceInfo nsInfo) {
        StringBuilder newXPath = new StringBuilder(32);
        QName schemaName = property.getSchemaName();
        String namespace = schemaName.getNamespaceURI();

        if (null == namespace || namespace.equals(Constants.EMPTY_STRING)) {
            return unprefixedXPath;
        }

        String prefix = getPrefixForNamespace(namespace, getNamespaceResolverForDescriptor(nsInfo));
        if (null == prefix) {
            return unprefixedXPath;
        }

        StringTokenizer st = new StringTokenizer(unprefixedXPath, Constants.XPATH_SEPARATOR);
        while (st.hasMoreTokens()) {
            String nextToken = st.nextToken();
                
            if (st.hasMoreTokens()) {
                if (nextToken.lastIndexOf(Constants.COLON) != -1) {
                    // Token already has a user-supplied prefix
                    newXPath.append(nextToken);
                } else {
                    newXPath.append(prefix).append(Constants.COLON).append(nextToken);
                }
                newXPath.append(Constants.XPATH_SEPARATOR);
            } else {
                // Last token is text()
                newXPath.append(nextToken);
            }

        }
        return newXPath.toString();
    }

    public Field getXPathForField(Property property, NamespaceInfo namespaceInfo, boolean isTextMapping, boolean isAny) {
        Field xmlField = null;
        String xPath = property.getXmlPath();
        if (null != xPath) {
            String newXPath = prefixCustomXPath(xPath, property, namespaceInfo);
            xmlField = new XMLField(newXPath);
        } else {
            StringBuilder xPathBuilder = new StringBuilder();
            if (property.isSetXmlElementWrapper()) {
                XmlElementWrapper wrapper = property.getXmlElementWrapper();
                String namespace = wrapper.getNamespace();
                if (namespace.equals(XMLProcessor.DEFAULT)) {
                    if (namespaceInfo.isElementFormQualified()) {
                        namespace = namespaceInfo.getNamespace();
                    } else {
                        namespace = "";
                    }
                }

                if (namespace.equals("")) {
                    xPathBuilder.append(wrapper.getName()).append("/");
                } else {
			String prefix = getPrefixForNamespace(namespace, getNamespaceResolverForDescriptor(namespaceInfo));
			xPathBuilder.append(getQualifiedString(prefix, wrapper.getName() + "/"));
                }

                if (isAny || property.isMap()) {
                    xmlField = new XMLField(xPathBuilder.toString());
                    return xmlField;
                }

            }
            if (property.isAttribute()) {
                if (property.isSetXmlPath()) {
                    xPathBuilder.append(property.getXmlPath());
                } else {
                    QName name = property.getSchemaName();
                    String namespace = name.getNamespaceURI();
                    if (namespace.equals("")) {
                        xPathBuilder.append(ATT).append(name.getLocalPart());
                    } else {
                        String prefix = getPrefixForNamespace(namespace, getNamespaceResolverForDescriptor(namespaceInfo));
                        xPathBuilder.append(ATT).append(getQualifiedString(prefix, name.getLocalPart()));
                    }
                }
                xmlField = new XMLField(xPathBuilder.toString());
            } else if (property.isXmlValue()) {
		if(isBinaryData(property.getActualType())){
			xmlField = new XMLField(".");
            	}else{
            		xmlField = new XMLField("text()");
		}
            } else {
                QName elementName = property.getSchemaName();
                xmlField = getXPathForElement(xPathBuilder.toString(), elementName, namespaceInfo, isTextMapping);
            }
        }

        QName schemaType = userDefinedSchemaTypes.get(property.getActualType().getQualifiedName());
        if (property.getSchemaType() != null) {
            schemaType = property.getSchemaType();
        }
        if (schemaType == null) {
            String propertyActualTypeRawName = property.getActualType().getRawName();
            if(QName.class.getCanonicalName().equals(propertyActualTypeRawName)) {
                 schemaType = (QName) helper.getXMLToJavaTypeMap().get(propertyActualTypeRawName);
            }
        }
        if(schemaType !=null && !schemaType.equals (Constants.NORMALIZEDSTRING_QNAME)){
            xmlField.setSchemaType(schemaType);
        }
        
        return xmlField;
    }

    public Field getXPathForElement(String path, QName elementName, NamespaceInfo namespaceInfo, boolean isText) {
        String namespace = "";
        if (!elementName.getNamespaceURI().equals(Constants.EMPTY_STRING)) {
            namespace = elementName.getNamespaceURI();
        }
        if (namespace.equals(Constants.EMPTY_STRING)) {
            path += elementName.getLocalPart();
            if (isText) {
                path += TXT;
            }
        } else {
            String prefix = getPrefixForNamespace(namespace, getNamespaceResolverForDescriptor(namespaceInfo));
        	path += getQualifiedString(prefix, elementName.getLocalPart());
            if (isText) {
                path += TXT;
            }
        }
        return new XMLField(path);
    }

    public Property getXmlValueFieldForSimpleContent(ArrayList<Property> properties) {
        boolean foundValue = false;
        boolean foundNonAttribute = false;
        Property valueField = null;

        for (Property prop : properties) {
            if (helper.isAnnotationPresent(prop.getElement(), XmlValue.class)) {
                foundValue = true;
                valueField = prop;
            } else if (!helper.isAnnotationPresent(prop.getElement(), XmlAttribute.class) && !helper.isAnnotationPresent(prop.getElement(), XmlTransient.class) && !prop.isAnyAttribute()) {
                foundNonAttribute = true;
            }
        }
        if (foundValue && !foundNonAttribute) {
            return valueField;
        }
        return null;
    }

    public String getSchemaTypeNameForClassName(String className) {
        String typeName = Introspector.decapitalize(className.substring(className.lastIndexOf('.') + 1));
        return typeName;
    }

    public void processGlobalElements(CoreProject project) {
        //Find any global elements for classes we've generated descriptors for, and add them as possible
        //root elements.
        if(this.globalElements == null && this.localElements == null) {
            return;
        }
        List<ElementDeclaration> elements = new ArrayList<ElementDeclaration>();
        elements.addAll(this.localElements);
        elements.addAll(this.globalElements.values());
        for(ElementDeclaration nextElement:elements) {
            QName next = nextElement.getElementName();
            String nextClassName = nextElement.getJavaTypeName();
            TypeInfo type = this.typeInfo.get(nextClassName);

            if(helper.isBuiltInJavaType(nextElement.getJavaType()) || (type !=null && type.isEnumerationType())){

                //generate a class/descriptor for this element
                String attributeTypeName = nextClassName;
                if(nextElement.getJavaType().isPrimitive()) {
                    attributeTypeName = helper.getClassForJavaClass(nextElement.getJavaType()).getName();
                }
                if (nextElement.getAdaptedJavaTypeName() != null) {
                    attributeTypeName = nextElement.getAdaptedJavaTypeName();
                }

                if(next == null){
                	if(isBinaryData(nextElement.getJavaType())){
            			Class generatedClass = addByteArrayWrapperAndDescriptor(type, nextElement.getJavaType().getRawName(), nextElement,nextClassName, attributeTypeName);
            			 this.qNamesToGeneratedClasses.put(next, generatedClass);
                         if(nextElement.getTypeMappingInfo() != null) {
                             typeMappingInfoToGeneratedClasses.put(nextElement.getTypeMappingInfo(), generatedClass);
                         }
                         try{
                             Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader());
                             this.qNamesToDeclaredClasses.put(next, declaredClass);
                         }catch(Exception e){
                         }
            		}
                    if(nextElement.getJavaType().isEnum()) {
                        if(!(helper.getClassLoader() instanceof DynamicClassLoader)) {
                            //  Only generate enum wrappers in non-dynamic case.
                            Class generatedClass = addEnumerationWrapperAndDescriptor(type, nextElement.getJavaType().getRawName(), nextElement, nextClassName, attributeTypeName);
                            this.qNamesToGeneratedClasses.put(next, generatedClass);
                            if(nextElement.getTypeMappingInfo() != null) {
                                typeMappingInfoToGeneratedClasses.put(nextElement.getTypeMappingInfo(), generatedClass);
                            }
                            try{
                                Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader());
                                this.qNamesToDeclaredClasses.put(next, declaredClass);
                            }catch(Exception ex) {
                            
                            }
                        }                	

                    }
                    continue;
                }
                Class generatedClass = generateWrapperClassAndDescriptor(type, next, nextElement, nextClassName, attributeTypeName);
                
                this.qNamesToGeneratedClasses.put(next, generatedClass);
                if(type != null && type.isEnumerationType() && nextElement.isXmlRootElement()) {
                    this.classToGeneratedClasses.put(type.getJavaClassName(), generatedClass);
                }
                try{
                    Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader());
                    this.qNamesToDeclaredClasses.put(next, declaredClass);
                }catch(Exception e){

                }
            }else if(type != null && !type.isTransient()){
                if(next.getNamespaceURI() == null || next.getNamespaceURI().equals("")) {
                    type.getDescriptor().addRootElement(next.getLocalPart());
                } else {
                    Descriptor descriptor = type.getDescriptor();
                    String uri = next.getNamespaceURI();
                    String prefix = getPrefixForNamespace(uri, descriptor.getNamespaceResolver());
                    descriptor.addRootElement(getQualifiedString(prefix, next.getLocalPart()));
                }
            }
        }
    }

    private Class addByteArrayWrapperAndDescriptor(TypeInfo type , String javaClassName,  ElementDeclaration nextElement, String nextClassName, String attributeTypeName){
    	Class generatedClass = classToGeneratedClasses.get(javaClassName);
    	if(generatedClass == null){
    		generatedClass = generateWrapperClassAndDescriptor(type, null, nextElement, nextClassName, attributeTypeName);
    		classToGeneratedClasses.put(javaClassName, generatedClass);
    	}
    	return generatedClass;
    }

    private Class addEnumerationWrapperAndDescriptor(TypeInfo type, String javaClassName, ElementDeclaration nextElement, String nextClassName, String attributeTypeName) {
        Class generatedClass = classToGeneratedClasses.get(javaClassName);
        if(generatedClass == null){
            generatedClass = generateWrapperClassAndDescriptor(type, nextElement.getElementName(), nextElement, nextClassName, attributeTypeName);
            classToGeneratedClasses.put(javaClassName, generatedClass);
        }
        return generatedClass;
    }

     private Class generateWrapperClassAndDescriptor(TypeInfo type, QName next, ElementDeclaration nextElement, String nextClassName, String attributeTypeName){
        String namespaceUri = null;
      	if(next!= null){
              //generate a class/descriptor for this element
              namespaceUri = next.getNamespaceURI();
              if (namespaceUri == null || namespaceUri.equals(XMLProcessor.DEFAULT)) {
                  namespaceUri = "";
              }
      	}

      	TypeMappingInfo tmi = nextElement.getTypeMappingInfo();
      	Class generatedClass = null;

        JaxbClassLoader loader = getJaxbClassLoader();

      	if(tmi != null){
            generatedClass = CompilerHelper.getExisitingGeneratedClass(tmi, typeMappingInfoToGeneratedClasses, typeMappingInfoToAdapterClasses, helper.getClassLoader());
            if(generatedClass == null){
            	generatedClass = this.generateWrapperClass(loader.nextAvailableGeneratedClassName(), attributeTypeName, nextElement.isList(), next);
            }

            typeMappingInfoToGeneratedClasses.put(tmi, generatedClass);
      	}else{
      	    generatedClass = this.generateWrapperClass(loader.nextAvailableGeneratedClassName(), attributeTypeName, nextElement.isList(), next);
      	}

          this.qNamesToGeneratedClasses.put(next, generatedClass);
          try{
              Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader());
              this.qNamesToDeclaredClasses.put(next, declaredClass);
          }catch(Exception e){

          }

          Descriptor desc = (Descriptor)project.getDescriptor(generatedClass);

          if(desc == null){
	          desc = new XMLDescriptor();
	          desc.setJavaClass(generatedClass);


	          if(nextElement.isList()){
	              DirectCollectionMapping mapping = new XMLCompositeDirectCollectionMapping();
	              mapping.setAttributeName("value");
	              mapping.setXPath("text()");
	              mapping.setUsesSingleNode(true);
	              mapping.setReuseContainer(true);

	              if(type != null && type.isEnumerationType()){
	                  mapping.setValueConverter(buildJAXBEnumTypeConverter(mapping, (EnumTypeInfo)type));
	              }else{
	                  try{
	                      Class fieldElementClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader());
	                      mapping.setFieldElementClass(fieldElementClass);
	                  }catch(ClassNotFoundException e){
	                  }
	              }

	              if(nextClassName.equals("[B") || nextClassName.equals("[Ljava.lang.Byte;")) {
	                 ((Field)mapping.getField()).setSchemaType(Constants.BASE_64_BINARY_QNAME);
	              }
	              else if(nextClassName.equals("javax.xml.namespace.QName")){
	                  ((Field)mapping.getField()).setSchemaType(Constants.QNAME_QNAME);
	              }
	              desc.addMapping((CoreMapping)mapping);
	          } else{
	              if(nextElement.getJavaTypeName().equals(OBJECT_CLASS_NAME)){
	                  CompositeObjectMapping mapping = new XMLCompositeObjectMapping();
	                  mapping.setAttributeName("value");
	                  mapping.setSetMethodName("setValue");
	                  mapping.setGetMethodName("getValue");
	                  mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT);
	                  mapping.setXPath(".");
	              	  setTypedTextField((Field)mapping.getField());

	                  desc.addMapping((CoreMapping)mapping);	                 
	              }else if(isBinaryData(nextElement.getJavaType())){
	              	  BinaryDataMapping mapping = new XMLBinaryDataMapping();
	              	  mapping.setAttributeName("value");
	              	  mapping.setXPath(".");
	                  ((Field)mapping.getField()).setSchemaType(Constants.BASE_64_BINARY_QNAME);
	                  mapping.setSetMethodName("setValue");
	                  mapping.setGetMethodName("getValue");
	                  mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
	                  mapping.getNullPolicy().setNullRepresentedByEmptyNode(false);

	                  Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(attributeTypeName, helper.getClassLoader());
	                  mapping.setAttributeClassification(attributeClassification);

	              	  mapping.setShouldInlineBinaryData(false);
	              	  //if(nextElement.getTypeMappingInfo() != null) {
	              	      mapping.setSwaRef(nextElement.isXmlAttachmentRef());
	              	      mapping.setMimeType(nextElement.getXmlMimeType());
	              	  //}
	                  desc.addMapping((CoreMapping)mapping);

	              }else{
	            	  DirectMapping mapping = new XMLDirectMapping();
	                  mapping.setNullValueMarshalled(true);
	                  mapping.setAttributeName("value");
	                  mapping.setXPath("text()");
	                  mapping.setSetMethodName("setValue");
	                  mapping.setGetMethodName("getValue");
	                  if(nextElement.getDefaultValue() != null) {
	                      mapping.setNullValue(nextElement.getDefaultValue());
	                      mapping.getNullPolicy().setNullRepresentedByXsiNil(true);
	                  }
	                  

	                  if(helper.isBuiltInJavaType(nextElement.getJavaType())){
	                      Class attributeClassification = null;
	                      if(nextElement.getJavaType().isPrimitive()) {
	                          attributeClassification = XMLConversionManager.getDefaultManager().convertClassNameToClass(attributeTypeName);
	                      } else {
	                          attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(attributeTypeName, helper.getClassLoader());
	                      }
	                      mapping.setAttributeClassification(attributeClassification);
	                  }

	                  IsSetNullPolicy nullPolicy = new IsSetNullPolicy("isSetValue", false, true, XMLNullRepresentationType.ABSENT_NODE);
	                  //nullPolicy.setNullRepresentedByEmptyNode(true);
	                  mapping.setNullPolicy(nullPolicy);

	                  if(type != null && type.isEnumerationType()){
	                      mapping.setConverter(buildJAXBEnumTypeConverter(mapping, (EnumTypeInfo)type));
	                  }
	                  if(nextClassName.equals("[B") || nextClassName.equals("[Ljava.lang.Byte;")) {
	                      ((Field)mapping.getField()).setSchemaType(Constants.BASE_64_BINARY_QNAME);
	                  }
	                  else if(nextClassName.equals("javax.xml.namespace.QName")){
	                      ((Field)mapping.getField()).setSchemaType(Constants.QNAME_QNAME);
	                  }

	                  if (nextElement.getJavaTypeAdapterClass() != null) {
	                      mapping.setConverter(new XMLJavaTypeConverter(nextElement.getJavaTypeAdapterClass()));
	                  }

	                  desc.addMapping((CoreMapping)mapping);
	              }
	          }
	          if(next != null){
	              NamespaceInfo info = getNamespaceInfoForURI(namespaceUri);

	  			if(info != null) {
	  				NamespaceResolver resolver = getNamespaceResolverForDescriptor(info);
	  				
	  				String prefix = null;
	  				if(namespaceUri != Constants.EMPTY_STRING){
	  				    prefix = resolver.resolveNamespaceURI(namespaceUri);
	  				    if(prefix == null){
	  					    prefix = getPrefixForNamespace(namespaceUri, resolver);	  					
	  				    }
	  				}
	  				desc.setNamespaceResolver(resolver);
	  				if(nextElement.isXmlRootElement()) {
	  				    desc.setDefaultRootElement(getQualifiedString(prefix, next.getLocalPart()));
	  				} else {
	  				    desc.setDefaultRootElement("");
	  				    desc.addRootElement(getQualifiedString(prefix, next.getLocalPart()));
	  				    desc.setResultAlwaysXMLRoot(true);
	  				}
	              } else {
	                  if(namespaceUri.equals("")) {
	                      desc.setDefaultRootElement(next.getLocalPart());
	                  } else {
	                      NamespaceResolver resolver = new org.eclipse.persistence.oxm.NamespaceResolver();
	                      String prefix = getPrefixForNamespace(namespaceUri, resolver);

	                      desc.setNamespaceResolver(resolver);
                          if(nextElement.isXmlRootElement()) {
                              desc.setDefaultRootElement(getQualifiedString(prefix, next.getLocalPart()));
                          } else {
                              desc.setDefaultRootElement("");
                              desc.addRootElement(getQualifiedString(prefix, next.getLocalPart()));
                              desc.setResultAlwaysXMLRoot(true);
                          }
	  				}
	  			}
	          }
	          project.addDescriptor((CoreDescriptor)desc);
          }
          return generatedClass;
    }

    private String getQualifiedString(String prefix, String localPart){
    	if(prefix == null){
    		return localPart;
    	}
    	return prefix + Constants.COLON + localPart;
    }

    private NamespaceInfo getNamespaceInfoForURI(String namespaceUri) {
        Iterator<PackageInfo> namespaces = this.packageToPackageInfoMappings.values().iterator();
        while(namespaces.hasNext()) {
            NamespaceInfo next = namespaces.next().getNamespaceInfo();
            if(next.getNamespace().equals(namespaceUri)) {
                return next;
            }
        }
        return null;
    }

    @SuppressWarnings("unused")
    private String getPackageNameForURI(String namespaceUri) {
        for(String next:this.packageToPackageInfoMappings.keySet()) {
            if(packageToPackageInfoMappings.get(next).getNamespace().equals(namespaceUri)) {
                return next;
            }
        }
        return null;
    }

    public Class generateWrapperClass(String className, String attributeType, boolean isList, QName theQName) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

        String sig = null;
        cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className.replace(".", "/"), sig, Type.getType(WrappedValue.class).getInternalName(), null);

        String fieldType = null;
        if(isList){
            fieldType ="Ljava/util/List;";
        }else{
            fieldType = attributeType.replace(".", "/");
            if(!(fieldType.startsWith("["))) {
                fieldType = "L" + fieldType + ";";
            }
        }

        	if(theQName == null){
        		theQName = RESERVED_QNAME;
        	}

	        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);

	        mv.visitVarInsn(Opcodes.ALOAD, 0);
	        mv.visitTypeInsn(Opcodes.NEW, "javax/xml/namespace/QName");
	        mv.visitInsn(Opcodes.DUP);
	        mv.visitLdcInsn(theQName.getNamespaceURI());
	        mv.visitLdcInsn(theQName.getLocalPart());
	        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "javax/xml/namespace/QName", "<init>", "(Ljava/lang/String;Ljava/lang/String;)V", false);
	        mv.visitLdcInsn(Type.getType(fieldType));
	        mv.visitInsn(Opcodes.ACONST_NULL);

	        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/eclipse/persistence/internal/jaxb/WrappedValue", "<init>", "(Ljavax/xml/namespace/QName;Ljava/lang/Class;Ljava/lang/Object;)V", false);
	        mv.visitInsn(Opcodes.RETURN);
	        mv.visitMaxs(5, 1);
	        mv.visitEnd();


        cw.visitEnd();

        byte[] classBytes = cw.toByteArray();
        //byte[] classBytes = new byte[]{};

        Class generatedClass = getJaxbClassLoader().generateClass(className, classBytes);
        return generatedClass;
    }

    public Map<QName, Class> getQNamesToGeneratedClasses() {
        return qNamesToGeneratedClasses;
    }

    public Map<String, Class> getClassToGeneratedClasses() {
        return classToGeneratedClasses;
    }
    public Map<QName, Class> getQNamesToDeclaredClasses() {
        return qNamesToDeclaredClasses;
    }

    private Map<MapEntryGeneratedKey, Class> getGeneratedMapEntryClasses() {
        if(generatedMapEntryClasses == null){
            generatedMapEntryClasses = new HashMap<MapEntryGeneratedKey, Class>();
        }
        return generatedMapEntryClasses;
    }

    // Made static final for performance reasons.
    private static final class MapEntryGeneratedKey {
	@SuppressWarnings("unused")
        String keyClassName;
		@SuppressWarnings("unused")
        String valueClassName;

    	public MapEntryGeneratedKey(String keyClass, String valueClass){
    		keyClassName = keyClass;
    		valueClassName = valueClass;
    	}
	}

    private AbstractNullPolicy getWrapperNullPolicyFromProperty(Property property) {
        NullPolicy nullPolicy = null;

        if (property.isSetXmlElementWrapper()) {
            nullPolicy = new NullPolicy();
            nullPolicy.setNullRepresentedByEmptyNode(false);
            nullPolicy.setSetPerformedForAbsentNode(false);

            if (property.getXmlElementWrapper().isNillable()) {
                nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL);
                nullPolicy.setNullRepresentedByXsiNil(true);
            } else {
                nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.ABSENT_NODE);
                nullPolicy.setNullRepresentedByXsiNil(false);
            }
        }

        return nullPolicy;
    }

    /**
     * Convenience method which returns an AbstractNullPolicy built from an XmlAbstractNullPolicy.
     *
     * @param property
     * @param nsr if 'NullRepresentedByXsiNil' is true, this is the resolver
     *            that we will add the schema instance prefix/uri pair to
     * @return
     * @see org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy
     * @see org.eclipse.persistence.jaxb.xmlmodel.XmlAbstractNullPolicy
     */
    private AbstractNullPolicy getNullPolicyFromProperty(Property property, NamespaceResolver nsr) {
        AbstractNullPolicy absNullPolicy = null;
        XmlAbstractNullPolicy xmlAbsNullPolicy = property.getNullPolicy();

        // policy is assumed to be one of XmlNullPolicy or XmlIsSetNullPolicy
        if (xmlAbsNullPolicy instanceof XmlNullPolicy) {
            XmlNullPolicy xmlNullPolicy = (XmlNullPolicy) xmlAbsNullPolicy;
            NullPolicy nullPolicy = new NullPolicy();
            nullPolicy.setSetPerformedForAbsentNode(xmlNullPolicy.isIsSetPerformedForAbsentNode());
            absNullPolicy = nullPolicy;
        } else {
            XmlIsSetNullPolicy xmlIsSetNullPolicy = (XmlIsSetNullPolicy) xmlAbsNullPolicy;
            IsSetNullPolicy isSetNullPolicy = new IsSetNullPolicy();
            isSetNullPolicy.setIsSetMethodName(xmlIsSetNullPolicy.getIsSetMethodName());
            // handle isSetParams
            ArrayList<Object> parameters = new ArrayList<Object>();
            ArrayList<Class> parameterTypes = new ArrayList<Class>();
            List<XmlIsSetNullPolicy.IsSetParameter> params = xmlIsSetNullPolicy.getIsSetParameter();
            for (XmlIsSetNullPolicy.IsSetParameter param : params) {
                String valueStr = param.getValue();
                String typeStr = param.getType();
                // create a conversion manager instance with the helper's loader
                XMLConversionManager mgr = new XMLConversionManager();
                mgr.setLoader(helper.getClassLoader());
                // handle parameter type
                Class typeClass = mgr.convertClassNameToClass(typeStr);
                // handle parameter value
                Object parameterValue = mgr.convertObject(valueStr, typeClass);
                parameters.add(parameterValue);
                parameterTypes.add(typeClass);
            }
            isSetNullPolicy.setIsSetParameters(parameters.toArray());
            isSetNullPolicy.setIsSetParameterTypes(parameterTypes.toArray(new Class[parameterTypes.size()]));
            absNullPolicy = isSetNullPolicy;
        }
        // handle commmon settings
        absNullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.valueOf(xmlAbsNullPolicy.getNullRepresentationForXml().name()));
        absNullPolicy.setNullRepresentedByEmptyNode(xmlAbsNullPolicy.isEmptyNodeRepresentsNull());
        boolean xsiRepresentsNull = xmlAbsNullPolicy.isXsiNilRepresentsNull();
        if (xsiRepresentsNull) {
            absNullPolicy.setNullRepresentedByXsiNil(true);
        }

        return absNullPolicy;
    }

    /**
     * Return the base component type for a class.  For example, the base 
     * component type for Integer, Integer[], and Integer[][] are all Integer.
     */
    private JavaClass getBaseComponentType(JavaClass javaClass) {
        JavaClass componentType = javaClass.getComponentType();
        if(null == componentType) {
            return javaClass;
        }
        if(!componentType.isArray()) {
            return componentType;
        }
        return getBaseComponentType(componentType);
    }

    public JaxbClassLoader getJaxbClassLoader() {
        if (helper.getClassLoader() instanceof DynamicClassLoader) {
            return (JaxbClassLoader) helper.getClassLoader().getParent();
        } else {
            return (JaxbClassLoader) helper.getClassLoader();
        }
    }
    
    private boolean isBinaryData(JavaClass type){
    	return areEquals(type, CoreClassConstants.APBYTE) ||areEquals(type, "javax.activation.DataHandler") || areEquals(type, "java.awt.Image") || areEquals(type, "javax.xml.transform.Source") || areEquals(type, "javax.mail.internet.MimeMultipart");
    }

    // Made static final for performance reasons.
    /**
     * <p>An InstantiationPolicy that does not construct any objects (and therefore
     * will not throw validation errors caused by a lack of a no-arg constructor).</p>
     *
     * <p>This is used by @XmlLocation, where we want to have a real mapping created
     * (so we can later set its value through the mapping), but where we will never
     * instantiate a Locator from XML (the Locator will be built internally during parsing).</p>
     *
     * @see org.eclipse.persistence.internal.descriptors.InstantiationPolicy
     * @see org.xml.sax.Locator
     */
    private static final class NullInstantiationPolicy extends InstantiationPolicy {

        /**
         * Returns a new instance of this InstantiationPolicy's Descriptor's class.
         *
         * In this case, do nothing and return null.
         */
        @Override
        public Object buildNewInstance() throws DescriptorException {
            return null;
        }

    }

    private void initializeXMLContainerMapping(XMLContainerMapping xmlContainerMapping, boolean isArray) {
        xmlContainerMapping.setReuseContainer(!isArray);
        xmlContainerMapping.setDefaultEmptyContainer(false);
    }
    
    private void initializeXMLMapping(XMLMapping mapping, Property property){
        mapping.setAttributeName(property.getPropertyName());

    	 // handle read-only set via metadata
        if (property.isSetReadOnly()) {
            mapping.setIsReadOnly(property.isReadOnly());
        }
        // handle write-only set via metadata
        if (property.isSetWriteOnly()) {
            mapping.setIsWriteOnly(property.isWriteOnly());
        }
        
        if (property.isMethodProperty()) {
            if (property.getGetMethodName() == null) {
                // handle case of set with no get method
                String paramTypeAsString = property.getType().getName();
                mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader()));
                mapping.setIsReadOnly(true);
                mapping.setSetMethodName(property.getSetMethodName());
            } else if (property.getSetMethodName() == null) {
                mapping.setGetMethodName(property.getGetMethodName());
                mapping.setIsWriteOnly(true);
            } else {
                mapping.setSetMethodName(property.getSetMethodName());
                mapping.setGetMethodName(property.getGetMethodName());
            }
        }
    }
    
    private JavaClass containerClassImpl(JavaClass collectionType) {
        if (areEquals(collectionType, List.class) || areEquals(collectionType, Collection.class) || collectionType.isArray() || helper.isMapType(collectionType) ) {
            return jotArrayList;
        } else if (areEquals(collectionType, Set.class)) {
            return jotHashSet;
        } else if (areEquals(collectionType, Deque.class) || areEquals(collectionType, Queue.class)) {
            return jotLinkedList;
        } else if (areEquals(collectionType, NavigableSet.class) || areEquals(collectionType, SortedSet.class)) {
            return jotTreeSet;
        } else {
            return collectionType;
        }
    }

    private void processDefaultNamespacePreferences(Collection<PackageInfo> packageInfos) {
        if (isDefaultNamespaceAllowed && globalNamespaceResolver.getDefaultNamespaceURI() == null) {
            for (PackageInfo packageInfo : packageInfos) {
                NamespaceResolver resolver = packageInfo.getNamespaceInfo().getNamespaceResolver();
                String defaultNS = resolver.getDefaultNamespaceURI();
                if (defaultNS != null) {
                    globalNamespaceResolver.setDefaultNamespaceURI(defaultNS);
                    break;
                }
            }
        }
    }

    private NamespaceResolver getNamespaceResolverForDescriptor(NamespaceInfo info) {
        return info.getNamespaceResolverForDescriptor(globalNamespaceResolver, isDefaultNamespaceAllowed);
    }
}
