+1  A: 

The short answer is no. The JVM appropriately handles this functionality on initialization, or at runtime. If a required class is not found on the classpath, a ClassNotFoundException will be thrown. If a class was found, but a required method was not, a NoSuchMethodException is thrown.

Droo
That was a concise answer, but here is why it didn't covered all the aspects : i've seen code compiled with JDK1.3 and app running on JDK1.4, resulting a NoSuchMethodException and failed to perform some task..or worse. What if i use some method (or in my case, a custom widget), and the app works fine until it encounters the missing lib, needed to display the widget? The initial test would not allowed that to happen..and that is why i've asked for a best practice advice.
Hypercube
+1  A: 

Regarding 1 through 3 , there are 2 main use cases here:

  • application packaging is under your control, and can make sure that all required dependencies are packaged properly. Run-time validations are not useful here.
  • application packaging is not under your control, and you deliver the main jar and the instructions on what the requirements are. Run-time validations might be useful, but someone who wants to package your application usually has enough skill to understand what a ClassNotFoundException: org.apache.logging.LogManager means.

Regarding 4, as long as you keep the same version of the dependency included in your project, you will have no problems in keeping control. Upgrading to a newer version is a conscious decision, which requires thought and testing.

Robert Munteanu
Yes, every developer knows what a "ClassNotFoundException" is. I knew what it was when i 1st see that. But..the average user has absolutely no idea. So, a user friendly message should be pop-up-ed and the technical details should be logged. Now, correct me if i am wrong, but there is one thing to change 2 lib versions (performing your suggested tests after that), and a completely different story to change 5 libs, with their new versions, for instance. I know, little can be done if u badly need the libraries..but i am sure SOMETHING can be done. Any idea what?
Hypercube
+1  A: 

I agree with your need. Checking for required runtime environment provides:

  • immediate feedback, instead of randomly breaking when accessing some functionnality
  • hopefully more skilled user, as the immediate feedback is available to the guy that is installing the software, hopefully more skilled than an average user, or at least less confident (installing is always a special operation). A more skilled user is less disturbed if the error is coming in the console, he doesn't depend on a graphical interface.
  • improved reporting : the error message can be explicit (you're in charge), while default error messages come in many flavours (they are not always that helpful on 1. what's wrong 2. suggesting a fix).


But please note that the runtime requirements could be checked in two situations:

  • when installing : long verifications are always acceptable ; if a library is not here, a required database or WebService is not accessible, it won't be here at runtime either, so you can complain immediately.
  • when starting the execution : you can verify again (and some verifications may only happen at that point)

This suggests creating an installer for your application.

Potentially, errors would not all be blocking for the installation. Some would rather accumulate as a list of tasks to be done after installation, maybe nicely formatted in a file with all reference information.

Here, we once again hit the notion of error level in validation (similar to what happens for Log4j) : some validation errors are at fatal level, others are errors, possibly also warnings ...


In our projects, we have some sort of initialization and validation going on on startup. Based on our day-to-day experience, I would suggest the following:

When the application gets big, you don't want to have all init centralized in one class, so we have a modular structure.

  • A small kernel is configured with a list of modules classes. It's whole init sequence is under strict control, ready for any exceptions (translating them to appropriate messages, but memorizing the stack traces that are so useful to the developpers), making no assumption on the available libraries and so on... CheckStyle can be configured specially for this code.
  • The interface (of course, abstract class is possible) that the modules implement typically have several initialization methods. They could be:

    • getDependencies : returns a list of modules that this one depends on.
    • startup : when the whole application is starting. This will be called only once during startup, and cannot be called again.
    • start : when the module gets ready for regular operation
    • stop : reverse from start
    • shutdown : reverse from startup.
  • The kernel instanciates each of the module in turn. Then he calls one init method on all of them, then another init method and so on as needed. Each init method can:

    • signal error conditions (using levels, like Log4J).
    • an exception thrown would be caught by the kernel, and translated to an error condition
    • consult another module for its status (because dependencies are the general case), and react accordingly. If needed, the dependencies could be made declaratively.
  • The kernel takes care of module dependencies generically:

    • He sorts the modules so that dependencies are respected.
    • He doesn't initialize a module if one of its dependencies couldn't make it.
    • If asked to stop a module, he will first stop the modules that depends on it.
  • A nice feature of this kernel approach is that it is easy to aggregate the errors, at various levels (although fatal could stop it), and report all of them at the end, using whatever means is available (SWT or not, Log4J or not ...). So instead of discovering the problems one after the other, and having to start again each time, you could deliver in one blow (nicely prioritized of course).


Concerning your precise questions:

Should the app check itself for the required dependencies?

Yes (see higher)

If yes, should the user be given specific details of what it's missing? Or just a message, and details to the logs?

As said higher, when installing the user is more prepared to deal with this.

When starting, we use an easy message for the end-user, but give access to the full stack traces for the developper (we have a button that copies in the clipboard the application environment, the stack traces and so on).

What if the log4J library is unavailable?

Log without it (see higher).

What is the best to do the test? Verifying the file existance (using file.exists(), at specified path), or loading a class, say Class.forName("org.apache.log4j.Logger")?

I would load a class. But if it failed, I might check the file existence on disk to give a improved message, including "how to fix".

What should be the proper order to do the checks? For instance, if i test for SWT, i have no idea if logger is available or not, and the error will occur when i try to access that. Backwards, if i test for the logger 1st : a) The lib could be unavailable - i cannot log the error; b) SWT could be unavailable - unable to display the user message.

As I said higher, I suggest these low-level errors get accumulated in a small area of code (kernel), where you could use anything that is available to display them. If nothing is available, you could simply log in the console without Log4J.

KLE
Are you by any chance looking to describe OSGi?
Robert Munteanu
@Robert OSGI is certainly a source of inspiration to me. It is also very successful, being adopted by many major players. But a few modules, and a little validation, in no way compares to OSGI. It is little and easy code, it brings no additional dependencies (the OP Hypercube seem to care about this), doesn't affect classloading... But you question gave me an idea, and shows that you are closer to the truth than I thought : using SWT already, Hypercube might agree to use Eclipse RCP, which would effectively bring OSGI into play :-)
KLE
Yes, Hypercube is already using Eclipse RCP, but OSGI is a foreign concept to me right now :-(. I will write down and google it. Your answer was more than OK, giving me some directions. To be honest, my "intuition" told me exactly what you said. Make it modular, perform the test, log the errors and inform the user. I guess the law here is the order of performing operations during app init. Like, there is little use of displaying a GUI message if not sure the GUI is available an so on. Do you have a short list of things to be performed upon start up, and what is the order of them?
Hypercube
@Hypercube Glad you like the answer :-) If you use RCP, you already use OSGI under the hood. Good for your intuition. I don't have any list, I think it will come to you as you go.
KLE