8222793: Javadoc tool ignores "-locale" param and uses default locale for all messages and texts
Reviewed-by: prappo
This commit is contained in:
parent
c0f23a8604
commit
98f5d98a88
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets
formats/html
toolkit
test/langtools/jdk/javadoc/tool/testLocaleOption
@ -39,6 +39,9 @@ import com.sun.source.util.DocTreePath;
|
||||
|
||||
import jdk.javadoc.doclet.Doclet;
|
||||
import jdk.javadoc.doclet.DocletEnvironment;
|
||||
import jdk.javadoc.doclet.Reporter;
|
||||
import jdk.javadoc.doclet.StandardDoclet;
|
||||
import jdk.javadoc.doclet.Taglet;
|
||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
||||
import jdk.javadoc.internal.doclets.toolkit.DocletException;
|
||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
||||
@ -113,13 +116,24 @@ public class HtmlConfiguration extends BaseConfiguration {
|
||||
private final HtmlOptions options;
|
||||
|
||||
/**
|
||||
* Creates an object to hold the configuration for a doclet.
|
||||
* Constructs the full configuration needed by the doclet, including
|
||||
* the format-specific part, defined in this class, and the format-independent
|
||||
* part, defined in the supertype.
|
||||
*
|
||||
* @param doclet the doclet
|
||||
* @apiNote The {@code doclet} parameter is used when
|
||||
* {@link Taglet#init(DocletEnvironment, Doclet) initializing tags}.
|
||||
* Some doclets (such as the {@link StandardDoclet}), may delegate to another
|
||||
* (such as the {@link HtmlDoclet}). In such cases, the primary doclet (i.e
|
||||
* {@code StandardDoclet}) should be provided here, and not any internal
|
||||
* class like {@code HtmlDoclet}.
|
||||
*
|
||||
* @param doclet the doclet for this run of javadoc
|
||||
* @param locale the locale for the generated documentation
|
||||
* @param reporter the reporter to use for console messages
|
||||
*/
|
||||
public HtmlConfiguration(Doclet doclet) {
|
||||
super(doclet);
|
||||
resources = new Resources(this,
|
||||
public HtmlConfiguration(Doclet doclet, Locale locale, Reporter reporter) {
|
||||
super(doclet, locale, reporter);
|
||||
resources = new Resources(locale,
|
||||
BaseConfiguration.sharedResourceBundleName,
|
||||
"jdk.javadoc.internal.doclets.formats.html.resources.standard");
|
||||
|
||||
|
@ -55,8 +55,17 @@ import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
|
||||
*/
|
||||
public class HtmlDoclet extends AbstractDoclet {
|
||||
|
||||
public HtmlDoclet(Doclet parent) {
|
||||
configuration = new HtmlConfiguration(parent);
|
||||
/**
|
||||
* Creates a doclet to generate HTML documentation,
|
||||
* specifying the "initiating doclet" to be used when
|
||||
* initializing any taglets for this doclet.
|
||||
* An initiating doclet is one that delegates to
|
||||
* this doclet.
|
||||
*
|
||||
* @param initiatingDoclet the initiating doclet
|
||||
*/
|
||||
public HtmlDoclet(Doclet initiatingDoclet) {
|
||||
this.initiatingDoclet = initiatingDoclet;
|
||||
}
|
||||
|
||||
@Override // defined by Doclet
|
||||
@ -65,20 +74,31 @@ public class HtmlDoclet extends AbstractDoclet {
|
||||
}
|
||||
|
||||
/**
|
||||
* The global configuration information for this run.
|
||||
* The initiating doclet, to be specified when creating
|
||||
* the configuration.
|
||||
*/
|
||||
private final HtmlConfiguration configuration;
|
||||
private final Doclet initiatingDoclet;
|
||||
|
||||
/**
|
||||
* The global configuration information for this run.
|
||||
* Initialized in {@link #init(Locale, Reporter)}.
|
||||
*/
|
||||
private HtmlConfiguration configuration;
|
||||
|
||||
/**
|
||||
* Object for generating messages and diagnostics.
|
||||
*/
|
||||
private Messages messages;
|
||||
|
||||
|
||||
/**
|
||||
* Base path for resources for this doclet.
|
||||
*/
|
||||
private static final DocPath DOCLET_RESOURCES = DocPath
|
||||
.create("/jdk/javadoc/internal/doclets/formats/html/resources");
|
||||
|
||||
@Override // defined by Doclet
|
||||
public void init(Locale locale, Reporter reporter) {
|
||||
configuration.reporter = reporter;
|
||||
configuration.locale = locale;
|
||||
configuration = new HtmlConfiguration(initiatingDoclet, locale, reporter);
|
||||
messages = configuration.getMessages();
|
||||
}
|
||||
|
||||
|
@ -148,9 +148,9 @@ public abstract class BaseConfiguration {
|
||||
*/
|
||||
public Extern extern;
|
||||
|
||||
public Reporter reporter;
|
||||
public final Reporter reporter;
|
||||
|
||||
public Locale locale;
|
||||
public final Locale locale;
|
||||
|
||||
public abstract Messages getMessages();
|
||||
|
||||
@ -202,20 +202,23 @@ public abstract class BaseConfiguration {
|
||||
public PropertyUtils propertyUtils = null;
|
||||
|
||||
/**
|
||||
* Constructs the configurations needed by the doclet.
|
||||
* Constructs the format-independent configuration needed by the doclet.
|
||||
*
|
||||
* @apiNote
|
||||
* The {@code doclet} parameter is used when {@link Taglet#init(DocletEnvironment, Doclet)
|
||||
* initializing tags}.
|
||||
* Some doclets (such as the {@link StandardDoclet), may delegate to another
|
||||
* @apiNote The {@code doclet} parameter is used when
|
||||
* {@link Taglet#init(DocletEnvironment, Doclet) initializing tags}.
|
||||
* Some doclets (such as the {@link StandardDoclet}), may delegate to another
|
||||
* (such as the {@link HtmlDoclet}). In such cases, the primary doclet (i.e
|
||||
* {@code StandardDoclet}) should be provided here, and not any internal
|
||||
* class like {@code HtmlDoclet}.
|
||||
*
|
||||
* @param doclet the doclet for this run of javadoc
|
||||
* @param doclet the doclet for this run of javadoc
|
||||
* @param locale the locale for the generated documentation
|
||||
* @param reporter the reporter to use for console messages
|
||||
*/
|
||||
public BaseConfiguration(Doclet doclet) {
|
||||
public BaseConfiguration(Doclet doclet, Locale locale, Reporter reporter) {
|
||||
this.doclet = doclet;
|
||||
this.locale = locale;
|
||||
this.reporter = reporter;
|
||||
}
|
||||
|
||||
public abstract BaseOptions getOptions();
|
||||
|
@ -45,7 +45,7 @@ import static javax.tools.Diagnostic.Kind.*;
|
||||
public class Messages {
|
||||
private final BaseConfiguration configuration;
|
||||
private final Resources resources;
|
||||
private Reporter reporter;
|
||||
private final Reporter reporter;
|
||||
|
||||
/**
|
||||
* Creates a {@code Messages} object to provide standardized access to
|
||||
@ -58,6 +58,7 @@ public class Messages {
|
||||
public Messages(BaseConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
resources = configuration.getResources();
|
||||
reporter = configuration.getReporter();
|
||||
}
|
||||
|
||||
// ***** Errors *****
|
||||
@ -140,25 +141,14 @@ public class Messages {
|
||||
// ***** Internal support *****
|
||||
|
||||
private void report(Diagnostic.Kind k, String msg) {
|
||||
initReporter();
|
||||
reporter.print(k, msg);
|
||||
}
|
||||
|
||||
private void report(Diagnostic.Kind k, DocTreePath p, String msg) {
|
||||
initReporter();
|
||||
reporter.print(k, p, msg);
|
||||
}
|
||||
|
||||
private void report(Diagnostic.Kind k, Element e, String msg) {
|
||||
initReporter();
|
||||
reporter.print(k, e, msg);
|
||||
}
|
||||
|
||||
// Lazy init the reporter for now, until we can fix/improve
|
||||
// the init of HtmlConfiguration in HtmlDoclet (and similar.)
|
||||
private void initReporter() {
|
||||
if (reporter == null) {
|
||||
reporter = configuration.reporter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, 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
|
||||
@ -41,9 +41,6 @@ import java.util.ResourceBundle;
|
||||
public class Resources {
|
||||
public final String annotationTypeSummary;
|
||||
public final String classSummary;
|
||||
private final BaseConfiguration configuration;
|
||||
private final String commonBundleName;
|
||||
private final String docletBundleName;
|
||||
public final String enumSummary;
|
||||
public final String errorSummary;
|
||||
public final String exceptionSummary;
|
||||
@ -55,21 +52,21 @@ public class Resources {
|
||||
protected ResourceBundle docletBundle;
|
||||
|
||||
/**
|
||||
* Creates a {@code Resources} to provide access the resource
|
||||
* Creates a {@code Resources} object to provide access the resource
|
||||
* bundles used by a doclet.
|
||||
*
|
||||
* @param configuration the configuration for the doclet,
|
||||
* to provide access the locale to be used when accessing the
|
||||
* names resource bundles.
|
||||
* @param locale the locale to be used when accessing the
|
||||
* resource bundles.
|
||||
* @param commonBundleName the name of the bundle containing the strings
|
||||
* common to all output formats
|
||||
* common to all output formats
|
||||
* @param docletBundleName the name of the bundle containing the strings
|
||||
* specific to a particular format
|
||||
* specific to a particular format
|
||||
*/
|
||||
public Resources(BaseConfiguration configuration, String commonBundleName, String docletBundleName) {
|
||||
this.configuration = configuration;
|
||||
this.commonBundleName = commonBundleName;
|
||||
this.docletBundleName = docletBundleName;
|
||||
public Resources(Locale locale, String commonBundleName, String docletBundleName) {
|
||||
|
||||
this.commonBundle = ResourceBundle.getBundle(commonBundleName, locale);
|
||||
this.docletBundle = ResourceBundle.getBundle(docletBundleName, locale);
|
||||
|
||||
this.annotationTypeSummary = getText("doclet.Annotation_Types_Summary");
|
||||
this.classSummary = getText("doclet.Class_Summary");
|
||||
this.enumSummary = getText("doclet.Enum_Summary");
|
||||
@ -81,7 +78,7 @@ public class Resources {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string for the given key from one of the doclet's
|
||||
* Returns the string for the given key from one of the doclet's
|
||||
* resource bundles.
|
||||
*
|
||||
* The more specific bundle is checked first;
|
||||
@ -90,18 +87,16 @@ public class Resources {
|
||||
* @param key the key for the desired string
|
||||
* @return the string for the given key
|
||||
* @throws MissingResourceException if the key is not found in either
|
||||
* bundle.
|
||||
* bundle.
|
||||
*/
|
||||
public String getText(String key) throws MissingResourceException {
|
||||
initBundles();
|
||||
|
||||
if (docletBundle.containsKey(key))
|
||||
return docletBundle.getString(key);
|
||||
|
||||
return commonBundle.getString(key);
|
||||
}
|
||||
/**
|
||||
* Gets the string for the given key from one of the doclet's
|
||||
* Returns the string for the given key from one of the doclet's
|
||||
* resource bundles, substituting additional arguments into
|
||||
* into the resulting string with {@link MessageFormat#format}.
|
||||
*
|
||||
@ -117,16 +112,4 @@ public class Resources {
|
||||
public String getText(String key, Object... args) throws MissingResourceException {
|
||||
return MessageFormat.format(getText(key), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily initializes the bundles. This is (currently) necessary because
|
||||
* this object may be created before the locale to be used is known.
|
||||
*/
|
||||
protected void initBundles() {
|
||||
if (commonBundle == null) {
|
||||
Locale locale = configuration.getLocale();
|
||||
this.commonBundle = ResourceBundle.getBundle(commonBundleName, locale);
|
||||
this.docletBundle = ResourceBundle.getBundle(docletBundleName, locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8222793
|
||||
* @summary Javadoc tool ignores "-locale" param and uses default locale for
|
||||
* all messages and texts
|
||||
* @library /tools/lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.api
|
||||
* jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* jdk.javadoc/jdk.javadoc.internal.tool.resources:open
|
||||
* jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.resources:open
|
||||
* jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.resources:open
|
||||
* @build toolbox.JavadocTask toolbox.ToolBox
|
||||
* @run main TestLocaleOption
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Writer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import jdk.javadoc.internal.tool.Main;
|
||||
|
||||
import toolbox.JavadocTask;
|
||||
import toolbox.Task;
|
||||
import toolbox.TestRunner;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
/**
|
||||
* Tests the {@code -locale} option.
|
||||
*
|
||||
* The test generates a set of resources files for javadoc and the doclet
|
||||
* that can be used to "simulate" a non-default locale. These resource files
|
||||
* have to be patched into the {@code jdk.javadoc} module, which means that
|
||||
* the tool must be run in a separate VM, meaning that we cannot use the
|
||||
* standard {@code JavadocTester} framework. Instead, we fall back on ToolBox.
|
||||
*/
|
||||
|
||||
public class TestLocaleOption extends TestRunner {
|
||||
public static void main(String... args) throws Exception {
|
||||
Locale.setDefault(Locale.US);
|
||||
TestLocaleOption t = new TestLocaleOption();
|
||||
t.run();
|
||||
}
|
||||
|
||||
private ToolBox tb = new ToolBox();
|
||||
private Path patchDir;
|
||||
private Path srcDir;
|
||||
|
||||
/** Locale for the generated resource files with uppercase values. */
|
||||
private static final String LOCALE = "en_GB_ALLCAPS";
|
||||
|
||||
TestLocaleOption() {
|
||||
super(System.err);
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
patchDir = Path.of("patch");
|
||||
generateBundle(patchDir, "jdk.javadoc.internal.tool.resources.javadoc");
|
||||
generateBundle(patchDir, "jdk.javadoc.internal.doclets.toolkit.resources.doclets");
|
||||
generateBundle(patchDir, "jdk.javadoc.internal.doclets.formats.html.resources.standard");
|
||||
|
||||
srcDir = Path.of("src");
|
||||
tb.writeJavaFiles(srcDir,
|
||||
"package p;\n"
|
||||
+ "public class HelloWorld {\n"
|
||||
+ " public static void main(String... args) {\n"
|
||||
+ " System.out.println(\"Hello World!\");\n"
|
||||
+ " }\n"
|
||||
+ "}\n");
|
||||
|
||||
runTests(m -> new Object[] { Path.of(m.getName()) });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpDefault(Path base) {
|
||||
String stdOut = javadoc(patchDir, "-help")
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
checkContains(stdOut,
|
||||
"Usage:\n"
|
||||
+" javadoc [options] [packagenames] [sourcefiles] [@files]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelpLocale(Path base) {
|
||||
String stdOut = javadoc(patchDir, "-locale", LOCALE, "-help")
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
checkContains(stdOut,
|
||||
"USAGE:\n"
|
||||
+" JAVADOC [OPTIONS] [PACKAGENAMES] [SOURCEFILES] [@FILES]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelloWorldDefault(Path base) throws Exception {
|
||||
Path apiDir = base.resolve("api");
|
||||
String stdOut = javadoc(patchDir,
|
||||
"-sourcepath", srcDir.toString(),
|
||||
"-d", apiDir.toString(),
|
||||
"p")
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
|
||||
checkContains(stdOut,
|
||||
"Loading source files for package p...\n"
|
||||
+ "Constructing Javadoc information...");
|
||||
|
||||
String hw = Files.readString(apiDir.resolve("p/HelloWorld.html"));
|
||||
checkContains(hw,
|
||||
"<h2>Method Summary</h2>",
|
||||
"<th class=\"colFirst\" scope=\"col\">Modifier and Type</th>",
|
||||
"<th class=\"colSecond\" scope=\"col\">Method</th>",
|
||||
"<th class=\"colLast\" scope=\"col\">Description</th>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHelloWorldLocale(Path base) throws Exception {
|
||||
Path apiDir = base.resolve("api");
|
||||
String stdOut = javadoc(patchDir,
|
||||
"-locale", LOCALE,
|
||||
"-sourcepath", srcDir.toString(),
|
||||
"-d", apiDir.toString(),
|
||||
"p")
|
||||
.writeAll()
|
||||
.getOutput(Task.OutputKind.STDOUT);
|
||||
|
||||
checkContains(stdOut,
|
||||
"LOADING SOURCE FILES FOR PACKAGE p...\n"
|
||||
+ "CONSTRUCTING JAVADOC INFORMATION...");
|
||||
|
||||
String hw = Files.readString(apiDir.resolve("p/HelloWorld.html"));
|
||||
checkContains(hw,
|
||||
"<h2>METHOD SUMMARY</h2>",
|
||||
"<th class=\"colFirst\" scope=\"col\">MODIFIER AND TYPE</th>",
|
||||
"<th class=\"colSecond\" scope=\"col\">METHOD</th>",
|
||||
"<th class=\"colLast\" scope=\"col\">DESCRIPTION</th>");
|
||||
}
|
||||
|
||||
private void generateBundle(Path dir, String name) throws Exception {
|
||||
Module m = Main.class.getModule();
|
||||
ResourceBundle rb = ResourceBundle.getBundle(name, m);
|
||||
Properties p = new Properties();
|
||||
Enumeration<String> e = rb.getKeys();
|
||||
while (e.hasMoreElements()) {
|
||||
String key = e.nextElement();
|
||||
String value = rb.getString(key);
|
||||
p.put(key, value.toUpperCase(Locale.US));
|
||||
}
|
||||
Path outPath = dir.resolve(name.replace(".", File.separator) + "_" + LOCALE + ".properties");
|
||||
Files.createDirectories(outPath.getParent());
|
||||
try (Writer out = Files.newBufferedWriter(outPath)) {
|
||||
p.store(out, "Generated by TestLocaleOption");
|
||||
System.err.println("wrote: " + outPath);
|
||||
}
|
||||
}
|
||||
|
||||
private Task.Result javadoc(Path patchDir, String... args) {
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add("-J--patch-module=jdk.javadoc=" + patchDir);
|
||||
options.addAll(List.of(args));
|
||||
return new JavadocTask(tb, Task.Mode.EXEC)
|
||||
.options(options)
|
||||
.run();
|
||||
}
|
||||
|
||||
private String NL = System.lineSeparator();
|
||||
private void checkContains(String found, String... expect) {
|
||||
for (String e : expect) {
|
||||
String e2 = e.replace("\n", NL);
|
||||
if (!found.contains(e2)) {
|
||||
error("expected string not found: '" + e2 + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user