1

Java allows multiple top-level class declaration per file, at the condition that at most one of those class is public.

However, the Oracle Java compiler seems to have trouble resolving those kinds of dependencies. Consider:

// One.java
package jtest;
import jtest.Three;
public class One {}

// Two.java
package jtest;
public class Two {}
class Three {}

This first attempt to compile ends in an error:

javac -cp . jtest\One.java

jtest\One.java:3: error: cannot find symbol
import jtest.Three;
            ^
  symbol:   class Three
  location: package jtest
1 error

This however works as expected

javac -cp . jtest\Two.java
javac -cp . jtest\One.java

Now, this is "known" behaviour (it is reported in this answer for instance). However, most build systems don't seem to have problems with the scenario (I tried Eclipse and Apache Buildr). How do they resolve the problem?

Also consider that both Eclipse and Apache Buildr can compile this without batting an eyelash:

// One.java
package main;
import main.Four;
public class One {}
class Three {}

// Two.java
package main;
import main.Three;
public class Two {}
class Four {}
Community
  • 1
  • 1
Norswap
  • 11,740
  • 12
  • 47
  • 60
  • Because these tools save the order of the classes to how they must be compiled in the project, and then compile it. – Luiggi Mendoza Jun 02 '13 at 20:21
  • That's not it, look at the last example. Using only "javac", that example would be impossible to compile, no matter the ordering. – Norswap Jun 02 '13 at 20:22
  • I tested with `javac -cp ./main/ main/One.java main/Two.java` and worked with no problems. – Luiggi Mendoza Jun 02 '13 at 20:27
  • Indeed, so I suppose build tools simply pass all files from a package into a single `javac` command and let the compiler figure it out. Thanks! Would you mind making an answer out of that, so I can accept it? – Norswap Jun 02 '13 at 20:31
  • Not sure if my last comment is an answer since is a simple test that provides no explanation. – Luiggi Mendoza Jun 02 '13 at 20:32
  • Well the answer would be that, since javac can actually figure this out if you pass him all the concerned files, build tools simply let javac do it. If you don't want to make an answer, I'll simply answer it myself as soon as I'm allowed. – Norswap Jun 02 '13 at 20:36
  • I would use an IDE or a build tool like maven. These will save you a lot of time and grieve in the end. I wouldn't try running `javac` from the command lines as this is a really inefficient way to develop an application esp as you get more class files and libraries. – Peter Lawrey Jun 02 '13 at 21:09
  • Removing `[jvm]` as the question doesn't appear to be related to what the JVM does. – Peter Lawrey Jun 02 '13 at 21:10
  • @PeterLawrey I do use build tools; but I was curious how they solved this conundrum; which I am faced with myself. I'm writing a macro processor on top of Java and I need to handle dependencies between source files. – Norswap Jun 02 '13 at 22:17

1 Answers1

3

The javac compiler can compile multiple source files together, which enables it to handle circular dependencies.

For example:

$ javac main/One.java main/Two.java

or

$ javac main/*.java

If you take the last example and do each file one at a time, it is doomed to fail as you end up with a chicken or the egg problem, meaning each one requires the other one to already be compiled.

When you use the task against a source directory in ant, it scans the directory for all .java source files and passes them into an instance of the Java compiler together. That way, the compile can sort out the dependencies.

These two pages have good details:

http://www.dummies.com/how-to/content/how-to-use-the-javac-command.html http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javac.html

Brandon
  • 9,822
  • 3
  • 27
  • 37