001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.reflect; 014 015import java.lang.annotation.*; 016import java.lang.reflect.*; 017 018import org.apache.juneau.*; 019import org.apache.juneau.annotation.*; 020 021/** 022 * Lightweight utility class for introspecting information about a field. 023 */ 024@BeanIgnore 025public final class FieldInfo implements Comparable<FieldInfo> { 026 027 private final Field f; 028 private ClassInfo declaringClass, type; 029 030 //----------------------------------------------------------------------------------------------------------------- 031 // Instantiation. 032 //----------------------------------------------------------------------------------------------------------------- 033 034 /** 035 * Constructor. 036 * 037 * @param declaringClass The class that declares this method. 038 * @param f The field being wrapped. 039 */ 040 protected FieldInfo(ClassInfo declaringClass, Field f) { 041 this.declaringClass = declaringClass; 042 this.f = f; 043 } 044 045 /** 046 * Convenience method for instantiating a {@link FieldInfo}; 047 * 048 * @param declaringClass The class that declares this method. 049 * @param f The field being wrapped. 050 * @return A new {@link FieldInfo} object, or <jk>null</jk> if the field was null. 051 */ 052 public static FieldInfo of(ClassInfo declaringClass, Field f) { 053 if (f == null) 054 return null; 055 return new FieldInfo(declaringClass, f); 056 } 057 058 /** 059 * Convenience method for instantiating a {@link FieldInfo}; 060 * 061 * @param f The field being wrapped. 062 * @return A new {@link FieldInfo} object, or <jk>null</jk> if the field was null. 063 */ 064 public static FieldInfo of(Field f) { 065 if (f == null) 066 return null; 067 return new FieldInfo(null, f); 068 } 069 070 /** 071 * Returns the wrapped field. 072 * 073 * @return The wrapped field. 074 */ 075 public Field inner() { 076 return f; 077 } 078 079 /** 080 * Returns metadata about the declaring class. 081 * 082 * @return Metadata about the declaring class. 083 */ 084 public ClassInfo getDeclaringClass() { 085 if (declaringClass == null) 086 declaringClass = ClassInfo.of(f.getDeclaringClass()); 087 return declaringClass; 088 } 089 090 //----------------------------------------------------------------------------------------------------------------- 091 // Annotations 092 //----------------------------------------------------------------------------------------------------------------- 093 094 /** 095 * Returns the specified annotation on this field. 096 * 097 * @param a The annotation to look for. 098 * @return The annotation, or <jk>null</jk> if not found. 099 */ 100 public <T extends Annotation> T getAnnotation(Class<T> a) { 101 return getAnnotation(a, MetaProvider.DEFAULT); 102 } 103 104 /** 105 * Returns the specified annotation on this field. 106 * 107 * @param a The annotation to look for. 108 * @param mp The meta provider for looking up annotations on reflection objects (classes, methods, fields, constructors). 109 * @return The annotation, or <jk>null</jk> if not found. 110 */ 111 public <T extends Annotation> T getAnnotation(Class<T> a, MetaProvider mp) { 112 return mp.getAnnotation(a, f); 113 } 114 115 /** 116 * Returns <jk>true</jk> if the specified annotation is present. 117 * 118 * @param a The annotation to check for. 119 * @return <jk>true</jk> if the specified annotation is present. 120 */ 121 public boolean hasAnnotation(Class<? extends Annotation> a) { 122 return f.isAnnotationPresent(a); 123 } 124 125 /** 126 * Returns <jk>true</jk> if the specified annotation is present. 127 * 128 * @param a The annotation to check for. 129 * @param mp The meta provider for looking up annotations on reflection objects (classes, methods, fields, constructors). 130 * @return <jk>true</jk> if the specified annotation is present. 131 */ 132 public boolean hasAnnotation(Class<? extends Annotation> a, MetaProvider mp) { 133 return mp.getAnnotation(a, f) != null; 134 } 135 136 //----------------------------------------------------------------------------------------------------------------- 137 // Characteristics 138 //----------------------------------------------------------------------------------------------------------------- 139 140 /** 141 * Returns <jk>true</jk> if all specified flags are applicable to this field. 142 * 143 * @param flags The flags to test for. 144 * @return <jk>true</jk> if all specified flags are applicable to this field. 145 */ 146 public boolean isAll(ReflectFlags...flags) { 147 for (ReflectFlags f : flags) { 148 switch (f) { 149 case DEPRECATED: 150 if (isNotDeprecated()) 151 return false; 152 break; 153 case NOT_DEPRECATED: 154 if (isDeprecated()) 155 return false; 156 break; 157 case PUBLIC: 158 if (isNotPublic()) 159 return false; 160 break; 161 case NOT_PUBLIC: 162 if (isPublic()) 163 return false; 164 break; 165 case STATIC: 166 if (isNotStatic()) 167 return false; 168 break; 169 case NOT_STATIC: 170 if (isStatic()) 171 return false; 172 break; 173 case TRANSIENT: 174 if (isNotTransient()) 175 return false; 176 break; 177 case NOT_TRANSIENT: 178 if (isTransient()) 179 return false; 180 break; 181 default: 182 throw new RuntimeException("Invalid flag for field: " + f); 183 } 184 } 185 return true; 186 } 187 188 /** 189 * Returns <jk>true</jk> if all specified flags are applicable to this field. 190 * 191 * @param flags The flags to test for. 192 * @return <jk>true</jk> if all specified flags are applicable to this field. 193 */ 194 public boolean isAny(ReflectFlags...flags) { 195 for (ReflectFlags f : flags) { 196 switch (f) { 197 case DEPRECATED: 198 if (isDeprecated()) 199 return true; 200 break; 201 case NOT_DEPRECATED: 202 if (isNotDeprecated()) 203 return true; 204 break; 205 case PUBLIC: 206 if (isPublic()) 207 return true; 208 break; 209 case NOT_PUBLIC: 210 if (isNotPublic()) 211 return true; 212 break; 213 case STATIC: 214 if (isStatic()) 215 return true; 216 break; 217 case NOT_STATIC: 218 if (isNotStatic()) 219 return true; 220 break; 221 case TRANSIENT: 222 if (isTransient()) 223 return true; 224 break; 225 case NOT_TRANSIENT: 226 if (isNotTransient()) 227 return true; 228 break; 229 default: 230 throw new RuntimeException("Invalid flag for field: " + f); 231 } 232 } 233 return false; 234 } 235 236 /** 237 * Returns <jk>true</jk> if this field has the {@link Deprecated @Deprecated} annotation on it. 238 * 239 * @return <jk>true</jk> if this field has the {@link Deprecated @Deprecated} annotation on it. 240 */ 241 public boolean isDeprecated() { 242 return f.isAnnotationPresent(Deprecated.class); 243 } 244 245 /** 246 * Returns <jk>true</jk> if this field doesn't have the {@link Deprecated @Deprecated} annotation on it. 247 * 248 * @return <jk>true</jk> if this field doesn't have the {@link Deprecated @Deprecated} annotation on it. 249 */ 250 public boolean isNotDeprecated() { 251 return ! f.isAnnotationPresent(Deprecated.class); 252 } 253 254 /** 255 * Returns <jk>true</jk> if this field is public. 256 * 257 * @return <jk>true</jk> if this field is public. 258 */ 259 public boolean isPublic() { 260 return Modifier.isPublic(f.getModifiers()); 261 } 262 263 /** 264 * Returns <jk>true</jk> if this field is not public. 265 * 266 * @return <jk>true</jk> if this field is not public. 267 */ 268 public boolean isNotPublic() { 269 return ! Modifier.isPublic(f.getModifiers()); 270 } 271 272 /** 273 * Returns <jk>true</jk> if this field is static. 274 * 275 * @return <jk>true</jk> if this field is static. 276 */ 277 public boolean isStatic() { 278 return Modifier.isStatic(f.getModifiers()); 279 } 280 281 /** 282 * Returns <jk>true</jk> if this field is not static. 283 * 284 * @return <jk>true</jk> if this field is not static. 285 */ 286 public boolean isNotStatic() { 287 return ! Modifier.isStatic(f.getModifiers()); 288 } 289 290 /** 291 * Returns <jk>true</jk> if this field is transient. 292 * 293 * @return <jk>true</jk> if this field is transient. 294 */ 295 public boolean isTransient() { 296 return Modifier.isTransient(f.getModifiers()); 297 } 298 299 /** 300 * Returns <jk>true</jk> if this field is not transient. 301 * 302 * @return <jk>true</jk> if this field is not transient. 303 */ 304 public boolean isNotTransient() { 305 return ! Modifier.isTransient(f.getModifiers()); 306 } 307 308 /** 309 * Returns <jk>true</jk> if the field has the specified name. 310 * 311 * @param name The name to compare against. 312 * @return <jk>true</jk> if the field has the specified name. 313 */ 314 public boolean hasName(String name) { 315 return f.getName().equals(name); 316 } 317 318 //----------------------------------------------------------------------------------------------------------------- 319 // Visibility 320 //----------------------------------------------------------------------------------------------------------------- 321 322 /** 323 * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions. 324 * 325 * @return <jk>true</jk> if call was successful. 326 */ 327 public boolean setAccessible() { 328 try { 329 if (! (f.isAccessible())) 330 f.setAccessible(true); 331 return true; 332 } catch (SecurityException e) { 333 return false; 334 } 335 } 336 337 /** 338 * Identifies if the specified visibility matches this field. 339 * 340 * @param v The visibility to validate against. 341 * @return <jk>true</jk> if this visibility matches the modifier attribute of this field. 342 */ 343 public boolean isVisible(Visibility v) { 344 return v.isVisible(f); 345 } 346 347 //----------------------------------------------------------------------------------------------------------------- 348 // Other methods. 349 //----------------------------------------------------------------------------------------------------------------- 350 351 /** 352 * Returns the type of this field. 353 * 354 * @return The type of this field. 355 */ 356 public ClassInfo getType() { 357 if (type == null) 358 type = ClassInfo.of(f.getType()); 359 return type; 360 } 361 362 @Override 363 public String toString() { 364 return f.getDeclaringClass().getName() + "." + f.getName(); 365 } 366 367 @Override 368 public int compareTo(FieldInfo o) { 369 return getName().compareTo(o.getName()); 370 } 371 372 /** 373 * Returns the name of this field. 374 * 375 * @return The name of this field. 376 */ 377 public String getName() { 378 return f.getName(); 379 } 380}