aboutsummaryrefslogtreecommitdiffstats
path: root/compatibility-server/src/test/java/com/vaadin/tests/server/ClasspathHelper.java
blob: d32718196b2aac51a955e20d8e5513fbd730cdda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package com.vaadin.tests.server;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Allows to get classes from the current classpath using classes FQN filter.
 * <p>
 * The methods in the class return all real (not anonymous and not private)
 * classes from the filtered classpath.
 * 
 * @author Vaadin Ltd
 *
 */
class ClasspathHelper {

    private final Predicate<String> skipClassesFilter;

    ClasspathHelper(Predicate<String> skipClassesFilter) {
        this.skipClassesFilter = skipClassesFilter;
    }

    Stream<Class<?>> getVaadinClassesFromClasspath(
            Predicate<String> classpathFilter,
            Predicate<Class<?>> classFilter) {
        return getRawClasspathEntries().stream().filter(classpathFilter)
                .map(File::new).map(file -> getVaadinClassesFromFile(file))
                .flatMap(List::stream).filter(classFilter)
                .filter(cls -> !cls.isSynthetic() && !cls.isAnonymousClass()
                        && !Modifier.isPrivate(cls.getModifiers()));

    }

    Stream<Class<?>> getVaadinClassesFromClasspath(
            Predicate<String> classpathFilter) {
        return getVaadinClassesFromClasspath(classpathFilter, cls -> true);
    }

    private List<Class<?>> getVaadinClassesFromFile(File classesRoot) {
        try {
            if (classesRoot.isDirectory()) {
                return Files.walk(classesRoot.toPath())
                        .filter(Files::isRegularFile)
                        .filter(path -> path.toFile().getName()
                                .endsWith(".class"))
                        .filter(path -> classesRoot.toPath().relativize(path)
                                .toString().contains("com/vaadin/"))
                        .map(path -> getClassFromFile(path,
                                classesRoot.toPath()))
                        .filter(Objects::nonNull).collect(Collectors.toList());
            } else if (classesRoot.getName().toLowerCase(Locale.ENGLISH)
                    .endsWith(".jar")) {
                URI uri = URI.create("jar:file:" + classesRoot.getPath());
                Path root = FileSystems
                        .newFileSystem(uri, Collections.emptyMap())
                        .getPath("/");
                return Files.walk(root).filter(Files::isRegularFile)
                        .filter(path -> path.toUri().getSchemeSpecificPart()
                                .endsWith(".class"))
                        .filter(path -> root.relativize(path).toString()
                                .contains("com/vaadin/"))
                        .map(path -> getClassFromFile(path, root))
                        .filter(Objects::nonNull).collect(Collectors.toList());
            }
            return null;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Class<?> getClassFromFile(Path path, Path root) {
        Path relative = root.relativize(path);
        String name = relative.toString();
        name = name.substring(0, name.length() - ".class".length());
        name = name.replace('/', '.');
        if (skipClassesFilter.test(name)) {
            return null;
        }
        try {
            return Class.forName(name, false, getClass().getClassLoader());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private final static List<String> getRawClasspathEntries() {
        List<String> locations = new ArrayList<>();

        String pathSep = System.getProperty("path.separator");
        String classpath = System.getProperty("java.class.path");

        if (classpath.startsWith("\"")) {
            classpath = classpath.substring(1);
        }
        if (classpath.endsWith("\"")) {
            classpath = classpath.substring(0, classpath.length() - 1);
        }

        String[] split = classpath.split(pathSep);
        for (int i = 0; i < split.length; i++) {
            String classpathEntry = split[i];
            locations.add(classpathEntry);
        }

        return locations;
    }

}