RFR: 8292892: Javadoc index descriptions are not deterministic

John Neffenger jgneff at openjdk.org
Mon Aug 29 21:41:09 UTC 2022


On Mon, 29 Aug 2022 21:03:34 GMT, John Neffenger <jgneff at openjdk.org> wrote:

> Please review these changes to the Javadoc index builders. This pull request adds 423 missing entries to the index of the JDK API Specification, corrects their package names in the member search index, and makes their descriptions deterministic. I'll follow up with more information in a separate comment.

This is an interesting bug. It's the first one I've encountered that is impossible to miss with reproducible builds but might have been impossible to find without them. It also reveals a surprising feature of the Java language: inaccessible members can be made public by an intermediate subclass.

That feature first caused problems for Javadoc in 2002 with bug JDK-4780441. The fix for that bug made it so that "inherited members from package private classes are now documented as though they were declared in the inheriting class." The fix was released in Java SE 5 ("Tiger"), adding the members to the pages of their inheriting classes. The members were added to the index in Java SE 15.

Below is a description of the problem, as I understand it, and my proposed solution.

### The problem

The Javadoc code refers to the type in which a member is found as the *containing type element* and stores it in its own `IndexItem` class. The type in which a member is declared is referred to as the *enclosing element.* The problem occurs because the code assumes that these two elements are always the same, yet for the few cases where members are otherwise inaccessible, they aren't.

For example, there are four index items of `LOCCRC` in the `java.util.jar` package. They are shown below with their string values, where `iN` represents an instance of `IndexItem`.


i1.getLabel()                          "LOCCRC"
i1.getContainingTypeElement()          "java.util.jar.JarEntry"
i1.getElement().getEnclosingElement()  "java.util.zip.ZipConstants"

i2.getLabel()                          "LOCCRC"
i2.getContainingTypeElement()          "java.util.jar.JarFile"
i2.getElement().getEnclosingElement()  "java.util.zip.ZipConstants"

i3.getLabel()                          "LOCCRC"
i3.getContainingTypeElement()          "java.util.jar.JarInputStream"
i3.getElement().getEnclosingElement()  "java.util.zip.ZipConstants"

i4.getLabel()                          "LOCCRC"
i4.getContainingTypeElement()          "java.util.jar.JarOutputStream"
i4.getElement().getEnclosingElement()  "java.util.zip.ZipConstants"


Index items are stored in a set, and the set's comparator function uses the index label and the enclosing element to determine whether an item is already in the set. The four items above appear the same to the comparator, so only the first one makes it into the set. The first one is just the one first found in the package directory when they are loaded in *directory order* (unsorted). So the random order in which the source files are stored by the file system in their directory determines which one of the items gets listed in the index.

There's a related problem in the member search index. The class name of the containing type element is appended to the package name of the enclosing element. That works for most members, but for these specially-inherited members, it creates entries that don't exist. For example, the search index might list `java.util.zip.JarEntry.LOCCRC` and link it to the file `java/util/zip/JarEntry.html`.

### The solution

The solution is to add a step to the comparator: when two index items are the same after comparing their labels and enclosing elements, make an additional comparison of their containing type elements. For the related problem in the member search index, the solution is to get the package name from the containing type element instead of from the enclosing element.

The 423 new index entries are shown as insertions in the `git diff` files linked below:

* [JDK API Index: Before vs. After JDK-8292892 ](https://gist.github.com/jgneff/cd3d1622bf1b5150e9dde8fd26c41cfc)
* [JDK API Search: Before vs. After JDK-8292892](https://gist.github.com/jgneff/3c74d38ec7b46a29ebc4bb1282b47d16)

As far as I can tell, all of the new entries are inherited from just the following members:


package java.awt;
abstract class AttributeValue {
    public int hashCode() {...}
    public String toString() {...}
}

package java.lang;
abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
        permits StringBuilder, StringBuffer {
    public IntStream chars()  {...}
    public IntStream codePoints()  {...}
}

package java.lang.foreign;
public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout,
        GroupLayout, PaddingLayout, ValueLayout {
    long bitAlignment();
    long bitSize();
    long byteSize();
    boolean isPadding();
    Optional<String> name();
}

package java.time.chrono;
public interface ChronoLocalDate extends Temporal, TemporalAdjuster,
        Comparable<ChronoLocalDate> {
    String toString();
    long until(Temporal endExclusive, TemporalUnit unit);
}

package java.util.zip;
interface ZipConstants {
    static final int CENATT = 36;
    ...
    static final int LOCVER = 4;
}

package jdk.incubator.vector;
abstract class AbstractVector<E> extends Vector<E> {
    public final <F> Vector<F> castShape(VectorSpecies<F> toSpecies, int part) {...}
    public final <F> Vector<F> check(Class<F> elementType) {...}
    public final <F> Vector<F> check(VectorSpecies<F> species) {...}
    public abstract <F> Vector<F> convertShape(Conversion<E,F> conv,
        VectorSpecies<F> rsp, int part);
    public final <F> Vector<F> convert(Conversion<E,F> conv, int part) {...}
    public final VectorMask<E> maskAll(boolean bit) {...}
    public DoubleVector reinterpretAsDoubles() {...}
    public FloatVector reinterpretAsFloats() {...}
    public IntVector reinterpretAsInts() {...}
    public LongVector reinterpretAsLongs() {...}
    public ShortVector reinterpretAsShorts() {...}
    public final VectorSpecies<E> species() {...}
}

-------------

PR: https://git.openjdk.org/jdk/pull/10070


More information about the javadoc-dev mailing list