Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine all runtime (but not static) dependencies of Java source by reading the code?

Let's say I wanted to assert that a given Java source folder contained all of the source code required to run any of the programs contained in the source folder. Simply showing that the whole source folder compiles would be insufficient because perhaps some of those programs use reflection to instantiate objects. As such I could search through all the code and look for invocations of newInstance() to learn what classes are expected to be present at runtime. But what about calls to Class.forName(...) that are not involved in calls to newInstance() ? Better check for those as well. But how many such things do I need to check for?

Is there any sort of exhaustive list I could consult to ensure that I am considering each way in Java that such a runtime dependency could be introduced? Restated, does there exist some list of operations such that if I can show none of the source in a source folder use those operations (and that folder compiles) that all (code) dependencies are present?

If no such list exists, could we start one in this thread and make a best effort to cover all operations that we know of?

Edit

I'd like to narrow the question a little. What I'm most interested in showing is that if a codebase compiles, all dependencies are present. It seems to me to do this I would need to first compile the codebase and then check to see if any of the code ever calls certain methods (e.g. newInstance) that could introduce a runtime dependency. If no such methods are found, I'm reasonably sure that all required code is present in source form and running the program will not generate a ClassNotFoundException.

like image 450
Dejas Avatar asked May 22 '17 23:05

Dejas


People also ask

What is runtime dependency in Java?

Compiletime dependencies are only the dependencies (other classes) which you use directly in the class you're compiling. Runtime dependencies covers both the direct and indirect dependencies of the class you're running.

Where are dependencies stored in Java?

Declaring module dependencies Modules are usually stored in a repository, such as Maven Central, a corporate Maven or Ivy repository, or a directory in the local file system.

How do dependencies work in Java?

A Java class has a dependency on another class, if it uses an instance of this class. We call this a class dependency. For example, a class which accesses a logger service has a dependency on this service class. Ideally Java classes should be as independent as possible from other Java classes.


1 Answers

Answer to the original question

There is no extensive way You can do this as far as I know. I mean consider the following code:

public static Object calleableFromAnywhere(Object o) throws IllegalAccessException, InstantiationException {
    Object ret = null;
    if(!Objects.isNull(o)){
        ret = o.getClass().newInstance();
    }
    return ret;
}

In this case You do not even know what kind of dependency You will have at runtime.

If you restrict your search to constructor based object creation only you have a lot of choices also:

Constructor<?> constructor = o.getClass().getConstructor();
//there could be a lot of constructors enclosing different paramethers

Object something = o.getClass().newInstance();
//default constructor called

And even those could be obtained by reflection... The rabbit hole is infinitely deep.

The call You mentioned Class.forName(...) could take any parameter String and those could be given from a database or an input field from the user.

I do not think it is possible to predict all the String variables you could encounter at runtime. If you have anything like this You are not likely to succeed.

TL.DR.: there is no exact solution I know of. According to the question You are not only interested in newInstance or instance creations as you could have static methods on classes as dependency as well. The idea is nice, but there is no 100% solution to this problem.

Narrowed/clarified questions answer

The a newInstance call is not introducing a new dependency. It could be called on a loaded class definition only. (Basically you never get to the newInstance if the class could not be loaded.) So if your goal is to answer with high certainty that if a class will not be represented is an another problem.

Altering the previous example shows that you are not likely to have the definit dependent classes:

public static Class getClass(String name) throws ClassNotFoundException {
    return Class.forName(name);
}

As name could be anything that you can recieve runtime. Also there is an other ways to load classes as the following example shows.

public Class getClassExample1(String name) throws ClassNotFoundException {
    return this.getClass().getClassLoader().loadClass(name);
}

According to the JavaDoc of ClassNotFoundException exception these places are using it:

  • @see java.lang.Class#forName(java.lang.String)
  • @see java.lang.ClassLoader#findSystemClass(java.lang.String)
  • @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)

Those are the places where it is thrown, but you have to check every path to those methods like someInstance.getClass(name).

In addition to runtime dependencies You can encounter NoClassDefFoundError as well. If you are using some containers and set some dependencies as provided for example in maven You can also have some problems runtime, while the compilation was totally fine.

TL.DR.V2: You can only minimize the risk of not having a dependency with a static analysis, but if you want to try it you should check the mentioned methods and all of the call chains (even via reflection) that could lead to these.

like image 199
Hash Avatar answered Nov 06 '22 05:11

Hash