001package arez.annotations; 002 003import java.lang.annotation.Documented; 004import java.lang.annotation.ElementType; 005import java.lang.annotation.Target; 006import javax.annotation.Nonnull; 007import org.intellij.lang.annotations.Language; 008 009/** 010 * Annotation applied to methods that define a single "contextual" parameter to one or more {@link Memoize} 011 * annotated methods. A "contextual" parameter is one that is used within the {@link Memoize} annotated methods, 012 * but is not passed in but derived from the calling context. These are the conceptual equivalent of thread-local 013 * values accessed from within the function. 014 * 015 * <p>There are expected to be a three methods for each context parameter: one to get the value from the 016 * calling context (optionally prefixed with "capture" that returns the type of the context parameter), one 017 * to push the value to the calling context (prefixed with "push" with a single parameter that has the 018 * type of the context parameter), and one to pop the value from the calling context (prefixed with "pop" 019 * with a single parameter that has the type of the context parameter).</p> 020 * 021 * <h2>Capture Method</h2> 022 * 023 * <p>The method to capture the context parameter is invoked prior to the invocation of the {@link Memoize} 024 * annotated method when non-arez-framework code invokes the method. It may be invoked outside of an arez 025 * transaction if the associated method has {@link Memoize#readOutsideTransaction()} resolve to 026 * {@link Feature#DISABLE}. The method must also comply with the following additional constraints:</p> 027 * 028 * <ul> 029 * <li>Must not be annotated with any other arez annotation</li> 030 * <li>Must return a value</li> 031 * <li>Must not have any parameters</li> 032 * <li>Must not specify type parameters</li> 033 * <li>Must not be private</li> 034 * <li>Must not be static</li> 035 * <li>Must not be abstract</li> 036 * <li>Must not throw exceptions</li> 037 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li> 038 * </ul> 039 * 040 * <h2>Push Method</h2> 041 * 042 * <p>The method to push the context parameter into the current context is invoked prior to the invocation 043 * of the {@link Memoize} annotated method when the arez framework invokes the method to determine whether 044 * the result has changed. It is invoked outside of an arez transaction. The method must also comply 045 * with the following additional constraints:</p> 046 * 047 * <p>The method that is annotated with this annotation must comply with the additional constraints:</p> 048 * <ul> 049 * <li>The method name must start with "push"</li> 050 * <li>Must not be annotated with any other arez annotation</li> 051 * <li>Must not return a value</li> 052 * <li>Must have one parameter</li> 053 * <li>Must not specify type parameters</li> 054 * <li>Must not be private</li> 055 * <li>Must not be static</li> 056 * <li>Must not be abstract</li> 057 * <li>Must not throw exceptions</li> 058 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li> 059 * </ul> 060 * 061 * <h2>Pop Method</h2> 062 * 063 * <p>The method to pop the context parameter from the current context is invoked after to the invocation 064 * of the {@link Memoize} annotated method when the arez framework invokes the method to determine whether 065 * the result has changed. It is invoked outside of an arez transaction. The method must also comply 066 * with the following additional constraints:</p> 067 * 068 * <p>The method that is annotated with this annotation must comply with the additional constraints:</p> 069 * <ul> 070 * <li>The method name must start with "pop"</li> 071 * <li>Must not be annotated with any other arez annotation</li> 072 * <li>Must not return a value</li> 073 * <li>Must have one parameter</li> 074 * <li>Must not specify type parameters</li> 075 * <li>Must not be private</li> 076 * <li>Must not be static</li> 077 * <li>Must not be abstract</li> 078 * <li>Must not throw exceptions</li> 079 * <li>Must be accessible to the class annotated by the {@link ArezComponent} annotation.</li> 080 * </ul> 081 */ 082@Documented 083@Target( ElementType.METHOD ) 084public @interface MemoizeContextParameter 085{ 086 /** 087 * Return the name of the context parameter. 088 * If not specified, then the name will be derived from the name of the method. 089 * <ul> 090 * <li>To derive the name from a push method then remove the "push" prefix.</li> 091 * <li>To derive the name from a pop method then remove the "pop" prefix.</li> 092 * <li>To derive the name from a capture method then remove the optional "capture" prefix else just use the method name if no such prefix.</li> 093 * </ul> 094 * 095 * @return the name of the context parameter. 096 */ 097 @Nonnull 098 String name() default "<default>"; 099 100 /** 101 * Return a regular expression for matching the arez names of memoized methods where this context parameter is tracked. 102 * 103 * @return a regular expression for matching arez name of memoized methods. 104 */ 105 @Nonnull 106 @Language( "RegExp" ) 107 String pattern() default ".*"; 108 109 /** 110 * Return true if the component does not need to have {@link Memoize} annotated methods match. 111 * Otherwise, if no {@link Memoize} annotated methods match the {@link #pattern()} then the annotation 112 * processor will generate an error. 113 * 114 * @return true if the memoized methods must match annotation, false otherwise. 115 */ 116 boolean allowEmpty() default false; 117}