Search in sources :

Example 6 with PatchedClassReader

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));
}
Also used : Task(org.gradle.api.Task) VerificationTask(org.gradle.api.tasks.VerificationTask) ConventionTask(org.gradle.api.internal.ConventionTask) CacheableTask(org.gradle.api.tasks.CacheableTask) UncheckedIOException(org.gradle.api.UncheckedIOException) PatchedClassReader(org.gradle.util.internal.PatchedClassReader) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) EmptyFileVisitor(org.gradle.api.file.EmptyFileVisitor) Method(java.lang.reflect.Method) UncheckedIOException(org.gradle.api.UncheckedIOException) IOException(java.io.IOException) InvocationTargetException(java.lang.reflect.InvocationTargetException) FileVisitDetails(org.gradle.api.file.FileVisitDetails) GradleException(org.gradle.api.GradleException) PatchedClassReader(org.gradle.util.internal.PatchedClassReader) ClassReader(org.objectweb.asm.ClassReader) Map(java.util.Map)

Example 7 with PatchedClassReader

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);
    }
}
Also used : JarURLConnection(java.net.JarURLConnection) InputStream(java.io.InputStream) PatchedClassReader(org.gradle.util.internal.PatchedClassReader) URL(java.net.URL) URLConnection(java.net.URLConnection) JarURLConnection(java.net.JarURLConnection) GradleException(org.gradle.api.GradleException) Type(org.objectweb.asm.Type) GradleException(org.gradle.api.GradleException) PatchedClassReader(org.gradle.util.internal.PatchedClassReader) ClassReader(org.objectweb.asm.ClassReader) File(java.io.File)

Example 8 with PatchedClassReader

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();
        }
    });
}
Also used : JarOutputStream(java.util.jar.JarOutputStream) ApiClassExtractor(org.gradle.api.internal.tasks.compile.ApiClassExtractor) IOException(java.io.IOException) JarEntry(java.util.jar.JarEntry) PatchedClassReader(org.gradle.util.internal.PatchedClassReader) IOException(java.io.IOException) FileOutputStream(java.io.FileOutputStream) PatchedClassReader(org.gradle.util.internal.PatchedClassReader) ClassReader(org.objectweb.asm.ClassReader) File(java.io.File) OutputFile(org.gradle.api.tasks.OutputFile) BufferedOutputStream(java.io.BufferedOutputStream) TaskAction(org.gradle.api.tasks.TaskAction)

Aggregations

PatchedClassReader (org.gradle.util.internal.PatchedClassReader)8 ClassReader (org.objectweb.asm.ClassReader)8 IOException (java.io.IOException)3 GradleException (org.gradle.api.GradleException)3 File (java.io.File)2 InputStream (java.io.InputStream)2 ApiClassExtractor (org.gradle.api.internal.tasks.compile.ApiClassExtractor)2 ImmutableList (com.google.common.collect.ImmutableList)1 IntSet (it.unimi.dsi.fastutil.ints.IntSet)1 BufferedInputStream (java.io.BufferedInputStream)1 BufferedOutputStream (java.io.BufferedOutputStream)1 FileInputStream (java.io.FileInputStream)1 FileOutputStream (java.io.FileOutputStream)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Method (java.lang.reflect.Method)1 JarURLConnection (java.net.JarURLConnection)1 URL (java.net.URL)1 URLConnection (java.net.URLConnection)1 List (java.util.List)1 Map (java.util.Map)1