| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.commons.weaver; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.annotation.Annotation; |
| import java.lang.annotation.ElementType; |
| import java.lang.reflect.AnnotatedElement; |
| import java.lang.reflect.Array; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.IdentityHashMap; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.function.Function; |
| import java.util.function.Predicate; |
| import java.util.function.Supplier; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.commons.lang3.Validate; |
| import org.apache.commons.weaver.model.ScanRequest; |
| import org.apache.commons.weaver.model.ScanResult; |
| import org.apache.commons.weaver.model.Scanner; |
| import org.apache.commons.weaver.model.WeaveInterest; |
| import org.apache.commons.weaver.utils.Annotations; |
| import org.apache.xbean.asm6.AnnotationVisitor; |
| import org.apache.xbean.asm6.ClassReader; |
| import org.apache.xbean.asm6.ClassVisitor; |
| import org.apache.xbean.asm6.FieldVisitor; |
| import org.apache.xbean.asm6.MethodVisitor; |
| import org.apache.xbean.asm6.Opcodes; |
| import org.apache.xbean.asm6.Type; |
| import org.apache.xbean.finder.Annotated; |
| import org.apache.xbean.finder.AnnotationFinder; |
| import org.apache.xbean.finder.Parameter; |
| import org.apache.xbean.finder.archive.Archive; |
| |
| /** |
| * Scanner implementation. |
| */ |
| class Finder extends AnnotationFinder implements Scanner { |
| |
| private abstract class AnnotationInflater extends AnnotationCapturer { |
| final Class<? extends Annotation> annotationType; |
| final Map<String, Object> elements = new LinkedHashMap<>(); |
| |
| AnnotationInflater(final String desc, final AnnotationVisitor wrapped) { |
| super(wrapped); |
| this.annotationType = toClass(Type.getType(desc)).asSubclass(Annotation.class); |
| } |
| |
| Annotation inflate() { |
| return Annotations.instanceOf(annotationType, elements); |
| } |
| |
| @Override |
| protected void storeValue(final String name, final Object value) { |
| Object toStore = value; |
| Validate.notNull(toStore, "null annotation element"); |
| if (toStore.getClass().isArray()) { |
| final Class<?> requiredType; |
| try { |
| requiredType = annotationType.getDeclaredMethod(name).getReturnType(); |
| } catch (final Exception e) { |
| throw new RuntimeException(e); |
| } |
| if (!requiredType.isInstance(toStore)) { |
| final int len = Array.getLength(toStore); |
| final Object typedArray = Array.newInstance(requiredType.getComponentType(), len); |
| for (int i = 0; i < len; i++) { |
| Object element = Array.get(toStore, i); |
| if (element instanceof Type) { |
| element = toClass((Type) element); |
| } |
| Array.set(typedArray, i, element); |
| } |
| toStore = typedArray; |
| } |
| } else if (toStore instanceof Type) { |
| toStore = toClass((Type) toStore); |
| } |
| elements.put(name, toStore); |
| } |
| } |
| |
| private abstract class AnnotationCapturer extends AnnotationVisitor { |
| AnnotationCapturer(final AnnotationVisitor wrapped) { |
| super(ASM_VERSION, wrapped); |
| } |
| |
| /** |
| * Template method for storing an annotation value. |
| * @param name |
| * @param value |
| */ |
| protected abstract void storeValue(String name, Object value); |
| |
| @Override |
| public void visit(final String name, final Object value) { |
| storeValue(name, value); |
| } |
| |
| @Override |
| public AnnotationVisitor visitAnnotation(final String name, final String desc) { |
| final AnnotationCapturer owner = this; |
| return new AnnotationInflater(desc, super.visitAnnotation(name, desc)) { |
| |
| @Override |
| public void visitEnd() { |
| owner.storeValue(name, inflate()); |
| } |
| }; |
| } |
| |
| @Override |
| public AnnotationVisitor visitArray(final String name) { |
| final AnnotationCapturer owner = this; |
| final List<Object> values = new ArrayList<>(); |
| return new AnnotationCapturer(super.visitArray(name)) { |
| |
| @Override |
| public void visitEnd() { |
| owner.storeValue(name, values.toArray()); |
| super.visitEnd(); |
| } |
| |
| @Override |
| protected void storeValue(final String name, final Object value) { |
| values.add(value); |
| } |
| }; |
| } |
| |
| @Override |
| public void visitEnum(final String name, final String desc, final String value) { |
| super.visitEnum(name, desc, value); |
| @SuppressWarnings("rawtypes") |
| final Class<? extends Enum> enumType; |
| try { |
| enumType = Class.forName(Type.getType(desc).getClassName()).asSubclass(Enum.class); |
| } catch (final ClassNotFoundException e) { |
| throw new RuntimeException(e); |
| } |
| @SuppressWarnings("unchecked") |
| final Enum<?> enumValue = Enum.valueOf(enumType, value); |
| storeValue(name, enumValue); |
| } |
| |
| } |
| |
| private class TopLevelAnnotationInflater extends AnnotationInflater { |
| private final Info info; |
| |
| TopLevelAnnotationInflater(final String desc, final AnnotationVisitor wrapped, final Info info) { |
| super(desc, wrapped); |
| this.info = info; |
| } |
| |
| @Override |
| public void visitEnd() { |
| super.visitEnd(); |
| CLASSFILE_ANNOTATIONS.get().computeIfAbsent(info, k -> new ArrayList<>()).add(inflate()); |
| } |
| } |
| |
| /** |
| * Specialized {@link ClassVisitor} to inflate annotations for the info |
| * objects built by a wrapped {@link InfoBuildingVisitor}. |
| */ |
| public class Visitor extends ClassVisitor { |
| private final InfoBuildingVisitor wrapped; |
| |
| Visitor(final InfoBuildingVisitor wrapped) { |
| super(ASM_VERSION, wrapped); |
| this.wrapped = wrapped; |
| } |
| |
| @Override |
| public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, |
| final Object value) { |
| final FieldVisitor toWrap = wrapped.visitField(access, name, desc, signature, value); |
| final ClassInfo classInfo = (ClassInfo) wrapped.getInfo(); |
| final Type fieldType = Type.getType(desc); |
| FieldInfo testFieldInfo = null; |
| // should be the most recently added field, so iterate backward: |
| for (int i = classInfo.getFields().size() - 1; i >= 0; i--) { |
| final FieldInfo atI = classInfo.getFields().get(i); |
| if (atI.getName().equals(name)) { |
| final String type = atI.getType(); |
| if (StringUtils.equals(type, fieldType.getClassName()) |
| || StringUtils.equals(type, fieldType.getDescriptor())) { |
| testFieldInfo = atI; |
| break; |
| } |
| } |
| } |
| if (testFieldInfo == null) { |
| return toWrap; |
| } |
| final FieldInfo fieldInfo = testFieldInfo; |
| return new FieldVisitor(ASM_VERSION, toWrap) { |
| @Override |
| public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { |
| final AnnotationVisitor toWrap = super.visitAnnotation(desc, visible); |
| return visible ? toWrap : new TopLevelAnnotationInflater(desc, toWrap, fieldInfo); |
| } |
| }; |
| } |
| |
| @Override |
| @SuppressWarnings("PMD.UseVarargs") // overridden method |
| public MethodVisitor visitMethod(final int access, final String name, final String desc, |
| final String signature, final String[] exceptions) { |
| final MethodVisitor toWrap = wrapped.visitMethod(access, name, desc, signature, exceptions); |
| final ClassInfo classInfo = (ClassInfo) wrapped.getInfo(); |
| |
| // MethodInfo may not always come from a descriptor, so we must go by the |
| // Member represented. Make sure the method either has a valid name or is a constructor: |
| final MethodInfo compareMethodInfo = new MethodInfo(classInfo, name, desc); |
| if (!compareMethodInfo.isConstructor() && !isJavaIdentifier(name)) { |
| return toWrap; |
| } |
| MethodInfo testMethodInfo = null; |
| // should be the most recently added method, so iterate backward: |
| for (int i = classInfo.getMethods().size() - 1; i >= 0; i--) { |
| final MethodInfo atI = classInfo.getMethods().get(i); |
| if (atI.getName().equals(name) && StringUtils.equals(atI.getDescriptor(), desc)) { |
| testMethodInfo = atI; |
| break; |
| } |
| } |
| if (testMethodInfo == null) { |
| return toWrap; |
| } |
| final MethodInfo methodInfo = testMethodInfo; |
| return new MethodVisitor(ASM_VERSION, toWrap) { |
| @Override |
| public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { |
| final AnnotationVisitor toWrap = super.visitAnnotation(desc, visible); |
| return visible ? toWrap : new TopLevelAnnotationInflater(desc, toWrap, methodInfo); |
| } |
| |
| @Override |
| public AnnotationVisitor visitParameterAnnotation(final int param, final String desc, |
| final boolean visible) { |
| final AnnotationVisitor toWrap = super.visitParameterAnnotation(param, desc, visible); |
| if (visible) { |
| return toWrap; |
| } |
| ParameterInfo parameterInfo = null; |
| |
| // should be the most recently added parameter, so iterate backward: |
| for (int i = methodInfo.getParameters().size() - 1; i >= 0; i--) { |
| final ParameterInfo atI = methodInfo.getParameters().get(i); |
| if (atI.getName().equals(Integer.toString(param))) { |
| parameterInfo = atI; |
| break; |
| } |
| } |
| return parameterInfo == null ? toWrap : new TopLevelAnnotationInflater(desc, toWrap, parameterInfo); |
| } |
| }; |
| } |
| |
| @Override |
| public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { |
| final AnnotationVisitor toWrap = super.visitAnnotation(desc, visible); |
| return visible ? toWrap : new TopLevelAnnotationInflater(desc, toWrap, wrapped.getInfo()); |
| } |
| |
| private boolean isJavaIdentifier(final String toCheck) { |
| if (toCheck.isEmpty() || !Character.isJavaIdentifierStart(toCheck.charAt(0))) { |
| return false; |
| } |
| for (final char chr : toCheck.substring(1).toCharArray()) { |
| if (!Character.isJavaIdentifierPart(chr)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| |
| private static class IncludesClassfile<T extends AnnotatedElement> implements Annotated<T> { |
| private final T annotatedElement; |
| private final Annotation[] annotations; |
| |
| IncludesClassfile(final T annotatedElement, final List<Annotation> classfileAnnotations) { |
| this(annotatedElement, classfileAnnotations.toArray(new Annotation[0])); |
| } |
| |
| @SuppressWarnings("PMD.UseVarargs") // varargs not necessary here |
| IncludesClassfile(final T annotatedElement, final Annotation[] classfileAnnotations) { |
| super(); |
| this.annotatedElement = annotatedElement; |
| this.annotations = ArrayUtils.addAll(annotatedElement.getAnnotations(), classfileAnnotations); |
| } |
| |
| @Override |
| public <A extends Annotation> A getAnnotation(final Class<A> annotationType) { |
| for (final Annotation prospect : annotations) { |
| if (prospect.annotationType().equals(annotationType)) { |
| @SuppressWarnings("unchecked") |
| final A result = (A) prospect; |
| return result; |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public Annotation[] getAnnotations() { |
| final Annotation[] result = new Annotation[annotations.length]; |
| System.arraycopy(annotations, 0, result, 0, annotations.length); |
| return result; |
| } |
| |
| @Override |
| public Annotation[] getDeclaredAnnotations() { |
| return getAnnotations(); |
| } |
| |
| @Override |
| public boolean isAnnotationPresent(final Class<? extends Annotation> annotationType) { |
| return getAnnotation(annotationType) != null; |
| } |
| |
| @Override |
| public T get() { |
| return annotatedElement; |
| } |
| } |
| |
| /** |
| * Helper class for finding elements with annotations (including those with classfile-level retention). |
| */ |
| public final class WithAnnotations { |
| private WithAnnotations() { |
| } |
| |
| public List<Annotated<Package>> findAnnotatedPackages(final Class<? extends Annotation> annotation) { |
| Finder.this.findAnnotatedPackages(annotation); |
| |
| return typed(PackageInfo.class, getAnnotationInfos(annotation.getName())::stream).map(packageInfo -> { |
| try { |
| return new IncludesClassfile<>(packageInfo.get(), classfileAnnotationsFor(packageInfo)); |
| } catch (ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(hasAnnotation(annotation)).collect(Collectors.toList()); |
| } |
| |
| /** |
| * Get the list of objects representing all scanned classes. |
| * @since 1.3 |
| * @return {@link List} of {@link Annotated}{@code <Class<?>>} |
| */ |
| public List<Annotated<Class<?>>> getAllClasses() { |
| return annotate(originalInfos.values()); |
| } |
| |
| public List<Annotated<Class<?>>> findAnnotatedClasses(final Class<? extends Annotation> annotation) { |
| Finder.this.findAnnotatedClasses(annotation); |
| |
| return annotate(getAnnotationInfos(annotation.getName())).stream().filter(hasAnnotation(annotation)) |
| .collect(Collectors.toList()); |
| } |
| |
| private List<Annotated<Class<?>>> annotate(final Collection<? extends Info> infos) { |
| return typed(ClassInfo.class, infos::stream).map(classInfo -> { |
| try { |
| return new IncludesClassfile<Class<?>>(classInfo.get(), classfileAnnotationsFor(classInfo)); |
| } catch (ClassNotFoundException e1) { |
| return null; |
| } |
| }).filter(Objects::nonNull).collect(Collectors.toList()); |
| } |
| |
| public List<Annotated<Class<?>>> findAssignableTypes(final Class<?> supertype) { |
| @SuppressWarnings({ "unchecked", "rawtypes" }) |
| final List<Class<?>> assignableTypes = (List) (supertype.isInterface() |
| ? Finder.this.findImplementations(supertype) : Finder.this.findSubclasses(supertype)); |
| |
| return assignableTypes.stream().map(Class::getName).map(classInfos::get) |
| .<IncludesClassfile<Class<?>>> map(classInfo -> { |
| try { |
| return new IncludesClassfile<>(classInfo.get(), classfileAnnotationsFor(classInfo)); |
| } catch (final ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(Objects::nonNull).collect(Collectors.toList()); |
| } |
| |
| public List<Annotated<Method>> findAnnotatedMethods(final Class<? extends Annotation> annotation) { |
| Finder.this.findAnnotatedMethods(annotation); |
| |
| return typed(MethodInfo.class, getAnnotationInfos(annotation.getName())::stream).filter(CTOR.negate()) |
| .map(methodInfo -> { |
| try { |
| return new IncludesClassfile<>((Method) methodInfo.get(), |
| classfileAnnotationsFor(methodInfo)); |
| } catch (final ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(hasAnnotation(annotation)).collect(Collectors.toList()); |
| } |
| |
| public List<Annotated<Parameter<Method>>> findAnnotatedMethodParameters( |
| final Class<? extends Annotation> annotationType) { |
| Finder.this.findAnnotatedMethodParameters(annotationType); |
| |
| return typed(ParameterInfo.class, getAnnotationInfos(annotationType.getName())::stream) |
| .filter(isCtor(ParameterInfo::getDeclaringMethod).negate()).map(parameterInfo -> { |
| try { |
| @SuppressWarnings("unchecked") |
| final Parameter<Method> parameter = (Parameter<Method>) parameterInfo.get(); |
| return new IncludesClassfile<>(parameter, classfileAnnotationsFor(parameterInfo)); |
| } catch (final ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(hasAnnotation(annotationType)).collect(Collectors.toList()); |
| } |
| |
| public List<Annotated<Constructor<?>>> findAnnotatedConstructors(final Class<? extends Annotation> annotation) { |
| Finder.this.findAnnotatedConstructors(annotation); |
| |
| return typed(MethodInfo.class, getAnnotationInfos(annotation.getName())::stream).filter(CTOR) |
| .map(methodInfo -> { |
| try { |
| final IncludesClassfile<Constructor<?>> annotated = new IncludesClassfile<>( |
| (Constructor<?>) methodInfo.get(), classfileAnnotationsFor(methodInfo)); |
| return annotated; |
| } catch (final ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(hasAnnotation(annotation)).collect(Collectors.toList()); |
| } |
| |
| public List<Annotated<Parameter<Constructor<?>>>> findAnnotatedConstructorParameters( |
| final Class<? extends Annotation> annotation) { |
| Finder.this.findAnnotatedConstructorParameters(annotation); |
| |
| return typed(ParameterInfo.class, getAnnotationInfos(annotation.getName())::stream) |
| .filter(isCtor(ParameterInfo::getDeclaringMethod)).map(parameterInfo -> { |
| try { |
| @SuppressWarnings("unchecked") |
| final Parameter<Constructor<?>> parameter = (Parameter<Constructor<?>>) parameterInfo.get(); |
| return new IncludesClassfile<>(parameter, classfileAnnotationsFor(parameterInfo)); |
| } catch (final ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(hasAnnotation(annotation)).collect(Collectors.toList()); |
| } |
| |
| public List<Annotated<Field>> findAnnotatedFields(final Class<? extends Annotation> annotation) { |
| Finder.this.findAnnotatedFields(annotation); |
| |
| return typed(FieldInfo.class, getAnnotationInfos(annotation.getName())::stream).map(fieldInfo -> { |
| try { |
| return new IncludesClassfile<>((Field) fieldInfo.get(), classfileAnnotationsFor(fieldInfo)); |
| } catch (final ClassNotFoundException e) { |
| return null; |
| } |
| }).filter(hasAnnotation(annotation)).collect(Collectors.toList()); |
| } |
| |
| private List<Annotation> classfileAnnotationsFor(final Info info) { |
| return classfileAnnotations.computeIfAbsent(info, k -> new ArrayList<>()); |
| } |
| } |
| |
| private static final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES; |
| |
| private static final String INIT = "<init>"; |
| |
| /** |
| * ASM version in use. |
| */ |
| static final int ASM_VERSION = Opcodes.ASM6; |
| |
| /** |
| * Ctor {@link Predicate}. |
| */ |
| static final Predicate<MethodInfo> CTOR = methodInfo -> INIT.equals(methodInfo.getName()); |
| |
| /** |
| * The {@link #classfileAnnotations} member stores these; however the scanning takes place in the scope of the super |
| * constructor call, thus there is no opportunity to set the reference beforehand. To work around this, we use a |
| * static ThreadLocal with an initializer and pull/clear its value when we return from the super constructor. :P |
| */ |
| static final ThreadLocal<Map<Info, List<Annotation>>> CLASSFILE_ANNOTATIONS = |
| ThreadLocal.withInitial(IdentityHashMap::new); |
| |
| /** |
| * Filter and cast {@code stream}. |
| * @param type |
| * @param stream |
| * @return {@link Stream} |
| */ |
| static <T, U> Stream<U> typed(final Class<U> type, final Supplier<Stream<T>> stream) { |
| return stream.get().filter(type::isInstance).map(type::cast); |
| } |
| |
| /** |
| * Obtain a {@link Predicate} to test whether an {@link Annotated} instance |
| * hosts annotations of the specified type. |
| * |
| * @param annotation |
| * @return {@link Predicate} |
| */ |
| static Predicate<Annotated<?>> hasAnnotation(final Class<? extends Annotation> annotation) { |
| return annotated -> annotated != null && annotated.isAnnotationPresent(annotation); |
| } |
| |
| /** |
| * Obtain a {@link Predicate} to test whether an argument, once transformed |
| * by the specified {@link Function}, represents a Java constructor. |
| * |
| * @param xform |
| * @return {@link Predicate} |
| */ |
| static <T> Predicate<T> isCtor(final Function<? super T, MethodInfo> xform) { |
| return t -> CTOR.test(xform.apply(t)); |
| } |
| |
| /** |
| * Map of {@link Info} to {@link List} of classfile {@link Annotation}s. |
| */ |
| final Map<Info, List<Annotation>> classfileAnnotations; |
| |
| private final WithAnnotations withAnnotations = new WithAnnotations(); |
| private final Inflater inflater; |
| |
| /** |
| * Create a new {@link Finder} instance. |
| * @param archive |
| */ |
| Finder(final Archive archive) { |
| super(archive, false); |
| classfileAnnotations = CLASSFILE_ANNOTATIONS.get(); |
| CLASSFILE_ANNOTATIONS.remove(); |
| inflater = new Inflater(classfileAnnotations); |
| enableFindImplementations(); |
| enableFindSubclasses(); |
| } |
| |
| /** |
| * Fluent "finder with annotations". |
| * @return {@link WithAnnotations} |
| */ |
| public WithAnnotations withAnnotations() { |
| return withAnnotations; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void readClassDef(final InputStream bytecode) throws IOException { |
| try { |
| new ClassReader(bytecode).accept(new Visitor(new InfoBuildingVisitor()), ASM_FLAGS); |
| } finally { |
| bytecode.close(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public AnnotationFinder select(final Class<?>... arg0) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public AnnotationFinder select(final Iterable<String> clazz) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public AnnotationFinder select(final String... clazz) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public ScanResult scan(final ScanRequest request) { |
| final ScanResult result = new ScanResult(); |
| |
| if (!request.isConstrained() || request.getSupertypes().contains(Object.class)) { |
| for (final Annotated<Class<?>> type : this.withAnnotations().getAllClasses()) { |
| result.getWeavable(type.get()).addAnnotations(type.getAnnotations()); |
| } |
| } else { |
| for (final WeaveInterest interest : request.getInterests()) { |
| final ElementType target = interest.target; |
| switch (target) { |
| case PACKAGE: |
| for (final Annotated<Package> pkg : this.withAnnotations().findAnnotatedPackages( |
| interest.annotationType)) { |
| result.getWeavable(pkg.get()).addAnnotations(pkg.getAnnotations()); |
| } |
| break; |
| case TYPE: |
| for (final Annotated<Class<?>> type : this.withAnnotations().findAnnotatedClasses( |
| interest.annotationType)) { |
| result.getWeavable(type.get()).addAnnotations(type.getAnnotations()); |
| } |
| break; |
| case METHOD: |
| for (final Annotated<Method> method : this.withAnnotations().findAnnotatedMethods( |
| interest.annotationType)) { |
| result.getWeavable(method.get()).addAnnotations(method.getAnnotations()); |
| } |
| break; |
| case CONSTRUCTOR: |
| for (final Annotated<Constructor<?>> ctor : this.withAnnotations().findAnnotatedConstructors( |
| interest.annotationType)) { |
| result.getWeavable(ctor.get()).addAnnotations(ctor.getAnnotations()); |
| } |
| break; |
| case FIELD: |
| for (final Annotated<Field> fld : this.withAnnotations() |
| .findAnnotatedFields(interest.annotationType)) { |
| result.getWeavable(fld.get()).addAnnotations(fld.getAnnotations()); |
| } |
| break; |
| case PARAMETER: |
| for (final Annotated<Parameter<Method>> parameter : this.withAnnotations() |
| .findAnnotatedMethodParameters(interest.annotationType)) { |
| result.getWeavable(parameter.get().getDeclaringExecutable()) |
| .getWeavableParameter(parameter.get().getIndex()) |
| .addAnnotations(parameter.getAnnotations()); |
| } |
| for (final Annotated<Parameter<Constructor<?>>> parameter : this.withAnnotations() |
| .findAnnotatedConstructorParameters(interest.annotationType)) { |
| result.getWeavable(parameter.get().getDeclaringExecutable()) |
| .getWeavableParameter(parameter.get().getIndex()) |
| .addAnnotations(parameter.getAnnotations()); |
| } |
| break; |
| default: |
| // should we log something? |
| break; |
| } |
| } |
| request.getSupertypes().stream().map(this.withAnnotations()::findAssignableTypes) |
| .flatMap(Collection::stream) |
| .forEach(type -> result.getWeavable(type.get()).addAnnotations(type.getAnnotations())); |
| } |
| return inflater.inflate(result); |
| } |
| |
| /** |
| * Transform a {@link java.lang.reflect.Type} instance to a {@link Class}. |
| * @param type |
| * @return {@link Class} |
| */ |
| Class<?> toClass(final Type type) { |
| final String className; |
| if (type.getSort() == Type.ARRAY) { |
| className = type.getElementType().getClassName(); |
| } else { |
| className = type.getClassName(); |
| } |
| Class<?> result; |
| try { |
| result = Class.forName(className); |
| } catch (final ClassNotFoundException e) { |
| try { |
| result = getArchive().loadClass(className); |
| } catch (final ClassNotFoundException e1) { |
| throw new RuntimeException(e1); |
| } |
| } |
| if (type.getSort() == Type.ARRAY) { |
| final int[] dims = new int[type.getDimensions()]; |
| Arrays.fill(dims, 0); |
| result = Array.newInstance(result, dims).getClass(); |
| } |
| return result; |
| } |
| } |