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
Related
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();
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());
I have the following code:
public static void main( String[] args ) {
System.out.println(Locale.getDefault());
File f = new File("/Users/johngoering/Documents");
File[] fs = f.listFiles();
for (File ff : fs) {
System.out.println(ff.getName());
System.out.println(ff.exists());
}
}
In my Documents folder I have a file called "öß.pdf". Here is the output under Java 6:
en_US
(...)
öß.pdf
true
(...)
But here is the output under Java 7:
en_US
(...)
o����.pdf
false
(...)
Note especially that file.exists returns false for a file returned by listFiles!!
What gives? Is there any way to fix this? This seems like quite the Java 7 bug...
With some help from Oracle, we discovered a workaround: the environment variable LC_CTYPE was not set to UTF-8 within Eclipse (and when starting from a JNLP or wherever else).
This explains why the code worked on the terminal, since the OS X terminal by default "sets the locale environment variables" (an option which can be turned off and then you get the same issue as above even in the terminal).
Setting this environment variable in the launcher worked around the problem.
I still consider this a bug for Java 7 because Java 6 still worked even WITHOUT this variable.
I have the following code:
public static void main( String[] args ) {
System.out.println(Locale.getDefault());
File f = new File("/Users/johngoering/Documents");
File[] fs = f.listFiles();
for (File ff : fs) {
System.out.println(ff.getName());
System.out.println(ff.exists());
}
}
In my Documents folder I have a file called "öß.pdf". Here is the output under Java 6:
en_US
(...)
öß.pdf
true
(...)
But here is the output under Java 7:
en_US
(...)
o����.pdf
false
(...)
Note especially that file.exists returns false for a file returned by listFiles!!
What gives? Is there any way to fix this? This seems like quite the Java 7 bug...
With some help from Oracle, we discovered a workaround: the environment variable LC_CTYPE was not set to UTF-8 within Eclipse (and when starting from a JNLP or wherever else).
This explains why the code worked on the terminal, since the OS X terminal by default "sets the locale environment variables" (an option which can be turned off and then you get the same issue as above even in the terminal).
Setting this environment variable in the launcher worked around the problem.
I still consider this a bug for Java 7 because Java 6 still worked even WITHOUT this variable.
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.