diff options
author | pfullbright | 2012-04-03 21:24:40 +0000 |
---|---|---|
committer | pfullbright | 2012-04-03 21:24:40 +0000 |
commit | a8c296ee167f0fc315d310049d37f536ebb972ed (patch) | |
tree | ee9cc61f058d20d3f56a0a2876f1d32498622483 /jaxb | |
parent | f3f7412ac0097ad3fac7b43ea75c13db828ba154 (diff) | |
download | webtools.dali-a8c296ee167f0fc315d310049d37f536ebb972ed.tar.gz webtools.dali-a8c296ee167f0fc315d310049d37f536ebb972ed.tar.xz webtools.dali-a8c296ee167f0fc315d310049d37f536ebb972ed.zip |
bug 366901 - XmlJoinNode support
Diffstat (limited to 'jaxb')
15 files changed, 1202 insertions, 30 deletions
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/context/JaxbPackageInfo.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/context/JaxbPackageInfo.java index 0ce4d2fc3c..062c95439f 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/context/JaxbPackageInfo.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/context/JaxbPackageInfo.java @@ -87,6 +87,8 @@ public interface JaxbPackageInfo String getNamespaceForPrefix(String prefix); + String getPrefixForNamespace(String namespace); + // ***** validation ***** diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaPackageInfo.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaPackageInfo.java index 53b86a8cb2..df21aa2d69 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaPackageInfo.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaPackageInfo.java @@ -313,6 +313,17 @@ public class GenericJavaPackageInfo return null; } + public String getPrefixForNamespace(String namespace) { + if (this.xmlSchema != null) { + for (XmlNs xmlns : this.xmlSchema.getXmlNsPrefixes()) { + if (StringTools.stringsAreEqual(xmlns.getNamespaceURI(), namespace)) { + return xmlns.getPrefix(); + } + } + } + return null; + } + // ***** content assist ****** diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties index b21b7d8f4b..b9f8f38304 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties @@ -11,25 +11,33 @@ PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY = Project is missing a jaxb.properties file specifying the EclipseLink JAXB context factory XML_DISCRIMINATOR_NODE__NOT_SPECIFIED = XmlDiscriminatorNode not specified. -XML_DISCRIMINATOR_NODE__ROOT_NOT_SUPPORTED = Root XPath not supported. XML_DISCRIMINATOR_VALUE__NOT_SPECIFIED = XmlDiscriminatorValue not specified. XML_ELEMENT_DECL__INVALID_METHOD_SIGNATURE_RETURN_TYPE = An element factory method must have a return type consistent with ''javax.xml.bind.JAXBElement''. +XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED = XmlJoinNode xmlPath not specified. +XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED = XmlJoinNode referencedXmlPath not specified. +XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS = There is no XmlKey or XmlID on the target class ''{0}'' with XPath \"{1}\". + +XML_JOIN_NODES__INVALID_REFERENCED_CLASS = The referenced class ''{0}'' is invalid for use with XmlJoinNodes. +XML_JOIN_NODES__DUPLICATE_XML_PATH = Duplicate xmlPath ''{0}'' in XmlJoinNodes. +XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH = Duplicate referencedXmlpath ''{0}'' in XmlJoinNodes. + XML_PATH__NOT_SPECIFIED = XmlPath not specified. -XML_PATH__ROOT_NOT_SUPPORTED = Root XmlPath is not supported. -XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT = Illegal XmlPath step \"{0}\". -XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = Self XmlPath step must be first step. -XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = Text XmlPath step must be last step. -XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = An attribute XmlPath step must be the last step. -XML_PATH__INVALID_NS_PREFIX = Cannot resolve a namespace for the prefix \"{0}\". -XML_PATH__UNRESOLVED_ELEMENT = Cannot resolve element with namespace \"{0}\" and local name \"{1}\" in this context. -XML_PATH__UNRESOLVED_ATTRIBUTE = Cannot resolve attribute with namespace \"{0}\" and local name \"{1}\" in this context. XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS = Insufficient XmlPaths specified. There must be an XmlPath for each XmlElement. XML_PATH__INSUFFICIENT_XML_ELEMENTS_FOR_XML_PATHS = There is no XmlElement to match this XmlPath. There must be an XmlElement for each Xmlpath. XML_INVERSE_REFERENCE__MAPPED_BY_NOT_SPECIFIED = The 'mappedBy' property must be specified on an XmlInverseReference. XML_INVERSE_REFERENCE__MAPPED_BY_NOT_RESOLVED = Cannot resolve the attribute ''{0}'' on the class ''{1}''. -XML_INVERSE_REFERENCE__MAPPED_BY_ILLEGAL_MAPPING_TYPE = The attribute ''{0}'' on the class ''{1}'' must be mapped as XmlElement, XmlElements, XmlAttribute, or XmlValue.
\ No newline at end of file +XML_INVERSE_REFERENCE__MAPPED_BY_ILLEGAL_MAPPING_TYPE = The attribute ''{0}'' on the class ''{1}'' must be mapped as XmlElement, XmlElements, XmlAttribute, or XmlValue.j + +XPATH__INVALID_FORM_ILLEGAL_SEGMENT = Illegal XPath step \"{0}\". +XPATH__ROOT_NOT_SUPPORTED = Root XPath is not supported in this context. +XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = Self XPath step must be first step. +XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = Text XPath step must be last step. +XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = An attribute XPath step must be the last step. +XPATH__INVALID_NS_PREFIX = Cannot resolve a namespace for the prefix \"{0}\". +XPATH__UNRESOLVED_ELEMENT = Cannot resolve element with namespace \"{0}\" and local name \"{1}\" in this context. +XPATH__UNRESOLVED_ATTRIBUTE = Cannot resolve attribute with namespace \"{0}\" and local name \"{1}\" in this context. diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java index c1fb95d5bb..253472585f 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java @@ -46,4 +46,14 @@ public interface ELClassMapping ELXmlDiscriminatorValue addXmlDiscriminatorValue(); void removeXmlDiscriminatorValue(); + + + // ***** misc ***** + + /** + * Return an {@link Iterable} of XPaths that represent the attributes annotated with XmlID or + * XmlKey. (Includes those attributes that are not annotated with XmlPath - those XPaths + * will be calculated.) + */ + Iterable<String> getKeyXPaths(); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNode.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNode.java new file mode 100644 index 0000000000..0166f05684 --- /dev/null +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNode.java @@ -0,0 +1,58 @@ +package org.eclipse.jpt.jaxb.eclipselink.core.context.java; + +import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode; + +/** + * Represents an @XmlJoinNode, whether at top level or nested in @XmlJoinNodes + * <p> + * Provisional API: This interface is part of an interim API that is still + * under development and expected to change significantly before reaching + * stability. It is available at this early stage to solicit feedback from + * pioneering adopters on the understanding that any code that uses this API + * will almost certainly be broken (repeatedly) as the API evolves. + * + * @version 3.2 + * @since 3.2 + */ +public interface ELXmlJoinNode + extends JavaContextNode { + + // ***** xmlPath ***** + + /** + * String associated with changes to the xmlPath property + */ + String XML_PATH_PROPERTY = "xmlPath"; ///$NON-NLS-1$ + + /** + * Return the xmlPath property value. + * A null indicates it is not specified. + */ + String getXmlPath(); + + /** + * Set the xmlPath property value. + * Null unspecifies the value. + */ + void setXmlPath(String value); + + + // ***** referencedXmlPath ***** + + /** + * String associated with changes to the referencedXmlPath property + */ + String REFERENCED_XML_PATH_PROPERTY = "referencedXmlPath"; ///$NON-NLS-1$ + + /** + * Return the referencedXmlPath property value. + * A null indicates it is not specified. + */ + String getReferencedXmlPath(); + + /** + * Set the referencedXmlPath property value. + * Null unspecifies the value. + */ + void setReferencedXmlPath(String value); +} diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java index e65f928ff2..f821fa18fb 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java @@ -9,7 +9,9 @@ *******************************************************************************/ package org.eclipse.jpt.jaxb.eclipselink.core.context.java; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; +import org.eclipse.jpt.jaxb.core.xsd.XsdTypeDefinition; /** * Represents an EclipseLink XmlJoinNodes attribute mapping in either @@ -27,4 +29,25 @@ import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; public interface ELXmlJoinNodesMapping extends JaxbAttributeMapping { + + // ***** XmlJoinNodes ***** + + String XML_JOIN_NODES_LIST = "xmlJoinNodes"; //$NON-NLS-1$ + + ListIterable<ELXmlJoinNode> getXmlJoinNodes(); + + int getXmlJoinNodesSize(); + + ELXmlJoinNode addXmlJoinNode(int index); + + void removeXmlJoinNode(int index); + + void moveXmlJoinNode(int targetIndex, int sourceIndex); + + + // ***** misc ***** + + ELClassMapping getReferencedClassMapping(); + + XsdTypeDefinition getReferencedXsdTypeDefinition(); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java index 2fcc36fcd6..1065f4fd69 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java @@ -4,12 +4,20 @@ import java.util.List; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jpt.common.utility.Filter; import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.NotNullFilter; import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SubIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; +import org.eclipse.jpt.jaxb.core.MappingKeys; +import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; import org.eclipse.jpt.jaxb.core.context.JaxbClass; +import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; import org.eclipse.jpt.jaxb.core.internal.context.java.GenericJavaClassMapping; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELClassMapping; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlDiscriminatorNode; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlDiscriminatorValue; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlNamedNodeMapping; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlDiscriminatorNodeAnnotation; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlDiscriminatorValueAnnotation; @@ -180,6 +188,43 @@ public class ELJavaClassMapping } + // ***** misc ***** + + public Iterable<String> getKeyXPaths() { + return new FilteringIterable( + new TransformationIterable<ELXmlNamedNodeMapping, String>(getAllKeyMappings()) { + @Override + protected String transform(ELXmlNamedNodeMapping o) { + return o.getXPath(); + } + }, + NotNullFilter.instance()); + } + + protected Iterable<ELXmlNamedNodeMapping> getAllKeyMappings() { + return new FilteringIterable<ELXmlNamedNodeMapping>( + new SubIterableWrapper<JaxbAttributeMapping, ELXmlNamedNodeMapping>( + new FilteringIterable<JaxbAttributeMapping>( + new TransformationIterable<JaxbPersistentAttribute, JaxbAttributeMapping>(getAllAttributes()) { + @Override + protected JaxbAttributeMapping transform(JaxbPersistentAttribute o) { + return o.getMapping(); + } + }) { + @Override + protected boolean accept(JaxbAttributeMapping o) { + return (o.getKey() == MappingKeys.XML_ELEMENT_ATTRIBUTE_MAPPING_KEY + || o.getKey() == MappingKeys.XML_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY); + } + })) { + @Override + protected boolean accept(ELXmlNamedNodeMapping o) { + return o.getXmlID() != null || o.getXmlKey() != null; + } + }; + } + + // ***** content assist ***** @Override diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java new file mode 100644 index 0000000000..8c7a989c4a --- /dev/null +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java @@ -0,0 +1,314 @@ +/******************************************************************************* + * Copyright (c) 2012 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jaxb.eclipselink.core.internal.context.java; + +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.jaxb.core.JaxbNode; +import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; +import org.eclipse.jpt.jaxb.core.context.JaxbPackage; +import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode; +import org.eclipse.jpt.jaxb.core.internal.context.java.AbstractJavaContextNode; +import org.eclipse.jpt.jaxb.core.xsd.XsdTypeDefinition; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELClassMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNode; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNodesMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.xpath.java.XPath; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.xpath.java.XPathFactory; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.validation.ELJaxbValidationMessageBuilder; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.validation.ELJaxbValidationMessages; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlJoinNodeAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + + +public class ELJavaXmlJoinNode + extends AbstractJavaContextNode + implements ELXmlJoinNode { + + protected String xmlPath; + + protected String referencedXmlPath; + + protected Context context; + + + public ELJavaXmlJoinNode(JavaContextNode parent, Context context) { + super(parent); + this.context = context; + initXmlPath(); + initReferencedXmlPath(); + } + + + protected JaxbPackage getJaxbPackage() { + return getClassMapping().getJaxbType().getJaxbPackage(); + } + + + // ***** sync/update ***** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + syncXmlPath(); + syncReferencedXmlPath(); + } + + + // ***** xmlPath ***** + + public String getXmlPath() { + return this.xmlPath; + } + + public void setXmlPath(String xmlPath) { + getAnnotation().setXmlPath(xmlPath); + setXmlPath_(xmlPath); + } + + protected void setXmlPath_(String xmlPath) { + String old = this.xmlPath; + this.xmlPath = xmlPath; + firePropertyChanged(XML_PATH_PROPERTY, old, this.xmlPath); + } + + protected void initXmlPath() { + this.xmlPath = getAnnotation().getXmlPath(); + } + + protected void syncXmlPath() { + setXmlPath_(getAnnotation().getXmlPath()); + } + + + // ***** referencedXmlPath ***** + + public String getReferencedXmlPath() { + return this.referencedXmlPath; + } + + public void setReferencedXmlPath(String referencedXmlPath) { + getAnnotation().setReferencedXmlPath(referencedXmlPath); + setReferencedXmlPath_(referencedXmlPath); + } + + protected void setReferencedXmlPath_(String referencedXmlPath) { + String old = this.referencedXmlPath; + this.referencedXmlPath = referencedXmlPath; + firePropertyChanged(REFERENCED_XML_PATH_PROPERTY, old, this.referencedXmlPath); + } + + protected void initReferencedXmlPath() { + this.referencedXmlPath = getAnnotation().getReferencedXmlPath(); + } + + protected void syncReferencedXmlPath() { + setReferencedXmlPath_(getAnnotation().getReferencedXmlPath()); + } + + + protected XmlJoinNodeAnnotation getAnnotation() { + return this.context.getAnnotation(); + } + + protected ELXmlJoinNodesMapping getAttributeMapping() { + return this.context.getAttributeMapping(); + } + + protected JaxbClassMapping getClassMapping() { + return getAttributeMapping().getClassMapping(); + } + + + // ***** content assist ***** + + @Override + public Iterable<String> getJavaCompletionProposals( + int pos, Filter<String> filter, CompilationUnit astRoot) { + + if (getAnnotation().xmlPathTouches(pos, astRoot) && this.xmlPath != null) { + XsdTypeDefinition xsdType = getClassMapping().getXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.xmlPath); + return xpath.getCompletionProposals(new XmlPathContext(astRoot), xsdType, pos, filter); + } + + if (getAnnotation().referencedXmlPathTouches(pos, astRoot) && this.referencedXmlPath != null) { + + + XsdTypeDefinition xsdType = getAttributeMapping().getReferencedXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.referencedXmlPath); + Iterable<String> result = xpath.getCompletionProposals(new ReferencedXmlPathContext(astRoot), xsdType, pos, filter); + + ELClassMapping referencedClassMapping = this.context.getAttributeMapping().getReferencedClassMapping(); + if (referencedClassMapping != null) { + result = new CompositeIterable<String>( + result, + StringTools.convertToJavaStringLiterals(referencedClassMapping.getKeyXPaths())); + } + + return CollectionTools.sortedSet(result); + } + + return EmptyIterable.instance(); + } + + + // ***** validation ***** + + @Override + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return getAnnotation().getTextRange(astRoot); + } + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + validateXmlPath(messages, astRoot); + validateReferencedXmlPath(messages, astRoot); + } + + protected void validateXmlPath(List<IMessage> messages, CompilationUnit astRoot) { + if (StringTools.stringIsEmpty(this.xmlPath)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED, + ELJavaXmlJoinNode.this, + getXmlPathTextRange(astRoot))); + return; + } + + if (this.xmlPath.startsWith(XPath.DELIM)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XPATH__ROOT_NOT_SUPPORTED, + ELJavaXmlJoinNode.this, + getXmlPathTextRange(astRoot))); + return; + } + + XsdTypeDefinition xsdType = getClassMapping().getXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.xmlPath); + xpath.validate(new XmlPathContext(astRoot), xsdType, messages); + } + + protected void validateReferencedXmlPath(List<IMessage> messages, CompilationUnit astRoot) { + if (StringTools.stringIsEmpty(this.referencedXmlPath)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED, + ELJavaXmlJoinNode.this, + getReferencedXmlPathTextRange(astRoot))); + return; + } + + if (this.referencedXmlPath.startsWith(XPath.DELIM)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XPATH__ROOT_NOT_SUPPORTED, + ELJavaXmlJoinNode.this, + getReferencedXmlPathTextRange(astRoot))); + return; + } + + ELClassMapping referencedClassMapping = this.context.getAttributeMapping().getReferencedClassMapping(); + if (referencedClassMapping != null && + ! CollectionTools.contains(referencedClassMapping.getKeyXPaths(), this.referencedXmlPath)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS, + new String[] { referencedClassMapping.getJaxbType().getFullyQualifiedName(), this.referencedXmlPath }, + ELJavaXmlJoinNode.this, + getReferencedXmlPathTextRange(astRoot))); + } + + XsdTypeDefinition xsdType = getAttributeMapping().getReferencedXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.referencedXmlPath); + xpath.validate(new ReferencedXmlPathContext(astRoot), xsdType, messages); + } + + protected TextRange getXmlPathTextRange(CompilationUnit astRoot) { + // should never be null + return getAnnotation().getXmlPathTextRange(astRoot); + } + + protected TextRange getReferencedXmlPathTextRange(CompilationUnit astRoot) { + // should never be null + return getAnnotation().getReferencedXmlPathTextRange(astRoot); + } + + + public interface Context { + + XmlJoinNodeAnnotation getAnnotation(); + + ELXmlJoinNodesMapping getAttributeMapping(); + } + + + protected abstract class XPathContext + implements XPath.Context { + + protected CompilationUnit astRoot; + + protected XPathContext(CompilationUnit astRoot) { + this.astRoot = astRoot; + } + + + public JaxbNode getContextObject() { + return ELJavaXmlJoinNode.this; + } + + public JaxbPackage getJaxbPackage() { + return ELJavaXmlJoinNode.this.getJaxbPackage(); + } + } + + + protected class XmlPathContext + extends XPathContext { + + protected XmlPathContext(CompilationUnit astRoot) { + super(astRoot); + } + + + public TextRange getTextRange() { + return ELJavaXmlJoinNode.this.getXmlPathTextRange(this.astRoot); + } + } + + + protected class ReferencedXmlPathContext + extends XPathContext { + + protected ReferencedXmlPathContext(CompilationUnit astRoot) { + super(astRoot); + } + + + public TextRange getTextRange() { + return ELJavaXmlJoinNode.this.getReferencedXmlPathTextRange(this.astRoot); + } + } +} diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java index 7715ef9dd4..2752036b04 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java @@ -9,20 +9,47 @@ *******************************************************************************/ package org.eclipse.jpt.jaxb.eclipselink.core.internal.context.java; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.resource.java.Annotation; +import org.eclipse.jpt.common.core.resource.java.NestableAnnotation; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.Bag; import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.HashBag; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SubListIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterables.SuperListIterableWrapper; +import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; import org.eclipse.jpt.jaxb.core.internal.context.java.AbstractJavaAttributeMapping; +import org.eclipse.jpt.jaxb.core.xsd.XsdTypeDefinition; import org.eclipse.jpt.jaxb.eclipselink.core.ELJaxbMappingKeys; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELClassMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlElementsMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNode; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNodesMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.validation.ELJaxbValidationMessageBuilder; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.validation.ELJaxbValidationMessages; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlJoinNodeAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; public class ELJavaXmlJoinNodesMapping extends AbstractJavaAttributeMapping implements ELXmlJoinNodesMapping { + protected final ContextListContainer<ELJavaXmlJoinNode, XmlJoinNodeAnnotation> xmlJoinNodeContainer; + + public ELJavaXmlJoinNodesMapping(JaxbPersistentAttribute parent) { super(parent); + this.xmlJoinNodeContainer = buildXmlJoinNodeContainer(); } @@ -43,4 +70,230 @@ public class ELJavaXmlJoinNodesMapping return getAnnotation() == null && CollectionTools.isEmpty(getPersistentAttribute().getJavaResourceAttribute().getAnnotations(ELJaxb.XML_JOIN_NODE)); } + + + // ***** sync/update ***** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.xmlJoinNodeContainer.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.xmlJoinNodeContainer.update(); + } + + + // ***** xmlJoinNodes ***** + + public ListIterable<ELXmlJoinNode> getXmlJoinNodes() { + return new SuperListIterableWrapper<ELXmlJoinNode>(this.xmlJoinNodeContainer.getContextElements()); + } + + public int getXmlJoinNodesSize() { + return this.xmlJoinNodeContainer.getContextElementsSize(); + } + + public ELXmlJoinNode addXmlJoinNode(int index) { + XmlJoinNodeAnnotation annotation = + (XmlJoinNodeAnnotation) getJavaResourceAttribute().addAnnotation(index, ELJaxb.XML_JOIN_NODE); + return this.xmlJoinNodeContainer.addContextElement(index, annotation); + } + + public void removeXmlJoinNode(int index) { + getJavaResourceAttribute().removeAnnotation(index, ELJaxb.XML_JOIN_NODE); + this.xmlJoinNodeContainer.removeContextElement(index); + } + + public void moveXmlJoinNode(int targetIndex, int sourceIndex) { + getJavaResourceAttribute().moveAnnotation(targetIndex, sourceIndex, ELJaxb.XML_JOIN_NODE); + this.xmlJoinNodeContainer.moveContextElement(targetIndex, sourceIndex); + } + + protected ELJavaXmlJoinNode buildXmlJoinNode(XmlJoinNodeAnnotation xmlJoinNodeAnnotation) { + return new ELJavaXmlJoinNode(this, new XmlJoinNodeContext(xmlJoinNodeAnnotation)); + } + + protected ContextListContainer<ELJavaXmlJoinNode, XmlJoinNodeAnnotation> buildXmlJoinNodeContainer() { + XmlJoinNodeContainer container = new XmlJoinNodeContainer(); + container.initialize(); + return container; + } + + protected ListIterable<XmlJoinNodeAnnotation> getXmlJoinNodeAnnotations() { + return new SubListIterableWrapper<NestableAnnotation, XmlJoinNodeAnnotation>( + getJavaResourceAttribute().getAnnotations(ELJaxb.XML_JOIN_NODE)); + } + + + // ***** misc ***** + + public ELClassMapping getReferencedClassMapping() { + String valueType = getValueTypeName(); + if (StringTools.stringIsEmpty(valueType)) { + return null; + } + + return (ELClassMapping) getContextRoot().getClassMapping(valueType); + } + + public XsdTypeDefinition getReferencedXsdTypeDefinition() { + JaxbClassMapping classMapping = getReferencedClassMapping(); + return (classMapping == null) ? null : classMapping.getXsdTypeDefinition(); + } + + + // ***** content assist ***** + + @Override + public Iterable<String> getJavaCompletionProposals( + int pos, Filter<String> filter, CompilationUnit astRoot) { + + Iterable<String> result = super.getJavaCompletionProposals(pos, filter, astRoot); + if (! CollectionTools.isEmpty(result)) { + return result; + } + + for (ELJavaXmlJoinNode xmlJoinNode : this.xmlJoinNodeContainer.getContextElements()) { + result = xmlJoinNode.getJavaCompletionProposals(pos, filter, astRoot); + if (! CollectionTools.isEmpty(result)) { + return result; + } + } + + return EmptyIterable.instance(); + } + + + // ***** validation ***** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + JaxbClassMapping referencedClass = getReferencedClassMapping(); + + if (referencedClass == null) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODES__INVALID_REFERENCED_CLASS, + new String[] { getValueTypeName() }, + ELJavaXmlJoinNodesMapping.this, + getValidationTextRange(astRoot))); + } + + validateDuplicateXmlPaths(messages, reporter, astRoot); + + for (ELJavaXmlJoinNode xmlJoinNode : this.xmlJoinNodeContainer.getContextElements()) { + xmlJoinNode.validate(messages, reporter, astRoot); + } + } + + protected void validateDuplicateXmlPaths(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + Bag<String> xmlPaths = new HashBag<String>(); + Bag<String> referencedXmlPaths = new HashBag<String>(); + + for (ELJavaXmlJoinNode joinNode : this.xmlJoinNodeContainer.getContextElements()) { + String xmlPath = joinNode.getXmlPath(); + if (! StringTools.stringIsEmpty(xmlPath)) { + xmlPaths.add(xmlPath); + } + String referencedXmlPath = joinNode.getReferencedXmlPath(); + if (! StringTools.stringIsEmpty(referencedXmlPath)) { + referencedXmlPaths.add(referencedXmlPath); + } + } + + for (ELJavaXmlJoinNode joinNode : this.xmlJoinNodeContainer.getContextElements()) { + validateDuplicateXmlPath(joinNode, xmlPaths, messages, astRoot); + validateDuplicateReferencedXmlPath(joinNode, referencedXmlPaths, messages, astRoot); + } + } + + protected void validateDuplicateXmlPath(ELJavaXmlJoinNode joinNode, Bag<String> xmlPaths, + List<IMessage> messages, CompilationUnit astRoot) { + String xmlPath = joinNode.getXmlPath(); + if (xmlPaths.count(xmlPath) > 1) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODES__DUPLICATE_XML_PATH, + new String[] { xmlPath }, + joinNode, + joinNode.getXmlPathTextRange(astRoot))); + } + } + + protected void validateDuplicateReferencedXmlPath(ELJavaXmlJoinNode joinNode, Bag<String> referencedXmlPaths, + List<IMessage> messages, CompilationUnit astRoot) { + String referencedXmlPath = joinNode.getReferencedXmlPath(); + if (referencedXmlPaths.count(referencedXmlPath) > 1) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH, + new String[] { referencedXmlPath }, + joinNode, + joinNode.getReferencedXmlPathTextRange(astRoot))); + } + } + + @Override + public TextRange getValidationTextRange(CompilationUnit astRoot) { + Annotation annotation = getAnnotation(); + if (annotation == null) { + annotation = getJavaResourceAttribute().getAnnotation(0, ELJaxb.XML_JOIN_NODE); + } + return annotation.getTextRange(astRoot); + } + + + protected class XmlJoinNodeContainer + extends ContextListContainer<ELJavaXmlJoinNode, XmlJoinNodeAnnotation> { + + @Override + protected String getContextElementsPropertyName() { + return ELXmlElementsMapping.XML_PATHS_LIST; + } + + @Override + protected ELJavaXmlJoinNode buildContextElement(XmlJoinNodeAnnotation resourceElement) { + return ELJavaXmlJoinNodesMapping.this.buildXmlJoinNode(resourceElement); + } + + @Override + protected ListIterable<XmlJoinNodeAnnotation> getResourceElements() { + return ELJavaXmlJoinNodesMapping.this.getXmlJoinNodeAnnotations(); + } + + @Override + protected XmlJoinNodeAnnotation getResourceElement(ELJavaXmlJoinNode contextElement) { + // in the context of this mapping, there will never be an ELXmlJoinNode without an annotation + return contextElement.getAnnotation(); + } + } + + + protected class XmlJoinNodeContext + implements ELJavaXmlJoinNode.Context { + + protected XmlJoinNodeAnnotation annotation; + + + protected XmlJoinNodeContext(XmlJoinNodeAnnotation annotation) { + this.annotation = annotation; + } + + public XmlJoinNodeAnnotation getAnnotation() { + return this.annotation; + } + + public ELXmlJoinNodesMapping getAttributeMapping() { + return ELJavaXmlJoinNodesMapping.this; + } + } } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java index c451848dbe..0415dbb21d 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java @@ -52,6 +52,21 @@ public class XPath { public static char CLOSE_BRACKET = ']'; + public static String attributeXPath(String prefix, String localName) { + if (prefix == null) { + return StringTools.concatenate(ATT_PREFIX, localName); + } + return StringTools.concatenate(ATT_PREFIX, prefix, COLON, localName); + } + + public static String elementXPath(String prefix, String localName) { + if (prefix == null) { + return localName; + } + return StringTools.concatenate(prefix, COLON, localName); + } + + List<Step> steps; @@ -224,7 +239,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT, + ELJaxbValidationMessages.XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT, context.getContextObject(), getTextRange(context))); return; @@ -242,7 +257,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__UNRESOLVED_ATTRIBUTE, + ELJaxbValidationMessages.XPATH__UNRESOLVED_ATTRIBUTE, new String[] { namespace, this.localName }, context.getContextObject(), getTextRange(context))); @@ -292,7 +307,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__UNRESOLVED_ELEMENT, + ELJaxbValidationMessages.XPATH__UNRESOLVED_ELEMENT, new String[] { namespace, this.localName }, context.getContextObject(), getTextRange(context))); @@ -339,7 +354,7 @@ public class XPath { messages. add(ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT, + ELJaxbValidationMessages.XPATH__INVALID_FORM_ILLEGAL_SEGMENT, new String[] { getValue() }, context.getContextObject(), getTextRange(context))); @@ -402,7 +417,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__INVALID_NS_PREFIX, + ELJaxbValidationMessages.XPATH__INVALID_NS_PREFIX, new String[] { this.nsPrefix }, context.getContextObject(), getTextRange(context))); @@ -451,7 +466,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT, + ELJaxbValidationMessages.XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT, context.getContextObject(), getTextRange(context))); return; @@ -486,7 +501,7 @@ public class XPath { new FilteringIterable<String>( new TransformationIterable<String, String>( new CompositeIterable<String>( - new SingleElementIterable(TEXT), + getTextProposals(context, previousType), getAttributeProposals(context, previousType), getElementProposals(context, previousType))) { @Override @@ -506,6 +521,10 @@ public class XPath { return new SingleElementIterable(TEXT); } + protected Iterable<String> getTextProposals(Context context, final XsdTypeDefinition xsdType) { + return (xsdType.hasTextContent()) ? new SingleElementIterable(TEXT) : EmptyIterable.instance(); + } + protected Iterable<String> getAttributeProposals(Context context, final XsdTypeDefinition xsdType) { return new CompositeIterable<String>( new CompositeIterable<String>( @@ -515,7 +534,7 @@ public class XPath { return new TransformationIterable<String, String>(xsdType.getAttributeNames(xmlns.getNamespaceURI())) { @Override protected String transform(String o) { - return StringTools.concatenate(ATT_PREFIX, xmlns.getPrefix(), COLON, o); + return XPath.attributeXPath(xmlns.getPrefix(), o); } }; } @@ -523,7 +542,7 @@ public class XPath { new TransformationIterable<String, String>(xsdType.getAttributeNames("")) { @Override protected String transform(String o) { - return StringTools.concatenate(ATT_PREFIX, o); + return XPath.attributeXPath(null, o); } }); } @@ -537,7 +556,7 @@ public class XPath { return new TransformationIterable<String, String>(xsdType.getElementNames(xmlns.getNamespaceURI(), false)) { @Override protected String transform(String o) { - return StringTools.concatenate(xmlns.getPrefix(), COLON, o); + return XPath.elementXPath(xmlns.getPrefix(), o); } }; } @@ -587,7 +606,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT, + ELJaxbValidationMessages.XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT, context.getContextObject(), getTextRange(context))); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java index 45f25e7d65..cbf6e5780e 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java @@ -20,21 +20,20 @@ public interface ELJaxbValidationMessages { String PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY = "PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY"; String XML_DISCRIMINATOR_NODE__NOT_SPECIFIED = "XML_DISCRIMINATOR_NODE__NOT_SPECIFIED"; - String XML_DISCRIMINATOR_NODE__ROOT_NOT_SUPPORTED = "XML_DISCRIMINATOR_NODE__ROOT_NOT_SUPPORTED"; String XML_DISCRIMINATOR_VALUE__NOT_SPECIFIED = "XML_DISCRIMINATOR_VALUE__NOT_SPECIFIED"; String XML_ELEMENT_DECL__INVALID_METHOD_SIGNATURE_RETURN_TYPE = "XML_ELEMENT_DECL__INVALID_METHOD_SIGNATURE_RETURN_TYPE"; + String XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED = "XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED"; + String XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED = "XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED"; + String XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS = "XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS"; + + String XML_JOIN_NODES__INVALID_REFERENCED_CLASS = "XML_JOIN_NODES__INVALID_REFERENCED_CLASS"; + String XML_JOIN_NODES__DUPLICATE_XML_PATH = "XML_JOIN_NODES__DUPLICATE_XML_PATH"; + String XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH = "XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH"; + String XML_PATH__NOT_SPECIFIED = "XML_PATH__NOT_SPECIFIED"; - String XML_PATH__ROOT_NOT_SUPPORTED = "XML_PATH__ROOT_NOT_SUPPORTED"; - String XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT = "XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT"; - String XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = "XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT"; - String XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = "XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT"; - String XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = "XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT"; - String XML_PATH__INVALID_NS_PREFIX = "XML_PATH__INVALID_NS_PREFIX"; - String XML_PATH__UNRESOLVED_ELEMENT = "XML_PATH__UNRESOLVED_ELEMENT"; - String XML_PATH__UNRESOLVED_ATTRIBUTE = "XML_PATH__UNRESOLVED_ATTRIBUTE"; // used on XmlElements mapping String XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS = "XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS"; @@ -43,4 +42,14 @@ public interface ELJaxbValidationMessages { String XML_INVERSE_REFERENCE__MAPPED_BY_NOT_SPECIFIED = "XML_INVERSE_REFERENCE__MAPPED_BY_NOT_SPECIFIED"; String XML_INVERSE_REFERENCE__MAPPED_BY_NOT_RESOLVED = "XML_INVERSE_REFERENCE__MAPPED_BY_NOT_RESOLVED"; String XML_INVERSE_REFERENCE__MAPPED_BY_ILLEGAL_MAPPING_TYPE = "XML_INVERSE_REFERENCE__MAPPED_BY_ILLEGAL_MAPPING_TYPE"; + + // for all XPath usage + String XPATH__INVALID_FORM_ILLEGAL_SEGMENT = "XPATH__INVALID_FORM_ILLEGAL_SEGMENT"; + String XPATH__ROOT_NOT_SUPPORTED = "XPATH__ROOT_NOT_SUPPORTED"; + String XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = "XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT"; + String XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = "XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT"; + String XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = "XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT"; + String XPATH__INVALID_NS_PREFIX = "XPATH__INVALID_NS_PREFIX"; + String XPATH__UNRESOLVED_ELEMENT = "XPATH__UNRESOLVED_ELEMENT"; + String XPATH__UNRESOLVED_ATTRIBUTE = "XPATH__UNRESOLVED_ATTRIBUTE"; } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java index 1b4b37c6f3..7e8ff12345 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java @@ -53,6 +53,12 @@ public interface XmlJoinNodeAnnotation TextRange getXmlPathTextRange(CompilationUnit astRoot); /** + * Return whether the specified text position is within the 'xmlPath' element. + */ + boolean xmlPathTouches(int pos, CompilationUnit astRoot); + + + /** * String associated with change events to the 'referencedXmlPath' property */ String REFERENCED_XML_PATH_PROPERTY = "referencedXmlPath"; //$NON-NLS-1$ @@ -74,4 +80,9 @@ public interface XmlJoinNodeAnnotation * Return the text range of this annotation if the element is absent. */ TextRange getReferencedXmlPathTextRange(CompilationUnit astRoot); + + /** + * Return whether the specified text position is within the 'referencedXmlPath' element. + */ + boolean referencedXmlPathTouches(int pos, CompilationUnit astRoot); } diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlJoinNodeTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlJoinNodeTests.java new file mode 100644 index 0000000000..0cbe7d3f3e --- /dev/null +++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlJoinNodeTests.java @@ -0,0 +1,209 @@ +package org.eclipse.jpt.jaxb.eclipselink.core.tests.internal.context.java; + +import java.util.Iterator; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute; +import org.eclipse.jpt.common.core.utility.jdt.AnnotatedElement; +import org.eclipse.jpt.common.core.utility.jdt.Member; +import org.eclipse.jpt.common.core.utility.jdt.ModifiedDeclaration; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterators.ArrayIterator; +import org.eclipse.jpt.jaxb.core.context.JaxbClass; +import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; +import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; +import org.eclipse.jpt.jaxb.core.platform.JaxbPlatformDescription; +import org.eclipse.jpt.jaxb.core.resource.java.JAXB; +import org.eclipse.jpt.jaxb.eclipselink.core.ELJaxbPlatform; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNode; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNodesMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.java.ELJavaXmlJoinNodesMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlJoinNodeAnnotation; +import org.eclipse.jpt.jaxb.eclipselink.core.tests.internal.context.ELJaxbContextModelTestCase; + + +public class ELJavaXmlJoinNodeTests + extends ELJaxbContextModelTestCase { + + public ELJavaXmlJoinNodeTests(String name) { + super(name); + } + + + @Override + protected JaxbPlatformDescription getPlatform() { + return ELJaxbPlatform.VERSION_2_2; + } + + private ICompilationUnit createTypeWithXmlJoinNode() throws Exception { + return this.createTestType(new DefaultAnnotationWriter() { + @Override + public Iterator<String> imports() { + return new ArrayIterator<String>(JAXB.XML_TYPE, ELJaxb.XML_JOIN_NODE); + } + + @Override + public void appendTypeAnnotationTo(StringBuilder sb) { + sb.append("@XmlType"); + } + + @Override + public void appendIdFieldAnnotationTo(StringBuilder sb) { + sb.append("@XmlJoinNode"); + } + }); + } + + + public void testModifyXmlPath() throws Exception { + createTypeWithXmlJoinNode(); + + JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0); + JaxbClassMapping classMapping = jaxbClass.getMapping(); + JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0); + ELXmlJoinNodesMapping mapping = (ELXmlJoinNodesMapping) persistentAttribute.getMapping(); + JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute(); + ELXmlJoinNode xmlJoinNode = CollectionTools.get(mapping.getXmlJoinNodes(), 0); + XmlJoinNodeAnnotation annotation = (XmlJoinNodeAnnotation) resourceAttribute.getAnnotation(0, ELJaxb.XML_JOIN_NODE); + + assertNull(annotation.getXmlPath()); + assertNull(xmlJoinNode.getXmlPath()); + + xmlJoinNode.setXmlPath("foo"); + + assertEquals("foo", annotation.getXmlPath()); + assertEquals("foo", xmlJoinNode.getXmlPath()); + + xmlJoinNode.setXmlPath(""); + + assertEquals("", annotation.getXmlPath()); + assertEquals("", xmlJoinNode.getXmlPath()); + + xmlJoinNode.setXmlPath(null); + + assertNull(annotation.getXmlPath()); + assertNull(xmlJoinNode.getXmlPath()); + } + + public void testUpdateXmlPath() throws Exception { + createTypeWithXmlJoinNode(); + + JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0); + JaxbClassMapping classMapping = jaxbClass.getMapping(); + JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0); + ELJavaXmlJoinNodesMapping mapping = (ELJavaXmlJoinNodesMapping) persistentAttribute.getMapping(); + JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute(); + ELXmlJoinNode xmlJoinNode = CollectionTools.get(mapping.getXmlJoinNodes(), 0); + XmlJoinNodeAnnotation annotation = (XmlJoinNodeAnnotation) resourceAttribute.getAnnotation(0, ELJaxb.XML_JOIN_NODE); + + assertNull(annotation.getXmlPath()); + assertNull(xmlJoinNode.getXmlPath()); + + AnnotatedElement annotatedElement = this.annotatedElement(resourceAttribute); + annotatedElement.edit(new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodeTests.this.setMemberValuePair( + declaration, ELJaxb.XML_JOIN_NODE, ELJaxb.XML_JOIN_NODE__XML_PATH, "foo"); + } + }); + + assertEquals("foo", annotation.getXmlPath()); + assertEquals("foo", xmlJoinNode.getXmlPath()); + + annotatedElement.edit(new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodeTests.this.setMemberValuePair( + declaration, ELJaxb.XML_JOIN_NODE, ELJaxb.XML_JOIN_NODE__XML_PATH, ""); + } + }); + + assertEquals("", annotation.getXmlPath()); + assertEquals("", xmlJoinNode.getXmlPath()); + + annotatedElement.edit(new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodeTests.this.removeMemberValuePair( + declaration, ELJaxb.XML_JOIN_NODE, ELJaxb.XML_JOIN_NODE__XML_PATH); + } + }); + + assertNull(annotation.getXmlPath()); + assertNull(xmlJoinNode.getXmlPath()); + } + + public void testModifyReferencedXmlPath() throws Exception { + createTypeWithXmlJoinNode(); + + JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0); + JaxbClassMapping classMapping = jaxbClass.getMapping(); + JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0); + ELXmlJoinNodesMapping mapping = (ELXmlJoinNodesMapping) persistentAttribute.getMapping(); + JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute(); + ELXmlJoinNode xmlJoinNode = CollectionTools.get(mapping.getXmlJoinNodes(), 0); + XmlJoinNodeAnnotation annotation = (XmlJoinNodeAnnotation) resourceAttribute.getAnnotation(0, ELJaxb.XML_JOIN_NODE); + + assertNull(annotation.getReferencedXmlPath()); + assertNull(xmlJoinNode.getReferencedXmlPath()); + + xmlJoinNode.setReferencedXmlPath("foo"); + + assertEquals("foo", annotation.getReferencedXmlPath()); + assertEquals("foo", xmlJoinNode.getReferencedXmlPath()); + + xmlJoinNode.setReferencedXmlPath(""); + + assertEquals("", annotation.getReferencedXmlPath()); + assertEquals("", xmlJoinNode.getReferencedXmlPath()); + + xmlJoinNode.setReferencedXmlPath(null); + + assertNull(annotation.getReferencedXmlPath()); + assertNull(xmlJoinNode.getReferencedXmlPath()); + } + + public void testUpdateReferencedXmlPath() throws Exception { + createTypeWithXmlJoinNode(); + + JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0); + JaxbClassMapping classMapping = jaxbClass.getMapping(); + JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0); + ELJavaXmlJoinNodesMapping mapping = (ELJavaXmlJoinNodesMapping) persistentAttribute.getMapping(); + JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute(); + ELXmlJoinNode xmlJoinNode = CollectionTools.get(mapping.getXmlJoinNodes(), 0); + XmlJoinNodeAnnotation annotation = (XmlJoinNodeAnnotation) resourceAttribute.getAnnotation(0, ELJaxb.XML_JOIN_NODE); + + assertNull(annotation.getReferencedXmlPath()); + assertNull(xmlJoinNode.getReferencedXmlPath()); + + AnnotatedElement annotatedElement = this.annotatedElement(resourceAttribute); + annotatedElement.edit(new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodeTests.this.setMemberValuePair( + declaration, ELJaxb.XML_JOIN_NODE, ELJaxb.XML_JOIN_NODE__REFERENCED_XML_PATH, "foo"); + } + }); + + assertEquals("foo", annotation.getReferencedXmlPath()); + assertEquals("foo", xmlJoinNode.getReferencedXmlPath()); + + annotatedElement.edit(new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodeTests.this.setMemberValuePair( + declaration, ELJaxb.XML_JOIN_NODE, ELJaxb.XML_JOIN_NODE__REFERENCED_XML_PATH, ""); + } + }); + + assertEquals("", annotation.getReferencedXmlPath()); + assertEquals("", xmlJoinNode.getReferencedXmlPath()); + + annotatedElement.edit(new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodeTests.this.removeMemberValuePair( + declaration, ELJaxb.XML_JOIN_NODE, ELJaxb.XML_JOIN_NODE__REFERENCED_XML_PATH); + } + }); + + assertNull(annotation.getReferencedXmlPath()); + assertNull(xmlJoinNode.getReferencedXmlPath()); + } +}
\ No newline at end of file diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlJoinNodesMappingTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlJoinNodesMappingTests.java new file mode 100644 index 0000000000..ce0559ae6a --- /dev/null +++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlJoinNodesMappingTests.java @@ -0,0 +1,197 @@ +package org.eclipse.jpt.jaxb.eclipselink.core.tests.internal.context.java; + +import java.util.Iterator; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute; +import org.eclipse.jpt.common.core.utility.jdt.AnnotatedElement; +import org.eclipse.jpt.common.core.utility.jdt.Member; +import org.eclipse.jpt.common.core.utility.jdt.ModifiedDeclaration; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterables.SubIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterators.ArrayIterator; +import org.eclipse.jpt.jaxb.core.context.JaxbClass; +import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; +import org.eclipse.jpt.jaxb.core.platform.JaxbPlatformDescription; +import org.eclipse.jpt.jaxb.core.resource.java.JAXB; +import org.eclipse.jpt.jaxb.eclipselink.core.ELJaxbPlatform; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNode; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNodesMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlJoinNodeAnnotation; +import org.eclipse.jpt.jaxb.eclipselink.core.tests.internal.context.ELJaxbContextModelTestCase; + + +public class ELJavaXmlJoinNodesMappingTests + extends ELJaxbContextModelTestCase { + + public ELJavaXmlJoinNodesMappingTests(String name) { + super(name); + } + + + @Override + protected JaxbPlatformDescription getPlatform() { + return ELJaxbPlatform.VERSION_2_2; + } + + private ICompilationUnit createTypeWithXmlJoinNodes() throws Exception { + return this.createTestType(new DefaultAnnotationWriter() { + @Override + public Iterator<String> imports() { + return new ArrayIterator<String>(JAXB.XML_TYPE, ELJaxb.XML_JOIN_NODES); + } + + @Override + public void appendTypeAnnotationTo(StringBuilder sb) { + sb.append("@XmlType"); + } + + @Override + public void appendIdFieldAnnotationTo(StringBuilder sb) { + sb.append("@XmlJoinNodes"); + } + }); + } + + protected NormalAnnotation newXmlJoinNodeAnnotation(AST ast, String xmlPath, String referencedXmlPath) { + NormalAnnotation annotation = newNormalAnnotation(ast, ELJaxb.XML_JOIN_NODE); + addMemberValuePair(annotation, ELJaxb.XML_JOIN_NODE__XML_PATH, xmlPath); + addMemberValuePair(annotation, ELJaxb.XML_JOIN_NODE__REFERENCED_XML_PATH, referencedXmlPath); + return annotation; + } + + protected void addXmlJoinNode(ModifiedDeclaration declaration, int index, String xmlPath, String referencedXmlPath) { + NormalAnnotation annotation = newXmlJoinNodeAnnotation(declaration.getAst(), xmlPath, referencedXmlPath); + addArrayElement(declaration, ELJaxb.XML_JOIN_NODES, index, "value", annotation); + } + + protected void moveXmlJoinNode(ModifiedDeclaration declaration, int targetIndex, int sourceIndex) { + moveArrayElement((NormalAnnotation) declaration.getAnnotationNamed(ELJaxb.XML_JOIN_NODES), "value", targetIndex, sourceIndex); + } + + protected void removeXmlJoinNode(ModifiedDeclaration declaration, int index) { + removeArrayElement((NormalAnnotation) declaration.getAnnotationNamed(ELJaxb.XML_JOIN_NODES), "value", index); + } + + + public void testUpdateXmlJoinNodes() throws Exception { + createTypeWithXmlJoinNodes(); + JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0); + JaxbClassMapping classMapping = jaxbClass.getMapping(); + ELXmlJoinNodesMapping mapping = (ELXmlJoinNodesMapping) CollectionTools.get(classMapping.getAttributes(), 0).getMapping(); + JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute(); + + Iterable<ELXmlJoinNode> xmlJoinNodes = mapping.getXmlJoinNodes(); + assertTrue(CollectionTools.isEmpty(xmlJoinNodes)); + assertEquals(0, mapping.getXmlJoinNodesSize()); + + //add 2 XmlJoinNode annotations + AnnotatedElement annotatedElement = annotatedElement(resourceAttribute); + annotatedElement.edit( + new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodesMappingTests.this.addXmlJoinNode(declaration, 0, "foo", "@foo"); + ELJavaXmlJoinNodesMappingTests.this.addXmlJoinNode(declaration, 1, "bar", "@bar"); + } + }); + + xmlJoinNodes = mapping.getXmlJoinNodes(); + + assertFalse(CollectionTools.isEmpty(xmlJoinNodes)); + assertEquals(2, mapping.getXmlJoinNodesSize()); + assertEquals("foo", CollectionTools.get(xmlJoinNodes, 0).getXmlPath()); + assertEquals("@foo", CollectionTools.get(xmlJoinNodes, 0).getReferencedXmlPath()); + assertEquals("bar", CollectionTools.get(xmlJoinNodes, 1).getXmlPath()); + assertEquals("@bar", CollectionTools.get(xmlJoinNodes, 1).getReferencedXmlPath()); + + // switch XmlJoinNode annotations + annotatedElement.edit( + new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodesMappingTests.this.moveXmlJoinNode(declaration, 0, 1); + } + }); + + xmlJoinNodes = mapping.getXmlJoinNodes(); + + assertFalse(CollectionTools.isEmpty(xmlJoinNodes)); + assertEquals(2, mapping.getXmlJoinNodesSize()); + assertEquals("bar", CollectionTools.get(xmlJoinNodes, 0).getXmlPath()); + assertEquals("@bar", CollectionTools.get(xmlJoinNodes, 0).getReferencedXmlPath()); + assertEquals("foo", CollectionTools.get(xmlJoinNodes, 1).getXmlPath()); + assertEquals("@foo", CollectionTools.get(xmlJoinNodes, 1).getReferencedXmlPath()); + + // remove XmlJoinNode annotations + annotatedElement.edit( + new Member.Editor() { + public void edit(ModifiedDeclaration declaration) { + ELJavaXmlJoinNodesMappingTests.this.removeXmlJoinNode(declaration, 1); + ELJavaXmlJoinNodesMappingTests.this.removeXmlJoinNode(declaration, 0); + } + }); + + xmlJoinNodes = mapping.getXmlJoinNodes(); + + assertTrue(CollectionTools.isEmpty(xmlJoinNodes)); + assertEquals(0, mapping.getXmlJoinNodesSize()); + } + + public void testModifyXmlJoinNodes() throws Exception { + createTypeWithXmlJoinNodes(); + JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0); + JaxbClassMapping classMapping = jaxbClass.getMapping(); + ELXmlJoinNodesMapping mapping = (ELXmlJoinNodesMapping) CollectionTools.get(classMapping.getAttributes(), 0).getMapping(); + JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute(); + + assertEquals(0, resourceAttribute.getAnnotationsSize(ELJaxb.XML_JOIN_NODE)); + assertEquals(0, mapping.getXmlJoinNodesSize()); + + ELXmlJoinNode joinNode = mapping.addXmlJoinNode(0); + joinNode.setXmlPath("foo"); + joinNode.setReferencedXmlPath("@foo"); + joinNode = mapping.addXmlJoinNode(1); + joinNode.setXmlPath("baz"); + joinNode.setReferencedXmlPath("@baz"); + joinNode = mapping.addXmlJoinNode(1); + joinNode.setXmlPath("bar"); + joinNode.setReferencedXmlPath("@bar"); + + Iterable<XmlJoinNodeAnnotation> xmlJoinNodeAnnotations = + new SubIterableWrapper(resourceAttribute.getAnnotations(ELJaxb.XML_JOIN_NODE)); + + assertEquals(3, CollectionTools.size(xmlJoinNodeAnnotations)); + assertEquals(3, mapping.getXmlJoinNodesSize()); + assertEquals("foo", CollectionTools.get(xmlJoinNodeAnnotations, 0).getXmlPath()); + assertEquals("@foo", CollectionTools.get(xmlJoinNodeAnnotations, 0).getReferencedXmlPath()); + assertEquals("bar", CollectionTools.get(xmlJoinNodeAnnotations, 1).getXmlPath()); + assertEquals("@bar", CollectionTools.get(xmlJoinNodeAnnotations, 1).getReferencedXmlPath()); + assertEquals("baz", CollectionTools.get(xmlJoinNodeAnnotations, 2).getXmlPath()); + assertEquals("@baz", CollectionTools.get(xmlJoinNodeAnnotations, 2).getReferencedXmlPath()); + + mapping.moveXmlJoinNode(1, 2); + + xmlJoinNodeAnnotations = + new SubIterableWrapper(resourceAttribute.getAnnotations(ELJaxb.XML_JOIN_NODE)); + + assertEquals(3, CollectionTools.size(xmlJoinNodeAnnotations)); + assertEquals(3, mapping.getXmlJoinNodesSize()); + assertEquals("foo", CollectionTools.get(xmlJoinNodeAnnotations, 0).getXmlPath()); + assertEquals("@foo", CollectionTools.get(xmlJoinNodeAnnotations, 0).getReferencedXmlPath()); + assertEquals("baz", CollectionTools.get(xmlJoinNodeAnnotations, 1).getXmlPath()); + assertEquals("@baz", CollectionTools.get(xmlJoinNodeAnnotations, 1).getReferencedXmlPath()); + assertEquals("bar", CollectionTools.get(xmlJoinNodeAnnotations, 2).getXmlPath()); + assertEquals("@bar", CollectionTools.get(xmlJoinNodeAnnotations, 2).getReferencedXmlPath()); + + mapping.removeXmlJoinNode(2); + mapping.removeXmlJoinNode(0); + mapping.removeXmlJoinNode(0); + + xmlJoinNodeAnnotations = + new SubIterableWrapper(resourceAttribute.getAnnotations(ELJaxb.XML_JOIN_NODE)); + + assertEquals(0, CollectionTools.size(xmlJoinNodeAnnotations)); + assertEquals(0, mapping.getXmlJoinNodesSize()); + } +} diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJaxbCoreJavaContextModelTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJaxbCoreJavaContextModelTests.java index aa4e37152c..29bc7f62f8 100644 --- a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJaxbCoreJavaContextModelTests.java +++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJaxbCoreJavaContextModelTests.java @@ -28,7 +28,10 @@ public class ELJaxbCoreJavaContextModelTests suite.addTestSuite(ELJavaXmlElementMappingTests.class); suite.addTestSuite(ELJavaXmlElementsMappingTests.class); suite.addTestSuite(ELJavaXmlInverseReferenceMappingTests.class); + suite.addTestSuite(ELJavaXmlJoinNodesMappingTests.class); + suite.addTestSuite(ELJavaXmlJoinNodeTests.class); suite.addTestSuite(ELJavaXmlPathTests.class); + suite.addTestSuite(ELJavaXmlValueMappingTests.class); return suite; } |