use of org.gradle.util.internal.PatchedClassReader in project gradle by gradle.
the class ValidateTaskProperties method validateTaskClasses.
private void validateTaskClasses(final ClassLoader classLoader) throws IOException {
final Map<String, Boolean> taskValidationProblems = Maps.newTreeMap();
final Class<?> taskInterface;
final Method validatorMethod;
try {
taskInterface = classLoader.loadClass(Task.class.getName());
Class<?> validatorClass = classLoader.loadClass("org.gradle.api.internal.tasks.properties.PropertyValidationAccess");
validatorMethod = validatorClass.getMethod("collectTaskValidationProblems", Class.class, Map.class);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
getClasses().getAsFileTree().visit(new EmptyFileVisitor() {
@Override
public void visitFile(FileVisitDetails fileDetails) {
if (!fileDetails.getPath().endsWith(".class")) {
return;
}
ClassReader reader;
try {
reader = new PatchedClassReader(Files.asByteSource(fileDetails.getFile()).read());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
List<String> classNames = Lists.newArrayList();
reader.accept(new TaskNameCollectorVisitor(classNames), ClassReader.SKIP_CODE);
for (String className : classNames) {
Class<?> clazz;
try {
clazz = classLoader.loadClass(className);
} catch (IllegalAccessError e) {
throw new GradleException("Could not load class: " + className, e);
} catch (ClassNotFoundException e) {
throw new GradleException("Could not load class: " + className, e);
} catch (NoClassDefFoundError e) {
throw new GradleException("Could not load class: " + className, e);
}
if (!Modifier.isPublic(clazz.getModifiers())) {
continue;
}
if (Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
if (!taskInterface.isAssignableFrom(clazz)) {
continue;
}
Class<? extends Task> taskClass = Cast.uncheckedCast(clazz);
try {
validatorMethod.invoke(null, taskClass, taskValidationProblems);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
});
List<String> problemMessages = toProblemMessages(taskValidationProblems);
storeResults(problemMessages);
communicateResult(problemMessages, taskValidationProblems.values().contains(Boolean.TRUE));
}
use of org.gradle.util.internal.PatchedClassReader in project gradle by gradle.
the class ClasspathInferer method find.
/**
* Locates the classpath required by the given target class. Traverses the dependency graph of classes used by the specified class and collects the result in the given collection.
*/
private void find(Class<?> target, Collection<Class<?>> visited, Collection<URL> dest) {
ClassLoader targetClassLoader = target.getClassLoader();
if (targetClassLoader == null || targetClassLoader == ClassLoaderUtils.getPlatformClassLoader()) {
// A system class, skip it
return;
}
if (!visited.add(target)) {
// Already seen this class, skip it
return;
}
String resourceName = target.getName().replace('.', '/') + ".class";
URL resource = targetClassLoader.getResource(resourceName);
try {
if (resource == null) {
LOGGER.warn("Could not determine classpath for {}", target);
return;
}
File classPathRoot = ClasspathUtil.getClasspathForClass(target);
dest.add(classPathRoot.toURI().toURL());
// To determine the dependencies of the class, load up the byte code and look for CONSTANT_Class entries in the constant pool
ClassReader reader;
URLConnection urlConnection = resource.openConnection();
if (urlConnection instanceof JarURLConnection) {
// Using the caches for these connections leaves the Jar files open. Don't use the cache, so that the Jar file is closed when the stream is closed below
// There are other options for solving this that may be more performant. However a class is inspected this way once and the result reused, so this approach is probably fine
urlConnection.setUseCaches(false);
}
InputStream inputStream = urlConnection.getInputStream();
try {
reader = new PatchedClassReader(ByteStreams.toByteArray(inputStream));
} finally {
inputStream.close();
}
char[] charBuffer = new char[reader.getMaxStringLength()];
for (int i = 1; i < reader.getItemCount(); i++) {
int itemOffset = reader.getItem(i);
if (itemOffset > 0 && reader.readByte(itemOffset - 1) == 7) {
// A CONSTANT_Class entry, read the class descriptor
String classDescriptor = reader.readUTF8(itemOffset, charBuffer);
Type type = Type.getObjectType(classDescriptor);
while (type.getSort() == Type.ARRAY) {
type = type.getElementType();
}
if (type.getSort() != Type.OBJECT) {
// A primitive type
continue;
}
String className = type.getClassName();
if (className.equals(target.getName())) {
// A reference to this class
continue;
}
Class<?> cl;
try {
cl = Class.forName(className, false, targetClassLoader);
} catch (ClassNotFoundException e) {
// This is fine, just ignore it
LOGGER.warn("Could not determine classpath for {}", target);
continue;
}
find(cl, visited, dest);
}
}
} catch (Exception e) {
throw new GradleException(String.format("Could not determine the class-path for %s.", target), e);
}
}
use of org.gradle.util.internal.PatchedClassReader in project gradle by gradle.
the class ApiJar method createApiJar.
@TaskAction
public void createApiJar() throws IOException {
// Make sure all entries are always written in the same order
final List<File> sourceFiles = sortedSourceFiles();
final ApiClassExtractor apiClassExtractor = new ApiClassExtractor(getExportedPackages());
withResource(new JarOutputStream(new BufferedOutputStream(new FileOutputStream(getOutputFile()), 65536)), new ErroringAction<JarOutputStream>() {
@Override
protected void doExecute(final JarOutputStream jos) throws Exception {
writeManifest(jos);
writeClasses(jos);
}
private void writeManifest(JarOutputStream jos) throws IOException {
writeEntry(jos, "META-INF/MANIFEST.MF", "Manifest-Version: 1.0\n".getBytes());
}
private void writeClasses(JarOutputStream jos) throws Exception {
for (File sourceFile : sourceFiles) {
if (!isClassFile(sourceFile)) {
continue;
}
ClassReader classReader = new PatchedClassReader(readFileToByteArray(sourceFile));
if (!apiClassExtractor.shouldExtractApiClassFrom(classReader)) {
continue;
}
byte[] apiClassBytes = apiClassExtractor.extractApiClassFrom(classReader);
if (apiClassBytes == null) {
// Should be excluded
continue;
}
String internalClassName = classReader.getClassName();
String entryPath = internalClassName + ".class";
writeEntry(jos, entryPath, apiClassBytes);
}
}
private void writeEntry(JarOutputStream jos, String name, byte[] bytes) throws IOException {
JarEntry je = new JarEntry(name);
// Setting time to 0 because we need API jars to be identical independently of
// the timestamps of class files
je.setTime(0);
je.setSize(bytes.length);
jos.putNextEntry(je);
jos.write(bytes);
jos.closeEntry();
}
});
}
Aggregations