View Javadoc
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 }