1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.incubator.code;
27
28 import java.lang.annotation.*;
29 import java.lang.reflect.Method;
30
31 /**
32 * An annotation that is used to declare reflectable methods, lambda expressions, and method references. Declaration
33 * of such reflectable program elements enables access to their code as a code model.
34 * <p>
35 * The code model of a reflectable method is accessed by invoking {@link Op#ofMethod(Method)} with an argument
36 * that is a {@link Method} instance (retrieved using core reflection) representing the reflectable method. The result
37 * is an optional value that contains a root operation modeling the method. For example,
38 * {@snippet lang = java:
39 * static class MyClass {
40 * @Reflect
41 * void reflectableMethod(int i) { IO.println(i); }
42 * }
43 *
44 * Method m = MyClass.class.getDeclaredMethod("reflectableMethod", int.class);
45 * CoreOp.FuncOp codeModel = Op.ofMethod(m).orElseThrow();
46 * }
47 * <p>
48 * The code model of a reflectable lambda expression (or method reference) is accessed by invoking
49 * {@link Op#ofLambda(Object)} with an argument that is an instance of a functional interface associated with the
50 * reflectable lambda expression. The result is an optional value that contains a {@link Quoted quoted} instance, from
51 * which may be retrieved the operation modeling the lambda expression. In addition, it is possible to retrieve
52 * a mapping from {@link Value values} in the code model that model final, or effectively final, variables used but not
53 * declared in the lambda expression to their corresponding run time values. Such run time values are commonly referred
54 * to as captured values. For example:
55 * {@snippet lang = java:
56 * int capture = 42;
57 * @Reflect
58 * IntConsumer reflectableLambda = i -> { IO.println(i + capture); };
59 *
60 * Quoted<JavaOp.LambdaOp> quotedCodeModel = Op.ofLambda(reflectableLambda)
61 * .orElseThrow();
62 * JavaOp.LambdaOp codeModel = quotedCodeModel.op();
63 *
64 * SequencedMap<Value, Object> capturedValues = quotedCodeModel.capturedValues();
65 * assert capturedValues.size() == 1;
66 * assert capturedValues.values().contains(42);
67 * }
68 * <p>
69 * There are four syntactic locations where {@code @Reflect} can appear, forming three cases in increasing scope of what
70 * is declared reflectable.
71 * <ol>
72 * <li>
73 * If the annotation appears in a cast expression of a lambda expression (or method reference), annotating the use of
74 * the type in the cast operator of the cast expression, then the lambda expression is declared reflectable. For
75 * example,
76 * {@snippet lang=java :
77 * method((@Reflect IntConsumer) i -> { ... });
78 * }
79 * </li>
80 * <li>
81 * If the annotation appears as a modifier for a field declaration or a local variable declaration, annotating the
82 * field or local variable, then any lambda expressions (or method references) in the variable initializer expression
83 * (if present) are declared reflectable. This is useful when cast expressions become verbose and/or types become hard
84 * to reason about, such as with fluent stream-like expressions where many reflectable lambda expressions are
85 * passed as arguments. For example,
86 * {@snippet lang=java :
87 * @Reflect
88 * IntConsumer reflectableLambda = i -> { ... };
89 * method(reflectableLambda);
90 * }
91 * </li>
92 * <li>
93 * Finally, if the annotation appears as a modifier for a non-abstract method declaration, annotating the method, then
94 * the method and any lambda expressions (or method references) it contains are declared reflectable. For example,
95 * {@snippet lang=java :
96 * @Reflect
97 * void reflectableMethod(int i) { ... }
98 * }
99 * </li>
100 * </ol>
101 * If a method or lambda expression (or method reference) is declared reflectable then the compiler generates an error
102 * message if it contains program elements that cannot be modeled (and therefore a code model cannot be produced).
103 * <p>
104 * The annotation is ignored if it appears in any other valid syntactic location.
105 * <p>
106 * Declaring a reflectable lambda expression or method does not implicitly broaden the scope of what is reflectable to
107 * methods they invoke. Furthermore, declaring a reflectable lambda expression does broaden the scope to the surrounding
108 * code of final, or effectively final, variables used but not declared in the lambda expression.
109 * Declaring a reflectable method reference does not implicitly broaden the scope to the referenced method.
110 * A reflectable method reference's code model is the same as the code model of an equivalent reflectable lambda
111 * expression whose body invokes the referenced method.
112 *
113 * @see Op#ofMethod(Method)
114 * @see Op#ofLambda(Object)
115 */
116 @Target({ElementType.LOCAL_VARIABLE, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE_USE})
117 @Retention(RetentionPolicy.RUNTIME)
118 public @interface Reflect {
119 }