001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.commons.weaver.model; 021 022import java.lang.annotation.Annotation; 023import java.lang.reflect.AnnotatedElement; 024import java.lang.reflect.Constructor; 025import java.lang.reflect.Field; 026import java.lang.reflect.Method; 027import java.util.Iterator; 028import java.util.NoSuchElementException; 029import java.util.concurrent.ConcurrentNavigableMap; 030import java.util.concurrent.ConcurrentSkipListMap; 031 032import org.apache.commons.lang3.Validate; 033import org.apache.commons.weaver.WeaveProcessor; 034import org.apache.commons.weaver.spi.Weaver; 035 036/** 037 * <p>Encapsulates the result of scanning based on a {@link ScanRequest}. The 038 * scan results are available in a structure corresponding to the Java class 039 * hierarchy; i.e.: 040 * <pre> 041 * package 042 * |_class 043 * |_field 044 * |_method 045 * | |_method parameter 046 * |_constructor 047 * |_constructor parameter 048 * </pre> 049 * </p><p> 050 * The tree of results can be iterated in this manner using 051 * {@link #getPackages()}. However, if a given {@link Weaver} is known not to 052 * handle packages but some other element, convenience methods are provided 053 * here giving direct access to the various elements that may have been 054 * discovered. 055 * </p> 056 */ 057public class ScanResult { 058 private abstract static class Projection<PARENT, CHILD extends AnnotatedElement> implements 059 AnnotatedElements<CHILD> { 060 private final Iterable<PARENT> parents; 061 062 Projection(final Iterable<PARENT> parents) { 063 super(); 064 this.parents = parents; 065 } 066 067 protected abstract Iterable<CHILD> childrenOf(PARENT parent); 068 069 @Override 070 public Iterator<CHILD> iterator() { 071 final Iterator<PARENT> parentIterator = parents.iterator(); 072 return new Iterator<CHILD>() { 073 private Iterator<CHILD> children = nextChildren(); 074 075 @Override 076 public synchronized boolean hasNext() { 077 return children != null; 078 } 079 080 @Override 081 public synchronized CHILD next() { 082 if (children == null) { 083 throw new NoSuchElementException(); 084 } 085 try { 086 return children.next(); 087 } finally { 088 if (!children.hasNext()) { 089 children = nextChildren(); 090 } 091 } 092 } 093 094 @Override 095 public void remove() { 096 throw new UnsupportedOperationException(); 097 } 098 099 private Iterator<CHILD> nextChildren() { 100 while (parentIterator.hasNext()) { 101 final Iterator<CHILD> prospect = childrenOf(parentIterator.next()).iterator(); 102 if (prospect.hasNext()) { 103 return prospect; 104 } 105 } 106 return null; 107 } 108 }; 109 } 110 111 @Override 112 public AnnotatedElements<CHILD> with(final Class<? extends Annotation> annotationType) { 113 return new AnnotatedWith<CHILD>(this, annotationType); 114 } 115 } 116 117 private static class AnnotatedWith<W extends AnnotatedElement> implements AnnotatedElements<W> { 118 final Iterable<W> wrapped; 119 final Class<? extends Annotation> annotationType; 120 121 AnnotatedWith(final Iterable<W> wrapped, final Class<? extends Annotation> annotationType) { 122 super(); 123 this.wrapped = wrapped; 124 this.annotationType = annotationType; 125 } 126 127 @Override 128 public Iterator<W> iterator() { 129 final Iterator<W> iter = wrapped.iterator(); 130 return new Iterator<W>() { 131 W next = read(); 132 133 private W read() { 134 while (iter.hasNext()) { 135 final W element = iter.next(); 136 if (element.isAnnotationPresent(annotationType)) { 137 return element; 138 } 139 } 140 return null; 141 } 142 143 @Override 144 public boolean hasNext() { 145 return next != null; 146 } 147 148 @Override 149 public W next() { 150 if (next == null) { 151 throw new NoSuchElementException(); 152 } 153 try { 154 return next; 155 } finally { 156 next = read(); 157 } 158 } 159 160 @Override 161 public void remove() { 162 throw new UnsupportedOperationException(); 163 } 164 }; 165 } 166 167 @Override 168 public AnnotatedElements<W> with(final Class<? extends Annotation> annotationType) { 169 return new AnnotatedWith<W>(this, annotationType); 170 } 171 172 } 173 174 private final ConcurrentNavigableMap<String, WeavablePackage> packages = 175 new ConcurrentSkipListMap<String, WeavablePackage>(); 176 177 /** 178 * Public for use by {@link WeaveProcessor}. 179 * @param pkg to wrap 180 * @return {@link WeavablePackage} 181 */ 182 public WeavablePackage getWeavable(final Package pkg) { 183 final String key = pkg.getName(); 184 if (packages.containsKey(key)) { 185 return packages.get(key); 186 } 187 final WeavablePackage result = new WeavablePackage(pkg); 188 final WeavablePackage faster = packages.putIfAbsent(key, result); 189 return faster == null ? result : faster; 190 } 191 192 /** 193 * Public for use by {@link WeaveProcessor}. 194 * @param cls to wrap 195 * @param <T> type 196 * @return {@link WeavableClass} 197 */ 198 public <T> WeavableClass<T> getWeavable(final Class<T> cls) { 199 return getWeavable(cls.getPackage()).getWeavable(cls); 200 } 201 202 /** 203 * Public for use by {@link WeaveProcessor}. 204 * @param fld to wrap 205 * @return {@link WeavableField} 206 */ 207 public WeavableField<?> getWeavable(final Field fld) { 208 return getWeavable(fld.getDeclaringClass()).getWeavable(fld); 209 } 210 211 /** 212 * Public for use by {@link WeaveProcessor}. 213 * @param methd to wrap 214 * @return {@link WeavableMethod} 215 */ 216 public WeavableMethod<?> getWeavable(final Method methd) { 217 return getWeavable(methd.getDeclaringClass()).getWeavable(methd); 218 } 219 220 /** 221 * Public for use by {@link WeaveProcessor}. 222 * @param ctor to wrap 223 * @param <T> type 224 * @return {@link WeavableConstructor} 225 */ 226 public <T> WeavableConstructor<T> getWeavable(final Constructor<T> ctor) { 227 return getWeavable(ctor.getDeclaringClass()).getWeavable(ctor); 228 } 229 230 /** 231 * Iterate or filter {@link WeavablePackage}s. 232 * @return {@link AnnotatedElements} 233 */ 234 public AnnotatedElements<WeavablePackage> getPackages() { 235 return new AnnotatedElements<WeavablePackage>() { 236 237 @Override 238 public Iterator<WeavablePackage> iterator() { 239 return packages.values().iterator(); 240 } 241 242 @Override 243 public AnnotatedElements<WeavablePackage> with(final Class<? extends Annotation> annotationType) { 244 return new AnnotatedWith<WeavablePackage>(packages.values(), annotationType); 245 } 246 }; 247 } 248 249 /** 250 * Iterate or filter {@link WeavableClass}es. 251 * @return {@link AnnotatedElements} 252 */ 253 public AnnotatedElements<WeavableClass<?>> getClasses() { 254 return new Projection<WeavablePackage, WeavableClass<?>>(getPackages()) { 255 256 @Override 257 protected Iterable<WeavableClass<?>> childrenOf(final WeavablePackage parent) { 258 return parent.getClasses(); 259 } 260 }; 261 } 262 263 /** 264 * Iterate or filter {@link WeavableClass}es assignable to {@code supertype}. 265 * @param supertype {@link Class} whose subtypes are sought 266 * @return {@link AnnotatedElements} 267 */ 268 public AnnotatedElements<WeavableClass<?>> getClassesAssignableTo(final Class<?> supertype) { 269 Validate.notNull(supertype, "supertype"); 270 271 return new Projection<WeavablePackage, WeavableClass<?>>(getPackages()) { 272 273 @Override 274 protected Iterable<WeavableClass<?>> childrenOf(final WeavablePackage parent) { 275 return parent.getClasses(); 276 } 277 278 @Override 279 public Iterator<WeavableClass<?>> iterator() { 280 final Iterator<WeavableClass<?>> toWrap = super.iterator(); 281 return new Iterator<WeavableClass<?>>() { 282 { 283 read(); 284 } 285 286 private WeavableClass<?> next; 287 288 private void read() { 289 while (toWrap.hasNext()) { 290 final WeavableClass<?> test = toWrap.next(); 291 if (supertype.isAssignableFrom(test.getTarget())) { 292 next = test; 293 return; 294 } 295 } 296 next = null; 297 } 298 299 @Override 300 public boolean hasNext() { 301 return next != null; 302 } 303 304 @Override 305 public WeavableClass<?> next() { 306 try { 307 return next; 308 } finally { 309 read(); 310 } 311 } 312 313 @Override 314 public void remove() { 315 toWrap.remove(); 316 } 317 }; 318 } 319 }; 320 } 321 322 /** 323 * Iterate or filter {@link WeavableField}s. 324 * @return {@link AnnotatedElements} 325 */ 326 public AnnotatedElements<WeavableField<?>> getFields() { 327 return new Projection<WeavableClass<?>, WeavableField<?>>(getClasses()) { 328 329 @Override 330 protected Iterable<WeavableField<?>> childrenOf(final WeavableClass<?> parent) { 331 @SuppressWarnings({ "unchecked", "rawtypes" }) 332 final Iterable<WeavableField<?>> result = ((WeavableClass) parent).getFields(); 333 return result; 334 } 335 }; 336 } 337 338 /** 339 * Iterate or filter {@link WeavableConstructor}s. 340 * @return {@link AnnotatedElements} 341 */ 342 public AnnotatedElements<WeavableConstructor<?>> getConstructors() { 343 return new Projection<WeavableClass<?>, WeavableConstructor<?>>(getClasses()) { 344 345 @Override 346 protected Iterable<WeavableConstructor<?>> childrenOf(final WeavableClass<?> parent) { 347 @SuppressWarnings({ "unchecked", "rawtypes" }) 348 final Iterable<WeavableConstructor<?>> result = ((WeavableClass) parent).getConstructors(); 349 return result; 350 } 351 }; 352 } 353 354 /** 355 * Iterate or filter {@link WeavableMethod}s. 356 * @return {@link AnnotatedElements} 357 */ 358 public AnnotatedElements<WeavableMethod<?>> getMethods() { 359 return new Projection<WeavableClass<?>, WeavableMethod<?>>(getClasses()) { 360 361 @Override 362 protected Iterable<WeavableMethod<?>> childrenOf(final WeavableClass<?> parent) { 363 @SuppressWarnings({ "unchecked", "rawtypes" }) 364 final Iterable<WeavableMethod<?>> result = ((WeavableClass) parent).getMethods(); 365 return result; 366 } 367 }; 368 } 369 370 /** 371 * Iterate or filter {@link WeavableMethodParameter}s. 372 * @return {@link AnnotatedElements} 373 */ 374 public AnnotatedElements<WeavableMethodParameter<?>> getMethodParameters() { 375 return new Projection<WeavableMethod<?>, WeavableMethodParameter<?>>(getMethods()) { 376 377 @Override 378 protected Iterable<WeavableMethodParameter<?>> childrenOf(final WeavableMethod<?> parent) { 379 @SuppressWarnings({ "unchecked", "rawtypes" }) 380 final Iterable<WeavableMethodParameter<?>> result = ((WeavableMethod) parent).getParameters(); 381 return result; 382 } 383 }; 384 } 385 386 /** 387 * Iterate or filter {@link WeavableConstructorParameter}s. 388 * @return {@link AnnotatedElements} 389 */ 390 public AnnotatedElements<WeavableConstructorParameter<?>> getConstructorParameters() { 391 392 return new Projection<WeavableConstructor<?>, WeavableConstructorParameter<?>>(getConstructors()) { 393 394 @Override 395 protected Iterable<WeavableConstructorParameter<?>> childrenOf(final WeavableConstructor<?> parent) { 396 @SuppressWarnings({ "unchecked", "rawtypes" }) 397 final Iterable<WeavableConstructorParameter<?>> result = ((WeavableConstructor) parent).getParameters(); 398 return result; 399 } 400 }; 401 } 402 403}