Programmatically define a list of JRE classes that do not need to be imported

I need to programmatically find out which JRE classes can be referenced in a compilation unit without importing (for static code analysis). We can ignore package-local classes. According to JLS, classes from a package are java.langimported implicitly. The result should be a list of binary class names . The solution should work with simple Java 5 and higher (no Guava, Reflections , etc.) and be an agnostic of the provider.

Any reliable Java-based solution is welcome.


Here are some notes on what I have tried so far:

At first glance, it seems that the question boils down to “How to load all classes from a package?”, Which, of course, is almost impossible, although there are several workarounds (for example, this and also blog posts related to them). But my case is much simpler because the problem with multiple class loaders does not exist. java.langstuff can always be loaded by the / bootstrap class loader, and you cannot create your own classes in this package. The problem is that the system class loader does not divulge its path to the class that related applications rely on.

So far, I have not been able to access the classloader class path of the system, because on the HotSpot virtual machine that I use, it Object.class.getClassLoader()returns nullor Thread.currentThread().getContextClassLoader()can be downloaded java.lang.Objectby delegation, but by itself does not include the class path. Therefore, solutions like this do not work for me. In addition, the list of guaranteed system properties does not include properties with this type of route information (for example, sun.boot.class.path).

It would be nice if I did not assume that there is rt.jar at all, and rather scans the list of resources used by the system class loader. This approach would be safer with respect to implementing a vendor-specific JRE.

+3
source share
2

, , java/lang. , , . , , , / jar , .

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;

public class Q21102294 {

public static final String EXTERNAL_JAR = "resources/appboot-1.1.1.jar";
public static final String SAMPLE_CLASS_NAME = "com/descartes/appboot/AppBoot.class";

public static HashSet<String> usedLangClasses = new HashSet<String>();

public static void main(String[] args) {

    try {
        Path f = Paths.get(EXTERNAL_JAR);
        if (!Files.exists(f)) {
            throw new RuntimeException("Could not find file " + f);
        }
        URLClassLoader loader = new URLClassLoader(new URL[] { f.toUri().toURL() }, null);
        findLangClasses(loader, SAMPLE_CLASS_NAME);

        ArrayList<String> sortedClasses = new ArrayList<String>();
        sortedClasses.addAll(usedLangClasses);
        Collections.sort(sortedClasses);
        System.out.println("Loaded classes: ");
        for (String s : sortedClasses) {
            System.out.println(s);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

public static void findLangClasses(URLClassLoader loader, String classResource) throws Exception {

    URL curl = loader.getResource(classResource);
    if (curl != null) {
        System.out.println("Got class as resource.");
    } else {
        throw new RuntimeException("Can't open resource.");
    }
    ByteArrayOutputStream bout = new ByteArrayOutputStream();
    InputStream in = curl.openStream();
    try { 
        byte[] buf = new byte[8192];
        int l = 0;
        while ((l = in.read(buf)) > -1) {
            bout.write(buf, 0, l);
        }
    } finally {
        in.close();
    }
    String ctext = new String(bout.toByteArray(), StandardCharsets.UTF_8);
    int offSet = -1;
    while ((offSet = ctext.indexOf("java/lang/", offSet)) > -1) {
        int beginIndex = offSet;
        offSet += "java/lang/".length();
        char cnext = ctext.charAt(offSet);
        while (cnext != ';' && (cnext == '/' || Character.isAlphabetic(cnext))) {
            offSet += 1;
            cnext = ctext.charAt(offSet);
        }
        String langClass = ctext.substring(beginIndex, offSet);
        //System.out.println("adding class " + langClass);
        usedLangClasses.add(langClass);
    }
}

}

:

Got class as resource.
Loaded classes: 
java/lang/Class
java/lang/ClassLoader
java/lang/Exception
java/lang/Object
java/lang/RuntimeException
java/lang/String
java/lang/StringBuilder
java/lang/System
java/lang/Thread
java/lang/Throwable
java/lang/reflect/Method

.

+1

, . JLS, :

" , java.lang, import java.lang. * ., ."

(http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html)

, , Java...

0

All Articles