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