先のエントリで、ConcurrentLinkedDequeクラスを見つけた時にふと思ったのですが、新しいバージョンのJDKで追加されたクラスって、みなさんどうやって探しているんでしょうね?
だいたい新しいJDKのリリース前に新機能に関する記事が出てきて、それを使って掘り下げていくうちに、また別のクラスを知る、みたいな感じだと思います。
そして、その時ってJavadocの@sinceタグを見ていることが多いんじゃないかなーと思うわけです。なのであれば、Javadocを使えば、例えば「JDK 7で追加されたクラスを探す」なんてことができるのではないかと思った次第です。
で、実際できそうですね。
http://docs.oracle.com/javase/jp/6/technotes/guides/javadoc/index.html
http://docs.oracle.com/javase/jp/6/technotes/guides/javadoc/doclet/overview.html
http://docs.oracle.com/javase/jp/6/jdk/api/javadoc/doclet/index.html
ドックレットを使えばいいみたいです。ドックレットは、本来Javadocの出力を好みの形式にカスタマイズすることに使うんだとか。
以前、XDocletとか名前だけ聞いたことはありましたけど、この辺りのテクノロジの話だったんだなと、今更ながらに思いました。
では、目的のドックレットを書いてみます。
SinceFindDoclet.java
import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Set; import java.util.TreeSet; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.RootDoc; import com.sun.javadoc.Tag; public class SinceFindDoclet { public static boolean start(RootDoc root) { Set<String> classes = new TreeSet<>(); for (ClassDoc classDoc : root.classes()) { for (Tag tag : classDoc.tags("since")) { if ("1.7".equals(tag.text())) { classes.add(classDoc.toString()); } } } try { Files.write(Paths.get("classes_" + System.currentTimeMillis() + ".txt"), classes, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException e) { e.printStackTrace(); } return true; } }
ドックレットは、staticなstartメソッドで開始されるのだとか。
public static boolean start(RootDoc root) {
今回は、渡ってきたRootDocからClassの一覧を取得し、クラスに付与された@sinceタグの値が「1.7」のものを抽出しています。
抽出結果は、タイムスタンプ付きで出力。
それでは、まずはコンパイル。
$ javac -cp $JAVA_HOME/lib/tools.jar SinceFindDoclet.java
コンパイル時に、クラスパスにtools.jarを加える必要があります。
続いて、Javaのソースを対象にするので…とりあえず適当にディレクトリを作成して、そこにsrc.zipをコピーしてunzip。
$ mkdir src $ cd src $ unzip src.zip
まあ、こうなりますよ、と。
$ ll 合計 19420 drwxrwxr-x 8 xxxxx xxxxx 4096 Mar 30 02:30 ./ drwxrwxr-x 3 xxxxx xxxxx 4096 Mar 30 02:43 ../ drwxr-xr-x 3 xxxxx xxxxx 4096 Mar 1 20:20 com/ drwxr-xr-x 15 xxxxx xxxxx 4096 Mar 1 20:20 java/ drwxr-xr-x 17 xxxxx xxxxx 4096 Mar 1 20:20 javax/ drwxr-xr-x 2 xxxxx xxxxx 4096 Mar 1 20:20 launcher/ drwxr-xr-x 6 xxxxx xxxxx 4096 Mar 1 20:20 org/ -rw-r--r-- 1 xxxxx xxxxx 19852819 Mar 30 00:26 src.zip drwxr-xr-x 4 xxxxx xxxxx 4096 Mar 1 20:20 sunw/
ひとつ上のディレクトリから見ると、こんな感じになっています。
$ find ./ -maxdepth 2 ./ ./src ./src/org ./src/sunw ./src/src.zip ./src/java ./src/com ./src/launcher ./src/javax ./SinceFindDoclet.class ./SinceFindDoclet.java
で、再度srcに降りて
$ cd src
java、javax、orgで始まるパッケージくらいに絞ってドックレットを動かします。
$ find java javax org -name "*.java"
ドックレットを組み込んでjavadocコマンドを動かすには、以下の様に書きます。
$ javadoc -doclet SinceFindDoclet -docletpath ../ [ソースコード]
「-doclet」オプションではドックレットのクラス名を指定し、「-docletpath」ではドックレットに対してのクラスパスを設定します。また、追加のクラスパス設定が必要な場合は、「-classpath」を使用します。
で、これを組み合わせてこんなコマンドを作って実行。
$ find java javax org -name "*.java" | xargs javadoc -doclet SinceFindDoclet -docletpath ../
少々待つと、カレントディレクトリに実行結果ができます。結果は、最後に。
とりあえず、今回のコマンドでは191クラスが検出されました。とはいえ、「Javadocに@sinceタグが律儀に書かれていること」がこの調べ方の大前提なので、@sinceタグを書いてなかったりすると普通にスルーされます。
なので、完璧ではありませんし、そんなに他のコードに適用できる方法ではないかもしれませんね。
で、実行結果についてですが、できた結果を開いてみると
$ cat classes_*
こんな感じになりました。ほとんどNIO.2とSwing。って、java.lang.invokeとかがほとんど入ってないので、やっぱりご参考程度、ですね。
java.awt.GraphicsDevice.WindowTranslucency java.awt.SecondaryLoop java.awt.Window.Type java.awt.font.NumericShaper.Range java.beans.Transient java.lang.AutoCloseable java.lang.BootstrapMethodError java.lang.Character.UnicodeScript java.lang.ClassValue java.lang.ProcessBuilder.Redirect java.lang.ReflectiveOperationException java.lang.invoke.WrongMethodTypeException java.lang.management.BufferPoolMXBean java.lang.management.PlatformLoggingMXBean java.lang.management.PlatformManagedObject java.net.ProtocolFamily java.net.SocketOption java.net.StandardProtocolFamily java.net.StandardSocketOptions java.nio.channels.AcceptPendingException java.nio.channels.AlreadyBoundException java.nio.channels.AsynchronousByteChannel java.nio.channels.AsynchronousChannel java.nio.channels.AsynchronousChannelGroup java.nio.channels.AsynchronousFileChannel java.nio.channels.AsynchronousServerSocketChannel java.nio.channels.AsynchronousSocketChannel java.nio.channels.CompletionHandler java.nio.channels.IllegalChannelGroupException java.nio.channels.InterruptedByTimeoutException java.nio.channels.MembershipKey java.nio.channels.MulticastChannel java.nio.channels.NetworkChannel java.nio.channels.ReadPendingException java.nio.channels.SeekableByteChannel java.nio.channels.ShutdownChannelGroupException java.nio.channels.WritePendingException java.nio.channels.spi.AsynchronousChannelProvider java.nio.charset.StandardCharsets java.nio.file.AccessDeniedException java.nio.file.AccessMode java.nio.file.AtomicMoveNotSupportedException java.nio.file.ClosedDirectoryStreamException java.nio.file.CopyOption java.nio.file.DirectoryIteratorException java.nio.file.DirectoryNotEmptyException java.nio.file.DirectoryStream java.nio.file.DirectoryStream.Filter java.nio.file.FileAlreadyExistsException java.nio.file.FileStore java.nio.file.FileSystem java.nio.file.FileSystemException java.nio.file.FileSystemLoopException java.nio.file.FileSystems java.nio.file.FileVisitOption java.nio.file.FileVisitResult java.nio.file.FileVisitor java.nio.file.Files java.nio.file.LinkOption java.nio.file.LinkPermission java.nio.file.NoSuchFileException java.nio.file.NotDirectoryException java.nio.file.NotLinkException java.nio.file.OpenOption java.nio.file.Path java.nio.file.PathMatcher java.nio.file.Paths java.nio.file.SecureDirectoryStream java.nio.file.SimpleFileVisitor java.nio.file.StandardCopyOption java.nio.file.StandardOpenOption java.nio.file.StandardWatchEventKinds java.nio.file.WatchEvent java.nio.file.WatchEvent.Kind java.nio.file.WatchEvent.Modifier java.nio.file.WatchKey java.nio.file.WatchService java.nio.file.Watchable java.nio.file.attribute.AclEntry java.nio.file.attribute.AclEntry.Builder java.nio.file.attribute.AclEntryFlag java.nio.file.attribute.AclEntryPermission java.nio.file.attribute.AclEntryType java.nio.file.attribute.AclFileAttributeView java.nio.file.attribute.AttributeView java.nio.file.attribute.BasicFileAttributeView java.nio.file.attribute.BasicFileAttributes java.nio.file.attribute.DosFileAttributeView java.nio.file.attribute.DosFileAttributes java.nio.file.attribute.FileAttribute java.nio.file.attribute.FileAttributeView java.nio.file.attribute.FileOwnerAttributeView java.nio.file.attribute.FileStoreAttributeView java.nio.file.attribute.FileTime java.nio.file.attribute.GroupPrincipal java.nio.file.attribute.PosixFileAttributeView java.nio.file.attribute.PosixFileAttributes java.nio.file.attribute.PosixFilePermission java.nio.file.attribute.PosixFilePermissions java.nio.file.attribute.UserDefinedFileAttributeView java.nio.file.attribute.UserPrincipal java.nio.file.attribute.UserPrincipalLookupService java.nio.file.attribute.UserPrincipalNotFoundException java.nio.file.spi.FileSystemProvider java.nio.file.spi.FileTypeDetector java.security.AlgorithmConstraints java.security.CryptoPrimitive java.security.cert.CRLReason java.security.cert.CertPathValidatorException.BasicReason java.security.cert.CertPathValidatorException.Reason java.security.cert.CertificateRevokedException java.security.cert.Extension java.security.cert.PKIXReason java.sql.PseudoColumnUsage java.util.IllformedLocaleException java.util.Locale.Builder java.util.Locale.Category java.util.Objects java.util.concurrent.ConcurrentLinkedDeque java.util.concurrent.ForkJoinPool java.util.concurrent.ForkJoinTask java.util.concurrent.ForkJoinWorkerThread java.util.concurrent.LinkedTransferQueue java.util.concurrent.Phaser java.util.concurrent.RecursiveAction java.util.concurrent.RecursiveTask java.util.concurrent.ThreadLocalRandom java.util.concurrent.TransferQueue javax.lang.model.UnknownEntityException javax.lang.model.element.Parameterizable javax.lang.model.element.QualifiedNameable javax.lang.model.type.UnionType javax.lang.model.util.AbstractAnnotationValueVisitor7 javax.lang.model.util.AbstractElementVisitor7 javax.lang.model.util.AbstractTypeVisitor7 javax.lang.model.util.ElementKindVisitor7 javax.lang.model.util.ElementScanner7 javax.lang.model.util.SimpleAnnotationValueVisitor7 javax.lang.model.util.SimpleElementVisitor7 javax.lang.model.util.SimpleTypeVisitor7 javax.lang.model.util.TypeKindVisitor7 javax.print.attribute.standard.DialogTypeSelection javax.security.auth.kerberos.KeyTab javax.sql.rowset.RowSetFactory javax.sql.rowset.RowSetProvider javax.swing.JLayer javax.swing.border.StrokeBorder javax.swing.plaf.LayerUI javax.swing.plaf.synth.SynthButtonUI javax.swing.plaf.synth.SynthCheckBoxMenuItemUI javax.swing.plaf.synth.SynthCheckBoxUI javax.swing.plaf.synth.SynthColorChooserUI javax.swing.plaf.synth.SynthComboBoxUI javax.swing.plaf.synth.SynthDesktopIconUI javax.swing.plaf.synth.SynthDesktopPaneUI javax.swing.plaf.synth.SynthEditorPaneUI javax.swing.plaf.synth.SynthFormattedTextFieldUI javax.swing.plaf.synth.SynthInternalFrameUI javax.swing.plaf.synth.SynthLabelUI javax.swing.plaf.synth.SynthListUI javax.swing.plaf.synth.SynthMenuBarUI javax.swing.plaf.synth.SynthMenuItemUI javax.swing.plaf.synth.SynthMenuUI javax.swing.plaf.synth.SynthOptionPaneUI javax.swing.plaf.synth.SynthPanelUI javax.swing.plaf.synth.SynthPasswordFieldUI javax.swing.plaf.synth.SynthPopupMenuUI javax.swing.plaf.synth.SynthProgressBarUI javax.swing.plaf.synth.SynthRadioButtonMenuItemUI javax.swing.plaf.synth.SynthRadioButtonUI javax.swing.plaf.synth.SynthRootPaneUI javax.swing.plaf.synth.SynthScrollBarUI javax.swing.plaf.synth.SynthScrollPaneUI javax.swing.plaf.synth.SynthSeparatorUI javax.swing.plaf.synth.SynthSliderUI javax.swing.plaf.synth.SynthSpinnerUI javax.swing.plaf.synth.SynthSplitPaneUI javax.swing.plaf.synth.SynthTabbedPaneUI javax.swing.plaf.synth.SynthTableHeaderUI javax.swing.plaf.synth.SynthTableUI javax.swing.plaf.synth.SynthTextAreaUI javax.swing.plaf.synth.SynthTextFieldUI javax.swing.plaf.synth.SynthTextPaneUI javax.swing.plaf.synth.SynthToggleButtonUI javax.swing.plaf.synth.SynthToolBarUI javax.swing.plaf.synth.SynthToolTipUI javax.swing.plaf.synth.SynthTreeUI javax.swing.plaf.synth.SynthUI javax.swing.plaf.synth.SynthViewportUI javax.sound.midi.MidiDeviceReceiver javax.sound.midi.MidiDeviceTransmitter