Friday Stats: classfile versioning tool

Stuart Marks stuart.marks at oracle.com
Fri Jun 21 18:44:11 PDT 2013


Hi all, nice project ya got here!

Here's a script and some Friday stats for you. I've written a script that 
prints out the class file versions of class files and classes found within jar 
files. The script is calls "classvers" and I've attached a patch to add it to 
the repo.

Basically when run it and it will take a list of jars or classes. For each 
class, it lists the class file version number and the class file name. For each 
jar file, it unpacks the jar into a temp area and lists the classes and 
versions of classfiles within that jar. If given no arguments, it searches the 
hierarchy beneath the current working directory and prints out class file 
versions for all class and jar files found.

(Oh, I guess I should have added that as help text to the script.)

I ran it over JDK 7 Update 25, and the output is like the following:

---------

48 db/lib/derby.jar!/org/apache/derby/authentication/SystemPrincipal.class
48 db/lib/derby.jar!/org/apache/derby/authentication/UserAuthenticator.class
48 db/lib/derby.jar!/org/apache/derby/catalog/AliasInfo.class
48 db/lib/derby.jar!/org/apache/derby/catalog/DefaultInfo.class
48 db/lib/derby.jar!/org/apache/derby/catalog/Dependable.class
... 47,025 lines omitted ...

---------

Who cares about class file versions? Well, given the entire output in 
classes.list, one can generate a few summary statistics, like so:

     awk '{print $1}' classes.list | sort -k 1n | uniq -c

   18 45
1315 47
2672 48
2631 49
14850 50
25544 51

Looking at Joe Darcy's class file version decoder ring [1], one can see that 
the latest JDK 7 update release contains mostly JDK 7 classes, lots of JDK 6 
classes, a fair number of classes from JDK 5, JDK 1.4, and JDK 1.3, and even a 
handful of files in the JDK 1.1 format!

(I'll leave it as an exercise to the reader to find out which classes are the 
JDK 1.1 versions.)

Enjoy,

s'marks


[1] https://blogs.oracle.com/darcy/entry/source_target_class_file_version

-------------- next part --------------
# HG changeset patch
# User smarks
# Date 1371864704 25200
# Node ID 8a9e02901ded7df14ec55568313ce08cb2f6109a
# Parent  49376e5d18f1c0a7fbac8dad5b21fddff45d0134
Add class file versioning script.

diff -r 49376e5d18f1 -r 8a9e02901ded scripts/classvers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/classvers	Fri Jun 21 18:31:44 2013 -0700
@@ -0,0 +1,74 @@
+#!/bin/bash
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+TMPDIR=/tmp/classvers$$
+trap 'rm -rf $TMPDIR; exit 0' 0 1 2 3 15
+
+# oneclass classfile prefix
+# extracts class version byte in hex
+# od output is like:
+#     0000007    34                                                            
+function oneclass {
+    vers=$(od -t u1 -j 7 -N 1 "$1" | awk '$1 == 0000007 { print $2 }')
+    echo $vers $2$1
+}
+
+# findclasses [prefix]
+function findclasses {
+    find . -name '*.class' -print |
+    while read clname ; do
+        clname=${clname#./}
+        oneclass "$clname" "$1"
+    done
+}
+
+# onejar jarfile
+function onejar {
+    mkdir $TMPDIR
+    ( cd $TMPDIR
+      jar -x
+      findclasses "${1}!/"
+    ) < $1
+    rm -rf $TMPDIR
+}
+
+function classorjar {
+    case "$1" in
+        *.class)
+            oneclass "$1"
+            ;;
+        *.jar)
+            onejar "$1"
+            ;;
+    esac
+}
+
+if [ $# -eq 0 ]; then
+    find . \( -name '*.class' -o -name '*.jar' \) -print |
+    while read f ; do
+        classorjar "${f#./}"
+    done
+else
+    for arg in "$@" ; do
+        classorjar "$arg"
+    done
+fi


More information about the friday-stats-dev mailing list