10

I have the source for a java program, but I don't have it's dependencies. Is it possible to compile Java code that uses fields, classes and methods that can't be resolved? If not, is there a program or Eclipse plugin that will automatically generate fake classes, variables and methods that can't be resolved during the compilation? Please give examples.

public class Main {
    public static void main(String[] args) {
        // ...
        UnknownClass.unknownMethod();
    }
}

I want it to automatically generate the Class UnknownClass with a method unknownMethod():

public class UnknownClass {
    public static void unknownMethod() {}
}

But not export it in the output .jar

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Victor2748
  • 4,149
  • 13
  • 52
  • 89
  • 2
    If you need the dependencies for those classes, you can either download them yourself and place them on the classpath, or use a tool like Maven or Gradle to manage and download them for you. – Makoto Jul 14 '14 at 00:49
  • 2
    No, they are not for download, is it possible to simply generate a fake methods and variables during the compilation to compile code that calls unknown methods? – Victor2748 Jul 14 '14 at 00:51
  • 1
    In theory you could...but that's not going to work in practice, since the code obviously depends on those classes being there. If you can't download those dependencies for whatever reason, you may be stuck. – Makoto Jul 14 '14 at 00:52
  • 1
    @Makoto You mean, that when Java code compiles, it uses information from the used classes and methods? Then how do people create APIs? – Victor2748 Jul 14 '14 at 00:54
  • It is possible to obfuscate Java code, have a look at [Java ProGuard](http://proguard.sourceforge.net/). – ForguesR Jul 14 '14 at 00:54
  • It needs a class to satisfy the signature provided. You could stub them out but I really, *really* doubt that's going to give you the behavior you want. – Makoto Jul 14 '14 at 00:54
  • 1
    @Makoto But how do people create APIs? for example Bukkit and craftbukkit (http://bukkit.org). Craftbukkit is the actual program, and Bukkit is just the API that only contains the methods, but no inner code. However when a plugin is compiled for Bukkit, it works with CraftBukkit as well. – Victor2748 Jul 14 '14 at 00:57
  • @Victor2748 - Why do you want to do this ? If it is for testing, then see if you can get access to some `mock objects`. – Erran Morad Jul 14 '14 at 00:58
  • @Victor2748 In your exemple of craftbukkit, You can download craftbukkit jar build with some reaserch and with help of doc and putting the jar in your classpath compile a program that use the jar methods. –  Jul 14 '14 at 01:01
  • 1
    @CarlierRobin But it is also possible without craftbukkit.jar, and just with Bukkit.jar (which is the API), and your plugin will work with the craftbukkit.jar as well. – Victor2748 Jul 14 '14 at 01:05

1 Answers1

5

Is it possible to compile Java code that uses fields, classes and methods that can't be resolved?

No. The static dependencies for your source code must all be available at compile time.

If not, is there a program or Eclipse plugin that will automatically generate fake classes, variables and methods that can't be resolved during the compilation?

AFAIK, No.

In fact, I think that it is technically impossible to build such a program. It would entail inferring signatures for classes and methods that we don't have any information about. I don't think it is possible to do that accurately; i.e. accurately enough that the signatures would match the actual signatures of the real classes.

(Some of the problems that would need to be resolved are inferring the correct supertypes for classes, inferring the correct types for arguments and results of methods, inferring whether a method has varargs, inferring whether a method exists with overloads, and so on. Some of these problems are tractable, some are definitely not.)


But how did Bukkit did it with CraftBukkit.jar and Bukkit.jar? in Bukkit.jar, there are the method headers with no inner code, however when compiling your code for BUkkit.jar, it works with Craftbukkit.jar.

I think you have answered your own question. The class hierarchy and the method headers are in the Bukkit JAR file that is provided. Therefore, they don't need to be inferred.

By contrast, what you are asking to do here is to infer the classes hierarchy and method signatures from a clean slate ... plus some constraints implied by the code (your source code) that uses them.


Here is an example:

   UnknownClass c = ...
   c.method(42);
   c.method(42.0);

There are multiple different solutions to that:

   public class UnknownClass ... {
       void method(double arg) {...}
   }

   public class UnknownClass ... {
       int method(double arg) {...}
   }

   public class UnknownClass ... {
       void method(int arg) {...}
       void method(double arg) {...}
   }

   public class UnknownClass ... {
       void method(byte arg) {...}
       void method(double arg) {...}
   }

   public class UnknownClass ... {
       void method(double... arg) {...}
   }

and so on.

Question: Which is the correct one; i.e. the one that is going to match the actual signatures in the real UnknownClass?

Answer: We have no way of knowing! And it DOES matter, because if we get it wrong there are likely to be classloader errors when you attempt to run the compiled code against the JAR containing the real class.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • But how did Bukkit did it with CraftBukkit.jar and Bukkit.jar? in Bukkit.jar, there are the method headers with no inner code, however when compiling your code for BUkkit.jar, it works with Craftbukkit.jar. – Victor2748 Jul 14 '14 at 01:11
  • And do you mean that compiled code contains more information than the source? – Victor2748 Jul 14 '14 at 01:11
  • @Victor2748 - No. That's not the issue. – Stephen C Jul 14 '14 at 01:19
  • Agreed inferring signatures accurately is a difficult problem (and that it may not match the missing library), however I wouldn't necessarily say it's impossible. Eclipse is quite capable of generating valid class files even if you have a big typo and red squiggle in the middle of its source (only to throw an exception when you try to run that part of the code, but that's a different issue). There are also automatic suggestions to create methods. A code analysis tool that would prepare stubs of missing from from an existing code base doesn't seem out of reach (with some effort indeed). – Bruno Jul 14 '14 at 01:19
  • @Bruno - It is not simply a matter of generating a possible solution. The solution has to match the actual signatures in the classes. In reality, there can be multiple different solutions, that satisfy the constraints; see example. The problem is that if you infer the wrong one, you generate code that fails at runtime due to binary incompatibility. In short, the "tool" is unreliable ... probably to the point of being useless. – Stephen C Jul 14 '14 at 01:42
  • @Bruno - It is true that Eclipse will generate code in such cases (modulo your Eclipse preferences). But that code *may* not load, and it certainly won't run. The methods that contain the compilation errors are "implemented" as `throw RuntimeException(...)`. – Stephen C Jul 14 '14 at 01:45
  • You're absolutely right, I hadn't realised the OP wanted to replace the library exactly (I thought an approximation with mock objects could be OK, even if it failed once in a while). – Bruno Jul 14 '14 at 09:50