Char constant display in the Javadoc "Constant field values"
Is there a way to get the generated "Constant Field Values" page to use readable characters instead of integers for type constants char
?
For example, if the class contains the following constants:
public static final char YES = 'Y';
public static final char NO = 'N';
public static final char ERROR = 'E';
I want the javadoc field constant values page to have a character representation ('Y', 'N', 'E'), not an integer version (69, 78, 89).
We have hundreds of them, so I don't want to go and add some specific javadoc comment for every event (using for example @value
).
UPDATE: Thanks to SubOptimal below, I was able to use the 1.6 source code for ConstantsSummaryWriterImpl
which I found here to change the method writeValue
like this:
private void writeValue(FieldDoc member) {
tdAlign("right");
code();
if ("char".equals(member.type().toString())) {
print(Util.escapeHtmlChars("'" + ((char) ((Integer)member.constantValue()).intValue()) + "'"));
} else {
print(Util.escapeHtmlChars(member.constantValueExpression()));
}
codeEnd();
tdEnd();
}
After this class is compiled and used to override the value in "tools.jar", the constants char
are output as a symbol, not a number.
source to share
You can achieve this by changing slightly javadoc
.
- get the source for the javadoc tool (don't worry, we only need one file to configure ;-))
I took the filelangtools-ce654f4ecfd8.tar.gz
here JDK 7 langtools source - extract the file
ConstantsSummaryWriterImpl.java
-
change method
getValue(FieldDoc member)
... private Content getValue(FieldDoc member) { Content valueContent; if ("char".equals(member.type().toString())) { valueContent = new StringContent("'" + (char) ((Integer) member.constantValue()).intValue() + "'" ); } else { valueContent = new StringContent(member.constantValueExpression()); } Content code = HtmlTree.CODE(valueContent); return HtmlTree.TD(HtmlStyle.colLast, code); } ...
-
compile modified file
javac -cp ${JAVA_HOME}/lib/tools.jar -d . ConstantsSummaryWriterImpl.java
-
run javadoc
javadoc -J-Xbootclasspath/p:.;${JAVA_HOME}/lib/tools.jar -d api/ Scratch.java
Scratch.java file
public class Scratch {
public static final char YES = 'Y';
public static final char NO = 'N';
public static final char ERROR = 'E';
}
source to share
It's impossible. Unfortunately the javadoc is a bit tight in this regard - a char
is a numeric primitive.
You can get around this using the lines
public static final String YES = "Y";
public static final String NO = "N";
public static final String ERROR = "E";
and refactoring the code to use the utility where you previously used char constants:
public static char asChar(String str) {
if (str.length() != 1) {
throw new IllegalArgumentException(str + " must be exactly 1 character long");
}
return str.charAt(0);
}
eg,
if (ch == asChar(ERROR))
which will hopefully make this portable.
Pay attention to parameter validation to ensure that you don't accidentally declare one of the strings with more than one character.
source to share
Could some post-processing be valid?
This program looks through the file tree and processes all files that are named constant-values.html
. They are loaded with Jericho HTML Parser . A table is considered, which is called constantValuesContainer
: if the first column contains text static final char
, and the value in the last column is an integer value, then it is replaced by the corresponding symbol.
Please note that this is just a sketch (but at least tested on "my" JavaDoc ;-)). Replacement conditions may be specified. For example, matching the text in the first column should be more robust (for the case where someone creates a class starting with char
....). The replacement should probably only be done when the integer value is a valid ASCII character to avoid messing up constants such as static final char CHAR_MAX = 0xFFFF
. But such adjustments should be easy if (!) Such a post-processing step is a possible way.
import static java.nio.file.FileVisitResult.CONTINUE;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Segment;
import net.htmlparser.jericho.Source;
public class ConstantsTest
{
private static final char CHAR_A = 'A';
protected static final char CHAR_B = 'B';
static final char CHAR_C = 'C';
public static final char CHAR_D = 'D';
public static final char CHAR_E = 'E';
public static final char CHAR_F = 'F';
public static final int INT_65 = 65;
public static void main(String[] args) throws MalformedURLException, IOException
{
Path path = FileSystems.getDefault().getPath("./doc/");
Files.walkFileTree(path, new FileProcessor());
}
static class FileProcessor extends SimpleFileVisitor<Path>
{
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attributes)
{
//System.out.println("Visit "+file+" name '"+file.getFileName()+"'");
if (file.getFileName().toString().equals("constant-values.html"))
{
process(file);
}
return CONTINUE;
}
}
private static void process(Path file)
{
try
{
doProcess(file);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private static void doProcess(Path file) throws IOException
{
System.out.println("Processing "+file);
Source source=new Source(file.toFile());
OutputDocument outputDocument=new OutputDocument(source);
for (Element element : source.getAllElementsByClass("constantValuesContainer"))
{
List<Element> colFirsts = element.getAllElementsByClass("colFirst");
List<Element> colLasts = element.getAllElementsByClass("colLast");
for (int i=0; i<colFirsts.size(); i++)
{
Element colFirst = colFirsts.get(i);
Segment colFirstContent = colFirst.getContent();
String colFirstText = colFirstContent.getTextExtractor().toString();
// TODO Generalize this according to your needs,
// maybe with some RegEx...
if (colFirstText.contains("static final char"))
{
Element colLast = colLasts.get(i);
List<Element> children = colLast.getAllElements("code");
if (children.size() == 1)
{
Element child = children.get(0);
Segment childContent = child.getContent();
String childText = childContent.getTextExtractor().toString();
try
{
int value = Integer.parseInt(childText);
outputDocument.replace(childContent, String.valueOf((char)value));
}
catch (NumberFormatException e)
{
System.out.println("Value is not a number: "+childText+", ignoring");
}
}
}
}
}
outputDocument.writeTo(
new OutputStreamWriter(new FileOutputStream(file.toFile())));
System.out.println("Processing "+file+" DONE");
}
}
source to share