| /* |
| * Copyright (c) 2012, 2021 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 v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Blaise Doughan - 2.5 - initial implementation |
| package org.eclipse.persistence.internal.oxm; |
| |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.core.mappings.CoreMapping; |
| import org.eclipse.persistence.core.sessions.CoreProject; |
| import org.eclipse.persistence.core.sessions.CoreSession; |
| import org.eclipse.persistence.core.sessions.CoreSessionEventListener; |
| import org.eclipse.persistence.exceptions.XMLMarshalException; |
| import org.eclipse.persistence.internal.core.databaseaccess.CorePlatform; |
| import org.eclipse.persistence.internal.core.descriptors.CoreObjectBuilder; |
| import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; |
| import org.eclipse.persistence.internal.oxm.mappings.Descriptor; |
| import org.eclipse.persistence.internal.oxm.mappings.Field; |
| import org.eclipse.persistence.oxm.schema.XMLSchemaReference; |
| |
| public abstract class Context< |
| ABSTRACT_SESSION extends CoreAbstractSession, |
| DESCRIPTOR extends Descriptor<?, ?, ?, ?, ?, NAMESPACE_RESOLVER, ?, ?, ?, ?>, |
| FIELD extends Field, |
| NAMESPACE_RESOLVER extends NamespaceResolver, |
| PROJECT extends CoreProject, |
| SESSION extends CoreSession, |
| SESSION_EVENT_LISTENER extends CoreSessionEventListener> { |
| |
| public static class ContextState< |
| ABSTRACT_SESSION extends CoreAbstractSession, |
| DESCRIPTOR extends Descriptor, |
| PROJECT extends CoreProject, |
| SESSION extends CoreSession, |
| SESSION_EVENT_LISTENER extends CoreSessionEventListener> { |
| |
| protected Context context; |
| protected Map<XPathQName, DESCRIPTOR> descriptorsByQName; |
| protected Map<XPathFragment, DESCRIPTOR> descriptorsByGlobalType; |
| protected SESSION session; |
| private Collection<SESSION_EVENT_LISTENER> sessionEventListeners; |
| |
| protected ContextState() { |
| descriptorsByQName = new HashMap<>(); |
| descriptorsByGlobalType = new HashMap<>(); |
| } |
| |
| protected ContextState(Context context, PROJECT project, ClassLoader classLoader, Collection<SESSION_EVENT_LISTENER> sessionEventListeners) { |
| this(); |
| this.context = context; |
| preLogin(project, classLoader); |
| session = (SESSION) project.createDatabaseSession(); |
| |
| // if an event listener was passed in as a parameter, register it with the event manager |
| if (sessionEventListeners != null) { |
| for(SESSION_EVENT_LISTENER sessionEventListener : sessionEventListeners) { |
| session.getEventManager().addListener(sessionEventListener); |
| } |
| } |
| |
| setupSession(session); |
| storeDescriptorsByQName(session); |
| } |
| |
| public void addDescriptorByQName(QName qName, DESCRIPTOR descriptor) { |
| XPathQName xpathQName = new XPathQName(qName, true); |
| addDescriptorByQName(xpathQName, descriptor); |
| } |
| |
| private void addDescriptorByQName(XPathQName qName, DESCRIPTOR descriptor) { |
| descriptorsByQName.put(qName, descriptor); |
| } |
| |
| protected void preLogin(PROJECT project, ClassLoader classLoader) { |
| } |
| |
| /** |
| * INTERNAL: Return the Descriptor with the default root mapping matching |
| * the QName parameter. |
| */ |
| private DESCRIPTOR getDescriptor(QName qName) { |
| XPathQName xpathQName = new XPathQName(qName, true); |
| return descriptorsByQName.get(xpathQName); |
| } |
| |
| /** |
| * INTERNAL: Return the Descriptor with the default root mapping matching |
| * the QName parameter. |
| */ |
| private DESCRIPTOR getDescriptor(XPathQName qName) { |
| return descriptorsByQName.get(qName); |
| } |
| |
| /** |
| * INTERNAL: Return the Descriptor mapped to the global type matching the |
| * XPathFragment parameter. |
| */ |
| private DESCRIPTOR getDescriptorByGlobalType(XPathFragment xPathFragment) { |
| return this.descriptorsByGlobalType.get(xPathFragment); |
| } |
| |
| protected SESSION getSession() { |
| return session; |
| } |
| |
| /** |
| * INTERNAL: Return the session corresponding to this class. Since the class |
| * may be mapped by more that one of the projects used to create the |
| * Context, this method will return the first match. |
| */ |
| protected ABSTRACT_SESSION getSession(Class clazz) { |
| if (null == clazz) { |
| return null; |
| } |
| if (session.getDescriptor(clazz) != null) { |
| return (ABSTRACT_SESSION) session; |
| } |
| throw XMLMarshalException.descriptorNotFoundInProject(clazz.getName()); |
| } |
| |
| /** |
| * INTERNAL: Return the session corresponding to this Descriptor. Since |
| * the class may be mapped by more that one of the projects used to create |
| * the Context, this method will return the first match. |
| */ |
| protected ABSTRACT_SESSION getSession(DESCRIPTOR descriptor) { |
| if (null == descriptor) { |
| return null; |
| } |
| if (session.getProject().getOrderedDescriptors().contains(descriptor)) { |
| return (ABSTRACT_SESSION) session; |
| } |
| throw XMLMarshalException.descriptorNotFoundInProject(descriptor.getJavaClass().getName()); |
| } |
| |
| /** |
| * INTERNAL: Return the session corresponding to this object. Since the |
| * object may be mapped by more that one of the projects used to create the |
| * Context, this method will return the first match. |
| */ |
| protected ABSTRACT_SESSION getSession(Object object) { |
| if (null == object) { |
| return null; |
| } |
| if (session.getDescriptor(object) != null) { |
| return (ABSTRACT_SESSION) session; |
| } |
| throw XMLMarshalException.descriptorNotFoundInProject(object.getClass().getName()); |
| } |
| |
| protected void setupSession(SESSION session) { |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public void storeDescriptorByQName(DESCRIPTOR descriptor, CorePlatform platform, Set<DESCRIPTOR> processedDescriptors) { |
| XPathQName descriptorQName; |
| String defaultRootName; |
| |
| if (processedDescriptors == null) { |
| processedDescriptors = new HashSet<>(); |
| } |
| |
| if (processedDescriptors.contains(descriptor)) { |
| return; |
| } else { |
| processedDescriptors.add(descriptor); |
| if (descriptor.hasInheritance() && !descriptor.getInheritancePolicy().isRootParentDescriptor()) { |
| //this means we have a descriptor that is a child in an inheritance hierarchy |
| storeDescriptorByQName((DESCRIPTOR) descriptor.getInheritancePolicy().getParentDescriptor(), platform, processedDescriptors); |
| } |
| } |
| |
| List tableNames = descriptor.getTableNames(); |
| for (int i = 0; i < tableNames.size(); i++) { |
| defaultRootName = (String) tableNames.get(i); |
| |
| if (null != defaultRootName) { |
| int index = defaultRootName.indexOf(':'); |
| String defaultRootLocalName = defaultRootName.substring(index + 1); |
| if (!defaultRootLocalName.isEmpty()) { |
| if (index > -1) { |
| String defaultRootPrefix = defaultRootName.substring(0, index); |
| String defaultRootNamespaceURI = descriptor.getNamespaceResolver().resolveNamespacePrefix(defaultRootPrefix); |
| descriptorQName = new XPathQName(defaultRootNamespaceURI, defaultRootLocalName, true); |
| } else { |
| if(descriptor.getNamespaceResolver() != null) { |
| descriptorQName = new XPathQName(descriptor.getNamespaceResolver().getDefaultNamespaceURI(), defaultRootLocalName, true); |
| } else { |
| descriptorQName = new XPathQName(defaultRootLocalName, true); |
| } |
| } |
| if (!descriptor.hasInheritance() || descriptor.getInheritancePolicy().isRootParentDescriptor()) { |
| addDescriptorByQName(descriptorQName, descriptor); |
| } else { |
| Descriptor existingDescriptor = getDescriptor(descriptorQName); |
| if (existingDescriptor == null) { |
| addDescriptorByQName(descriptorQName, descriptor); |
| } |
| } |
| } |
| } |
| } |
| |
| XMLSchemaReference xmlSchemaReference = descriptor.getSchemaReference(); |
| if (null != xmlSchemaReference) { |
| String schemaContext = xmlSchemaReference.getSchemaContext(); |
| if ((xmlSchemaReference.getType() == XMLSchemaReference.COMPLEX_TYPE) || (xmlSchemaReference.getType() == XMLSchemaReference.SIMPLE_TYPE)) { |
| if ((null != schemaContext) && (schemaContext.lastIndexOf('/') == 0)) { |
| schemaContext = schemaContext.substring(1, schemaContext.length()); |
| XPathFragment typeFragment = new XPathFragment(schemaContext); |
| if (null != descriptor.getNamespaceResolver()) { |
| String uri = descriptor.getNamespaceResolver().resolveNamespacePrefix(typeFragment.getPrefix()); |
| if(uri == null && xmlSchemaReference.getSchemaContextAsQName() != null){ |
| uri = xmlSchemaReference.getSchemaContextAsQName().getNamespaceURI(); |
| } |
| typeFragment.setNamespaceURI(uri); |
| } |
| this.descriptorsByGlobalType.put(typeFragment, descriptor); |
| } else { |
| QName qname = xmlSchemaReference.getSchemaContextAsQName(); |
| if (qname != null) { |
| if (descriptor.isWrapper() && descriptor.getJavaClassName().contains("ObjectWrapper")) { |
| return; |
| } |
| XPathFragment typeFragment = new XPathFragment(); |
| typeFragment.setLocalName(qname.getLocalPart()); |
| typeFragment.setNamespaceURI(qname.getNamespaceURI()); |
| this.descriptorsByGlobalType.put(typeFragment, descriptor); |
| } |
| } |
| } |
| } |
| } |
| |
| public void storeDescriptorsByQName(CoreSession session) { |
| Iterator iterator = session.getProject().getOrderedDescriptors().iterator(); |
| Set<DESCRIPTOR> processedDescriptors = new HashSet<>(); |
| while (iterator.hasNext()) { |
| DESCRIPTOR descriptor = (DESCRIPTOR) iterator.next(); |
| storeDescriptorByQName(descriptor, session.getDatasourcePlatform(), processedDescriptors); |
| } |
| } |
| |
| } |
| |
| private class XPathQueryResult { |
| /* |
| * Mapping corresponding to the XPath query |
| */ |
| private CoreMapping mapping; |
| |
| /* |
| * Mapping's owning object |
| */ |
| private Object owner; |
| |
| /* |
| * Index into mapping, from XPath query (may be null) |
| */ |
| private Integer index; |
| } |
| |
| protected volatile ContextState<ABSTRACT_SESSION, DESCRIPTOR, PROJECT, SESSION, SESSION_EVENT_LISTENER> contextState; |
| |
| private <T> T createByXPath(Object object, CoreObjectBuilder objectBuilder, StringTokenizer stringTokenizer, NAMESPACE_RESOLVER namespaceResolver, Class<T> returnType) { |
| XPathQueryResult queryResult = getMappingForXPath(object, objectBuilder, stringTokenizer, namespaceResolver); |
| |
| if (null != queryResult.mapping) { |
| DESCRIPTOR refDescriptor = (DESCRIPTOR) queryResult.mapping.getReferenceDescriptor(); |
| if (null != refDescriptor) { |
| return (T) refDescriptor.getInstantiationPolicy().buildNewInstance(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Create a new object instance for a given XPath, relative to the parentObject. |
| * |
| * @param <T> |
| * The return type of this method corresponds to the returnType parameter. |
| * @param parentObject |
| * The XPath will be executed relative to this object. |
| * @param xPath |
| * The XPath statement. |
| * @param namespaceResolver |
| * A NamespaceResolver containing the prefix/URI pairings from the XPath statement. |
| * @param returnType |
| * The return type. |
| * |
| * @return |
| * An instance of the Java class mapped to the supplied return type, or null |
| * if no result was found. |
| */ |
| public <T> T createByXPath(Object parentObject, String xPath, NAMESPACE_RESOLVER namespaceResolver, Class<T> returnType) { |
| ABSTRACT_SESSION session = this.getSession(parentObject); |
| DESCRIPTOR descriptor = (DESCRIPTOR) session.getDescriptor(parentObject); |
| StringTokenizer stringTokenizer = new StringTokenizer(xPath, "/"); |
| return createByXPath(parentObject, descriptor.getObjectBuilder(), stringTokenizer, namespaceResolver, returnType); |
| } |
| |
| protected abstract FIELD createField(String path); |
| |
| public abstract Marshaller createMarshaller(); |
| |
| public abstract Unmarshaller createUnmarshaller(); |
| |
| /** |
| * INTERNAL: |
| * Return the Descriptor with the default root mapping matching the QName |
| * parameter. |
| */ |
| public DESCRIPTOR getDescriptor(QName qName) { |
| XPathQName xpathQName = new XPathQName(qName, true); |
| return contextState.getDescriptor(xpathQName); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the Descriptor with the default root mapping matching the |
| * XPathQName parameter. |
| */ |
| public DESCRIPTOR getDescriptor(XPathQName xpathQName) { |
| return contextState.getDescriptor(xpathQName); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the Descriptor mapped to the global type matching the |
| * XPathFragment parameter. |
| */ |
| public DESCRIPTOR getDescriptorByGlobalType(XPathFragment xPathFragment) { |
| return contextState.getDescriptorByGlobalType(xPathFragment); |
| } |
| |
| private XPathQueryResult getMappingForXPath(Object object, CoreObjectBuilder objectBuilder, StringTokenizer stringTokenizer, NAMESPACE_RESOLVER namespaceResolver) { |
| XPathQueryResult queryResult = new XPathQueryResult(); |
| |
| String xPath = ""; |
| FIELD field = createField(null); |
| field.setNamespaceResolver(namespaceResolver); |
| while (stringTokenizer.hasMoreElements()) { |
| String nextToken = stringTokenizer.nextToken(); |
| field.setXPath(xPath + nextToken); |
| field.initialize(); |
| CoreMapping mapping = objectBuilder.getMappingForField(field); |
| if (null == mapping) { |
| // XPath might have indexes, while the mapping's XPath may not, |
| // so remove them and look again |
| XPathFragment xPathFragment = new XPathFragment(nextToken); |
| int fieldIndex = field.getXPathFragment().getIndexValue(); |
| int fragmentIndex = xPathFragment.getIndexValue(); |
| if (fieldIndex > 0 || fragmentIndex > 0) { |
| int index = fieldIndex - 1; |
| if (index < 0) { |
| index = fragmentIndex - 1; |
| } |
| String xPathNoIndexes = removeIndexesFromXPath(field.getXPath()); |
| field.setXPath(xPathNoIndexes); |
| field.initialize(); |
| mapping = objectBuilder.getMappingForField(field); |
| if (null == mapping) { |
| // Try adding /text() |
| field.setXPath(xPathNoIndexes + Constants.XPATH_SEPARATOR + Constants.TEXT); |
| field.initialize(); |
| mapping = objectBuilder.getMappingForField(field); |
| } |
| if (null != mapping) { |
| if (field.getXPath().endsWith(Constants.TEXT) || !stringTokenizer.hasMoreElements()) { |
| // End of the line, we found a mapping so return it |
| queryResult.mapping = mapping; |
| queryResult.owner = object; |
| queryResult.index = index; |
| return queryResult; |
| } else { |
| // We need to keep looking -- get the mapping value, |
| // then recurse into getMappingForXPath with new root object |
| Object childObject = mapping.getAttributeValueFromObject(object); |
| if (mapping.isCollectionMapping()) { |
| Object collection = mapping.getAttributeValueFromObject(object); |
| if (null != collection && List.class.isAssignableFrom(collection.getClass())) { |
| List list = (List) collection; |
| if (index >= list.size()) { |
| // Index used in query is out of range, no matches |
| return null; |
| } |
| childObject = list.get(index); |
| } |
| } |
| if (null == childObject) { |
| childObject = mapping.getReferenceDescriptor().getObjectBuilder().buildNewInstance(); |
| } |
| CoreObjectBuilder childObjectBuilder = mapping.getReferenceDescriptor().getObjectBuilder(); |
| return getMappingForXPath(childObject, childObjectBuilder, stringTokenizer, namespaceResolver); |
| } |
| } |
| } |
| } else { |
| if (!stringTokenizer.hasMoreElements()) { |
| // End of the line, we found a mapping so return it |
| queryResult.mapping = mapping; |
| queryResult.owner = object; |
| return queryResult; |
| } else { |
| // We need to keep looking -- get the mapping value, |
| // then recurse into getMappingForXPath with new root object |
| Object childObject = mapping.getAttributeValueFromObject(object); |
| if (mapping.isCollectionMapping()) { |
| Object collection = mapping.getAttributeValueFromObject(object); |
| if (null != collection && List.class.isAssignableFrom(collection.getClass())) { |
| List list = (List) collection; |
| if (0 >= list.size()) { |
| return null; |
| } |
| childObject = list.get(0); |
| } |
| } |
| if (null == childObject) { |
| childObject = mapping.getReferenceDescriptor().getObjectBuilder().buildNewInstance(); |
| } |
| CoreObjectBuilder childObjectBuilder = mapping.getReferenceDescriptor().getObjectBuilder(); |
| return getMappingForXPath(childObject, childObjectBuilder, stringTokenizer, namespaceResolver); |
| } |
| } |
| xPath = xPath + nextToken + Constants.XPATH_SEPARATOR; |
| } |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the session corresponding to this class. Since the class |
| * may be mapped by more that one of the projects used to create the |
| * Context, this method will return the first match. |
| */ |
| public ABSTRACT_SESSION getSession(Class clazz) { |
| return contextState.getSession(clazz); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public SESSION getSession() { |
| return contextState.getSession(); |
| } |
| |
| public ABSTRACT_SESSION getSession(DESCRIPTOR descriptor) { |
| return contextState.getSession(descriptor); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the session corresponding to this object. Since the |
| * object may be mapped by more that one of the projects used to create the |
| * Context, this method will return the first match. |
| */ |
| public ABSTRACT_SESSION getSession(Object object) { |
| return contextState.getSession(object); |
| } |
| |
| /** |
| * <p>Query the object model based on the corresponding document. The following pairings are equivalent:</p> |
| * |
| * <i>Return the Customer's ID</i> |
| * <pre> Integer id = context.getValueByXPath(customer, "@id", null, Integer.class); |
| * Integer id = customer.getId();</pre> |
| * |
| * <i>Return the Customer's Name</i> |
| * <pre> String name = context.getValueByXPath(customer, "ns:personal-info/ns:name/text()", null, String.class); |
| * String name = customer.getName();</pre> |
| * |
| * <i>Return the Customer's Address</i> |
| * <pre> Address address = context.getValueByXPath(customer, "ns:contact-info/ns:address", aNamespaceResolver, Address.class); |
| * Address address = customer.getAddress();</pre> |
| * |
| * <i>Return all the Customer's PhoneNumbers</i> |
| * <pre> List phoneNumbers = context.getValueByXPath(customer, "ns:contact-info/ns:phone-number", aNamespaceResolver, List.class); |
| * List phoneNumbers = customer.getPhoneNumbers();</pre> |
| * |
| * <i>Return the Customer's second PhoneNumber</i> |
| * <pre> PhoneNumber phoneNumber = context.getValueByXPath(customer, "ns:contact-info/ns:phone-number[2]", aNamespaceResolver, PhoneNumber.class); |
| * PhoneNumber phoneNumber = customer.getPhoneNumbers().get(1);</pre> |
| * |
| * <i>Return the base object</i> |
| * <pre> Customer customer = context.getValueByXPath(customer, ".", aNamespaceResolver, Customer.class); |
| * Customer customer = customer; |
| * </pre> |
| * |
| * @param <T> The return type of this method corresponds to the returnType parameter. |
| * @param object The XPath will be executed relative to this object. |
| * @param xPath The XPath statement |
| * @param namespaceResolver A NamespaceResolver containing the prefix/URI pairings from the XPath statement. |
| * @param returnType The return type. |
| * @return The object corresponding to the XPath or null if no result was found. |
| */ |
| public <T> T getValueByXPath(Object object, String xPath, NAMESPACE_RESOLVER namespaceResolver, Class<T> returnType) { |
| if (null == xPath || null == object) { |
| return null; |
| } |
| if (".".equals(xPath)) { |
| return (T) object; |
| } |
| ABSTRACT_SESSION session = this.getSession(object); |
| DESCRIPTOR descriptor = (DESCRIPTOR) session.getDescriptor(object); |
| StringTokenizer stringTokenizer = new StringTokenizer(xPath, Constants.XPATH_SEPARATOR); |
| T value = getValueByXPath(object, descriptor.getObjectBuilder(), stringTokenizer, namespaceResolver, returnType); |
| if (null == value) { |
| CoreMapping selfMapping = descriptor.getObjectBuilder().getMappingForField(createField(String.valueOf(Constants.DOT))); |
| if (null != selfMapping && selfMapping.getReferenceDescriptor() != null) { |
| return getValueByXPath(selfMapping.getAttributeValueFromObject(object), selfMapping.getReferenceDescriptor().getObjectBuilder(), |
| new StringTokenizer(xPath, Constants.XPATH_SEPARATOR), ((DESCRIPTOR) selfMapping.getReferenceDescriptor()).getNamespaceResolver(), returnType); |
| } |
| } |
| return value; |
| } |
| |
| private <T> T getValueByXPath(Object object, CoreObjectBuilder objectBuilder, StringTokenizer stringTokenizer, NAMESPACE_RESOLVER namespaceResolver, Class<T> returnType) { |
| XPathQueryResult queryResult = getMappingForXPath(object, objectBuilder, stringTokenizer, namespaceResolver); |
| |
| if (null != queryResult) { |
| CoreMapping mapping = queryResult.mapping; |
| Object owner = queryResult.owner; |
| Integer index = queryResult.index; |
| |
| if (null != owner) { |
| Object childObject = null; |
| if (mapping.isCollectionMapping()) { |
| Object collection = mapping.getAttributeValueFromObject(owner); |
| if (List.class.isAssignableFrom(collection.getClass())) { |
| List list = (List) collection; |
| if (null == index) { |
| return (T) collection; |
| } |
| if (index >= list.size()) { |
| return null; |
| } |
| childObject = list.get(index); |
| } |
| } else { |
| childObject = mapping.getAttributeValueFromObject(owner); |
| } |
| return (T) childObject; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return true if any session held onto by this context has a document preservation |
| * policy that requires unmarshalling from a Node. |
| */ |
| public abstract boolean hasDocumentPreservation(); |
| |
| private String removeIndexesFromXPath(String xpathWithIndexes) { |
| String newXPath = xpathWithIndexes; |
| while (newXPath.contains(Constants.XPATH_INDEX_OPEN)) { |
| int open = newXPath.lastIndexOf(Constants.XPATH_INDEX_OPEN); |
| int closed = newXPath.lastIndexOf(Constants.XPATH_INDEX_CLOSED); |
| newXPath = newXPath.substring(0, open) + newXPath.substring(closed + 1); |
| } |
| return newXPath; |
| } |
| |
| private void setValueByXPath(Object object, CoreObjectBuilder objectBuilder, StringTokenizer stringTokenizer, NAMESPACE_RESOLVER namespaceResolver, Object value) { |
| XPathQueryResult queryResult = getMappingForXPath(object, objectBuilder, stringTokenizer, namespaceResolver); |
| |
| if (null != queryResult) { |
| CoreMapping mapping = queryResult.mapping; |
| Object owner = queryResult.owner; |
| Integer index = queryResult.index; |
| |
| if (null != owner) { |
| if (mapping.isCollectionMapping()) { |
| Object childObject = null; |
| Object collection = mapping.getAttributeValueFromObject(owner); |
| if (List.class.isAssignableFrom(collection.getClass())) { |
| List list = (List) collection; |
| if (null == index) { |
| // We are setting the whole collection, not an element in the collection |
| if (value.getClass().isArray()) { |
| ArrayList newList = new ArrayList(); |
| int length = Array.getLength(value); |
| for (int i = 0; i < length; i++) { |
| newList.add(Array.get(value, i)); |
| } |
| value = newList; |
| } |
| mapping.setAttributeValueInObject(owner, value); |
| return; |
| } |
| if (index >= list.size()) { |
| return; |
| } |
| // Set into collection |
| list.set(index, value); |
| mapping.setAttributeValueInObject(owner, list); |
| return; |
| } |
| } else { |
| mapping.setAttributeValueInObject(owner, value); |
| } |
| } |
| } |
| } |
| |
| /** |
| * <p>Set values in the object model based on the corresponding document. The following pairings are equivalent:</p> |
| * |
| * <i>Set the Customer's ID</i> |
| * <pre> context.setValueByXPath(customer, "@id", null, Integer.valueOf(123)); |
| * customer.setId(Integer.valueOf(123));</pre> |
| * |
| * <i>Set the Customer's Name</i> |
| * <pre> context.setValueByXPath(customer, "ns:personal-info/ns:name/text()", aNamespaceResolver, "Jane Doe"); |
| * customer.setName("Jane Doe");</pre> |
| * |
| * <i>Set the Customer's Address</i> |
| * <pre> context.setValueByXPath(customer, "ns:contact-info/ns:address", aNamespaceResolver, anAddress); |
| * customer.setAddress(anAddress);</pre> |
| * |
| * <i>Set the Customer's PhoneNumbers</i> |
| * <pre> context.setValueByXPath(customer, "ns:contact-info/ns:phone-number", aNamespaceResolver, phoneNumbers); |
| * customer.setPhoneNumbers(phoneNumbers);</pre> |
| * |
| * <i>Set the Customer's second PhoneNumber</i> |
| * <pre> context.setValueByXPath(customer, "ns:contact-info/ns:phone-number[2]", aNamespaceResolver, aPhoneNumber); |
| * customer.getPhoneNumbers().get(1);</pre> |
| * |
| * @param object The XPath will be executed relative to this object. |
| * @param xPath The XPath statement |
| * @param namespaceResolver A NamespaceResolver containing the prefix/URI pairings from the XPath statement. |
| * @param value The value to be set. |
| */ |
| public void setValueByXPath(Object object, String xPath, NAMESPACE_RESOLVER namespaceResolver, Object value) { |
| ABSTRACT_SESSION session = this.getSession(object); |
| DESCRIPTOR descriptor = (DESCRIPTOR) session.getDescriptor(object); |
| StringTokenizer stringTokenizer = new StringTokenizer(xPath, "/"); |
| setValueByXPath(object, descriptor.getObjectBuilder(), stringTokenizer, namespaceResolver, value); |
| } |
| |
| } |