Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK-8267204: Expose access to underlying streams in Reporter #4077

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -25,6 +25,8 @@

package jdk.javadoc.doclet;

import java.io.PrintWriter;
import java.util.Locale;
import java.util.Set;

import javax.lang.model.SourceVersion;
@@ -35,6 +37,8 @@
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject.Kind;

import jdk.javadoc.doclet.Reporter;

import com.sun.source.util.DocTrees;

/**
@@ -136,7 +140,47 @@ public interface DocletEnvironment {
* @param type the type element
* @return the file kind
*/
Kind getFileKind(TypeElement type);
Kind getFileKind(TypeElement type);

/**
* Returns a writer that can be used by a doclet to write non-diagnostic output,
* or {@code null} if no such writer is available.
*
* @apiNote
* The value may or may not be the same as that returned by {@link #getDiagnosticWriter()}.
*
* @implSpec
* This implementation returns {@code null}.
* The implementation provided by the `javadoc` tool to
Copy link
Member

@pavelrappo pavelrappo May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use {@code javadoc} or just javadoc instead of `javadoc` (back ticks).

Copy link
Contributor Author

@jonathan-gibbons jonathan-gibbons May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops

* {@link Doclet#init(Locale, Reporter) initialize doclets}
* always returns a non-{@code null} value.
Copy link
Member

@pavelrappo pavelrappo May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean {@link Doclet#run(DocletEnvironment) run doclets} instead?

Copy link
Contributor Author

@jonathan-gibbons jonathan-gibbons May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I guess I did. Good catch.

*
* @return the writer
* @since 17
*/
default PrintWriter getStandardWriter() {
return null;
}

/**
* Returns a writer that can be used by a doclet to write diagnostic output,
* or {@code null} if no such writer is available.
*
* @apiNote
* The value may or may not be the same as that returned by {@link #getStandardWriter()}.
*
* @implSpec
* This implementation returns {@code null}.
* The implementation provided by the `javadoc` tool to
* {@link Doclet#init(Locale, Reporter) initialize doclets}
* always returns a non-{@code null} value.
Copy link
Member

@pavelrappo pavelrappo May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as two preceding comments.

Copy link
Contributor Author

@jonathan-gibbons jonathan-gibbons May 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as preceding response!

*
* @return the writer
* @since 17
*/
default PrintWriter getDiagnosticWriter() {
return null;
}

/**
* The mode specifying the level of detail of module documentation.
@@ -25,6 +25,7 @@

package jdk.javadoc.internal.tool;

import java.io.PrintWriter;
import java.util.Set;

import javax.lang.model.SourceVersion;
@@ -37,6 +38,7 @@

import com.sun.source.util.DocTrees;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.util.Log;
import jdk.javadoc.doclet.DocletEnvironment;

/**
@@ -120,4 +122,14 @@ public Kind getFileKind(TypeElement type) {
public boolean isSelected(Element e) {
return etable.isSelected(e);
}

@Override
public PrintWriter getStandardWriter() {
return toolEnv.messager.getWriter(Log.WriterKind.STDOUT);
}

@Override
public PrintWriter getDiagnosticWriter() {
return toolEnv.messager.getWriter(Log.WriterKind.STDERR);
}
}
@@ -26,6 +26,7 @@
package jdk.javadoc.internal.tool;


import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.ResourceBundle;
@@ -137,17 +138,25 @@ public void print(Kind kind, Element e, String msg) {
private final JavacMessages messages;
private final JCDiagnostic.Factory javadocDiags;

/** The default writer for diagnostics
*/
static final PrintWriter defaultOutWriter = new PrintWriter(System.out);
static final PrintWriter defaultErrWriter = new PrintWriter(System.err);
private static PrintWriter createPrintWriter(PrintStream ps, boolean autoflush) {
return new PrintWriter(ps, autoflush) {
// avoid closing system streams
@Override
public void close() {
super.flush();
}
};
}

/**
* Constructor
* @param programName Name of the program (for error messages).
*/
public Messager(Context context, String programName) {
this(context, programName, defaultOutWriter, defaultErrWriter);
// use the current values of System.out, System,err, in case they have been redirected
this(context, programName,
createPrintWriter(System.out, false),
createPrintWriter(System.err, true));
}

/**
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2021, 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.
*/

import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Element;

import com.sun.source.doctree.DocTree;

import jdk.javadoc.doclet.Doclet;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.Taglet;

/**
* A taglet whose purpose is to write to the streams available in the DocletEnvironment.
*/
public class MyTaglet implements Taglet {
private DocletEnvironment env;

@Override
public void init(DocletEnvironment env, Doclet doclet) {
this.env = env;
}

@Override
public Set<Location> getAllowedLocations() {
return EnumSet.allOf(Location.class);
}

@Override
public boolean isInlineTag() {
return true;
}

@Override
public String getName() {
return "myTaglet";
}

@Override
public String toString(List<? extends DocTree> tags, Element element) {
env.getStandardWriter().println("writing to the standard writer");
env.getDiagnosticWriter().println("writing to the diagnostic writer");
return "<b>my-taglet</b>";
}
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2021, 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.
*/

/*
* @test
* @bug 8267204
* @summary Expose access to underlying streams in DocletEnvironment
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
* @build toolbox.ToolBox javadoc.tester.* MyTaglet
* @run main TestDocEnvStreams
*/

import java.io.IOException;
import java.nio.file.Path;

import javadoc.tester.JavadocTester;
import toolbox.ToolBox;

public class TestDocEnvStreams extends JavadocTester {

public static void main(String... args) throws Exception {
TestDocEnvStreams tester = new TestDocEnvStreams();
tester.runTests(m -> new Object[] { Path.of(m.getName() )});
}

ToolBox tb = new ToolBox();

/**
* Tests the entry point used by the DocumentationTool API and JavadocTester, in which
* all output is written to a single specified writer.
*/
@Test
public void testSingleStream(Path base) throws IOException {
test(base, false, Output.OUT, Output.OUT);
}

/**
* Tests the entry point used by the launcher, in which output is written to
* writers that wrap {@code System.out} and {@code System.err}.
*/
@Test
public void testStandardStreams(Path base) throws IOException {
test(base, true, Output.STDOUT, Output.STDERR);
}

void test(Path base, boolean useStdStreams, Output stdOut, Output stdErr) throws IOException {
Path src = base.resolve("src");
tb.writeJavaFiles(src, """
/**
* First sentence.
* abc {@myTaglet} def.
*/
public class C { }
""");

String testClasses = System.getProperty("test.classes");

setUseStandardStreams(useStdStreams);
javadoc("-d", base.resolve("out").toString(),
"-tagletpath", testClasses,
"-taglet", "MyTaglet",
src.resolve("C.java").toString()
);
checkExit(Exit.OK);
checkOutput(stdOut, true,
"writing to the standard writer");
checkOutput(stdErr, true,
"writing to the diagnostic writer");
}
}
@@ -236,6 +236,7 @@ void check(File dir) {
private boolean automaticCheckAccessibility = true;
private boolean automaticCheckLinks = true;
private boolean automaticCheckUniqueOUT = true;
private boolean useStandardStreams = false;

/** The current subtest number. Incremented when checking(...) is called. */
private int numTestsRun = 0;
@@ -351,7 +352,7 @@ public void javadoc(String... args) {

outputDirectoryCheck.check(outputDir);

// This is the sole stream used by javadoc
// This is the sole stream normally used by javadoc
WriterOutput outOut = new WriterOutput();

// These are to catch output to System.out and System.err,
@@ -360,7 +361,9 @@ public void javadoc(String... args) {
StreamOutput sysErr = new StreamOutput(System.err, System::setErr);

try {
exitCode = jdk.javadoc.internal.tool.Main.execute(args, outOut.pw);
exitCode = useStandardStreams
? jdk.javadoc.internal.tool.Main.execute(args) // use sysOut, sysErr
: jdk.javadoc.internal.tool.Main.execute(args, outOut.pw); // default
} finally {
outputMap.put(Output.STDOUT, sysOut.close());
outputMap.put(Output.STDERR, sysErr.close());
@@ -418,6 +421,16 @@ public void setAutomaticCheckUniqueOUT(boolean b) {
automaticCheckUniqueOUT = b;
}

/**
* Sets whether to use standard output streams (stdout and stderr)
* instead of a single temporary stream.
* Tests using standard streams should generally take care to avoid
* conflicting use of stdout and stderr.
*/
public void setUseStandardStreams(boolean b) {
useStandardStreams = b;
}

/**
* The exit codes returned by the javadoc tool.
* @see jdk.javadoc.internal.tool.Main.Result