I want to set the default Locale for my JVM to fr_CA. What are the possible options to do this?
I know of only one option Locale.setDefault()
You can set it on the command line via JVM parameters:
java -Duser.country=CA -Duser.language=fr ... com.x.Main
For further information look at Internationalization: Understanding Locale in the Java Platform - Using Locale
From the Oracle Reference:
The default locale of your application is determined in three ways.
First, unless you have explicitly changed the default, the
Locale.getDefault() method returns the locale that was initially determined
by the Java Virtual Machine (JVM) when it first loaded. That is, the
JVM determines the default locale from the host environment. The host
environment's locale is determined by the host operating system and
the user preferences established on that system.
Second, on some Java runtime implementations, the application user can
override the host's default locale by providing this information on
the command line by setting the user.language, user.country, and
user.variant system properties.
Third, your application can call the Locale.setDefault(Locale)
method. The setDefault(Locale aLocale) method lets your application
set a systemwide (actually VM-wide) resource. After you set the default locale with this
method, subsequent calls to Locale.getDefault() will return the newly
set locale.
In the answers here, up to now, we find two ways of changing the JRE locale setting:
Programatically, using Locale.setDefault() (which, in my case, was the solution, since I didn't want to require any action of the user):
Locale.setDefault(new Locale("pt", "BR"));
Via arguments to the JVM:
java -jar anApp.jar -Duser.language=pt-BR
But, just as reference, I want to note that, on Windows, there is one more way of changing the locale used by the JRE, as documented here: changing the system-wide language.
Note: You must be logged in with an account that has Administrative Privileges.
Click Start > Control Panel.
Windows 7 and Vista: Click Clock, Language and Region > Region and Language.
Windows XP: Double click the Regional and Language Options
icon.
The Regional and Language Options dialog box appears.
Windows 7: Click the Administrative tab.
Windows XP and Vista: Click the Advanced tab.
(If there is no Advanced tab, then you are not logged in with
administrative privileges.)
Under the Language for non-Unicode programs section, select the desired language from the drop down menu.
Click OK.
The system displays a dialog box asking whether to use existing
files or to install from the operating system CD. Ensure that you have
the CD ready.
Follow the guided instructions to install the files.
Restart the computer after the installation is complete.
Certainly on Linux the JRE also uses the system settings to determine which locale to use, but the instructions to set the system-wide language change from distro to distro.
You can use JVM args
java -Duser.country=ES -Duser.language=es -Duser.variant=Traditional_WIN
There is another away if you don't like to change System locale but the JVM. you can setup a System (or user) Environment variable JAVA_TOOL_OPTIONS and set its value to -Duser.language=en-US or any other language-REGION you want.
You can do this:
And to capture locale. You can do this:
private static final String LOCALE = LocaleContextHolder.getLocale().getLanguage()
+ "-" + LocaleContextHolder.getLocale().getCountry();
You can enforce VM arguments for a JAR file with the following code:
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
public class JVMArgumentEnforcer
{
private String argument;
public JVMArgumentEnforcer(String argument)
{
this.argument = argument;
}
public static long getTotalPhysicalMemory()
{
com.sun.management.OperatingSystemMXBean bean =
(com.sun.management.OperatingSystemMXBean)
java.lang.management.ManagementFactory.getOperatingSystemMXBean();
return bean.getTotalPhysicalMemorySize();
}
public static boolean isUsing64BitJavaInstallation()
{
String bitVersion = System.getProperty("sun.arch.data.model");
return bitVersion.equals("64");
}
private boolean hasTargetArgument()
{
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
List<String> inputArguments = runtimeMXBean.getInputArguments();
return inputArguments.contains(argument);
}
public void forceArgument() throws Exception
{
if (!hasTargetArgument())
{
// This won't work from IDEs
if (JARUtilities.isRunningFromJARFile())
{
// Supply the desired argument
restartApplication();
} else
{
throw new IllegalStateException("Please supply the VM argument with your IDE: " + argument);
}
}
}
private void restartApplication() throws Exception
{
String javaBinary = getJavaBinaryPath();
ArrayList<String> command = new ArrayList<>();
command.add(javaBinary);
command.add("-jar");
command.add(argument);
String currentJARFilePath = JARUtilities.getCurrentJARFilePath();
command.add(currentJARFilePath);
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.start();
// Kill the current process
System.exit(0);
}
private String getJavaBinaryPath()
{
return System.getProperty("java.home")
+ File.separator + "bin"
+ File.separator + "java";
}
public static class JARUtilities
{
static boolean isRunningFromJARFile() throws URISyntaxException
{
File currentJarFile = getCurrentJARFile();
return currentJarFile.getName().endsWith(".jar");
}
static String getCurrentJARFilePath() throws URISyntaxException
{
File currentJarFile = getCurrentJARFile();
return currentJarFile.getPath();
}
private static File getCurrentJARFile() throws URISyntaxException
{
return new File(JVMArgumentEnforcer.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
}
}
It is used as follows:
JVMArgumentEnforcer jvmArgumentEnforcer = new JVMArgumentEnforcer("-Duser.language=pt-BR"); // For example
jvmArgumentEnforcer.forceArgument();
Related
I try to retrieve the windows directory of my OS.
To get the correct path I tried the following 2 commands:
System.getenv().get("WINDIR")
System.getenv().get("SystemRoot")
Both commands work, but the strange thing is, that the first command (WINDIR) returns the path only, if I
run the program in debug mode. The latter command (SystemRoot) returns the path only if I run the program not in debug mode.
So this program
public static void main(String[] args) {
System.out.println(System.getenv().get("WINDIR"));
System.out.println(System.getenv().get("SystemRoot"));
}
evaluates to
// Debug mode
C:\Windows
null
// No Debug mode
null
C:\Windows
Is this a defined behavior?
(My application is Windows specific, and if i speak of debug mode I mean the default Eclipse "Debug as Java Applicaton" run configiguration)
System.getEnv() is an overloaded method, one implementation having no parameters and one having a String parameter.
static Map getenv​() Returns an unmodifiable string map view of the current system environment.
static String getenv​(String name) Gets the value of the specified environment variable.
You are calling the implementatation with no parameters, and then calling get() on the returned Map. From the Javadoc for System.getEnv():
For getEnv(): The returned map is typically case-sensitive on all platforms.
For getEnv(String): On UNIX systems the alphabetic case of name is typically significant, while on Microsoft Windows systems it is typically not.
So it is essential for your code to be providing the name of the environment variable in the correct case, specifying windir in all lower case, not upper case.
That said, I can't explain the differences you see when running in debug mode at all. If I run the program below - which is just an enhanced version of yours - I get identical results (as expected) regardless of whether it is run in debug mode or not:
System.getenv().get() windir=C:\WINDOWS
System.getenv().get() WINDIR=null
System.getenv().get() systemroot=null
System.getenv().get() SystemRoot=C:\WINDOWS
System.getenv() windir=C:\WINDOWS
System.getenv() WINDIR=C:\WINDOWS
System.getenv() systemroot=C:\WINDOWS
System.getenv() SystemRoot=C:\WINDOWS
Could you run the code below twice, once in debug mode and once in normal mode, and advise of the results? Also, advise of your environment: Windows version, Eclipse version and Java version.
[This is more of a request for further information than a final answer, but I couldn't fit it all into a comment.]
import java.lang.management.ManagementFactory;
import java.util.regex.Pattern;
public class App {
private final static Pattern debugPattern = Pattern.compile("-Xdebug|jdwp");
public static boolean isDebugging() {
// https://stackoverflow.com/questions/7397584/how-to-know-my-code-is-running-in-debug-mode-in-ide
// Taken from the code provided by SO user AlexR
for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
if (debugPattern.matcher(arg).find()) {
return true;
}
}
return false;
}
public static void main(String[] args) {
System.out.println("Running in debug mode? " + App.isDebugging());
System.out.println("System.getenv().get() windir=" + System.getenv().get("windir"));
System.out.println("System.getenv().get() WINDIR=" + System.getenv().get("WINDIR"));
System.out.println("System.getenv().get() systemroot=" + System.getenv().get("systemroot"));
System.out.println("System.getenv().get() SystemRoot=" + System.getenv().get("SystemRoot"));
System.out.println("System.getenv() windir=" + System.getenv("windir"));
System.out.println("System.getenv() WINDIR=" + System.getenv("WINDIR"));
System.out.println("System.getenv() systemroot=" + System.getenv("systemroot"));
System.out.println("System.getenv() SystemRoot=" + System.getenv("SystemRoot"));
}
}
Is there a way to distinguish a Java system property which has been set from the command line using a -D option from a system property which got the same value by default?
E.g., this program
class Test {
public static void main(String[] args) {
System.out.println(System.getProperty("user.home"));
}
}
prints
/home/uckelman
for me regardless of whether I run it as
java Test
or
java -Duser.home=/home/uckelman Test
Is there anything which the JDK provides which I could test to distinguish these two situations?
One way is to get the command line arguments used to start the JVM and check the returned List if a given system property is set or not.
RuntimeMXBean mx = ManagementFactory.getRuntimeMXBean();
System.out.println("COMMAND LINE ARGS:\n" + mx.getInputArguments());
the following code will help illustrate my problem:
import java.util.Locale;
import java.text.*;
public class LocaleTest {
public static void main(String[] args) {
System.out.println(Locale.getDefault());
System.out.println("java-version-" +System.getProperty("java.version"));
System.setProperty("sun.locale.formatasdefault","true");
System.out.println("prop:" +System.getProperty("sun.locale.formatasdefault"));
System.out.println("getLocale-" +Locale.getDefault());
}
}
As we know, there is bug in Java 7, in Locale.getDefault().However as recommended by Oracle I have set the system property 'sun.locale.formatasdefault' to true. Even though I am now getting my m/c Locale, it is always showing as en_US even though my m/c Locale is set to fr_BE.
Here is the output of above code, which is compiled and run on Java 1.7.0_09:
en_US
java-version-1.7.0_09
prop:true
getLocale-en_US
Any thoughts on what might be causing thus? Many thanks in advance.
You need to set that system property before starting up your JVM. You can do this via command line arguments:
java -Dsun.locale.formatasdefault=true TargetClass
Or in environments where you don't control the launching of the JVM, you can set it via _JAVA_OPTIONS environment variable:
*Nix
export _JAVA_OPTIONS=-Dsun.locale.formatasdefault=true
Windows
SET _JAVA_OPTIONS=-Dsun.locale.formatasdefault=true
In Windows, if you want the change to be applied not only for that CMD but systemwide, you create a Windows System Variable JAVA_TOOL_OPTIONS
Ok, I know that System.getProperty("os.name") will give me the name of the OS I'm running under, but that's not a lot of help. What I need to know is if the OS I'm running on is a 'Unix-like' OS, I don't care if it's HP-UX, AIX, Mac OS X or whatever.
From the list of possible os.name values it seems like a quick and dirty way of detecting a 'Unix-like' OS is checking if os.name does not contain "Windows". The false positives that will give me are OSes my code is very unlikely to encounter! Still, I'd love to know a better way if there is one.
Use the org.apache.commons.lang.SystemUtils utility class from Commons Lang, it has a nice IS_OS_UNIX constant. From the javadoc:
Is true if this is a POSIX compilant
system, as in any of AIX, HP-UX, Irix,
Linux, MacOSX, Solaris or SUN OS.
The field will return false if OS_NAME
is null.
And the test becomes:
if (SystemUtils.IS_OS_UNIX) {
...
}
Simple, effective, easy to read, no cryptic tricks.
I've used your scheme in production code on Windows XP, Vista, Win7, Mac OS 10.3 - 10.6 and a variety of Linux distros without an issue:
if (System.getProperty("os.name").startsWith("Windows")) {
// includes: Windows 2000, Windows 95, Windows 98, Windows NT, Windows Vista, Windows XP
} else {
// everything else
}
Essentially, detect Unix-like by not detecting Windows.
File.listRoots() will give you an array of the file system root directories.
If you are on a Unix-like system, then the array should contain a single entry "/" and on Windows systems you'll get something like ["C:", "D:", ...]
Edit: #chris_l: I totally forgot about mobile phones. Some digging turns up that Android returns a "/\0\0" - a slash followed by two null bytes (assumed to be a bug). Looks like we avoid false positives for the time being through luck and coincidence. Couldn't find good data on other phones, unfortunately.
It's probably not a good idea to run the same code on desktops and mobile phones regardless, but it is interesting to know. Looks like it comes down to needing to check for specific features instead of simply the system type.
Javadoc says: On UNIX systems the value of this
* field is '/'; on Microsoft Windows systems it is '\'.
System.out.println( File.separatorChar == '/' ? "Unix" : "Windows" );
System.getProperty("os.name"); is about the best you are going to get.
I agree with #Fuzzy in that I think the only way that Java intended you to be able to get that information was through the os.name property.
The only other things I can think of are:
Have a shell script or batch file wrapper to launch your Java app that passes in OS information using the -D argument to the JVM. Though given your description, this doesn't sound doable.
You could try to check for the existence of an OS-specific directory. For instance, you could assume the directory "/" will always exist on a Unix-like system, but not on Windows and do something like this:
if((new File("/")).exists())
{
System.out.println("I'm on a Unix system!");
}
Try to kick off a Unix-specific command line command like ls and check the return code. If it worked, you're on a Unix-like system, if not you're on Windows.
All of those solutions are really just hacks though and frankly I don't really feel all that great about any of them. You're unfortunately probably best off with your original thought. Fun, eh?
Use File.pathSeparator or File.separator. The first will return ";" in Windows and ":" in Unix. The second will return "\" in Windows and "/" in Unix.
You could try to execute the uname command - should be available on all unixoid systems.
package com.appspot.x19290;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class UnixCheck {
public static void main(String[] args) {
UnixCheck s = UnixCheck.S;
String isUnix = s.unix ? "is Unix" : "not Unix";
try {
System.out.println(isUnix + ", devnull: " + s.devnull.getPath());
} catch (NullPointerException e) {
System.out.println(isUnix + ", devnull: unknown");
}
}
public static final UnixCheck S = new UnixCheck();
public static final UnixCheck TEST = new UnixCheck(true);
public final boolean unix;
public final File devnull;
private UnixCheck() {
this(false);
}
private UnixCheck(boolean testing) {
String path;
path = testing ? "/<dev>/<no><such><null><device>" : "/dev/null";
File devnull = devnullOrNone(path);
if (devnull == null) {
this.unix = false;
path = testing ? "<no><such><null><device>" : "nul";
this.devnull = devnullOrNone(path);
} else {
this.unix = true;
this.devnull = devnull;
}
}
private static File devnullOrNone(String name) {
File file = new File(name);
if (file.isFile())
return null;
if (file.isDirectory())
return null;
try {
FileInputStream i = new FileInputStream(file);
try {
i.read();
} finally {
i.close();
}
} catch (IOException e) {
return null;
}
return file;
}
}
This is a followup to my own previous question and I'm kind of embarassed to ask this... But anyway: how would you start a second JVM from a standalone Java program in a system-independent way? And without relying on for instance an env variable like JAVA_HOME as that might point to a different JRE than the one that is currently running. I came up with the following code which actually works but feels just a little awkward:
public static void startSecondJVM() throws Exception {
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-cp",
classpath,
AnotherClassWithMainMethod.class.getName());
Process process = processBuilder.start();
process.waitFor();
}
Also, the currently running JVM might have been started with some other parameters (-D, -X..., ...) that the second JVM would not know about.
I think that the answer is "Yes". This probably as good as you can do in Java using system independent code. But be aware that even this is only relatively system independent. For example, in some systems:
the JAVA_HOME variable may not have been set,
the command name used to launch a JVM might be different (e.g. if it is not a Sun JVM), or
the command line options might be different (e.g. if it is not a Sun JVM).
If I was aiming for maximum portability in launching a (second) JVM, I think I would do it using wrapper scripts.
It's not clear to me that you would always want to use exactly the same parameters, classpath or whatever (especially -X kind of stuff - for example, why would the child need the same heap settings as its parents) when starting a secondary process.
I would prefer to use an external configuration of some sort to define these properties for the children. It's a bit more work, but I think in the end you will need the flexibility.
To see the extent of possible configuration settings you might look at thye "Run Configurations" settings in Eclipse. Quite a few tabs worth of configuration there.
To find the java executable that your code is currently running under (i.e. the 'path' variable in your question's sample code) there is a utility method within apache ant that can help you. You don't have to build your code with ant - just use it as a library, for this one method.
It is:
org.apache.tools.ant.util.JavaEnvUtils.getJreExecutable("java")
It takes care of the sort of special cases with different JVM vendors that others have mentioned. (And looking at the source code for it, there are more special cases than I would have imagined.)
It's in ant.jar. ant is distributed under the Apache license so hopefully you can use it how you want without hassle.
Here's a way that determines the java executable which runs the current JVM using ProcessHandle.current().info().command().
The ProcessHandle API also should allow to get the arguments. This code uses them for the new JVM if available, only replacing the current class name with another sample class. (Finding the current main class inside the arguments gets harder if you don't know its name, but in this demo it's simply "this" class. And maybe you want to reuse the same JVM options or some of them, but not the program arguments.)
However, for me (openjdk version 11.0.2, Windows 10), the ProcessInfo.arguments() is empty, so the fallback else path gets executed.
package test;
import java.lang.ProcessBuilder.Redirect;
import java.lang.management.ManagementFactory;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestStartJvm {
public static void main(String[] args) throws Exception {
ProcessHandle.Info currentProcessInfo = ProcessHandle.current().info();
List<String> newProcessCommandLine = new LinkedList<>();
newProcessCommandLine.add(currentProcessInfo.command().get());
Optional<String[]> currentProcessArgs = currentProcessInfo.arguments();
if (currentProcessArgs.isPresent()) { // I know about orElse, but sometimes isPresent + get is handy
for (String arg: currentProcessArgs.get()) {
newProcessCommandLine.add(TestStartJvm.class.getName().equals(arg) ? TargetMain.class.getName() : arg);
}
} else {
System.err.println("don't know all process arguments, falling back to passed args array");
newProcessCommandLine.add("-classpath");
newProcessCommandLine.add(ManagementFactory.getRuntimeMXBean().getClassPath());
newProcessCommandLine.add(TargetMain.class.getName());
newProcessCommandLine.addAll(List.of(args));
}
ProcessBuilder newProcessBuilder = new ProcessBuilder(newProcessCommandLine).redirectOutput(Redirect.INHERIT)
.redirectError(Redirect.INHERIT);
Process newProcess = newProcessBuilder.start();
System.out.format("%s: process %s started%n", TestStartJvm.class.getName(), newProcessBuilder.command());
System.out.format("process exited with status %s%n", newProcess.waitFor());
}
static class TargetMain {
public static void main(String[] args) {
System.out.format("in %s: PID %s, args: %s%n", TargetMain.class.getName(), ProcessHandle.current().pid(),
Stream.of(args).collect(Collectors.joining(", ")));
}
}
}
Before ProcessHandle was added in Java 9, I did something like this to query the current JVM's command-line:
Let the user pass or configure a "PID to command-line" command template; under Windows, this could be wmic process where 'processid=%s' get commandline /format:list.
Determine PID using java.lang.management.ManagementFactory.getRuntimeMXBean().getPid().
Expand command template; execute; parse its output.