I have a Java application that uses -D system properties that I create. I'm having issues getting one of them to be translated correctly.
In my test environment (localhost) on my local computer, I'm running Windows using IntelliJ Idea IDE and I enter the -D system properties through the IDE like so:
-Dproperty={\"prop1\":\"val1\",\"prop2\":\"val2\"}
I escape the double quotes because they need to be apart of the string literal. The above property works and the entire value including the curly braces is stored as a string literal.
The issue occurs when we deploy this application to our Linux cloud environment. I think the difference in architecture is causing the system property to not be read in correctly. In bash, I find the process ID of all the -D system properties and do a ps -fwwp [processId] command. I see that the above property is being broken up into a bunch of smaller properties that look like the following:
-Dproperty=prop1:val1
-Dproperty=prop2:val2
-Dproperty=prop3:val3
etc...
This is causing the part of my application that uses this property to fail. I've tried doing a bunch of escaping methods and none of them are working.
How can I escape this system property in such a way that the value is treated as the string literal {"prop1":"val1","prop2":"val2"}
Bash requires the curly braces to be escaped, as in:
-Dproperty=\{\"prop1\":\"val1\",\"prop2\":\"val2\"\}
The other option is to try surrounding the entire string in single quotes. Bash won't do any expansions inside single quotes:
-Dproperty='{"prop1":"val1","prop2":"val2"}'
I don't know which option will be easier to make compatible with your windows environment.
Related
I have the following simple java program:
import java.util.Arrays;
public class Arguments
{
public static void main(String [] args)
{
System.out.println("args: "+Arrays.toString(args));
}
}
When I execute this in powershell using the following command: java Arguments "*.java" the string received in the program is not "*.java" but a comma-separated list of all java files in the current directory. And if there are no java files in the current directory the string received is "*.java".
I want to know why this is happening and how to pass a string as it is without converting it.
Update: java Arguments '"*".java' and java Arguments `"*.java`" did the work but this creates the same problem when executed in cmd. Can anyone explain why this is happening? Is there any common solution for both PowerShell and cmd?
It is not PowerShell (nor cmd.exe) that interprets "*.java" as a filename pattern and expands (resolves) it to the matching files, known as globbing in the Unix world.
(You would only get that behavior if you used *.java - i.e., no quoting - in PowerShell Core on Unix-like platforms, but never with a quoted string such as "*.java" or '*.java', and even without quoting never on Windows).
Apparently, it is legacy versions of java.exe on Windows that automatically perform the globbing on unquoted arguments, in an apparent attempt to emulate the behavior of POSIX-like shells such as Bash on Unix.
As of (at least) JDK 12, this behavior no longer seems to be effect, at least not by default.
The linked answer suggests that in earlier versions there may be a system property that controls the behavior, but it's unclear what its name is.
Generally, the syntax java -D<systemPropName>=<value> ... can be used to set a system property on startup.
Therefore, you have the following options:
Upgrade to a Java version that no longer exhibits this behavior (by default).
In legacy versions, find the relevant system property name that disables the behavior and use the syntax shown above.
Use shell-specific quoting, as shown below.
Using quoting to prevent globbing:
To prevent java.exe from performing globbing, the invocation command line must ultimately contain "*.java", i.e., the argument must be enclosed in double quotes.
Unfortunately, there is no common syntax that works in both PowerShell and cmd.exe:
cmd.exe:
cmd.exe passes double-quoted arguments through as-is, so the following is sufficient:
java Arguments "*.java"
PowerShell:
PowerShell, by contrast, performs re-quoting as needed behind the scenes (see this answer for more information).
Since an argument with content *.java normally does not require quoting when you pass it to an external program, PowerShell translates both "*.java" and '*.java' to unquoted *.java in the command line that is ultimately used behind the scenes - which is what you experienced.
There are two ways around that:
Use java Arguments '"*.java"', i.e., embed the " chars. in the argument, inside a literal string ('...').
Use java Arguments --% "*.java"; --% is the stop-parsing symbol (PSv3+), which instructs PowerShell to pass the remainder of the command line through as-is (except for expanding cmd.exe-style environment-variable references).
We have a number of unit tests which assemble a multi-line string in memory and compare it against a reference string in a file.
We've gotten a bit carried away and implemented the tests to use System.getProperty("line.separator") to make the code OS-agnostic, but the reference files are just files with \n line endings (Linux), so the tests which compared generated content to reference file content fail on a Windows machine because System.getProperty("line.separator") returns \r\n there.
This is test code so we'll probably simply define a final String LINE_ENDING="\n" and update tests to use it instead of the "line.separator" property value, but that said, I'd really like to understand why I'm unable to specify a different line separator. I tried mvn -DargLine="-Dline.separator=\n" test, but the newline special character appears to have been interpreted as a literal letter "n" so tests failed again. To my surprise, trying \\n instead of \n made no difference, either.
Can anyone show how one would set the line.separator parameter properly?
Final note: the above commands were issued on a Linux machine. When running one of the tests from within Eclipse on a Windows, the \n special character (passed in the debug configuration as a JVM parameter -Dline.separator=\n) seems to be interpreted as the literal value "\\n". Searching the web proves frustratingly fruitless.
I have a .bat file on Windows/shell script on Linux that starts a large Java application from the command line. It configures the classpath, environment variables, etc.
At one point, it uses RMID to configure a bunch of services which will run in their own JVMs. The problem is that it won't allow me to specify multiple JARs for the codebase property on Linux. It's allowing me to do so on Windows just fine, but I think my syntax/styling must be wrong for the .sh script and am hoping a more experienced Linux user could have some tip. On Windows, the working line looks like this:
SET RMID_OPTIONS=%RMID_VM%
-J-DINSTALL_DIR=%CONFIG_PATH%
-C-DINSTALL_DIR=%CONFIG_PATH%
-J-DINSTALL_DIR_LOCAL=%HOME_DIR%
-C-DINSTALL_DIR_LOCAL=%HOME_DIR%
-J-Djava.security.policy=%PL_HOME%\windows\system.policy
-C-Djava.rmi.server.codebase=
"file:/%HOME_DIR%\jar1.jar file:/%HOME_DIR%\jar2.jar"
-J-Djava.rmi.server.codebase=
"file:/%HOME_DIR%\jar1.jar file:/%HOME_DIR%\jar2.jar"
// more stuff here
The only important lines are the ones setting the rmi.server.codebase property. The above works 100% fine, however, when trying to set multiple JARs in the codebase in Linux, it causes a general failure and the whole RMID command is not executed. My shell script looks like the following:
export RMID_OPTIONS="${RMID_VM}
-J-DINSTALL_DIR=${CONFIG_PATH}
-C-DINSTALL_DIR=${CONFIG_PATH}
-J-DINSTALL_DIR_LOCAL=${HOME_DIR}
-C-DINSTALL_DIR_LOCAL=${HOME_DIR}
-J-Djava.security.policy=${PL_HOME}/linux/system.policy
-C-Djava.rmi.server.codebase=
""file:/${HOME_DIR}/jar1.jar file:/${PL_HOME_LOCAL}/jar2.jar""
-J-Djava.rmi.server.codebase=
""file:/${HOME_DIR}/jar1.jar file:/${PL_HOME_LOCAL}/jar2.jar""
// more stuff here
"
The shell script itself works perfectly fine if only one JAR is specified, but any more and I get a general failure. Any suggestions on what I'm doing wrong? I'm open to try new things to fix this as all my attempts so far have been fruitless.
Under Linux, escaping quotes is done differently. You are attempting to use the Windows specific syntax, which will result in the jar files being passed as separate arguments, instead of a single one, as it should be.
Instead of "" to produce a quote inside quotes, you have to use \" in Linux:
export RMID_OPTIONS="... -C-Djava.rmi.server.codebase=\"file:/${HOME_DIR}/jar1.jar file:/${PL_HOME_LOCAL}/jar2.jar\" ..."
Aside from that, I'm not sure that the file:/ syntax is correct. It's probably either file:// or the absolute file path without anything preceding it, but you'll have to try it out.
You're doing this wrong. You don't need to start rmid with arguments and system properties at all. All that stuff should be specified when you register the ActivationGroup(s) you're going to use, in your activation setup program. That in turn means that all command-line problems should just disappear.
I'd like to create an universal launch configuration for deploying Java EE application to Tomcat server to share it with other team members.
To achieve it, I replaced all paths with variables.
Here are VM arguments for "Apache Tomcat" launch configuration:
-Dcatalina.base="${workspace_loc}/.metadata/.plugins/org.eclipse.wst.server.core/tmp1" -Dcatalina.home="${catalina_home}" -Dwtp.deploy="${workspace_loc}/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps" -Djava.endorsed.dirs="${catalina_home}/endorsed" -Dservices.properties="dbDriver=org.sqlite.JDBC,dbUrl=jdbc:sqlite:${workspace_loc}/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/Services/"
All variables are resolved properly, except the last one, that losses backslashes: Tomcat is started, application runs, but, when I'm trying to log into database I get an error: path to 'C:Usersvackovaworkspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/Services/BURZA8P4/BRSTST': 'C:\Program Files (x86)\eclipse\Usersvackovaworkspace' does not exist, because the dbUrl is resolved to jdbc:sqlite:C:Usersvackovaworkspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/Services/BURZA8P4/BRSTST instead of jdbc:sqlite:C:\Users\vackova/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/Services/BURZA8P4/BRSTST
Does it exist a way to say Eclipse, to not remove the backslashes? Or to enforce it for using slashes instead of backslashes?
This is because \ is an escape character.
C:\Users\vackova should be C:\\Users\\vackova, or you should read this from a configuration file.
I'm trying to compile a Java project under Cygwin using a native Win32 Java.
The Java binaries are correctly found under /cygdrive/c/jdk/bin on my machine.
The following command works fine:
javac -d . ./gnu/kawa/util/PreProcess.java
The PreProcess.class file is generated in ./gnu/kawa/util/. Trying to invoke Java on this fails however:
CLASSPATH=.:$CLASSPATH java gnu.kawa.util.PreProcess \
%java6 +use:com.sun.net.httpserver +enable:XML \
`sed -e 's|\([^ ]*\)|./\1|' < ./patch-source-list`
Error: Could not find or load main class gnu.kawa.util.PreProcess
...
This command was invoked by make, that's where the $CLASSPATH variable is set dynamically. patch-source-list is just a list of class names. The : in the classpath looks suspicious, but I'm not sure how to test ; while not annoying sh.
My only other suspicion is that the native Java is trying gnu\kawa\util\PreProcess, but I think cygwin can transparently handle that.
Any ideas? Thanks for your time.
Another option would be to build your path using the ':' and then fix the results using cygpath. This is probably overkill in your specific situation, but in a general case where you may have references to multiple directories, some of which may be referenced as absolute rather than relative paths, or if you are working with cygwin symlinks, it is much more useful.
$ ln -s /cygdrive/c/development/libraries/ ../libs
$ cygpath -pw /cygdrive/c/development/:.:../libs
C:\development\;.;C:\development\libraries\
so then you'd build your CLASSPATH variable as before, and in the final stage run
CLASSPATH="`cygpath -pw "$CLASSPATH"`" java (whatever)
Remember, the JVM has no idea that you are using the cygwin bash shell.
Two things:
for the classpath locations, use the windows path names. Thus, no "/cygdrive/c/somepath", but "c:\somepath\" ("/" and "\" can be used interchangeably however)
use ';' instead of ':' in the classpath list
This should work:
export CLASSPATH="./gnu/kawa/util/PreProcess.class"
CLASSPATH=".;$CLASSPATH" java gnu.kawa.util.PreProcess
The : in the classpath looks suspicious, but I'm not sure how to test ; while not annoying sh.
You're exactly right: you need to use ; instead of :. As for how to use it — as Mat alludes to above, you need to "quote" the semicolon. Any of these will work:
CLASSPATH=.\;$CLASSPATH java Foo
CLASSPATH=.';'$CLASSPATH java Foo
CLASSPATH='.;'$CLASSPATH java Foo
CLASSPATH=".;$CLASSPATH" java Foo
You can use whichever one you like best. (The first uses a backslash, which quotes a single following character. The second and third use single-quotes, which quote a sequence of zero or more characters. The fourth uses double-quotes, which are like single-quotes except that they still allow the variable $CLASSPATH to be expanded. For that matter, you could also write something like
CLASSPATH=".;"$CLASSPATH java Foo
if you want. See the above link for lots more information about quoting in Bash.)