001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.commons.reflect; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.ThrowableUtils.*; 021 022import java.lang.annotation.*; 023import java.lang.reflect.Modifier; 024 025/** 026 * Abstract base class for all reflection wrapper objects providing common modifier checking functionality. 027 * 028 * <p> 029 * This class provides the foundation for all reflection info wrappers (classes, methods, fields, constructors, etc.) 030 * by providing common functionality for checking Java language modifiers and element flags. Subclasses extend this 031 * to provide specific functionality for their element type. 032 * 033 * <h5 class='section'>Features:</h5> 034 * <ul class='spaced-list'> 035 * <li>Modifier checking - check for public, private, protected, static, final, etc. 036 * <li>Flag checking - check for element flags using {@link ElementFlag} 037 * <li>Combined flag checking - check for multiple flags at once 038 * <li>Extensible - subclasses can add element-specific flag checks 039 * </ul> 040 * 041 * <h5 class='section'>Use Cases:</h5> 042 * <ul class='spaced-list'> 043 * <li>Checking modifiers on reflection elements 044 * <li>Filtering elements by flags 045 * <li>Building frameworks that need to analyze element characteristics 046 * </ul> 047 * 048 * <h5 class='section'>Usage:</h5> 049 * <p class='bjava'> 050 * <jc>// Check modifiers</jc> 051 * ElementInfo <jv>ei</jv> = ...; 052 * <jk>boolean</jk> <jv>isPublic</jv> = <jv>ei</jv>.isPublic(); 053 * <jk>boolean</jk> <jv>isStatic</jv> = <jv>ei</jv>.isStatic(); 054 * 055 * <jc>// Check flags</jc> 056 * <jk>boolean</jk> <jv>hasFlag</jv> = <jv>ei</jv>.hasFlag(ElementFlag.PUBLIC); 057 * <jk>boolean</jk> <jv>hasAllFlags</jv> = <jv>ei</jv>.hasAllFlags(ElementFlag.PUBLIC, ElementFlag.STATIC); 058 * </p> 059 * 060 * <h5 class='section'>See Also:</h5><ul> 061 * <li class='jc'>{@link ElementFlag} - Element flags enumeration 062 * <li class='jc'>{@link ClassInfo} - Class introspection 063 * <li class='jc'>{@link MethodInfo} - Method introspection 064 * <li class='jc'>{@link FieldInfo} - Field introspection 065 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsReflection">Reflection Package</a> 066 * </ul> 067 */ 068public abstract class ElementInfo { 069 070 private final int modifiers; 071 072 /** 073 * Constructor. 074 * 075 * @param modifiers The Java modifiers for this element. 076 */ 077 protected ElementInfo(int modifiers) { 078 this.modifiers = modifiers; 079 } 080 081 /** 082 * Returns the Java language modifiers for this element. 083 * 084 * @return The Java language modifiers for this element. 085 */ 086 public int getModifiers() { return modifiers; } 087 088 /** 089 * Returns <jk>true</jk> if the specified flag is applicable to this element. 090 * 091 * <p> 092 * Subclasses should override this method and call {@code super.is(flag)} to handle common modifier flags, 093 * then handle their own specific flags. 094 * 095 * @param flag The flag to test for. 096 * @return <jk>true</jk> if the specified flag is applicable to this element. 097 */ 098 public boolean is(ElementFlag flag) { 099 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}