bug 366900 - XmlKey support
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlKey.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlKey.java
new file mode 100644
index 0000000..1f3c799
--- /dev/null
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlKey.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ *  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.context.java;
+
+import org.eclipse.jpt.jaxb.core.context.JaxbContextNode;
+
+/**
+ * Corresponds to the XmlKey annotation
+ * <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 ELXmlKey
+		extends JaxbContextNode {
+
+}
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlNamedNodeMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlNamedNodeMapping.java
index 053988f..31a59b6 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlNamedNodeMapping.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlNamedNodeMapping.java
@@ -27,4 +27,38 @@
 public interface ELXmlNamedNodeMapping
 		extends XmlNamedNodeMapping, ELXmlPathMapping {
 	
+	// ***** XmlKey *****
+	
+	/**
+	 * String associated with changes to the xmlKey property
+	 */
+	String XML_KEY_PROPERTY = "xmlKey";  ///$NON-NLS-1$
+	
+	/**
+	 * Return the xmlKey property value.
+	 * A null indicates it is not specified.
+	 */
+	ELXmlKey getXmlKey();
+	
+	/**
+	 * Add (and return) an xmlKey property value.
+	 * (Specifies the property)
+	 */
+	ELXmlKey addXmlKey();
+	
+	/**
+	 * Remove the xmlKey property value.
+	 * (Unspecifies the property)
+	 */
+	void removeXmlKey();
+	
+	
+	// ***** misc *****
+	
+	/**
+	 * Return an XPath to represent this attribute mapping.
+	 * Return <code>null</code> if no valid XPath can be constructed.
+	 * (Trivial if this mapping has an XmlPath annotation)
+	 */
+	String getXPath();
 }
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java
index 31a20c8..7905468 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java
@@ -13,6 +13,7 @@
 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.StringTools;
 import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable;
 import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping;
 import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute;
@@ -20,8 +21,11 @@
 import org.eclipse.jpt.jaxb.core.internal.context.java.GenericJavaXmlAttributeMapping;
 import org.eclipse.jpt.jaxb.core.resource.java.XmlIDAnnotation;
 import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlAttributeMapping;
+import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlKey;
 import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlPath;
+import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.xpath.java.XPath;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlKeyAnnotation;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlPathAnnotation;
 import org.eclipse.wst.validation.internal.provisional.core.IMessage;
 import org.eclipse.wst.validation.internal.provisional.core.IReporter;
@@ -33,10 +37,13 @@
 	
 	protected ELJavaXmlPath xmlPath;
 	
+	protected ELJavaXmlKey xmlKey;
+	
 	
 	public ELJavaXmlAttributeMapping(JaxbPersistentAttribute parent) {
 		super(parent);
 		initXmlPath();
+		initXmlKey();
 	}
 	
 	
@@ -45,12 +52,14 @@
 		return new ELJavaXmlID(this, xmlIDAnnotation);
 	}
 	
+	
 	// ***** sync/update *****
 	
 	@Override
 	public void synchronizeWithResourceModel() {
 		super.synchronizeWithResourceModel();
 		syncXmlPath();
+		syncXmlKey();
 	}
 	
 	
@@ -115,6 +124,91 @@
 	}
 	
 	
+	// ***** XmlKey *****
+	
+	public ELXmlKey getXmlKey() {
+		return this.xmlKey;
+	}
+	
+	protected void setXmlKey_(ELJavaXmlKey xmlKey) {
+		ELJavaXmlKey old = this.xmlKey;
+		this.xmlKey = xmlKey;
+		firePropertyChanged(XML_KEY_PROPERTY, old, this.xmlKey);
+	}
+	
+	public ELXmlKey addXmlKey() {
+		if (this.xmlKey != null) {
+			throw new IllegalStateException();
+		}
+		getJavaResourceAttribute().addAnnotation(ELJaxb.XML_KEY);
+		ELJavaXmlKey xmlKey = buildXmlKey();
+		setXmlKey_(xmlKey);
+		return xmlKey;
+	}
+	
+	public void removeXmlKey() {
+		if (this.xmlKey == null) {
+			throw new IllegalStateException();
+		}
+		getJavaResourceAttribute().removeAnnotation(ELJaxb.XML_KEY);
+		setXmlKey_(null);
+	}
+	
+	protected void initXmlKey() {
+		XmlKeyAnnotation annotation = getXmlKeyAnnotation();
+		this.xmlKey = (annotation == null) ? null : buildXmlKey();
+	}
+	
+	protected void syncXmlKey() {
+		XmlKeyAnnotation annotation = getXmlKeyAnnotation();
+		if (annotation != null) {
+			if (this.xmlKey == null) {
+				setXmlKey_(buildXmlKey());
+			}
+		}
+		else {
+			setXmlKey_(null);
+		}
+	}
+	
+	protected ELJavaXmlKey buildXmlKey() {
+		return new ELJavaXmlKey(this, new XmlKeyContext());
+	}
+	
+	protected XmlKeyAnnotation getXmlKeyAnnotation() {
+		return (XmlKeyAnnotation) getJavaResourceAttribute().getAnnotation(ELJaxb.XML_KEY);
+	}
+	
+	
+	// ***** misc *****
+	
+	public String getXPath() {
+		if (this.xmlPath != null) {
+			return this.xmlPath.getValue();
+		}
+		
+		String name = this.qName.getName();
+		if (StringTools.stringIsEmpty(name)) {
+			// no name is invalid
+			return null;
+		}
+		
+		String namespace = this.qName.getNamespace();
+		if (StringTools.stringIsEmpty(namespace)) {
+			// empty namespace means "no" namespace
+			return XPath.attributeXPath(null, name);
+		}
+		
+		String prefix = getJaxbPackage().getPackageInfo().getPrefixForNamespace(namespace);
+		if (prefix == null) {
+			// no prefix for non-null namespace is invalid
+			return null;
+		}
+		
+		return XPath.attributeXPath(prefix, this.qName.getName());
+	}
+	
+	
 	// ***** content assist *****
 	
 	@Override
@@ -163,4 +257,13 @@
 			return ELJavaXmlAttributeMapping.this;
 		}
 	}
+	
+	
+	protected class XmlKeyContext
+			implements ELJavaXmlKey.Context {
+		
+		public XmlKeyAnnotation getAnnotation() {
+			return ELJavaXmlAttributeMapping.this.getXmlKeyAnnotation();
+		}
+	}
 }
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMappingDefinition.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMappingDefinition.java
index 1f51fb4..957ce24 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMappingDefinition.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMappingDefinition.java
@@ -29,6 +29,7 @@
 	
 	private static final String[] SUPPORTING_ANNOTATION_NAMES = 
 			{
+				ELJaxb.XML_KEY,
 				ELJaxb.XML_PATH };
 	
 	/**
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java
index 1216580..7cd13a2 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java
@@ -13,6 +13,7 @@
 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.StringTools;
 import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable;
 import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping;
 import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute;
@@ -22,9 +23,14 @@
 import org.eclipse.jpt.jaxb.core.internal.context.java.GenericJavaXmlElementMapping;
 import org.eclipse.jpt.jaxb.core.resource.java.XmlElementWrapperAnnotation;
 import org.eclipse.jpt.jaxb.core.resource.java.XmlIDAnnotation;
+import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlCDATA;
 import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlElementMapping;
+import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlKey;
 import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlPath;
+import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.xpath.java.XPath;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlCDATAAnnotation;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlKeyAnnotation;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlPathAnnotation;
 import org.eclipse.wst.validation.internal.provisional.core.IMessage;
 import org.eclipse.wst.validation.internal.provisional.core.IReporter;
@@ -36,10 +42,16 @@
 	
 	protected ELJavaXmlPath xmlPath;
 	
+	protected ELJavaXmlKey xmlKey;
+	
+	protected ELJavaXmlCDATA xmlCDATA;
+	
 	
 	public ELJavaXmlElementMapping(JaxbPersistentAttribute parent) {
 		super(parent);
 		initXmlPath();
+		initXmlKey();
+		initXmlCDATA();
 	}
 	
 	
@@ -55,6 +67,8 @@
 	public void synchronizeWithResourceModel() {
 		super.synchronizeWithResourceModel();
 		syncXmlPath();
+		syncXmlKey();
+		syncXmlCDATA();
 	}
 	
 	
@@ -119,6 +133,118 @@
 	}
 	
 	
+	// ***** XmlKey *****
+	
+	public ELXmlKey getXmlKey() {
+		return this.xmlKey;
+	}
+	
+	protected void setXmlKey_(ELJavaXmlKey xmlKey) {
+		ELJavaXmlKey old = this.xmlKey;
+		this.xmlKey = xmlKey;
+		firePropertyChanged(XML_KEY_PROPERTY, old, this.xmlKey);
+	}
+	
+	public ELXmlKey addXmlKey() {
+		if (this.xmlKey != null) {
+			throw new IllegalStateException();
+		}
+		getJavaResourceAttribute().addAnnotation(ELJaxb.XML_KEY);
+		ELJavaXmlKey xmlKey = buildXmlKey();
+		setXmlKey_(xmlKey);
+		return xmlKey;
+	}
+	
+	public void removeXmlKey() {
+		if (this.xmlKey == null) {
+			throw new IllegalStateException();
+		}
+		getJavaResourceAttribute().removeAnnotation(ELJaxb.XML_KEY);
+		setXmlKey_(null);
+	}
+	
+	protected void initXmlKey() {
+		XmlKeyAnnotation annotation = getXmlKeyAnnotation();
+		this.xmlKey = (annotation == null) ? null : buildXmlKey();
+	}
+	
+	protected void syncXmlKey() {
+		XmlKeyAnnotation annotation = getXmlKeyAnnotation();
+		if (annotation != null) {
+			if (this.xmlKey == null) {
+				setXmlKey_(buildXmlKey());
+			}
+		}
+		else {
+			setXmlKey_(null);
+		}
+	}
+	
+	protected ELJavaXmlKey buildXmlKey() {
+		return new ELJavaXmlKey(this, new XmlKeyContext());
+	}
+	
+	protected XmlKeyAnnotation getXmlKeyAnnotation() {
+		return (XmlKeyAnnotation) getJavaResourceAttribute().getAnnotation(ELJaxb.XML_KEY);
+	}
+	
+	
+	// ***** XmlCDATA *****
+	
+	public ELXmlCDATA getXmlCDATA() {
+		return this.xmlCDATA;
+	}
+	
+	protected void setXmlCDATA_(ELJavaXmlCDATA xmlCDATA) {
+		ELJavaXmlCDATA old = this.xmlCDATA;
+		this.xmlCDATA = xmlCDATA;
+		firePropertyChanged(XML_CDATA_PROPERTY, old, this.xmlCDATA);
+	}
+	
+	public ELXmlCDATA addXmlCDATA() {
+		if (this.xmlCDATA != null) {
+			throw new IllegalStateException();
+		}
+		getJavaResourceAttribute().addAnnotation(ELJaxb.XML_CDATA);
+		ELJavaXmlCDATA xmlCDATA = buildXmlCDATA();
+		setXmlCDATA_(xmlCDATA);
+		return xmlCDATA;
+	}
+	
+	public void removeXmlCDATA() {
+		if (this.xmlCDATA == null) {
+			throw new IllegalStateException();
+		}
+		getJavaResourceAttribute().removeAnnotation(ELJaxb.XML_CDATA);
+		setXmlCDATA_(null);
+	}
+	
+	protected void initXmlCDATA() {
+		XmlCDATAAnnotation annotation = getXmlCDATAAnnotation();
+		this.xmlCDATA = (annotation == null) ? null : buildXmlCDATA();
+	}
+	
+	protected void syncXmlCDATA() {
+		XmlCDATAAnnotation annotation = getXmlCDATAAnnotation();
+		if (annotation != null) {
+			if (this.xmlCDATA == null) {
+				setXmlCDATA_(buildXmlCDATA());
+			}
+		}
+		else {
+			setXmlCDATA_(null);
+		}
+	}
+	
+	protected ELJavaXmlCDATA buildXmlCDATA() {
+		return new ELJavaXmlCDATA(this, new XmlCDATAContext());
+	}
+	
+	protected XmlCDATAAnnotation getXmlCDATAAnnotation() {
+		return (XmlCDATAAnnotation) getJavaResourceAttribute().getAnnotation(ELJaxb.XML_CDATA);
+	}
+	
+	
 	// ***** misc *****
 	
 	@Override
@@ -131,6 +257,32 @@
 		return new ELJavaXmlElementWrapper(this, new XmlElementWrapperContext());
 	}
 	
+	public String getXPath() {
+		if (this.xmlPath != null) {
+			return this.xmlPath.getValue();
+		}
+		
+		String name = this.xmlElement.getQName().getName();
+		if (StringTools.stringIsEmpty(name)) {
+			// no name is invalid
+			return null;
+		}
+		
+		String namespace = this.xmlElement.getQName().getNamespace();
+		if (StringTools.stringIsEmpty(namespace)) {
+			// empty namespace means "no" namespace
+			return XPath.elementXPath(null, name);
+		}
+		
+		String prefix = getJaxbPackage().getPackageInfo().getPrefixForNamespace(namespace);
+		if (prefix == null) {
+			// no prefix for non-null namespace is invalid
+			return null;
+		}
+		
+		return XPath.elementXPath(prefix, name);
+	}
+	
 	
 	// ***** content assist *****
 	
@@ -181,6 +333,24 @@
 	}
 	
 	
+	protected class XmlKeyContext
+			implements ELJavaXmlKey.Context {
+		
+		public XmlKeyAnnotation getAnnotation() {
+			return ELJavaXmlElementMapping.this.getXmlKeyAnnotation();
+		}
+	}
+	
+	
+	protected class XmlCDATAContext
+			implements ELJavaXmlCDATA.Context {
+		
+		public XmlCDATAAnnotation getAnnotation() {
+			return ELJavaXmlElementMapping.this.getXmlCDATAAnnotation();
+		}
+	}
+	
+	
 	protected class XmlElementContext
 			extends GenericJavaXmlElementMapping.XmlElementContext
 			implements ELJavaXmlElement.Context {
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMappingDefinition.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMappingDefinition.java
index e6a056d..a43ed49 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMappingDefinition.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMappingDefinition.java
@@ -26,6 +26,7 @@
 	private static final String[] SUPPORTING_ANNOTATION_NAMES = 
 			{
 				ELJaxb.XML_CDATA,
+				ELJaxb.XML_KEY,
 				ELJaxb.XML_PATH };
 	
 	/**
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlKey.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlKey.java
new file mode 100644
index 0000000..4f0122a
--- /dev/null
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlKey.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ *  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 org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jpt.common.core.utility.TextRange;
+import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode;
+import org.eclipse.jpt.jaxb.core.internal.context.java.AbstractJavaContextNode;
+import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlKey;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlKeyAnnotation;
+
+
+public class ELJavaXmlKey
+		extends AbstractJavaContextNode
+		implements ELXmlKey {
+	
+	protected final Context context;
+	
+	
+	public ELJavaXmlKey(JavaContextNode parent, Context context) {
+		super(parent);
+		this.context = context;
+	}
+	
+	
+	@Override
+	public TextRange getValidationTextRange(CompilationUnit astRoot) {
+		return this.context.getAnnotation().getTextRange(astRoot);
+	}
+	
+	
+	public interface Context {
+		
+		XmlKeyAnnotation getAnnotation();
+	}
+}
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/XmlKeyAnnotationDefinition.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/XmlKeyAnnotationDefinition.java
new file mode 100644
index 0000000..1f6fb71
--- /dev/null
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/XmlKeyAnnotationDefinition.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ *  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.resource.java;
+
+import org.eclipse.jdt.core.IAnnotation;
+import org.eclipse.jpt.common.core.resource.java.Annotation;
+import org.eclipse.jpt.common.core.resource.java.AnnotationDefinition;
+import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement;
+import org.eclipse.jpt.common.core.utility.jdt.AnnotatedElement;
+import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.binary.BinaryXmlKeyAnnotation;
+import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.source.SourceXmlKeyAnnotation;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
+
+
+public class XmlKeyAnnotationDefinition
+		implements AnnotationDefinition {
+	
+	// singleton
+	private static final AnnotationDefinition INSTANCE = new XmlKeyAnnotationDefinition();
+	
+	
+	/**
+	 * Return the singleton.
+	 */
+	public static AnnotationDefinition instance() {
+		return INSTANCE;
+	}
+	
+	
+	/**
+	 * Ensure single instance.
+	 */
+	private XmlKeyAnnotationDefinition() {
+		super();
+	}
+	
+	
+	public String getAnnotationName() {
+		return ELJaxb.XML_KEY;
+	}
+	
+	public Annotation buildAnnotation(JavaResourceAnnotatedElement parent, AnnotatedElement annotatedElement) {
+		return new SourceXmlKeyAnnotation(parent, annotatedElement);
+	}
+	
+	public Annotation buildNullAnnotation(JavaResourceAnnotatedElement parent) {
+		throw new UnsupportedOperationException();
+	}
+	
+	public Annotation buildAnnotation(JavaResourceAnnotatedElement parent, IAnnotation jdtAnnotation) {
+		return new BinaryXmlKeyAnnotation(parent, jdtAnnotation);
+	}
+}
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/binary/BinaryXmlKeyAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/binary/BinaryXmlKeyAnnotation.java
new file mode 100644
index 0000000..8fb9897
--- /dev/null
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/binary/BinaryXmlKeyAnnotation.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ *  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.resource.java.binary;
+
+import org.eclipse.jdt.core.IAnnotation;
+import org.eclipse.jpt.common.core.internal.resource.java.binary.BinaryAnnotation;
+import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlKeyAnnotation;
+
+
+public class BinaryXmlKeyAnnotation
+		extends BinaryAnnotation
+		implements XmlKeyAnnotation {
+
+	public BinaryXmlKeyAnnotation(JavaResourceAnnotatedElement parent, IAnnotation jdtAnnotation) {
+		super(parent, jdtAnnotation);
+	}
+	
+	
+	public String getAnnotationName() {
+		return ELJaxb.XML_KEY;
+	}
+	
+	@Override
+	public void update() {
+		super.update();
+	}
+	
+	@Override
+	public void toString(StringBuilder sb) {}
+}
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/source/SourceXmlKeyAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/source/SourceXmlKeyAnnotation.java
new file mode 100644
index 0000000..79ae0ad
--- /dev/null
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/resource/java/source/SourceXmlKeyAnnotation.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ *  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.resource.java.source;
+
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jpt.common.core.internal.resource.java.source.SourceAnnotation;
+import org.eclipse.jpt.common.core.internal.utility.jdt.ElementAnnotationAdapter;
+import org.eclipse.jpt.common.core.internal.utility.jdt.SimpleDeclarationAnnotationAdapter;
+import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement;
+import org.eclipse.jpt.common.core.utility.jdt.AnnotatedElement;
+import org.eclipse.jpt.common.core.utility.jdt.AnnotationAdapter;
+import org.eclipse.jpt.common.core.utility.jdt.DeclarationAnnotationAdapter;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlKeyAnnotation;
+
+
+public class SourceXmlKeyAnnotation
+		extends SourceAnnotation
+		implements XmlKeyAnnotation {
+
+	public static final DeclarationAnnotationAdapter DECLARATION_ANNOTATION_ADAPTER = new SimpleDeclarationAnnotationAdapter(ELJaxb.XML_KEY);
+	
+	
+	public SourceXmlKeyAnnotation(JavaResourceAnnotatedElement parent, AnnotatedElement element) {
+		this(parent, element, DECLARATION_ANNOTATION_ADAPTER, new ElementAnnotationAdapter(element, DECLARATION_ANNOTATION_ADAPTER));
+	}
+	
+	public SourceXmlKeyAnnotation(JavaResourceAnnotatedElement parent, AnnotatedElement element, DeclarationAnnotationAdapter daa, AnnotationAdapter annotationAdapter) {
+		super(parent, element, daa, annotationAdapter);
+	}
+	
+	
+	public String getAnnotationName() {
+		return ELJaxb.XML_KEY;
+	}
+	
+	public void initialize(CompilationUnit astRoot) {}
+	
+	public void synchronizeWith(CompilationUnit astRoot) {}
+	
+	@Override
+	public void toString(StringBuilder sb) {}
+}
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/v2_2/ELJaxb_2_2_PlatformDefinition.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/v2_2/ELJaxb_2_2_PlatformDefinition.java
index 4f50477..3ee2142 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/v2_2/ELJaxb_2_2_PlatformDefinition.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/v2_2/ELJaxb_2_2_PlatformDefinition.java
@@ -25,6 +25,7 @@
 import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.XmlDiscriminatorValueAnnotationDefinition;
 import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.XmlJoinNodeAnnotationDefinition;
 import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.XmlJoinNodesAnnotationDefinition;
+import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.XmlKeyAnnotationDefinition;
 import org.eclipse.jpt.jaxb.eclipselink.core.internal.resource.java.XmlTransformationAnnotationDefinition;
 import org.eclipse.jpt.jaxb.eclipselink.core.internal.v2_1.ELJaxb_2_1_PlatformDefinition;
 
@@ -67,6 +68,7 @@
 				XmlDiscriminatorNodeAnnotationDefinition.instance(),
 				XmlDiscriminatorValueAnnotationDefinition.instance(),
 				XmlJoinNodesAnnotationDefinition.instance(),
+				XmlKeyAnnotationDefinition.instance(),
 				XmlTransformationAnnotationDefinition.instance());
 	}
 	
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/ELJaxb.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/ELJaxb.java
index 01591df..ba5853d 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/ELJaxb.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/ELJaxb.java
@@ -50,6 +50,8 @@
 	String XML_JOIN_NODES = PACKAGE_ + "XmlJoinNodes";
 		String XML_JOIN_NODES__VALUE = "value";
 	
+	String XML_KEY = PACKAGE_ + "XmlKey";
+	
 	String XML_PATH = PACKAGE_ + "XmlPath";
 		String XML_PATH__VALUE = "value";
 	
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlKeyAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlKeyAnnotation.java
new file mode 100644
index 0000000..cd96cd9
--- /dev/null
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlKeyAnnotation.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *  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.resource.java;
+
+import org.eclipse.jpt.common.core.resource.java.Annotation;
+
+/**
+ * Corresponds to the EclipseLink annotation
+ * org.eclipse.persistence.oxm.annotations.XmlKey
+ * 
+ * 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 XmlKeyAnnotation
+		extends Annotation {
+
+}
diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlAttributeMappingTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlAttributeMappingTests.java
index 92bf535..5bd7097 100644
--- a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlAttributeMappingTests.java
+++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlAttributeMappingTests.java
@@ -21,7 +21,9 @@
 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.internal.context.java.ELJavaXmlAttributeMapping;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlPathAnnotation;
@@ -36,6 +38,11 @@
 	}
 	
 	
+	@Override
+	protected JaxbPlatformDescription getPlatform() {
+		return ELJaxbPlatform.VERSION_2_2;
+	}
+	
 	private ICompilationUnit createTypeWithXmlAttribute() throws Exception {
 		return this.createTestType(new DefaultAnnotationWriter() {
 			@Override
@@ -174,4 +181,60 @@
 		assertNull(xmlPathAnnotation.getValue());
 		assertFalse(persistentAttribute.getMapping().getKey() == MappingKeys.XML_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY);
 	}
+	
+	public void testModifyXmlKey() throws Exception {
+		createTypeWithXmlAttribute();
+		
+		JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0);
+		JaxbClassMapping classMapping = jaxbClass.getMapping();
+		JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0);
+		ELJavaXmlAttributeMapping mapping = (ELJavaXmlAttributeMapping) persistentAttribute.getMapping();
+		JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+		
+		mapping.addXmlKey();
+		
+		assertNotNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNotNull(mapping.getXmlKey());
+		
+		mapping.removeXmlKey();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+	}
+	
+	public void testUpdateXmlKey() throws Exception {
+		createTypeWithXmlAttribute();
+		
+		JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0);
+		JaxbClassMapping classMapping = jaxbClass.getMapping();
+		JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0);
+		ELJavaXmlAttributeMapping mapping = (ELJavaXmlAttributeMapping) persistentAttribute.getMapping();
+		JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+		
+		AnnotatedElement annotatedElement = this.annotatedElement(resourceAttribute);
+		annotatedElement.edit(new Member.Editor() {
+			public void edit(ModifiedDeclaration declaration) {
+				ELJavaXmlAttributeMappingTests.this.addMarkerAnnotation(
+						declaration.getDeclaration(), ELJaxb.XML_KEY);
+			}
+		});
+		
+		assertNotNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNotNull(mapping.getXmlKey());
+		
+		annotatedElement.edit(new Member.Editor() {
+			public void edit(ModifiedDeclaration declaration) {
+				ELJavaXmlAttributeMappingTests.this.removeAnnotation(declaration, ELJaxb.XML_KEY);
+			}
+		});
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+	}
 }
diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlElementMappingTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlElementMappingTests.java
index a70cb9a..c44f46f 100644
--- a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlElementMappingTests.java
+++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/context/java/ELJavaXmlElementMappingTests.java
@@ -21,7 +21,9 @@
 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.internal.context.java.ELJavaXmlElementMapping;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
 import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlPathAnnotation;
@@ -36,6 +38,11 @@
 	}
 	
 	
+	@Override
+	protected JaxbPlatformDescription getPlatform() {
+		return ELJaxbPlatform.VERSION_2_2;
+	}
+	
 	private ICompilationUnit createTypeWithXmlElement() throws Exception {
 		return this.createTestType(new DefaultAnnotationWriter() {
 			@Override
@@ -174,4 +181,116 @@
 		assertNull(xmlPathAnnotation.getValue());
 		assertTrue(persistentAttribute.getMapping().getKey() == MappingKeys.XML_ELEMENT_ATTRIBUTE_MAPPING_KEY);
 	}
+	
+	public void testModifyXmlKey() throws Exception {
+		createTypeWithXmlElement();
+		
+		JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0);
+		JaxbClassMapping classMapping = jaxbClass.getMapping();
+		JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0);
+		ELJavaXmlElementMapping mapping = (ELJavaXmlElementMapping) persistentAttribute.getMapping();
+		JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+		
+		mapping.addXmlKey();
+		
+		assertNotNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNotNull(mapping.getXmlKey());
+		
+		mapping.removeXmlKey();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+	}
+
+	public void testUpdateXmlKey() throws Exception {
+		createTypeWithXmlElement();
+		
+		JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0);
+		JaxbClassMapping classMapping = jaxbClass.getMapping();
+		JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0);
+		ELJavaXmlElementMapping mapping = (ELJavaXmlElementMapping) persistentAttribute.getMapping();
+		JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+		
+		AnnotatedElement annotatedElement = this.annotatedElement(resourceAttribute);
+		annotatedElement.edit(new Member.Editor() {
+			public void edit(ModifiedDeclaration declaration) {
+				ELJavaXmlElementMappingTests.this.addMarkerAnnotation(
+						declaration.getDeclaration(), ELJaxb.XML_KEY);
+			}
+		});
+		
+		assertNotNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNotNull(mapping.getXmlKey());
+		
+		annotatedElement.edit(new Member.Editor() {
+			public void edit(ModifiedDeclaration declaration) {
+				ELJavaXmlElementMappingTests.this.removeAnnotation(declaration, ELJaxb.XML_KEY);
+			}
+		});
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_KEY));
+		assertNull(mapping.getXmlKey());
+	}
+	
+	public void testModifyXmlCDATA() throws Exception {
+		createTypeWithXmlElement();
+		
+		JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0);
+		JaxbClassMapping classMapping = jaxbClass.getMapping();
+		JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0);
+		ELJavaXmlElementMapping mapping = (ELJavaXmlElementMapping) persistentAttribute.getMapping();
+		JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_CDATA));
+		assertNull(mapping.getXmlCDATA());
+		
+		mapping.addXmlCDATA();
+		
+		assertNotNull(resourceAttribute.getAnnotation(ELJaxb.XML_CDATA));
+		assertNotNull(mapping.getXmlCDATA());
+		
+		mapping.removeXmlCDATA();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_CDATA));
+		assertNull(mapping.getXmlCDATA());
+	}
+	
+	public void testUpdateXmlCDATA() throws Exception {
+		createTypeWithXmlElement();
+		
+		JaxbClass jaxbClass = (JaxbClass) CollectionTools.get(getContextRoot().getTypes(), 0);
+		JaxbClassMapping classMapping = jaxbClass.getMapping();
+		JaxbPersistentAttribute persistentAttribute = CollectionTools.get(classMapping.getAttributes(), 0);
+		ELJavaXmlElementMapping mapping = (ELJavaXmlElementMapping) persistentAttribute.getMapping();
+		JavaResourceAttribute resourceAttribute = mapping.getPersistentAttribute().getJavaResourceAttribute();
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_CDATA));
+		assertNull(mapping.getXmlCDATA());
+		
+		AnnotatedElement annotatedElement = this.annotatedElement(resourceAttribute);
+		annotatedElement.edit(new Member.Editor() {
+			public void edit(ModifiedDeclaration declaration) {
+				ELJavaXmlElementMappingTests.this.addMarkerAnnotation(
+						declaration.getDeclaration(), ELJaxb.XML_CDATA);
+			}
+		});
+		
+		assertNotNull(resourceAttribute.getAnnotation(ELJaxb.XML_CDATA));
+		assertNotNull(mapping.getXmlCDATA());
+		
+		annotatedElement.edit(new Member.Editor() {
+			public void edit(ModifiedDeclaration declaration) {
+				ELJavaXmlElementMappingTests.this.removeAnnotation(declaration, ELJaxb.XML_CDATA);
+			}
+		});
+		
+		assertNull(resourceAttribute.getAnnotation(ELJaxb.XML_CDATA));
+		assertNull(mapping.getXmlCDATA());
+	}
 }
diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/ELJaxbJavaResourceModelTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/ELJaxbJavaResourceModelTests.java
index 61a9b05..27c4a89 100644
--- a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/ELJaxbJavaResourceModelTests.java
+++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/ELJaxbJavaResourceModelTests.java
@@ -24,6 +24,7 @@
 		suite.addTestSuite(XmlDiscriminatorValueAnnotationTests.class);
 		suite.addTestSuite(XmlInverseReferenceAnnotationTests.class);
 		suite.addTestSuite(XmlJoinNodeAnnotationTests.class);
+		suite.addTestSuite(XmlKeyAnnotationTests.class);
 		suite.addTestSuite(XmlPathAnnotationTests.class);
 		suite.addTestSuite(XmlTransformationAnnotationTests.class);
 		
diff --git a/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/XmlKeyAnnotationTests.java b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/XmlKeyAnnotationTests.java
new file mode 100644
index 0000000..bbd0a16
--- /dev/null
+++ b/jaxb/tests/org.eclipse.jpt.jaxb.eclipselink.core.tests/src/org/eclipse/jpt/jaxb/eclipselink/core/tests/internal/resource/java/XmlKeyAnnotationTests.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ *  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.tests.internal.resource.java;
+
+import java.util.Iterator;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jpt.common.core.resource.java.AnnotationDefinition;
+import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute;
+import org.eclipse.jpt.common.core.resource.java.JavaResourceField;
+import org.eclipse.jpt.common.core.resource.java.JavaResourceType;
+import org.eclipse.jpt.common.core.resource.java.NestableAnnotationDefinition;
+import org.eclipse.jpt.common.utility.internal.iterators.ArrayIterator;
+import org.eclipse.jpt.jaxb.eclipselink.core.internal.v2_2.ELJaxb_2_2_PlatformDefinition;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb;
+import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlKeyAnnotation;
+
+
+public class XmlKeyAnnotationTests
+		extends ELJaxbJavaResourceModelTestCase {
+	
+	public XmlKeyAnnotationTests(String name) {
+		super(name);
+	}
+	
+	
+	@Override
+	protected AnnotationDefinition[] annotationDefinitions() {
+		return ELJaxb_2_2_PlatformDefinition.instance().getAnnotationDefinitions();
+	}
+	
+	@Override
+	protected NestableAnnotationDefinition[] nestableAnnotationDefinitions() {
+		return ELJaxb_2_2_PlatformDefinition.instance().getNestableAnnotationDefinitions();
+	}
+	
+	
+	private ICompilationUnit createTestXmlKey() 
+			throws Exception {
+		
+		return this.createTestType(new DefaultAnnotationWriter() {
+			
+			@Override
+			public Iterator<String> imports() {
+				return new ArrayIterator<String>(ELJaxb.XML_KEY);
+			}
+			
+			@Override
+			public void appendIdFieldAnnotationTo(StringBuilder sb) {
+				sb.append("@XmlKey");
+			}
+		});
+	}
+	
+	private XmlKeyAnnotation getXmlKeyAnnotation(JavaResourceAttribute resourceAttribute) {
+		return (XmlKeyAnnotation) resourceAttribute.getAnnotation(ELJaxb.XML_KEY);
+	}
+	
+	
+	public void testGetNull() throws Exception {
+		ICompilationUnit cu = createTestXmlKey();
+		JavaResourceType resourceType = buildJavaResourceType(cu); 
+		JavaResourceField resourceAttribute = getField(resourceType, 0);
+		XmlKeyAnnotation annotation = getXmlKeyAnnotation(resourceAttribute);
+		
+		assertTrue(annotation != null);
+	}
+}