Who resets JVM file.encoding back to original? - java

System.setProperty("file.encoding", "utf-8");
The comment below implies that file.encoding would be changed for all apps running on the same JVM, however, I don't observe this kind of behaviour.
Setting a system property programmatically will affect all code running within the same JVM, which is hazardous, especially when discussing such a low-level system property.
I have read this question and understand that there are many issues with caching and Java 1.5
Setting the default Java character encoding?
Please, now consider the following code:
public class FileEncodingTest {
public static void main (String[] args) {
System.out.println(System.getProperty("file.encoding"));
System.setProperty("file.encoding", "UTF-8");
System.out.println(System.getProperty("file.encoding"));
}
}
Then I create a jar-file using Eclipse and Java 1.6 set in project configuration.
Then I run jar-file with Java 1.7 and all this happens under Windows 7.
java -jar FileEncodingTest.jar
Cp1251
UTF-8
java -jar FileEncodingTest.jar
Cp1251
UTF-8
So who and why resets the value of file.encoding back to Cp1251?
UPD:
Anyone can explain or provide a link which explains step-by-step what happens in terms of JVM, processes when I type java -jar MyClass.jar?

you started 2 vm's. one with each "java -jar" command.
you can change the encoding your projects uses by editing the project properties in eclipse.
but note that when you hardcode stuff that relies on the fileformat and another project uses your implementation there will be problems. thats what the comment means.

Just like you open an IE browser, it goes to homepage at first. If you visit another website, then you open another IE, it will still be the homepage.
JVMs are quite similar. 2 different processes of java program use different JVMs. It means when the program ends, the file-encoding property will be default again.

Related

Java code - Best way to list java processes in localhost JVM (for Linux & Windows]

I'm writing a console app that will run in Linux and Windows systems. This app will mainly run on JRE 1.8 environments.
In my code, it needs to get a list of Java processes that run on the host running my application. I have read the posts about jps, which come as a part of JDK, but not JRE, and also it's a separate executable.
My question is, is there any java library that I can use, to list (and ideally also kill some of) the running Java processes? Preferably, I would not want to hassle of calling jps executable with sth like Runtime.exec().
Thanks in advance, for any suggestions.
Oops: I just spotted that you need solutions for JRE1.8, this will only help for JRE9+.
A simple way to scan processes within JRE is to use ProcessHandle.allProcesses(). This will read all processes and you can add filter on simple name match with "java" or "java.exe":
Path java = Path.of("bin", "java.exe"); // use "java" if not on Windows
ProcessHandle.allProcesses()
.filter(ph -> ph.info().command().isPresent())
.filter(ph -> Path.of(ph.info().command().get()).endsWith(java))
.forEach(ph -> {
System.out.println("PID "+ph.pid()+" "+ph.info().command());
})
This approach won't spot Java VMs embedded in EXE - such as from jpackage - so is not as reliable as using JDK jps which does recognise jpackage EXEs and JDK tools like jshell.exe.
I finally found the 3rd party library named Oshi, which apparently does not need JDK and is compatible with Java 1.8: https://github.com/oshi/oshi
For future reference, here is a sample method:
public static List<OSProcess> getOSProcesses() {
SystemInfo si = new SystemInfo();
OperatingSystem os = si.getOperatingSystem();
return os.getProcesses();
}

Get JRE version from application

I need to get the java version from my application that the user has currently installed on their machine. However, the application that I have is installed with a self-contained JRE and when I do a System.getProperty("java.version"), it only returns the version of that self-contained JRE. Is there anyway that I can get the version that is installed on the machine?
The JRE installation are listed in the registry in the key only for Windows, Linux do not have central registry.
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
You can make a simple program to test :
public class ShowVersion {
public static void main(String args[]) {
System.out.println(System.getProperty("java.version"));
}
}
Or you can try command prompt
Type java -version
For more you can refer sister site of SO :
https://superuser.com/questions/1221096/how-do-i-check-what-version-of-java-i-have-installed
if you're bundling a JRE (did you check the distribution license for it? Make sure you are allowed to do so) and it's running under that, you get that version back.
If the user were to run it under another JRE, you'd get the version of that JRE. That's just how things work.
In fact if you're using a self-contained JRE the user doesn't even have to have another JRE installed on his system at all, that's the entire point of bundling one in the first place.
Apart from a full file system scan it's impossible to know what other JVMs might be installed, and if you do that you'd have to account for all the different names the Java runtime executables may have depending on the files system you're running on. And after finding all those executables you still have no real way of knowing what version of Java they belong to unless you either do a binary analysis of the executables or somehow detect the information from other files in the directories where those executables are installed, files that may or may not be present depending on the system in question, how it was set up, what JVM is in use, and whether the installation has been manually altered or not.
For example, in the root directory of a JDK installation there is a file called "release" which contains the JVM version, but AFAIK that file isn't required to be there for the JVM to work properly. And your application may not have the rights to the file system to read that file.
You can try looking in known paths e.g. C:\Program Files\Java but unless you scan the entire file system for java or java.exe you will never be sure.
This might not work as expected as in the user that runs your application shouldn't have access to system directories. You can force you application to be started with administrator level access but that would be a security risk.
You requirement seems a bit pointless if you are already bundling a JRE with your application.
You can run cmd command using java (java -version) and use that output to get version.
List<String> cmdArgs = new ArrayList<>();
cmdArgs.add("cmd.exe");
cmdArgs.add("/C");
cmdArgs.add("java -version");
ProcessBuilder processBuilderObj = new ProcessBuilder();
processBuilderObj.command(cmdArgs);
Process process = processBuilderObj.start();
//get inputStream
BufferedReader data = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line1;
while ((line = data.readLine()) != null){
System.out.println(line);
}
While System.getProperty("java.version") returns the version of the Java that your app is running on, calling "java -version" as a system command from your Java app will return the version of the default(installed) Java in your system.
Here are the generic steps to find it programmatically:
Using ProcessBuilder in Java, execute the system command "java -version". This is certainly platform-independent.
Read the output from executed process. The version is usually on the 1st line of the output (smth like java version "1.8.0_191"), so reading the 1st line is enough.
Check using regular expression, if the output matches a string containing a java version, you just parse the version and that will be what you are looking for.
Otherwise, it means the output is an error message (smth like -bash: java: command not found), and there is no Java installed in your system.
control panel
java
Java tab
view
you can see exact version of java used and it's location.

Is JAVA_HOME fixed when executing a java command or can it be modified midcommand?

Just to be clear, I DON'T WANT to change the JAVA_HOME during a java command (and take this change into account for said command), but I'm facing a situation where several java commands can be run simultaneously from some ksh scripts, and in those scripts JAVA_HOME is set (and exported) to either a 32-bits or 64-bits version before executing the java command itself.
So I am concerned there could be some "clashes" of some sort... Any advice on how to avoid any "overlaps", if they are even possible?
Note: there can potentially be a lot of script executions at the same time, and >the commands run with 32-bits version of Java cannot be run with 64-bits >version of Java for compatibility issues with other-party processes
Thanks in advance
JAVA_HOME is just a convention and it has no effect on the running JVM.
You can set the JAVA_HOME safely for each script, however do not use export! or you might end up with unexpected results.
Also, usually, the java application is located at JAVA_HOME/bin so you need to make sure that your script is pointing to the correct JVM 32/64.
HTH,
Gal.
Like all environment variables, it's fixed at the start of the command. See, for example, this question (it's about a Python program, but the same concept applies).
However, as others have pointed out, it doesn't actually have any effect on Java commands.

How to pass 'unsafe' arguments to the JVM of a Java Webstart application

My Java Webstart application runs in a controlled trusted environment. This is a closed internal network where I have some control on how the application is started.
How can I pass JVM arguments to the application, even if they are considered 'unsecure' for use by webstart by the JVM?
There are several options to pass JVM arguments to webstart.
Through JNLP file.
Through the JAVA_TOOL_OPTIONS environment variable.
Through the deployment settings on the local computer.
Through the javaws command (I was unable to get this to work).
Note that I have included links to the java 8 version of this documentation. All of these ideas are supported and documented in other Java versions, however sometimes they work a tiny bit different, or have slightly changed restrictions.
Through JNLP file.
The JNLP supports many JVM arguments through the JNLP file. Some can be done though direct settings, such as initial-heap-size and max-heap-size. For other settings java-vm-args can be used.
The JNLP File Syntax documentation lists some supported java-vm-args for 'this version' however it is unsure if that is the version 1.4+ of the example, or JRE 8. I know some unlisted settings are actually supported, such as -XX:MaxGCPauseMillis and activating the G1 garbage collector. You can make a JNLP and then use jinfo -flag MaxGCPauseMillis <pid> to test if a setting has been correctly propagated.
This is the preferred method, because it does not require any direct control of the JVM. The down-side is that only supports specific parameters that are considered 'safe'.
Through the JAVA_TOOL_OPTIONS environment variable
When you start Java Webstart by using the javaws command, you can use the JAVA_TOOL_OPTIONS to set any parameter you want on all JVM started from that environment.
So in Linux you can do to set an unsupported parameter:
export JAVA_TOOL_OPTIONS=-XX:SoftRefLRUPolicyMSPerMB=2000
javaws <my jnlp>
Note that this will affect all java applications ran with this system variable. So setting this for all users, or a specific user should be done with great care. Setting this only for a single application as the example above is much safer.
The advantage of this solution is that you can pass any parameter you want. The downside is that it requires a specific way of launching the application, or a very broad setting. It also requires control over the client system.
Through the deployment settings on the local computer
You can also pass JVM arguments by changing the deployment settings of the JVM. This can be done through the Java Control Panel, which allows you to set default runtime settings.
If you want to automate these settings you can use the deployment properties file. Unfortunately the JRE specific section of this file is undocumented. Manually it is very easy to adapt this file:
deployment.javaws.jre.0.args=-XX\:SoftRefLRUPolicyMSPerMB\=2000
When automating this file, you have to watch very carefully that it contains these settings for all detected JVMs, so you have to be sure to change the correct one. Also this will be used for all Webstart and applets on your system.
Through the javaws command (I was unable to get this to work)
There should be another way (besides the JAVA_TOOL_OPTIONS method) to change the parameters using the command line. The javaws documentation lists the -J option to pass arguments to the JVM, for example by running your JNLP as follows:
javaws -J-XX:SoftRefLRUPolicyMSPerMB=2000 <my jnlp>
However I have not been able to get this to actually set the JVM parameters.

Setting the default Java character encoding

How do I properly set the default character encoding used by the JVM (1.5.x) programmatically?
I have read that -Dfile.encoding=whatever used to be the way to go for older JVMs. I don't have that luxury for reasons I wont get into.
I have tried:
System.setProperty("file.encoding", "UTF-8");
And the property gets set, but it doesn't seem to cause the final getBytes call below to use UTF8:
System.setProperty("file.encoding", "UTF-8");
byte inbytes[] = new byte[1024];
FileInputStream fis = new FileInputStream("response.txt");
fis.read(inbytes);
FileOutputStream fos = new FileOutputStream("response-2.txt");
String in = new String(inbytes, "UTF8");
fos.write(in.getBytes());
Unfortunately, the file.encoding property has to be specified as the JVM starts up; by the time your main method is entered, the character encoding used by String.getBytes() and the default constructors of InputStreamReader and OutputStreamWriter has been permanently cached.
As Edward Grech points out, in a special case like this, the environment variable JAVA_TOOL_OPTIONS can be used to specify this property, but it's normally done like this:
java -Dfile.encoding=UTF-8 … com.x.Main
Charset.defaultCharset() will reflect changes to the file.encoding property, but most of the code in the core Java libraries that need to determine the default character encoding do not use this mechanism.
When you are encoding or decoding, you can query the file.encoding property or Charset.defaultCharset() to find the current default encoding, and use the appropriate method or constructor overload to specify it.
From the JVM™ Tool Interface documentation…
Since the command-line cannot always be accessed or modified, for example in embedded VMs or simply VMs launched deep within scripts, a JAVA_TOOL_OPTIONS variable is provided so that agents may be launched in these cases.
By setting the (Windows) environment variable JAVA_TOOL_OPTIONS to -Dfile.encoding=UTF8, the (Java) System property will be set automatically every time a JVM is started. You will know that the parameter has been picked up because the following message will be posted to System.err:
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
I have a hacky way that definitely works!!
System.setProperty("file.encoding","UTF-8");
Field charset = Charset.class.getDeclaredField("defaultCharset");
charset.setAccessible(true);
charset.set(null,null);
This way you are going to trick JVM which would think that charset is not set and make it to set it again to UTF-8, on runtime!
I think a better approach than setting the platform's default character set, especially as you seem to have restrictions on affecting the application deployment, let alone the platform, is to call the much safer String.getBytes("charsetName"). That way your application is not dependent on things beyond its control.
I personally feel that String.getBytes() should be deprecated, as it has caused serious problems in a number of cases I have seen, where the developer did not account for the default charset possibly changing.
I can't answer your original question but I would like to offer you some advice -- don't depend on the JVM's default encoding. It's always best to explicitly specify the desired encoding (i.e. "UTF-8") in your code. That way, you know it will work even across different systems and JVM configurations.
Try this :
new OutputStreamWriter( new FileOutputStream("Your_file_fullpath" ),Charset.forName("UTF8"))
I have tried a lot of things, but the sample code here works perfect.
Link
The crux of the code is:
String s = "एक गाव में एक किसान";
String out = new String(s.getBytes("UTF-8"), "ISO-8859-1");
We were having the same issues. We methodically tried several suggestions from this article (and others) to no avail. We also tried adding the -Dfile.encoding=UTF8 and nothing seemed to be working.
For people that are having this issue, the following article finally helped us track down describes how the locale setting can break unicode/UTF-8 in Java/Tomcat
http://www.jvmhost.com/articles/locale-breaks-unicode-utf-8-java-tomcat
Setting the locale correctly in the ~/.bashrc file worked for us.
In case you are using Spring Boot and want to pass the argument file.encoding in JVM you have to run it like that:
mvn spring-boot:run -Drun.jvmArguments="-Dfile.encoding=UTF-8"
this was needed for us since we were using JTwig templates and the operating system had ANSI_X3.4-1968 that we found out through System.out.println(System.getProperty("file.encoding"));
Hope this helps someone!
My team encountered the same issue in machines with Windows.. then managed to resolve it in two ways:
a) Set enviroment variable (even in Windows system preferences)
JAVA_TOOL_OPTIONS
-Dfile.encoding=UTF8
b) Introduce following snippet to your pom.xml:
-Dfile.encoding=UTF-8
WITHIN
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001
-Dfile.encoding=UTF-8
</jvmArguments>
I'm using Amazon (AWS) Elastic Beanstalk and successfully changed it to UTF-8.
In Elastic Beanstalk, go to Configuration > Software, "Environment properties".
Add (name) JAVA_TOOL_OPTIONS with (value) -Dfile.encoding=UTF8
After saving, the environment will restart with the UTF-8 encoding.
Not clear on what you do and don't have control over at this point. If you can interpose a different OutputStream class on the destination file, you could use a subtype of OutputStream which converts Strings to bytes under a charset you define, say UTF-8 by default. If modified UTF-8 is suffcient for your needs, you can use DataOutputStream.writeUTF(String):
byte inbytes[] = new byte[1024];
FileInputStream fis = new FileInputStream("response.txt");
fis.read(inbytes);
String in = new String(inbytes, "UTF8");
DataOutputStream out = new DataOutputStream(new FileOutputStream("response-2.txt"));
out.writeUTF(in); // no getBytes() here
If this approach is not feasible, it may help if you clarify here exactly what you can and can't control in terms of data flow and execution environment (though I know that's sometimes easier said than determined). Good luck.
mvn clean install -Dfile.encoding=UTF-8 -Dmaven.repo.local=/path-to-m2
command worked with exec-maven-plugin to resolve following error while configuring a jenkins task.
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512m; support was removed in 8.0
Error occurred during initialization of VM
java.nio.charset.IllegalCharsetNameException: "UTF-8"
at java.nio.charset.Charset.checkName(Charset.java:315)
at java.nio.charset.Charset.lookup2(Charset.java:484)
at java.nio.charset.Charset.lookup(Charset.java:464)
at java.nio.charset.Charset.defaultCharset(Charset.java:609)
at sun.nio.cs.StreamEncoder.forOutputStreamWriter(StreamEncoder.java:56)
at java.io.OutputStreamWriter.<init>(OutputStreamWriter.java:111)
at java.io.PrintStream.<init>(PrintStream.java:104)
at java.io.PrintStream.<init>(PrintStream.java:151)
at java.lang.System.newPrintStream(System.java:1148)
at java.lang.System.initializeSystemClass(System.java:1192)
Solve this problem in my project. Hope it helps someone.
I use LIBGDX java framework and also had this issue in my android studio project.
In Mac OS encoding is correct, but in Windows 10 special characters and symbols and
also russian characters show as questions like: ????? and other incorrect symbols.
Change in android studio project settings:
File->Settings...->Editor-> File Encodings to UTF-8 in all three fields (Global Encoding, Project Encoding and Default below).
In any java file set:
System.setProperty("file.encoding","UTF-8");
And for test print debug log:
System.out.println("My project encoding is : "+ Charset.defaultCharset());
Setting up jvm arguments while starting application helped me resolve this issue. java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8.
file.encoding=UTF-8 - This helps to have the Unicode characters in the file.
sun.jnu.encoding=UTF-8 - This helps to have the Unicode characters as the File name in the file system.
We set there two system properties together and it makes the system take everything into utf8
file.encoding=UTF8
client.encoding.override=UTF-8
Following #Caspar comment on accepted answer, the preferred way to fix this according to Sun is :
"change the locale of the underlying platform before starting your Java program."
http://bugs.java.com/view_bug.do?bug_id=4163515
For docker see:
http://jaredmarkell.com/docker-and-locales/
Recently I bumped into a local company's Notes 6.5 system and found out the webmail would show unidentifiable characters on a non-Zhongwen localed Windows installation. Have dug for several weeks online, figured it out just few minutes ago:
In Java properties, add the following string to Runtime Parameters
-Dfile.encoding=MS950 -Duser.language=zh -Duser.country=TW -Dsun.jnu.encoding=MS950
UTF-8 setting would not work in this case.

Categories