/** * 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.cxf.common.util; import java.io.IOException; import java.lang.annotation.Annotation; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import org.apache.cxf.common.classloader.ClassLoaderUtils; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.util.ClassUtils; class SpringClasspathScanner extends ClasspathScanner { private static final Boolean IN_OSGI; static { IN_OSGI = isSpringInOsgi(); } SpringClasspathScanner() throws Exception { Class.forName("org.springframework.core.io.support.PathMatchingResourcePatternResolver"); Class.forName("org.springframework.core.type.classreading.CachingMetadataReaderFactory"); } private static boolean isSpringInOsgi() { try { Class.forName("org.springframework.osgi.io.OsgiBundleResourcePatternResolver"); Class.forName("org.springframework.osgi.util.BundleDelegatingClassLoader"); return true; } catch (Throwable ex) { return false; } } protected Map< Class< ? extends Annotation >, Collection< Class< ? > > > findClassesInternal( Collection< String > basePackages, List<Class< ? extends Annotation > > annotations, ClassLoader loader) throws IOException, ClassNotFoundException { ResourcePatternResolver resolver = getResolver(loader); MetadataReaderFactory factory = new CachingMetadataReaderFactory(resolver); final Map< Class< ? extends Annotation >, Collection< Class< ? > > > classes = new HashMap< Class< ? extends Annotation >, Collection< Class< ? > > >(); final Map< Class< ? extends Annotation >, Collection< String > > matchingInterfaces = new HashMap< Class< ? extends Annotation >, Collection< String > >(); final Map<String, String[]> nonMatchingClasses = new HashMap<>(); for (Class< ? extends Annotation > annotation: annotations) { classes.put(annotation, new HashSet< Class < ? > >()); matchingInterfaces.put(annotation, new HashSet< String >()); } if (basePackages == null || basePackages.isEmpty()) { return classes; } for (final String basePackage: basePackages) { final boolean scanAllPackages = basePackage.equals(WILDCARD); final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + (scanAllPackages ? "" : ClassUtils.convertClassNameToResourcePath(basePackage)) + ALL_CLASS_FILES; final Resource[] resources = resolver.getResources(packageSearchPath); for (final Resource resource: resources) { final MetadataReader reader = factory.getMetadataReader(resource); final AnnotationMetadata metadata = reader.getAnnotationMetadata(); if (scanAllPackages && shouldSkip(metadata.getClassName())) { continue; } for (Class< ? extends Annotation > annotation: annotations) { boolean concreteClass = !metadata.isInterface() && !metadata.isAbstract(); if (metadata.isAnnotated(annotation.getName())) { if (concreteClass) { classes.get(annotation).add(loadClass(metadata.getClassName(), loader)); } else { matchingInterfaces.get(annotation).add(metadata.getClassName()); } } else if (concreteClass && metadata.getInterfaceNames().length > 0) { nonMatchingClasses.put(metadata.getClassName(), metadata.getInterfaceNames()); } } } } if (!nonMatchingClasses.isEmpty()) { for (Map.Entry<Class<? extends Annotation>, Collection<String>> e1 : matchingInterfaces.entrySet()) { for (Map.Entry<String, String[]> e2 : nonMatchingClasses.entrySet()) { for (String intName : e2.getValue()) { if (e1.getValue().contains(intName)) { classes.get(e1.getKey()).add(loadClass(e2.getKey(), loader)); break; } } } } } for (Map.Entry<Class<? extends Annotation>, Collection<String>> e : matchingInterfaces.entrySet()) { if (classes.get(e.getKey()).isEmpty()) { for (String intName : e.getValue()) { classes.get(e.getKey()).add(loadClass(intName, loader)); } } } return classes; } protected List<URL> findResourcesInternal(Collection<String> basePackages, String extension, ClassLoader loader) throws IOException { final List<URL> resourceURLs = new ArrayList<>(); if (basePackages == null || basePackages.isEmpty()) { return resourceURLs; } ResourcePatternResolver resolver = getResolver(loader); for (final String basePackage: basePackages) { final boolean scanAllPackages = basePackage.equals(WILDCARD); String theBasePackage = basePackage; if (theBasePackage.startsWith(CLASSPATH_URL_SCHEME)) { theBasePackage = theBasePackage.substring(CLASSPATH_URL_SCHEME.length()); } final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + (scanAllPackages ? "" : basePackage.contains(WILDCARD) ? basePackage : ClassUtils.convertClassNameToResourcePath(theBasePackage)) + ALL_FILES + "." + extension; final Resource[] resources = resolver.getResources(packageSearchPath); for (final Resource resource: resources) { resourceURLs.add(resource.getURL()); } } return resourceURLs; } private ResourcePatternResolver getResolver(ClassLoader loader) { ResourcePatternResolver resolver = null; if (IN_OSGI) { resolver = SpringOsgiUtil.getResolver(loader); } if (resolver == null) { resolver = loader != null ? new PathMatchingResourcePatternResolver(loader) : new PathMatchingResourcePatternResolver(); } return resolver; } private boolean shouldSkip(final String classname) { for (String packageToSkip: PACKAGES_TO_SKIP) { if (classname.startsWith(packageToSkip)) { return true; } } return false; } private Class<?> loadClass(String className, ClassLoader loader) throws ClassNotFoundException { if (loader == null) { return ClassLoaderUtils.loadClass(className, getClass()); } else { return loader.loadClass(className); } } }