I believe I've seen all of the other posts on this issue. I think this is a different question because I am looking for a way to determine which class is causing the problem.
I build my jar using Maven.
If I ask it to build for Java 5 and I run it under Java 6 it works fine.
If I ask it to build for Java 6 and I run it under Java 6 it works fine.
If I ask it to build for Java 5 and I run it under Java 5 it fails:
java.lang.RuntimeException: public static void ....main(java.lang.String[]) failed for arguments (String[]{...})
Caused by: java.lang.reflect.InvocationTargetException:
...
Caused by: java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
...
I have inspected the jar using Java Version Check and it reports all classes in the jar as built for Java 5.
I can only conclude that it is hacking its own classpath and linking up with some other library/jar on my machine that is not Java 5. This is quite possible but I do not have access to the source of that process and as far as I am aware I cannot single-step into the class loader to find out which class it is loading.
Are there any techniques I can use that will help me work out which class is causing the exception?
Well to check what JVM versions JARs in your classpath have, I would do something like the recipe below. But as I already mentioned in the last comment, this solution doesn't cover cases when a JAR have a custom classloader which modifies classpath and does other evil things. Nevertheless you may try to use this solution and see if it helps. If no, a more elaborate solution is required...
retrieve a full classpath for your application. Usually I perform this step with Maven AppAssembler but certainly there're other ways. AppAssembler is handy because it builds a shell script with the classpath specified explicitly, so you may simply copy-paste it.
Run the following bash script with the classpath as the argument. The script uses
file
,unzip
andbc
internally, so you should have these tools installed.
The script:
#!/bin/sh -e
# force numeric to use decimal point
LC_NUMERIC=C
export LC_NUMERIC
tempdir=
cleanup() {
trap - EXIT
if test -n "$tempdir"; then
rm -rf "$tempdir" ||:
fi
exit "$@"
}
debug() {
test -z "$DEBUG" || echo "$@" >&2 ||:
}
get_jar_version() {
local ver maxVersion compare
maxVersion=0.0
for ver in $(find "$1" -type f -name '*.class' -exec file {} \; | grep 'Java class data, version' | sed -e 's;.*Java class data, version ;;'); do
debug "Version = '$ver'"
compare=$(echo "$ver > $maxVersion" | bc)
if [ "x$compare" = "x1" ]; then
maxVersion="$ver"
fi
done
debug "maxVersion=$maxVersion"
echo -n "$maxVersion"
}
process_classpath_jars() {
trap cleanup EXIT
local cp jar oldIFS maxVersion
oldIFS="$IFS"
for cp in "$@"; do
IFS=':'
for jar in $cp; do
if [ -z "$jar" -o "${jar%.jar}" = "$jar" ]; then
continue
fi
debug "processing JAR $jar"
tempdir=$(mktemp -d jar.XXXXXXX)
unzip -qq "$jar" -d "$tempdir"
IFS="$oldIFS"
maxVersion=$(get_jar_version "$tempdir")
rm -rf "$tempdir" ||:
tempdir=
IFS=':'
echo "$jar is compiled for $maxVersion JVM"
done
IFS="$oldIFS"
done
}
process_classpath_jars "$@"
I believe I've seen all of the other posts on this issue. I think this is a different question because I am looking for a way to determine which class is causing the problem.
I build my jar using Maven.
If I ask it to build for Java 5 and I run it under Java 6 it works fine.
If I ask it to build for Java 6 and I run it under Java 6 it works fine.
If I ask it to build for Java 5 and I run it under Java 5 it fails:
java.lang.RuntimeException: public static void ....main(java.lang.String[]) failed for arguments (String[]{...})
Caused by: java.lang.reflect.InvocationTargetException:
...
Caused by: java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
...
I have inspected the jar using Java Version Check and it reports all classes in the jar as built for Java 5.
I can only conclude that it is hacking its own classpath and linking up with some other library/jar on my machine that is not Java 5. This is quite possible but I do not have access to the source of that process and as far as I am aware I cannot single-step into the class loader to find out which class it is loading.
Are there any techniques I can use that will help me work out which class is causing the exception?
Well to check what JVM versions JARs in your classpath have, I would do something like the recipe below. But as I already mentioned in the last comment, this solution doesn't cover cases when a JAR have a custom classloader which modifies classpath and does other evil things. Nevertheless you may try to use this solution and see if it helps. If no, a more elaborate solution is required...
retrieve a full classpath for your application. Usually I perform this step with Maven AppAssembler but certainly there're other ways. AppAssembler is handy because it builds a shell script with the classpath specified explicitly, so you may simply copy-paste it.
Run the following bash script with the classpath as the argument. The script uses
file
,unzip
andbc
internally, so you should have these tools installed.
The script:
#!/bin/sh -e
# force numeric to use decimal point
LC_NUMERIC=C
export LC_NUMERIC
tempdir=
cleanup() {
trap - EXIT
if test -n "$tempdir"; then
rm -rf "$tempdir" ||:
fi
exit "$@"
}
debug() {
test -z "$DEBUG" || echo "$@" >&2 ||:
}
get_jar_version() {
local ver maxVersion compare
maxVersion=0.0
for ver in $(find "$1" -type f -name '*.class' -exec file {} \; | grep 'Java class data, version' | sed -e 's;.*Java class data, version ;;'); do
debug "Version = '$ver'"
compare=$(echo "$ver > $maxVersion" | bc)
if [ "x$compare" = "x1" ]; then
maxVersion="$ver"
fi
done
debug "maxVersion=$maxVersion"
echo -n "$maxVersion"
}
process_classpath_jars() {
trap cleanup EXIT
local cp jar oldIFS maxVersion
oldIFS="$IFS"
for cp in "$@"; do
IFS=':'
for jar in $cp; do
if [ -z "$jar" -o "${jar%.jar}" = "$jar" ]; then
continue
fi
debug "processing JAR $jar"
tempdir=$(mktemp -d jar.XXXXXXX)
unzip -qq "$jar" -d "$tempdir"
IFS="$oldIFS"
maxVersion=$(get_jar_version "$tempdir")
rm -rf "$tempdir" ||:
tempdir=
IFS=':'
echo "$jar is compiled for $maxVersion JVM"
done
IFS="$oldIFS"
done
}
process_classpath_jars "$@"
0 commentaires:
Enregistrer un commentaire