In Java, we can see the property value of os.name to know the name of the underlying operating system: System.getProperty("os.name").
For each edition of Windows, it used to return always the exact name of the OS: Windows XP for XP, Windows Vista for Vista, Windows 7 for Seven, Windows 8.1 for 8.1, and so on...
The problem is: I just updated my Windows 8.1 to Windows 10 using the released Microsoft updater, and it seems like this property still remains Windows 8.1:
public class OSTest {
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
}
}
How can I create a workaround for this? And, does anyone know if this problem persists if installing a fresh Windows 10 copy - that is, this bug is caused by the Microsoft auto-updater -?
This is a known problem JDK-8066504 that has been fixed in upcoming Java 8 update 60.
The reason is GetVersionEx function has changed its behavior since Windows 8.1.
There are multiple possible workarounds, see MSDN article.
The trivial one is to exec cmd.exe /c ver.
The other is to look at the version information of one of the system files, e.g. kernel32.dll.
This is definitely a known bug. It occurs because the os.name property gets its value from the GetVersionEx in the source code of the Windows API. GetVersionEx however,
may be altered or unavailable for releases after Windows 8.1
As per Microsoft's official website. Instead, we will need to use the IsWindows10OrGreater found in the Version Helper API functions in the versionhelpers.h file. As you probably guessed though, this file is not a Java file, it is written in C. As a result we need to include it in a somewhat roundabout way. It does take quite a bit of work (you need to program in JNI :/) but this tutorial will help you do it. Another solution is shown in this bug log, and does require less effort.
I faced the same issue, used the following workaround:
The cmd command "systeminfo" returns "OS Name:" which is the right name for the OS, wrote the following function for this:
private boolean os2k10Check()
{
try{
Process p = Runtime.getRuntime().exec("systeminfo"); /*Execute cmd command "systeminfo"*/
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true)
{
line = r.readLine();
if (line == null) { break; }
if(line.contains("OS Name:")) /*If output contains OS Name and 2010*/
{
if(line.contains("2010"))
return true;
else
return false;
}
}
}
catch(Exception e)
{System.out.println("Platform Type: os2010check: exception"+e);}
return false;
}
Hm... I don't know if it is a fix of Windows 10(10.0.17134.590) or of Java 8(1.8.0_171-b11 for me), but it is correct now: os.name gives me Windows 10.
Besides, if you don't trust it, you can check os.version. I have 10.0.
(By the way, I see os.arch:amd64. This is of JVM, not of OS. )
You could also use the .contains() method and just check for the "windows"
string maybe along the lines of
if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains(windows version here [xp, 7, 8, etc]))){}
If you need the windows version you could check for all versions and then assume 8.1 or 10 to move around the bug.
if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("xp")){
//code for windows xp }
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("vista")){
//code for windows vista
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("7")){
//code for windows 7}
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("8")){
//code for windows 8}
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("8.1")){
//code for both windows 8.1 and 10
}
Now to explain what is going on here:
the if statement is just a conditional to determine the version of windows
The System.getProperty("os.name") returns the name of the os as a string
The .toLowerCase() method makes that returned String lower case
The .contains(String) method checks if the given input string is contained in the String it is being called on
The last statement allows for different code for each os except 8.1 & 10 which would need to be handled as one block :(
Related
Is it just my setup or is anyone else having this problem?
Using AdoptOpenJDK 1.8.0_275 installed at:
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre
API docs of System.getProperties() do not specify any details.
Can confirm this is still happening on adoptopenjdk14, as well as openjdk early access build for j16.
You can file a bug if you want, but I bet it'll be denied. At this point, the name Mac OS X is not so much 'the name of the OS' as a 'globally agreed upon keyword identifying that unix-based mac operating system', where I mean globally literally (as in, 'around the planet', not 'across your source base/VM'). Changing it would just break stuff needlessly. The same applies, to a lesser degree, to version 10.16: The thing before the dot is not so much 'this is how the OS identifies itself' and more a 'globally agreed upon versioning scheme for Mac OS, identifying a wide and ill defined set of capabilities'.
There is no meaningful difference between the transition between big sur and catalina, other than the fact that apple made a marketing decision. If you want to point at an OS transition that might warrant the entirely nebulous choice to consider it a 'major change', surely it was the one to catalina, as that made by far the largest changes (including removing support for 32-bit entirely) in the last bunch of releases.
This leaves you with the challenge of: Okay, great, I can use System.getProperty("os.name") to get the globally agreed upon keyword that means unix-like Mac OS, and os.version for a string I can break into bits to figure out some nebulous batch of capabilities, but what if I need the actual name of the OS to e.g. show to a user?
Then you have three major options:
The easy one is to just write mapping code. Acknowledge that os.name and os.version give you (rather arguably) useful intent and not so much official names, and therefore, write some mappings. These would map name/version pairs to rendering strings, falling back to just printing the name string and the version string, concatenated, verbatim. You could add a mapping: Mac OS X/10.16 → Mac OS Big Sur in this table.
The hard way: Figure out you're on a mac (which is now easier; os.name returns Mac OS X, or just check for the existence: Files.isExecutable(Paths.get("/usr/bin/sw_vers"))), and then use ProcessBuilder to execute /usr/bin/sw_vers, picking up all output into a big string, and then parse it. Its output looks like:
ProductName: macOS
ProductVersion: 11.1
BuildVersion: 20C69
which, crucially, doesn't even include the words Big Sur, but does give you 11.1. I don't know how to run a command line tool that actually gives you Big Sur. Maybe system_profiler, but note that this takes many minutes to run, I really doubt you want to run that.
NB: you can also run .command("/usr/bin/sw_vers", "-productVersion") which gives you just 11.1, this may be a lot simpler to parse. -productName also works, gives you just macOS.
If you need this information to scan for OS capabilities, then stop doing this. It doesn't work with browsers, and it's not a good plan for OS releases either. What capability are you scanning for? Imagine, for example, if it is 'Can I run /usr/bin/sw_vers to figure stuff out', as a hypothetical example. The right strategy is NOT to check os.name/os.version, conclude that the command must exist, and then run it, failing catastrophically if it is not there. The right move is to check if /usr/bin/sw_vers exists, and then execute it, falling back to some non-mac based solution (perhaps /usr/bin/uname) in other cases. Scan for the capability, don't scan for the OS/version.
Java code to call native tool sw_vers
Regarding Option # 2 in the Answer by rzwitserloot, here is a complete code example to run from Java a command-line tool sw_vers that describes the version of macOS software running on the host computer.
If on the command-line (console) such as in Terminal.app, you run:
sw_vers
…in Big Sur on an Intel Mac we get:
ProductName: macOS
ProductVersion: 11.2
BuildVersion: 20D64
We only need the middle piece. So running:
sw_vers -productVersion
…shows simply 11.2, the value we need for your purpose.
Here is complete example app with a method to return this string into Java.
ProcessBuilder class creates operating system processes. Each new process is represented by the Process class.
We use try-with-resources syntax to automatically close the InputStream and Scanner objects.
Once you have the 11.2 string in hand, split on the FULL STOP, pull the first number 11, and you know you are running on Big Sur.
package org.example;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* Example code showing how to get current version of macOS from Java
* by running a native command-line tool `sw_vers`.
*/
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
String version = this.getMacOsVersionNumber();
System.out.println( "version = " + version );
}
public String getMacOsVersionNumber ( )
{
String result = "";
List < String > command = List.of( "sw_vers" , " -productVersion" );
try (
InputStream inputStream = new ProcessBuilder( command ).start().getInputStream() ;
Scanner s = new Scanner( inputStream ).useDelimiter( "\\A" ) ;
)
{
result = s.hasNext() ? s.next() : "";
}
catch ( IOException e )
{
e.printStackTrace();
}
return Objects.requireNonNull( result );
}
}
I wrote a very simple Java program and, trying to input a string with some accents, I noticed that Scanner (or the terminal) has issues to handle them.
I don't know how to resolve this problem with encoding.
Code
System.out.println("aeíóu"); // output => aeíóu
Scanner input = new Scanner(System.in, "UTF-8");
String str = input.nextLine(); // input => aeíóu
input.close();
System.out.println(str); // output => ae u
Outputs (Visual Studio Code)
Java Process Console:
cmd:
Enviroment
OS: Windows 10 Pro
JDK: 1.8.0_231
Visual Studio Code: 1.39.2
I don't know if this will be any help, it is a while since I have tested this in Windows and if Microsoft has fixed the issue or made improvements (or if the JVM has made any changes to how the unicode is outputted):
https://devblogs.microsoft.com/commandline/windows-command-line-unicode-and-utf-8-output-text-buffer/
The problem was (or still is?) that the windows console could not be reliably used for input and output of unicode from applications that use the C standard library (byte) I/O functions. This includes Java too. The codepage 65001 was broken.
Not sure if the above post can point you in the right direction though.
Is there a way to check if a specific program is installed on Windows using Java?
I'm trying to develop a Java program that automatically creates zip archives by using the code line command from 7-Zip.
So, I would like to check in Java if on my windows OS '7-Zip' is already installed. No check for running apps or if OS is Windows or Linux. I want to get a bool (true/false) if '7-Zip' is installed on Windows.
The library Apache Commons has a class called SystemUtils - full documentation is available at https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/SystemUtils.html.
In this library you have the following static boolean properties at your disposal:
SystemUtils.IS_OS_LINUX
SystemUtils.IS_OS_WINDOWS
The unix-like solution would be to simply try to run the program with --version flag (on windows probably the /? or - like in the 7zip case - without any at all) and check whether it fails, or what the return code will be.
Something like:
public boolean is7zipInstalled() {
try {
Process process = Runtime.getRuntime().exec("7zip.exe");
int code = process.waitFor();
return code == 0;
} catch (Exception e) {
return false;
}
}
I assume that you're talking about Windows. As Java is intended to be a platform-independent language and the way how to determine it differs per platform, there's no standard Java API to check that. You can however do it with help of JNI calls on a DLL which crawls the Windows registry. You can then just check if the registry key associated with the software is present in the registry. There's a 3rd party Java API with which you can crawl the Windows registry: jRegistryKey.
Here's an SSCCE with help of jRegistryKey:
package com.stackoverflow.q2439984;
import java.io.File;
import java.util.Iterator;
import ca.beq.util.win32.registry.RegistryKey;
import ca.beq.util.win32.registry.RootKey;
public class Test {
public static void main(String... args) throws Exception {
RegistryKey.initialize(Test.class.getResource("jRegistryKey.dll").getFile());
RegistryKey key = new RegistryKey(RootKey.HKLM, "Software\\Mozilla");
for (Iterator<RegistryKey> subkeys = key.subkeys(); subkeys.hasNext();) {
RegistryKey subkey = subkeys.next();
System.out.println(subkey.getName()); // You need to check here if there's anything which matches "Mozilla FireFox".
}
}
}
If you however intend to have a platformindependent application, then you'll also have to take into account the Linux/UNIX/Mac/Solaris/etc. (in other words: anywhere where Java is able to run) ways to detect whether FF is installed. Else you'll have to distribute it as a Windows-only application and do a System#exit() along with a warning whenever System.getProperty("os.name") is not Windows.
Sorry, I don't know how to detect in other platforms whether FF is installed or not, so don't expect an answer from me for that ;)
I know there is such a question on SO, but I could not find it. So asking again...
I need to set up properties to my program, but I need to make it OS indipendent - running both on Windows XP and Linux (unknown distro, unknown version)
More specifically - I need to set up to the system where to find the chromedriver binary. I need something like this pseudocode:
if (getOs() == Windows){
System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, "chromedriver.exe");
} else{
System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, "chromedriver");
}
Now I need the part for getting the OS. Thanks for help.
System.getProperty("os.name");
System.getProperty("os.version");
System.getProperty("os.arch");
You can use the utility class I wrote, you just need to copy the following class in your project
https://github.com/aurbroszniowski/os-platform-finder/blob/master/src/main/java/org/jsoftbiz/utils/OS.java
Then do:
import org.jsoftbiz.utils.OS;
OS myOS = OS.getOs();
myOS.getPlatformName()
myOS.getName()
myOS.getVersion()
myOS.getArch()
oslib is a library that provides information about the current OS. You won't need to parse the info you get from System.getProperty("os.name");.
Note: Most operating systems are tested and supported but some are not yet implemented. For a complete list check out their Github.
Code for your specific problem:
AbstractOperatingSystem os = OperatingSystem.getOperatingSystem();
if (os.getType == OperatingSystem.WINDOWS){
System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, "chromedriver.exe");
} else if(os.getType == OperatingSystem.LINUX) {
System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, "chromedriver");
} else {
throw new Exception("Unsupported OS.");
}
I'm trying the following Java code to shut down Windows operating system. I'm using Microsoft Windows XP Professional version 2002, Service pack 3 with Intel(R) Core(TM) i3 CPU using Netbeans IDE 6.9.1.
package shutdownos;
import java.io.IOException;
final public class Main
{
public static void main(String... args) throws IOException
{
String shutdownCommand="";
String operatingSystem = System.getProperty("os.name");
if ("Linux".equals(operatingSystem) || "Mac OS X".equals(operatingSystem))
{
shutdownCommand = "shutdown -h now";
}
else if ("Windows".equals(operatingSystem))
{
shutdownCommand = "shutdown.exe -s -t 0";
}
else
{
//throw new RuntimeException("Unsupported operating system.");
}
Runtime.getRuntime().exec(shutdownCommand);
System.exit(0);
}
}
It throws the following exception in Java.
Exception in thread "main" java.lang.IllegalArgumentException: Empty command
The exception occurs on the following line in the above code.
Runtime.getRuntime().exec(shutdownCommand);
The second-last in the main() method. What is wrong with this code?
You're looking for the wrong value of os.name -- whatever it is, it's not "Windows" and therefore the code runs through the else block where the variable shudowncommand is left as an empty string, which causes the "Empty command" exception. Do a System.out.println(operatingSystem) to see what value you should check for instead of "Windows".
It's probably something like "Windows NT", so if you replace the .equals() check by a .startsWith() check you should be set.
According to this page, you seem to be using the wrong value for O/S names. If that is the case, your shutdownCommand string will remain empty, which will cause your program to pass an empty command, which conforms with the exception you are getting.
the program is skipping both the if statements, os.name would not be just Windows, it would be i think Windows XP or more, so replace that with starts with
else if (operatingSystem.startsWith("Windows")){
}
There is no property "os.name" that is equal to "Windows". Did you mean to check for if the property contains "Windows"?. As far as I know all window os names have a quantifier such as "Windows 95", "Windows NT" etc.
The shutdown command for windows os should be shutdown -s -t 0. try with this.
I mostly use this site to find out the possible values: What os or arch value can I use?
As others said, you should use String.startsWith() method.