Thursday, December 28, 2017

Command line classpath is ignored when using -jar

I was a little shocked today by my discovery of -classpath (-cp) parameter being ignored silently by Java Virtual Machine, when -jar is provided. Look at this (my jar file prints out its working directory and classpath):
java -cp /home:./ -jar ./build/jarclassscanning.jar

Working Directory = /home/me/projects/jarclassscanning
----------------
Classpath elements:
/home/me/projects/jarclassscanning/build/jarclassscanning.jar
----------------

However, if I run the same jar without -jar parameter, here's what it prints out (I've added a couple of directories to -cp just to show that it works):
java -cp /home:./:./build/jarclassscanning.jar my.package.jarclassscanning.BaseClass

Working Directory = /home/me/projects/jarclassscanning
----------------
Classpath elements:
/home/
/home/me/projects/jarclassscanning/
/home/me/projects/jarclassscanning/build/jarclassscanning.jar
----------------

So if your jar uses classes from other jars (or just plain old .class files) and you have to specify classpath, one solution is to add classpath elements to the manifest file - https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html. Keep in mind, however, that you've got to use spaces to separate them, not colons.

Also I've ran into another thing - when specifying jar files as classpath elements using Class-Path field of the manifest file using relative paths, they had to be relative to the location of my jar (the one that I give to JVM using -jar).

So, since my folder structure looked like this:
build
    myjar.jar
jdbc
    postgresql-42.1.4.jar
amqp
    amqp-client-4.2.0.jar
sl4j
    slf4j-simple-1.7.25.jar
    slf4j-api-1.7.25.jar

The Class-Path field of the manifest in myjar.jar ended up looking like this (note the ".."'s):
Class-Path: ../jdbc/postgresql-42.1.4.jar ../amqp/amqp-client-4.2.0.jar ../slf4j/slf4j-simple-1.7.25.jar ../slf4j/slf4j-api-1.7.25.jar

Tuesday, December 26, 2017

Apache Ant modifies classpath

Just a quick note - I have discovered this thing while digging into Java class loading / reflection. When running my test program from command line, like so:
java -ea -cp ./build/jarclassscanning.jar my.package.jarclassscanning.BaseClass
(yes, I specify my main class directly and just add my jar file to the classpath)

my classpath contains what I expect it to contain:
/home/me/projects/jarclassscanning/build/jarclassscanning.jar

But if I use my simplistic ant build.xml, which contains target run:
<target name="run">
  <java classname="my.package.jarclassscanning.BaseClass">
    <arg value="-ea"/>
    <classpath>
      <pathelement location="./build/jarclassscanning.jar"/>
    </classpath>
  </java>
</target>

this is what my classpath becomes (printed out from the test program itself):
/home/me/apps/apache-ant-1.9.7/lib/ant-launcher.jar

However, if I add fork="true" to the java task (just as you should if you use jar attribute, which I don't):
<target name="run">
  <java classname="my.package.jarclassscanning.BaseClass" fork="true">
    <arg value="-ea"/>
    <classpath>
      <pathelement location="./build/jarclassscanning.jar"/>
    </classpath>
  </java>
</target>

everything's back to normal:
/home/me/projects/jarclassscanning/build/jarclassscanning.jar

Saturday, February 18, 2017

A C pitfall

Consider the following code:

#include ‹stdio.h›

int main(void)
{
 printf("This line ends with backslash (\\)\n"); // Print \
 printf("This is the second line\n");
 printf("This is the third line\n");
 return 0;
}

gcc 5.4.0 I have on my Xubuntu 16.04 box compiles this code without errors or warnings.
What do you think the code prints out when run?
This:

This line ends with backslash (\)
This is the third line

The second line is silently ignored by the compiler. The reason is that the line before it ends with backslash symbol (\). Even if the backslash belongs to the comment, gcc still considers the second line to be continuation of the line before it, and exactly because of this the second line is considered to be the continuation of the comment and is ignored.

Worst of all there's no warning or error, although ideone tells me that at least gcc 6.3 refuses to compile the code:
prog.c: In function ‘main’:
prog.c:5:50: error: multi-line comment [-Werror=comment]
  printf("This line ends with backslash (\\)\n"); // Print \
                                                  ^
cc1: all warnings being treated as errors

But anyway this is something to be aware of, especially if you're not sure about the way your compiler treats this case.