Skip to content

Instantly share code, notes, and snippets.

@jesperdj
Last active September 30, 2015 13:31
Show Gist options
  • Save jesperdj/ce2cff083eb48bbbfae2 to your computer and use it in GitHub Desktop.
Save jesperdj/ce2cff083eb48bbbfae2 to your computer and use it in GitHub Desktop.
Utilities for working with Java packages.
/*
* Copyright 2014 Jesper de Jong
*
* Licensed 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.jesperdj.sandbox;
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.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import java.io.IOException;
/**
* Utilities for working with Java packages.
*/
public final class PackageUtils {
private static final String WITH_SUBPACKAGES_PATTERN = "/**/*.class";
private static final String WITHOUT_SUBPACKAGES_PATTERN = "/*.class";
/**
* Callback interface for {@link #doWithClasses(String, boolean, org.jesperdj.sandbox.PackageUtils.ClassCallback)}.
*/
public interface ClassCallback {
/**
* Handle the class that was found.
*
* @param metadataReader Metadata reader from which information about the class that was found can be read,
* without the need for the class being loaded by a JVM classloader.
*/
void doWith(MetadataReader metadataReader);
}
private PackageUtils() {
}
/**
* Calls the specified callback for all classes that are found in the specified package or any subpackage of the
* specified package.
*
* @param basePackage The package in which to search for classes.
* @param callback The callback to be called for each class that is found.
* @throws IOException When an I/O error occurs.
*/
public static void doWithClasses(String basePackage, ClassCallback callback) throws IOException {
doWithClasses(basePackage, true, callback);
}
/**
* Calls the specified callback for all classes that are found in the specified package and optionally all the
* subpackages of the specified package.
*
* @param basePackage The package in which to search for classes.
* @param includeSubPackages {@code true} if subpackages should be included, {@code false} otherwise.
* @param callback The callback to be called for each class that is found.
* @throws IOException When an I/O error occurs.
*/
public static void doWithClasses(String basePackage, boolean includeSubPackages, ClassCallback callback)
throws IOException {
// Inspired by Spring's ClassPathScanningCandidateComponentProvider.findCandidateComponents(String basePackage)
// and Spring's ReflectionUtils
final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(basePackage) +
(includeSubPackages ? WITH_SUBPACKAGES_PATTERN : WITHOUT_SUBPACKAGES_PATTERN);
final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
final MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
for (Resource resource : resourcePatternResolver.getResources(packageSearchPath)) {
if (resource.isReadable()) {
callback.doWith(metadataReaderFactory.getMetadataReader(resource));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment