blob: 1e01173da1d4961396f0dacb3507414de7f04741 [file] [log] [blame]
/*
* Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Matt MacIvor = 2.1 - Initial contribution
package org.eclipse.persistence.oxm.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>XPath based mapping is what allows an existing object model to be mapped
* to an existing XML schema. The {@code @XmlPath} annotation is the means by
* which XPath based mapping is achieved.</p>
* <b>Example 1 - Using {@code @XmlPath} to Add a Grouping Element</b>
* <p>Sometimes grouping elements are added to your document to organise data.
* JAXB has this concept for collection properties in the form of
* {@code @XmlElementWrapper}. Here we'll use {@code @XmlPath} for
* non-collection properties. In this case we'll nest the billing/shipping
* address data within the "contact-info" element.</p>
* <pre>
* import jakarta.xml.bind.annotation.*;
* import org.eclipse.persistence.oxm.annotations.XmlPath;
*
* &#64;XmlRootElement
* &#64;XmlAccessorType(XmlAccessType.FIELD)
* public class Customer {
* &#64;XmlPath("contact-info/billing-address")
* private Address billingAddress;
*
* &#64;XmlPath("contact-info/shipping-address")
* private Address shippingAddress;
* }
* </pre>
* This will produce XML like:
* <pre>{@code
* <xmp>
* <customer>
* <contact-info>
* <billing-address>
* <street>1 Billing Street</street>
* </billing-address>
* <shipping-address>
* <street>2 Shipping Road</street>
* </shipping-address>
* </contact-info>
* </customer>
* </xmp>}
* </pre>
* <b>Example 2 - Using {@code @XmlPath} to Map by Position</b>
* <p>Normally in JAXB elements with the same name must be mapped to a
* collection property. Using the &#64;XmlPath extension you map non-collection
* properties to a repeated element by index.</p>
* <pre>
* import jakarta.xml.bind.annotation.*;
* import org.eclipse.persistence.oxm.annotations.XmlPath;
*
* &#64;XmlRootElement
* &#64;XmlAccessorType(XmlAccessType.FIELD)
* public class Customer {
* &#64;XmlPath("address[1]")
* private Address billingAddress;
*
* &#64;XmlPath("address[2]")
* private Address shippingAddress;
* }
* </pre>
* This will produce XML like:
* <pre>{@code
* <xmp>
* <customer>
* <address>
* <street>1 Billing Street</street>
* </address>
* <address>
* <street>2 Shipping Road</street>
* </address>
* </customer>
* </xmp>}
* </pre>
* <b>Example 3 - Using {@code @XmlPath} to Map Two Objects to the Same Node</b>
* <p>We have seen how {@code @XmlPath} can be used to expand the structure by
* adding a grouping element. {@code @XmlPath} can also be used to collapse the
* structure by mapping two objects to the same node.</p>
* <pre>
* import jakarta.xml.bind.annotation.*;
* import org.eclipse.persistence.oxm.annotations.XmlPath;
*
* &#64;XmlRootElement @XmlAccessorType(XmlAccessType.FIELD)
* public class Customer {
* &#64;XmlPath(".")
* private Address billingAddress;
*
* private Address shippingAddress;
* }
* </pre>
* This will produce XML like:
* <pre>{@code
* <xmp>
* <customer>
* <street>1 Billing Street</street>
* <shippingAddress>
* <street>2 Shipping Road</street>
* </shippingAddress>
* </customer>
* </xmp>}
* </pre>
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface XmlPath {
/**
* <p>The XPath for this property. A subset of the XPath specification may be
* used to specify mappings. The following concepts are supported:</p>
* <ul>
* <li>Attribute - "&#64;id"</li>
* <li>Element - "address"</li>
* <li>Element by Position - "address[1]"</li>
* <li>Element by Predicate - "address[@type='mailing']"</li>
* <li>Element Text - "name/text()"</li>
* <li>Text - "text()"</li>
* <li>Self - "."</li>
* <li>Combination - "personal-info/name[2]/text()"</li>
* </ul>
* <p>For namespace qualified nodes, the prefixes defined in the XmlNs
* annotations can be used to qualify the XPath fragments. Unqualified
* fragments will assumed to be in the namespace specified using
* &#64;XmlSchema.</p>
* <b>Example</b>
* <p>Assuming the following namespace information has been set up using the
* &#64;XmlSchema annotation:</p>
* <pre>
* &#64;XmlSchema(namespace = "http://www.example.org/FOO",
* xmlns = {&#64;XmlNs(prefix="ns", namespaceURI="http://www.example.com/BAR")},
* elementFormDefault = XmlNsForm.QUALIFIED)
* package org.example;
*
* import jakarta.xml.bind.annotation.*;
* </pre>
* <p>Then the following XPath:</p>
* <pre>
* &#64;XmlPath("contact-info/ns:address/&#64;id")
* </pre>
* <p>Will be qualified as:</p>
* <ul>
* <li>contact-info - in "http://www.example.org/FOO" namespace.</li>
* <li>address - in "http://www.example.com/BAR" namespace.</li>
* <li>&#64;id - in no namespace.</li>
* </ul>
* @see jakarta.xml.bind.annotation.XmlSchema
* @see jakarta.xml.bind.annotation.XmlNs
*/
String value();
}