1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.juneau.commons.reflect;
18
19 import static org.apache.juneau.commons.utils.CollectionUtils.*;
20 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
21
22 import java.lang.annotation.*;
23 import java.lang.reflect.Modifier;
24
25 /**
26 * Abstract base class for all reflection wrapper objects providing common modifier checking functionality.
27 *
28 * <p>
29 * This class provides the foundation for all reflection info wrappers (classes, methods, fields, constructors, etc.)
30 * by providing common functionality for checking Java language modifiers and element flags. Subclasses extend this
31 * to provide specific functionality for their element type.
32 *
33 * <h5 class='section'>Features:</h5>
34 * <ul class='spaced-list'>
35 * <li>Modifier checking - check for public, private, protected, static, final, etc.
36 * <li>Flag checking - check for element flags using {@link ElementFlag}
37 * <li>Combined flag checking - check for multiple flags at once
38 * <li>Extensible - subclasses can add element-specific flag checks
39 * </ul>
40 *
41 * <h5 class='section'>Use Cases:</h5>
42 * <ul class='spaced-list'>
43 * <li>Checking modifiers on reflection elements
44 * <li>Filtering elements by flags
45 * <li>Building frameworks that need to analyze element characteristics
46 * </ul>
47 *
48 * <h5 class='section'>Usage:</h5>
49 * <p class='bjava'>
50 * <jc>// Check modifiers</jc>
51 * ElementInfo <jv>ei</jv> = ...;
52 * <jk>boolean</jk> <jv>isPublic</jv> = <jv>ei</jv>.isPublic();
53 * <jk>boolean</jk> <jv>isStatic</jv> = <jv>ei</jv>.isStatic();
54 *
55 * <jc>// Check flags</jc>
56 * <jk>boolean</jk> <jv>hasFlag</jv> = <jv>ei</jv>.hasFlag(ElementFlag.PUBLIC);
57 * <jk>boolean</jk> <jv>hasAllFlags</jv> = <jv>ei</jv>.hasAllFlags(ElementFlag.PUBLIC, ElementFlag.STATIC);
58 * </p>
59 *
60 * <h5 class='section'>See Also:</h5><ul>
61 * <li class='jc'>{@link ElementFlag} - Element flags enumeration
62 * <li class='jc'>{@link ClassInfo} - Class introspection
63 * <li class='jc'>{@link MethodInfo} - Method introspection
64 * <li class='jc'>{@link FieldInfo} - Field introspection
65 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsReflection">Reflection Package</a>
66 * </ul>
67 */
68 public abstract class ElementInfo {
69
70 private final int modifiers;
71
72 /**
73 * Constructor.
74 *
75 * @param modifiers The Java modifiers for this element.
76 */
77 protected ElementInfo(int modifiers) {
78 this.modifiers = modifiers;
79 }
80
81 /**
82 * Returns the Java language modifiers for this element.
83 *
84 * @return The Java language modifiers for this element.
85 */
86 public int getModifiers() { return modifiers; }
87
88 /**
89 * Returns <jk>true</jk> if the specified flag is applicable to this element.
90 *
91 * <p>
92 * Subclasses should override this method and call {@code super.is(flag)} to handle common modifier flags,
93 * then handle their own specific flags.
94 *
95 * @param flag The flag to test for.
96 * @return <jk>true</jk> if the specified flag is applicable to this element.
97 */
98 public boolean is(ElementFlag flag) {
99 return switch (flag) {
100 case PUBLIC -> isPublic();
101 case NOT_PUBLIC -> isNotPublic();
102 case PRIVATE -> isPrivate();
103 case NOT_PRIVATE -> isNotPrivate();
104 case PROTECTED -> isProtected();
105 case NOT_PROTECTED -> isNotProtected();
106 case STATIC -> isStatic();
107 case NOT_STATIC -> isNotStatic();
108 case FINAL -> isFinal();
109 case NOT_FINAL -> isNotFinal();
110 case SYNCHRONIZED -> isSynchronized();
111 case NOT_SYNCHRONIZED -> isNotSynchronized();
112 case VOLATILE -> isVolatile();
113 case NOT_VOLATILE -> isNotVolatile();
114 case TRANSIENT -> isTransient();
115 case NOT_TRANSIENT -> isNotTransient();
116 case NATIVE -> isNative();
117 case NOT_NATIVE -> isNotNative();
118 case INTERFACE -> isInterface();
119 case ABSTRACT -> isAbstract();
120 case NOT_ABSTRACT -> isNotAbstract();
121 default -> throw rex("Invalid flag for element: {0}", flag);
122 };
123 }
124
125 /**
126 * Returns <jk>true</jk> if this element is abstract.
127 *
128 * @return <jk>true</jk> if this element is abstract.
129 */
130 public boolean isAbstract() { return Modifier.isAbstract(modifiers); }
131
132 /**
133 * Returns <jk>true</jk> if all specified flags are applicable to this element.
134 *
135 * <p>
136 * Subclasses should override this method and call {@code super.isAll(flags)} to handle common modifier flags,
137 * then handle their own specific flags.
138 *
139 * @param flags The flags to test for.
140 * @return <jk>true</jk> if all specified flags are applicable to this element.
141 */
142 public boolean isAll(ElementFlag...flags) {
143 return stream(flags).allMatch(this::is);
144 }
145
146 /**
147 * Returns <jk>true</jk> if any of the specified flags are applicable to this element.
148 *
149 * <p>
150 * Subclasses should override this method and call {@code super.isAny(flags)} to handle common modifier flags,
151 * then handle their own specific flags.
152 *
153 * @param flags The flags to test for.
154 * @return <jk>true</jk> if any of the specified flags are applicable to this element.
155 */
156 public boolean isAny(ElementFlag...flags) {
157 return stream(flags).anyMatch(this::is);
158 }
159
160 /**
161 * Returns <jk>true</jk> if this element is final.
162 *
163 * @return <jk>true</jk> if this element is final.
164 */
165 public boolean isFinal() { return Modifier.isFinal(modifiers); }
166
167 /**
168 * Returns <jk>true</jk> if this element is an interface.
169 *
170 * @return <jk>true</jk> if this element is an interface.
171 */
172 public boolean isInterface() { return Modifier.isInterface(modifiers); }
173
174 /**
175 * Returns <jk>true</jk> if this element is native.
176 *
177 * @return <jk>true</jk> if this element is native.
178 */
179 public boolean isNative() { return Modifier.isNative(modifiers); }
180
181 /**
182 * Returns <jk>true</jk> if this element is not abstract.
183 *
184 * @return <jk>true</jk> if this element is not abstract.
185 */
186 public boolean isNotAbstract() { return ! Modifier.isAbstract(modifiers); }
187
188 /**
189 * Returns <jk>true</jk> if this element is not final.
190 *
191 * @return <jk>true</jk> if this element is not final.
192 */
193 public boolean isNotFinal() { return ! Modifier.isFinal(modifiers); }
194
195 /**
196 * Returns <jk>true</jk> if this element is not an interface.
197 *
198 * @return <jk>true</jk> if this element is not an interface.
199 */
200 public boolean isNotInterface() { return ! Modifier.isInterface(modifiers); }
201
202 /**
203 * Returns <jk>true</jk> if this element is not native.
204 *
205 * @return <jk>true</jk> if this element is not native.
206 */
207 public boolean isNotNative() { return ! Modifier.isNative(modifiers); }
208
209 /**
210 * Returns <jk>true</jk> if this element is not private.
211 *
212 * @return <jk>true</jk> if this element is not private.
213 */
214 public boolean isNotPrivate() { return ! Modifier.isPrivate(modifiers); }
215
216 /**
217 * Returns <jk>true</jk> if this element is not protected.
218 *
219 * @return <jk>true</jk> if this element is not protected.
220 */
221 public boolean isNotProtected() { return ! Modifier.isProtected(modifiers); }
222
223 /**
224 * Returns <jk>true</jk> if this element is not public.
225 *
226 * @return <jk>true</jk> if this element is not public.
227 */
228 public boolean isNotPublic() { return ! Modifier.isPublic(modifiers); }
229
230 /**
231 * Returns <jk>true</jk> if this element is not static.
232 *
233 * @return <jk>true</jk> if this element is not static.
234 */
235 public boolean isNotStatic() { return ! Modifier.isStatic(modifiers); }
236
237 /**
238 * Returns <jk>true</jk> if this element is not synchronized.
239 *
240 * @return <jk>true</jk> if this element is not synchronized.
241 */
242 public boolean isNotSynchronized() { return ! Modifier.isSynchronized(modifiers); }
243
244 /**
245 * Returns <jk>true</jk> if this element is not transient.
246 *
247 * @return <jk>true</jk> if this element is not transient.
248 */
249 public boolean isNotTransient() { return ! Modifier.isTransient(modifiers); }
250
251 /**
252 * Returns <jk>true</jk> if this element is not volatile.
253 *
254 * @return <jk>true</jk> if this element is not volatile.
255 */
256 public boolean isNotVolatile() { return ! Modifier.isVolatile(modifiers); }
257
258 /**
259 * Returns <jk>true</jk> if this element is private.
260 *
261 * @return <jk>true</jk> if this element is private.
262 */
263 public boolean isPrivate() { return Modifier.isPrivate(modifiers); }
264
265 /**
266 * Returns <jk>true</jk> if this element is protected.
267 *
268 * @return <jk>true</jk> if this element is protected.
269 */
270 public boolean isProtected() { return Modifier.isProtected(modifiers); }
271
272 /**
273 * Returns <jk>true</jk> if this element is public.
274 *
275 * @return <jk>true</jk> if this element is public.
276 */
277 public boolean isPublic() { return Modifier.isPublic(modifiers); }
278
279 /**
280 * Returns <jk>true</jk> if this element is static.
281 *
282 * @return <jk>true</jk> if this element is static.
283 */
284 public boolean isStatic() { return Modifier.isStatic(modifiers); }
285
286 /**
287 * Returns <jk>true</jk> if this element is synchronized.
288 *
289 * @return <jk>true</jk> if this element is synchronized.
290 */
291 public boolean isSynchronized() { return Modifier.isSynchronized(modifiers); }
292
293 /**
294 * Returns <jk>true</jk> if this element is transient.
295 *
296 * @return <jk>true</jk> if this element is transient.
297 */
298 public boolean isTransient() { return Modifier.isTransient(modifiers); }
299
300 /**
301 * Returns <jk>true</jk> if this element is volatile.
302 *
303 * @return <jk>true</jk> if this element is volatile.
304 */
305 public boolean isVolatile() { return Modifier.isVolatile(modifiers); }
306
307 //-----------------------------------------------------------------------------------------------------------------
308 // Helper methods
309 //-----------------------------------------------------------------------------------------------------------------
310
311 protected <A extends Annotation> AnnotationInfo<A> ai(Annotatable on, A value) {
312 return AnnotationInfo.of(on, value);
313 }
314 }