io.permazen.annotation.FollowPath Maven / Gradle / Ivy
Show all versions of permazen-main Show documentation
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package io.permazen.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Java annotation for declaring methods that should return objects found by traversing a {@link io.permazen.ReferencePath}.
*
*
* This annotation can be used as a convenience to let Permazen auto-generate reference path traversal code.
* A common use case is inverting references, e.g., from a parent back to a child in a one-to-many relationship.
*
*
* Annotating an abstract method with {@code @FollowPath("some.path")} is just short-hand for providing an implementation
* that creates and traverses the {@linkplain io.permazen.ReferencePath reference path} {@code "some.path"}.
* See {@link io.permazen.ReferencePath} for details on reference paths. The specified reference path is assumed to not
* have any {@linkplain io.permazen.ReferencePath#getTargetField target field}.
*
*
* For example, the following declaration:
*
* @FollowPath("^TreeNode:parent^")
* public abstract NavigableSet<TreeNode> getChildren();
*
* is functionally equivalent to, and slightly more efficient than:
*
*
* public NavigableSet<TreeNode> getChildren() {
* final Permazen jdb = /* the Permazen instance associated with this instance */
* final ReferencePath path = jdb.parseReferencePath(this.getClass(), "^TreeNode:parent^", false);
* return jdb.followReferencePath(path, Collections.singleton(this));
* }
*
*
* Method Return Type
*
*
* The annotated method should return {@link java.util.NavigableSet NavigableSet<T>}, where {@code T} is any super-type of
* the type(s) at the other end of the reference path.
*
*
* However, if {@code firstOnly} is true then the method returns only the first object found (if any), and the method's
* return type should instead be {@link java.util.Optional}{@code }; this is always appropriate when the reference path
* contains only forward traversals of many-to-one relationships.
*
*
* For example:
*
* @PermazenType
* public interface TreeNode extends JObject {
*
* /**
* * Get the parent of this node, or null if node is a root.
* */
* TreeNode getParent();
* void setParent(TreeNode parent);
*
* /**
* * Get the children of this node.
* */
* @FollowPath("^TreeNode:parent^")
* NavigableSet<TreeNode> getChildren();
*
* /**
* * Get the siblings of this node (including this node).
* */
* @FollowPath("parent.^TreeNode:parent^")
* NavigableSet<TreeNode> getSiblings();
*
* /**
* * Get the grandparent of this node.
* */
* @FollowPath(value = "parent.parent", firstOnly = true)
* Optional<TreeNode> getGrandparent();
* }
*
*
* Inverse Paths
*
*
* Inverse paths may be specified using the combination of {@link #inverseOf} and {@link #startingFrom} properties.
* So the following two declarations are functionally equivalent:
*
* /**
* * Get the children of this node.
* */
* @FollowPath("^TreeNode:parent^")
* NavigableSet<TreeNode> getChildren();
*
* /**
* * Get the children of this node.
* */
* @FollowPath(inverseOf = "parent", startingFrom = TreeNode.class)
* NavigableSet<TreeNode> getChildren();
*
*
* Meta-Annotations
*
*
* This annotation may be configured indirectly as a Spring
* meta-annotation
* when {@code spring-core} is on the classpath.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Documented
public @interface FollowPath {
/**
* The reference path to follow in the forward direction.
*
*
* The starting type for the reference path is the class containing the annotated method.
*
*
* If this property is used, both of {@link #inverseOf} and {@link #startingFrom} must be left unset.
*
* @return the reference path to traverse in the forward direction
*/
String value() default "";
/**
* The reference path to follow in the inverse direction.
*
*
* If this property is used, {@link #startingFrom} must also be specified and {@link #value} must be left unset.
*
* @return the reference path to traverse in the inverse direction
*/
String inverseOf() default "";
/**
* The starting model type for the reference path to follow in the inverse direction.
*
*
* When an inverse reference path is specified, the starting type for the reference path is not implied, because
* the path starts from the "remote end", instead of from the class containing the annotated method.
* Therefore, it must be explicitly specified via this property.
*
*
* If this property is used, {@link #inverseOf} must also be specified and {@link #value} must be left unset.
*
* @return the starting model type for the inverted reference path
*/
Class> startingFrom() default void.class;
/**
* Whether only the first, if any, of the set of objects should be returned, or the entire set.
*
*
* If this property is true, then the annotated method's return type must be {@code java.util.Optional}{@code },
* or if false, it must be {@link java.util.NavigableSet}{@code }, where {@code T} is some super-type of the type(s)
* at the remote end of the reference path.
*
* @return whether to return only the first object
*/
boolean firstOnly() default false;
}