torutkのブログ

ソフトウェア・エンジニアのブログ

カスタムJavadocとJDK 7で新しく導入されたクラス・メソッド

JDK 7で追加されるクラス・メソッドを一覧してみようと思いました。標準APIソースコードJDKと一緒にインストールされるので(src.zip)、これを展開し、Javadocコメントの@sinceタグに1.7とあるものを抽出すればいいというのが最初の発想です。

JDK 7のソースコードからJavadocコメントの@sinceタグ部分抜粋

新しく導入されたクラスは、クラスのJavadocに記載される@sinceタグに1.7と書かれています。以下は、JDK 7で新規追加されるクラス javax.swing.JLayer の例です。

package javax.swing;
  :(中略)
/**
 * {@code JLayer} is a universal decorator for Swing components
  :(中略)
 * @since 1.7
  :(中略)
 */
public final class JLayer<V extends Component>
        extends JComponent
        implements Scrollable, PropertyChangeListener, Accessible {

以下は、java.util.logging.Loggerクラスに、JDK 7で新規追加されるメソッド getGlobal の例です。

    /**
     * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
     *
     * @return global logger object
     * @since 1.7
     */
    public static final Logger getGlobal() {
        return global;
    }

@since 1.7が記載されたクラスやメソッドを抽出するには

find, grep, awkでは、ちょっとつらい(同一行にクラス・メソッド情報がないため)ので、いろいろ考えてみましたが、これは自分でJavadocのDoclet実装を書き、@sinceタグで1.7の記述があるクラス・メソッドの名前だけ出力すればよいと思いました。

JavadocのDocletを書いてみる

そこで、見よう見まねで作ってみたのが以下です。

package jp.gr.java_conf.torutk.doclets;

import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.Tag;

public class ListBySinceDoclet {

    private static final String TAG_SINCE = "@since";

    public static boolean start(RootDoc root) {
        ClassDoc[] classDocs = root.classes();
        for (ClassDoc classDoc : classDocs) {
            Tag[] sinceTags = classDoc.tags(TAG_SINCE);
            if (isSinceTagMatches(sinceTags)) {
                System.out.println(classDoc.qualifiedName() + " [class]");
            }
            MethodDoc[] methodDocs = classDoc.methods();
            for (MethodDoc methodDoc : methodDocs) {
                if (isSinceTagMatches(methodDoc.tags(TAG_SINCE))) {
                    System.out.println(classDoc.qualifiedName() + "#" + methodDoc.name());
                }
            }
        }
        return true;
    }

    private static boolean isSinceTagMatches(Tag[] tags) {
        for (Tag tag : tags) {
            if ("1.7".equals(tag.text())) {
                return true;
            }
        }
        return false;
    }
}

自前のJavadocクラスを作るときは、特に継承するものはなく、public staticなstartメソッドを定義すればよいようです。引数に渡されるRootDocオブジェクトから芋づる的にたぐって、クラスやメソッドのJavadocコメントに書かれた@sinceタグを取り出し、値が1.7と一致するか調べ、一致していたらクラス名またはメソッド名をprintしているだけのコードです。

Javadocのパッケージcom.sun.javadocは、tools.jarに含まれる

コンパイル時にクラスパスに明示的にJDKのtool.jarを追加します。

実行

カレントディレクトリをjdk 7のsrc.zip展開場所に移動し、自前のJavadocクラスを置いた場所と自前のJavadocクラス、解析対象パッケージを指定します。

C:\work\jdk7\src> javadoc -docletpath C:\work\since \
  -doclet jp.gr.java_conf.torutk.doclets.ListBySinceDoclet \
  -subpackages java:javax:org
    :(中略)
java.lang.Byte#compare
java.lang.Boolean#compare
java.lang.AutoCloseable [class]
    :(後略)

JDK 7 build 130のsrc.zipに対して実行した結果一覧

java.applet.Applet#isValidateRoot
java.awt.Window#setAutoRequestFocus
java.awt.Window#isAutoRequestFocus
java.awt.Window#isValidateRoot
java.awt.Window#setType
java.awt.Window#getType
java.awt.Window#getOpacity
java.awt.Window#setOpacity
java.awt.Window#getShape
java.awt.Window#setShape
java.awt.Window#isOpaque
java.awt.Window#paint
java.awt.Window.Type [class]
java.awt.Toolkit#areExtraMouseButtonsEnabled
java.awt.SecondaryLoop [class]
java.awt.GraphicsDevice#isWindowTranslucencySupported
java.awt.GraphicsDevice.WindowTranslucency [class]
java.awt.GraphicsConfiguration#isTranslucencyCapable
java.awt.FileDialog#getFiles
java.awt.FileDialog#setMultipleMode
java.awt.FileDialog#isMultipleMode
java.awt.EventQueue#createSecondaryLoop
java.awt.Container#isValidateRoot
java.awt.event.MouseWheelEvent#getPreciseWheelRotation
java.awt.event.KeyEvent#getExtendedKeyCode
java.awt.event.KeyEvent#getExtendedKeyCodeForChar
java.awt.event.InvocationEvent#isDispatched
java.awt.font.NumericShaper#getShaper
java.awt.font.NumericShaper#getContextualShaper
java.awt.font.NumericShaper#getContextualShaper
java.awt.font.NumericShaper#shape
java.awt.font.NumericShaper#getRangeSet
java.awt.font.NumericShaper.Range [class]
.\java\awt\peer\DialogPeer.java:69: 警告 - タグ@see: java.awt.DialogでblockWindows()が見つかりません
java.awt.peer.ComponentPeer#applyShape
java.awt.peer.ComponentPeer#updateGraphicsData
java.awt.peer.CanvasPeer#getAppropriateGraphicsConfiguration
java.beans.XMLDecoder#createHandler
java.beans.Transient [class]
java.beans.PropertyChangeEvent#toString
java.beans.Introspector#getBeanInfo
java.beans.FeatureDescriptor#toString
java.beans.Expression#execute
java.io.File#toPath
java.lang.Throwable#addSuppressed
java.lang.Throwable#getSuppressed
java.lang.Short#compare
java.lang.ReflectiveOperationException [class]
java.lang.ProcessBuilder#redirectInput
java.lang.ProcessBuilder#redirectOutput
java.lang.ProcessBuilder#redirectError
java.lang.ProcessBuilder#redirectInput
java.lang.ProcessBuilder#redirectOutput
java.lang.ProcessBuilder#redirectError
java.lang.ProcessBuilder#redirectInput
java.lang.ProcessBuilder#redirectOutput
java.lang.ProcessBuilder#redirectError
java.lang.ProcessBuilder#inheritIO
java.lang.ProcessBuilder.Redirect [class]
java.lang.Long#compare
java.lang.Integer#compare
java.lang.ClassLoader#getClassLoadingLock
java.lang.ClassLoader#registerAsParallelCapable
java.lang.Character#isBmpCodePoint
java.lang.Character#isSurrogate
java.lang.Character#highSurrogate
java.lang.Character#lowSurrogate
java.lang.Character#compare
java.lang.Character#getName
java.lang.Character.UnicodeScript [class]
java.lang.Byte#compare
java.lang.Boolean#compare
java.lang.AutoCloseable [class]
java.lang.management.PlatformManagedObject [class]
java.lang.management.ManagementFactory#getPlatformMXBeans
java.lang.management.ManagementFactory#getPlatformMXBeans
java.lang.management.ManagementFactory#getAllPlatformMXBeanInterfaces
java.lang.reflect.Modifier#classModifiers
java.lang.reflect.Modifier#interfaceModifiers
java.lang.reflect.Modifier#constructorModifiers
java.lang.reflect.Modifier#methodModifiers
java.lang.reflect.Modifier#fieldModifiers
java.net.URLClassLoader#getResourceAsStream
java.net.URLClassLoader#close
java.net.StandardSocketOption [class]
java.net.StandardProtocolFamily [class]
java.net.SocketOption [class]
java.net.ProtocolFamily [class]
java.net.NetworkInterface#getIndex
java.net.NetworkInterface#getByIndex
java.net.InetSocketAddress#getHostString
java.net.InetAddress#getLoopbackAddress
java.net.HttpURLConnection#setFixedLengthStreamingMode
java.nio.BufferPoolMXBean [class]
java.nio.channels.WritePendingException [class]
java.nio.channels.SocketChannel#bind
java.nio.channels.SocketChannel#setOption
java.nio.channels.SocketChannel#shutdownInput
java.nio.channels.SocketChannel#shutdownOutput
java.nio.channels.SocketChannel#getRemoteAddress
java.nio.channels.ShutdownChannelGroupException [class]
java.nio.channels.ServerSocketChannel#bind
java.nio.channels.ServerSocketChannel#bind
java.nio.channels.ServerSocketChannel#setOption
java.nio.channels.SeekableByteChannel [class]
java.nio.channels.ReadPendingException [class]
java.nio.channels.NetworkChannel [class]
java.nio.channels.MulticastChannel [class]
java.nio.channels.MembershipKey [class]
java.nio.channels.InterruptedByTimeoutException [class]
java.nio.channels.IllegalChannelGroupException [class]
java.nio.channels.FileLock#acquiredBy
java.nio.channels.FileLock#close
java.nio.channels.FileChannel#open
java.nio.channels.FileChannel#open
java.nio.channels.DatagramChannel#open
java.nio.channels.DatagramChannel#bind
java.nio.channels.DatagramChannel#setOption
java.nio.channels.DatagramChannel#getRemoteAddress
java.nio.channels.CompletionHandler [class]
java.nio.channels.Channels#newInputStream
java.nio.channels.Channels#newOutputStream
java.nio.channels.AsynchronousSocketChannel [class]
java.nio.channels.AsynchronousServerSocketChannel [class]
java.nio.channels.AsynchronousFileChannel [class]
java.nio.channels.AsynchronousChannelGroup [class]
java.nio.channels.AsynchronousChannel [class]
java.nio.channels.AsynchronousByteChannel [class]
java.nio.channels.AlreadyBoundException [class]
java.nio.channels.AcceptPendingException [class]
java.nio.channels.spi.SelectorProvider#openDatagramChannel
java.nio.channels.spi.AsynchronousChannelProvider [class]
java.nio.file.Watchable [class]
java.nio.file.WatchService [class]
java.nio.file.WatchKey [class]
java.nio.file.WatchEvent [class]
java.nio.file.WatchEvent.Kind [class]
java.nio.file.WatchEvent.Modifier [class]
java.nio.file.StandardWatchEventKind [class]
java.nio.file.StandardOpenOption [class]
java.nio.file.StandardCopyOption [class]
java.nio.file.SimpleFileVisitor [class]
java.nio.file.SecureDirectoryStream [class]
java.nio.file.Paths [class]
java.nio.file.PathMatcher [class]
java.nio.file.Path [class]
java.nio.file.OpenOption [class]
java.nio.file.NotLinkException [class]
java.nio.file.NotDirectoryException [class]
java.nio.file.NoSuchFileException [class]
java.nio.file.LinkPermission [class]
java.nio.file.LinkOption [class]
java.nio.file.Files [class]
java.nio.file.FileVisitor [class]
java.nio.file.FileVisitResult [class]
java.nio.file.FileVisitOption [class]
java.nio.file.FileSystems [class]
java.nio.file.FileSystemLoopException [class]
java.nio.file.FileSystemException [class]
java.nio.file.FileSystem [class]
java.nio.file.FileStore [class]
java.nio.file.FileAlreadyExistsException [class]
java.nio.file.DirectoryStream [class]
java.nio.file.DirectoryStream.Filter [class]
java.nio.file.DirectoryNotEmptyException [class]
java.nio.file.DirectoryIteratorException [class]
java.nio.file.CopyOption [class]
java.nio.file.ClosedDirectoryStreamException [class]
java.nio.file.AtomicMoveNotSupportedException [class]
java.nio.file.AccessMode [class]
java.nio.file.AccessDeniedException [class]
java.nio.file.attribute.UserPrincipalNotFoundException [class]
java.nio.file.attribute.UserPrincipalLookupService [class]
java.nio.file.attribute.UserPrincipal [class]
java.nio.file.attribute.UserDefinedFileAttributeView [class]
java.nio.file.attribute.PosixFilePermissions [class]
java.nio.file.attribute.PosixFilePermission [class]
java.nio.file.attribute.PosixFileAttributes [class]
java.nio.file.attribute.PosixFileAttributeView [class]
java.nio.file.attribute.GroupPrincipal [class]
java.nio.file.attribute.FileTime [class]
java.nio.file.attribute.FileStoreAttributeView [class]
java.nio.file.attribute.FileOwnerAttributeView [class]
java.nio.file.attribute.FileAttributeView [class]
java.nio.file.attribute.FileAttribute [class]
java.nio.file.attribute.DosFileAttributes [class]
java.nio.file.attribute.DosFileAttributeView [class]
java.nio.file.attribute.BasicFileAttributes [class]
java.nio.file.attribute.BasicFileAttributeView [class]
java.nio.file.attribute.AttributeView [class]
java.nio.file.attribute.AclFileAttributeView [class]
java.nio.file.attribute.AclEntryType [class]
java.nio.file.attribute.AclEntryPermission [class]
java.nio.file.attribute.AclEntryFlag [class]
java.nio.file.attribute.AclEntry [class]
java.nio.file.attribute.AclEntry.Builder [class]
java.nio.file.spi.FileTypeDetector [class]
java.nio.file.spi.FileSystemProvider [class]
java.security.CryptoPrimitive [class]
java.security.AlgorithmConstraints [class]
java.security.cert.X509CRLEntry#getRevocationReason
java.security.cert.PKIXReason [class]
java.security.cert.Extension [class]
java.security.cert.CertificateRevokedException [class]
java.security.cert.CertPathValidatorException#getReason
java.security.cert.CertPathValidatorException.Reason [class]
java.security.cert.CertPathValidatorException.BasicReason [class]
java.security.cert.CRLReason [class]
java.sql.Statement#closeOnCompletion
java.sql.Statement#isCloseOnCompletion
java.sql.ResultSet#getObject
java.sql.ResultSet#getObject
java.sql.PseudoColumnUsage [class]
java.sql.Driver#getParentLogger
java.sql.DatabaseMetaData#getPseudoColumns
java.sql.DatabaseMetaData#generatedKeyAlwaysReturned
java.sql.Connection#setSchema
java.sql.Connection#getSchema
java.sql.Connection#abort
java.sql.Connection#setNetworkTimeout
java.sql.Connection#getNetworkTimeout
java.sql.CallableStatement#getObject
java.sql.CallableStatement#getObject
java.util.Objects [class]
java.util.Locale#getDefault
java.util.Locale#setDefault
java.util.Locale#getScript
java.util.Locale#getExtension
java.util.Locale#getExtensionKeys
java.util.Locale#getUnicodeLocaleAttributes
java.util.Locale#getUnicodeLocaleType
java.util.Locale#getUnicodeLocaleKeys
java.util.Locale#toLanguageTag
java.util.Locale#forLanguageTag
java.util.Locale#getDisplayScript
java.util.Locale#getDisplayScript
java.util.Locale.Category [class]
java.util.Locale.Builder [class]
java.util.IllformedLocaleException [class]
java.util.GregorianCalendar#isWeekDateSupported
java.util.GregorianCalendar#getWeekYear
java.util.GregorianCalendar#setWeekDate
java.util.GregorianCalendar#getWeeksInWeekYear
java.util.Currency#getAvailableCurrencies
java.util.Currency#getNumericCode
java.util.Currency#getDisplayName
java.util.Currency#getDisplayName
java.util.Collections#emptyIterator
java.util.Collections#emptyListIterator
java.util.Collections#emptyEnumeration
java.util.Calendar#isWeekDateSupported
java.util.Calendar#getWeekYear
java.util.Calendar#setWeekDate
java.util.Calendar#getWeeksInWeekYear
java.util.BitSet#valueOf
java.util.BitSet#valueOf
java.util.BitSet#valueOf
java.util.BitSet#valueOf
java.util.BitSet#toByteArray
java.util.BitSet#toLongArray
java.util.BitSet#previousSetBit
java.util.BitSet#previousClearBit
java.util.concurrent.TransferQueue [class]
java.util.concurrent.ThreadLocalRandom [class]
java.util.concurrent.ScheduledThreadPoolExecutor#setRemoveOnCancelPolicy
java.util.concurrent.ScheduledThreadPoolExecutor#getRemoveOnCancelPolicy
java.util.concurrent.RecursiveTask [class]
java.util.concurrent.RecursiveAction [class]
java.util.concurrent.Phaser [class]
java.util.concurrent.LinkedTransferQueue [class]
java.util.concurrent.ForkJoinWorkerThread [class]
java.util.concurrent.ForkJoinTask [class]
java.util.concurrent.ForkJoinPool [class]
java.util.concurrent.ConcurrentLinkedDeque [class]
java.util.concurrent.locks.AbstractQueuedSynchronizer#hasQueuedPredecessors
java.util.concurrent.locks.AbstractQueuedLongSynchronizer#hasQueuedPredecessors
java.util.logging.PlatformLoggingMXBean [class]
java.util.logging.Logger#getGlobal
java.util.spi.LocaleNameProvider#getDisplayScript
java.util.spi.CurrencyNameProvider#getDisplayName
java.util.zip.DeflaterOutputStream#flush
java.util.zip.Deflater#deflate
javax.lang.model.element.QualifiedNameable [class]
javax.lang.model.element.Parameterizable [class]
javax.lang.model.UnknownEntityException [class]
javax.lang.model.type.TypeVisitor#visitDisjunctive
javax.lang.model.type.DisjunctiveType [class]
javax.lang.model.util.TypeKindVisitor7 [class]
javax.lang.model.util.SimpleTypeVisitor7 [class]
javax.lang.model.util.SimpleElementVisitor7 [class]
javax.lang.model.util.SimpleAnnotationValueVisitor7 [class]
javax.lang.model.util.ElementScanner7 [class]
javax.lang.model.util.ElementKindVisitor7 [class]
javax.lang.model.util.ElementKindVisitor6#visitVariableAsResourceVariable
javax.lang.model.util.AbstractTypeVisitor7 [class]
javax.lang.model.util.AbstractTypeVisitor6#visitDisjunctive
javax.lang.model.util.AbstractElementVisitor7 [class]
javax.lang.model.util.AbstractAnnotationValueVisitor7 [class]
javax.print.attribute.standard.DialogTypeSelection [class]
javax.sound.midi.MidiDeviceTransmitter [class]
javax.sound.midi.MidiDeviceReceiver [class]
javax.sql.CommonDataSource#getParentLogger
javax.sql.rowset.RowSetProvider [class]
javax.sql.rowset.RowSetProvider#newFactory
javax.sql.rowset.RowSetProvider#newFactory
javax.sql.rowset.RowSetFactory [class]
javax.sql.rowset.RowSetFactory#createCachedRowSet
javax.sql.rowset.RowSetFactory#createFilteredRowSet
javax.sql.rowset.RowSetFactory#createJdbcRowSet
javax.sql.rowset.RowSetFactory#createJoinRowSet
javax.sql.rowset.RowSetFactory#createWebRowSet
javax.swing.SwingUtilities#getUnwrappedParent
javax.swing.SwingUtilities#getUnwrappedView
javax.swing.JTree.EmptySelectionModel#setSelectionMode
javax.swing.JTree.EmptySelectionModel#setRowMapper
javax.swing.JTree.EmptySelectionModel#addTreeSelectionListener
javax.swing.JTree.EmptySelectionModel#removeTreeSelectionListener
javax.swing.JTree.EmptySelectionModel#addPropertyChangeListener
javax.swing.JTree.EmptySelectionModel#removePropertyChangeListener
javax.swing.JSlider#imageUpdate
javax.swing.JList#getSelectedValuesList
javax.swing.JLayer [class]
javax.swing.BorderFactory#createLineBorder
javax.swing.BorderFactory#createRaisedSoftBevelBorder
javax.swing.BorderFactory#createLoweredSoftBevelBorder
javax.swing.BorderFactory#createSoftBevelBorder
javax.swing.BorderFactory#createSoftBevelBorder
javax.swing.BorderFactory#createSoftBevelBorder
javax.swing.BorderFactory#createStrokeBorder
javax.swing.BorderFactory#createStrokeBorder
javax.swing.BorderFactory#createDashedBorder
javax.swing.BorderFactory#createDashedBorder
javax.swing.BorderFactory#createDashedBorder
javax.swing.border.StrokeBorder [class]
javax.swing.event.HyperlinkEvent#getInputEvent
javax.swing.plaf.LayerUI [class]
javax.swing.plaf.FileChooserUI#getDefaultButton
javax.swing.plaf.basic.BasicTreeUI#isDropLine
javax.swing.plaf.basic.BasicTreeUI#paintDropLine
javax.swing.plaf.basic.BasicTreeUI#getDropLineRect
javax.swing.plaf.basic.BasicTreeUI#updateLeadSelectionRow
javax.swing.plaf.basic.BasicTreeUI#getLeadSelectionRow
javax.swing.plaf.basic.BasicFileChooserUI#createUI
javax.swing.plaf.basic.BasicComboBoxUI#getSizeForComponent
javax.swing.plaf.basic.BasicColorChooserUI#uninstallPreviewPanel
javax.swing.plaf.nimbus.NimbusLookAndFeel#shouldUpdateStyleOnEvent
javax.swing.plaf.synth.SynthViewportUI [class]
javax.swing.plaf.synth.SynthUI [class]
javax.swing.plaf.synth.SynthTreeUI [class]
javax.swing.plaf.synth.SynthToolTipUI [class]
javax.swing.plaf.synth.SynthToolBarUI [class]
javax.swing.plaf.synth.SynthToggleButtonUI [class]
javax.swing.plaf.synth.SynthTextPaneUI [class]
javax.swing.plaf.synth.SynthTextFieldUI [class]
javax.swing.plaf.synth.SynthTextAreaUI [class]
javax.swing.plaf.synth.SynthTableUI [class]
javax.swing.plaf.synth.SynthTableHeaderUI [class]
javax.swing.plaf.synth.SynthTabbedPaneUI [class]
javax.swing.plaf.synth.SynthSplitPaneUI [class]
javax.swing.plaf.synth.SynthSpinnerUI [class]
javax.swing.plaf.synth.SynthSliderUI [class]
javax.swing.plaf.synth.SynthSeparatorUI [class]
javax.swing.plaf.synth.SynthScrollPaneUI [class]
javax.swing.plaf.synth.SynthScrollBarUI [class]
javax.swing.plaf.synth.SynthRootPaneUI [class]
javax.swing.plaf.synth.SynthRadioButtonUI [class]
javax.swing.plaf.synth.SynthRadioButtonMenuItemUI [class]
javax.swing.plaf.synth.SynthProgressBarUI [class]
javax.swing.plaf.synth.SynthPopupMenuUI [class]
javax.swing.plaf.synth.SynthPasswordFieldUI [class]
javax.swing.plaf.synth.SynthPanelUI [class]
javax.swing.plaf.synth.SynthOptionPaneUI [class]
javax.swing.plaf.synth.SynthMenuUI [class]
javax.swing.plaf.synth.SynthMenuItemUI [class]
javax.swing.plaf.synth.SynthMenuBarUI [class]
javax.swing.plaf.synth.SynthLookAndFeel#shouldUpdateStyleOnEvent
javax.swing.plaf.synth.SynthListUI [class]
javax.swing.plaf.synth.SynthLabelUI [class]
javax.swing.plaf.synth.SynthInternalFrameUI [class]
javax.swing.plaf.synth.SynthFormattedTextFieldUI [class]
javax.swing.plaf.synth.SynthEditorPaneUI [class]
javax.swing.plaf.synth.SynthDesktopPaneUI [class]
javax.swing.plaf.synth.SynthDesktopIconUI [class]
javax.swing.plaf.synth.SynthComboBoxUI [class]
javax.swing.plaf.synth.SynthColorChooserUI [class]
javax.swing.plaf.synth.SynthCheckBoxUI [class]
javax.swing.plaf.synth.SynthCheckBoxMenuItemUI [class]
javax.swing.plaf.synth.SynthButtonUI [class]
javax.swing.text.JTextComponent#saveComposedText
javax.swing.text.JTextComponent#restoreComposedText
javax.swing.text.DefaultStyledDocument#removeElement
javax.swing.tree.DefaultTreeCellRenderer#updateUI