14

Note: All the similar questions are answering this from the perspective of the shell (e.g. Is javac available? java -version or which java). I'm looking explicitly for the perspective of the currently running JVM.

There are programs that require to be run from within a JDK's JRE, not "just" a JRE. I'm wondering if there's a simple way to find out what my currently running program is executed in.

I'm looking for a generic way to figure this out, rather than an analysis of the program in question and duplicating its use of JDK features. That's why I'd prefer not to execute an external process testing if javac is on the path, if possible. I'm rather looking for some code that will run within a JDK, but fail within a JRE.

It could be Class.forName with a class that's only available in a JDK. It could be a system property. Or anything else.

If I have to execute an external process with javac: So be it. But I'd prefer something simpler and generic.

Clarification from deep down in the comments:

From time to time I'm running into this problem with Liferay, which requires to be run from within a JDK's JRE. I was entertaining the thought to just deploy another plugin that provides a userfriendly error message if run without a JDK available. I shy away from analyzing which code is the one failing in a JRE-only environment, and I don't want to modify Liferay's code, rather add my own plugin to do the analysis and warn.

Mikhail Kholodkov
  • 23,642
  • 17
  • 61
  • 78
Olaf Kock
  • 46,930
  • 8
  • 59
  • 90
  • 1
    It will always be running on a JRE. – mwarren Jul 19 '19 at 14:47
  • So the *only* special features of a JDK available *are* the *externally available* programs? – Olaf Kock Jul 19 '19 at 14:48
  • 1
    The JDK supplies the tools to build a Java application and has a JRE included to run applications on. A JRE installation just has the JRE and no build tools. – mwarren Jul 19 '19 at 14:50
  • The JDK contains a JRE. You are always running on a JRE. As such, your question is founded upon a false premise. – Michael Jul 19 '19 at 14:51
  • execute /.../jvm/jdk/bin/java and you'll see `Java(TM) SE Runtime Environment 18.9 (build 11.0.2+9-LTS)` – Arnaud Claudel Jul 19 '19 at 14:52
  • 2
    Consider the keywords: a "kit" is something that you use; an "environment" is something that you live in. You make something in the kit and then run it in the environment. – zero298 Jul 19 '19 at 14:53
  • Ok, makes sense. I've changed the question title to be more accurate. I guess my only chance then is to execute `javac` from within the JVM. I was hoping I can avoid that through any other internal feature of the JDK's JRE. – Olaf Kock Jul 19 '19 at 14:55
  • @OlafKock How do you expect invoking `javac` to help you? I could have JDK6 installed, with `javac` on my path. I could be running the application in JRE 8. – Michael Jul 19 '19 at 14:56
  • 1
    Overall this seems like an XY problem to me. **Why** do you want to know? What are you hoping to accomplish? – Michael Jul 19 '19 at 14:56
  • 4
    Since Java has become modular, the distinction between JRE and JDK is obsolete. You have to clarify *which feature* you need and then, check for the presence of that feature. If it is the compiler, you can check for the presence of the compiler API. But if you don’t use that API but require the presence of a command line `javac` tool, you have to check for precisely that. – Holger Jul 19 '19 at 14:57
  • Fair question: From time to time I'm running into this problem myself, or with other people (in Liferay, which requires to be run from within a JDK's JRE). I was entertaining the thought to just deploy another plugin that provides a userfriendly error message if run without a JDK available. I shy away from analyzing which code is the one failing, and I don't want to change the product's code, rather add my own. – Olaf Kock Jul 19 '19 at 14:58
  • @OlafKock "in Liferay, which requires to be run from within a JDK's JRE" For what? – Michael Jul 19 '19 at 15:00
  • @Michael that's precisely what I don't want to dive into the code for. I assume it might be JSP compilation within the OSGi container, but I might be wrong. It just does not run in JRE-only. – Olaf Kock Jul 19 '19 at 15:03
  • 2
    So you’re saying, the problem is that Liferay has certain requirements on the environment, but doesn’t provide a user friendly error message? Then, you should file a bug report to Liferay’s developers and that’s it. – Holger Jul 19 '19 at 15:03
  • I would actually reword the question once more... smth like: "How to tell from within a Java program whether it is running in a JDK or JRE". The word "available" seems a bit weird. – Stefan Reich Jul 19 '19 at 15:14
  • @StefanReich according to the discussion above, 1) one is always running in a JRE 2) the JDK might or might not be available externally. While it's not what I thought of initially, it's probably technically more correct to ask for availability, than for "being inside a JDK". – Olaf Kock Jul 19 '19 at 15:17
  • 1
    Indeed, the most correct term probably being “the availability of JDK features”. – Holger Jul 19 '19 at 15:22

2 Answers2

20

javax.tools.ToolProvider.getSystemJavaCompiler() will return null if no compiler is available, and a JavaCompiler if it is.

Technically it just tells you if the compiler is available of course, but that in most scenarios will imply the existence of the JDK.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • 1
    Ah, that might be even better than my answer. – Stefan Reich Jul 19 '19 at 15:09
  • 1
    Awesome, thanks. That looks like it's also working in OpenJDKs, as they might not necessarily duplicate com.sun.* – Olaf Kock Jul 19 '19 at 15:09
  • 3
    Of course, that won’t tell you whether a command line `javac` command exists nor whether a software, naively assuming to run in a `jre` directy inside a `jdk` installation (which is not the case since Java 9), will work with the current environment. – Holger Jul 19 '19 at 15:13
  • 1
    @Holger: Good enough for a quickfix to the current pain. In the long run, your comment is right: Bring a friendlier message into the core product. But that's the long run, and I'm rather impatient. – Olaf Kock Jul 19 '19 at 15:15
4

Class.forName("com.sun.tools.javac.Main");

If there is no exception, it is a JDK.

It works with current JDKs, but it's probably not part of any official spec.

Stefan Reich
  • 1,000
  • 9
  • 12