Is there a way to add references to one or more of a method's parameters from the method documentation body?
Something like:
/**
* When {#paramref a} is null, we rely on b for the discombobulation.
*
* #param a this is one of the parameters
* #param b another param
*/
void foo(String a, int b)
{...}
As far as I can tell after reading the docs for javadoc there is no such feature.
Don't use <code>foo</code> as recommended in other answers; you can use {#code foo}. This is especially good to know when you refer to a generic type such as {#code Iterator<String>} -- sure looks nicer than <code>Iterator<String></code>, doesn't it!
The correct way of referring to a method parameter is like this:
As you can see in the Java Source of the java.lang.String class:
/**
* Allocates a new <code>String</code> that contains characters from
* a subarray of the character array argument. The <code>offset</code>
* argument is the index of the first character of the subarray and
* the <code>count</code> argument specifies the length of the
* subarray. The contents of the subarray are copied; subsequent
* modification of the character array does not affect the newly
* created string.
*
* #param value array that is the source of characters.
* #param offset the initial offset.
* #param count the length.
* #exception IndexOutOfBoundsException if the <code>offset</code>
* and <code>count</code> arguments index characters outside
* the bounds of the <code>value</code> array.
*/
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = new char[count];
this.count = count;
System.arraycopy(value, offset, this.value, 0, count);
}
Parameter references are surrounded by <code></code> tags, which means that the Javadoc syntax does not provide any way to do such a thing. (I think String.class is a good example of javadoc usage).
I guess you could write your own doclet or taglet to support this behaviour.
Taglet Overview
Doclet Overview
Here is how it is written in Eclipse Temurin JDK 8 sources:
It looks like the only way is or {#code }, but it's not a link - it's just formatting.
Related
I was using java1.8 which has parseUnsignedInt(). I was told that we have to use java1.7 since that is on the system. I thought I could just port the java.lang.Interger.java, java.lang.Long.java and java.lang.annotation.Native.java functions and compile with my code. This allowed the code to compile without errors. When I run I get the following error:
Exception in thread "Thread-6" java.lang.NoSuchMethodError: java.lang.Integer.parseUnsignedInt(Ljava/lang/String;)I
The eclipse debugger can't seem to find the function either. What do I have to do to get this working?
The method parseUnsignedInt was introduced with Java 1.8, as it is documented in its javadoc (mind the #since 1.8):
/**
* Parses the string argument as an unsigned decimal integer. The
* characters in the string must all be decimal digits, except
* that the first character may be an an ASCII plus sign {#code
* '+'} ({#code '\u005Cu002B'}). The resulting integer value
* is returned, exactly as if the argument and the radix 10 were
* given as arguments to the {#link
* #parseUnsignedInt(java.lang.String, int)} method.
*
* #param s a {#code String} containing the unsigned {#code int}
* representation to be parsed
* #return the unsigned integer value represented by the argument in decimal.
* #throws NumberFormatException if the string does not contain a
* parsable unsigned integer.
* #since 1.8
*/
public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s, 10);
}
But the JDK also contains the sources, so you could write your own parseUnsignedInt method in your own class, similar to the implementation contained in Java 8 if the Java 8 license allows that.
See http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/Integer.java
Line 661 ff
For details about security (i.e. why you can't place your own Integer class in java.lang package), option to overrule this security, and a reason why you should not (or better - why you are not allowed to), see selected answer in Why I am able to re-create java.lang package and classes?
So, you will have to implement your own class in your own package:
package com.yourname;
/*
* Contains code from OpenJDK Java8, Copyright (c) 1994, 2013, Oracle and/or its affiliates.
* TODO add more info from Oracle class comment here.
*/
public class IntCompatUtilities {
public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s,10);
}
public static int parseUnsignedInt(String s, int radix)
throws NumberFormatException {
//TODO content from OpenJDK 8's Integer.parseUnsignedInt(String,int) here.
//instead of return parseInt(s, radix); change to return Integer.parseInt(s, radix);
//instead of throw NumberFormatException.forInputString(s); throw new NumberFormatException(...)
}
}
And then, let all your callers call com.yourname.IntCompatUtilities.parseUnsignedInt(...)
I throw a bunch of custom runtime exceptions in my code and I want to make sure that in all public methods, I document which runtime exception might be thrown (by myself) and why. This would be very hulpful since I'm maintaining a library which is used by many projects and I want it to be upfront and predictable regarding thrown (runtime) exceptions.
Is there a compiler option, maven plugin, Intellij plugin or custom tool that can help me find missed throws clauses? With checked exceptions it's easy, the compiler will just complain if I missed one, but for runtime exceptions both throws and #throws are not enforced.
One thing I thought of was to temporarily make all my own runtime exceptions checked exceptions (they already share a super class), but that would be a one-off exercise. I would like to verify my code/documentation each time I make changes so I can never forget to document my runtime exceptions.
Another way could be to actually have checked exceptions throughout the code and convert them to runtime only in the public api:
class Foo {
// oops, throws not documented with #throws
public void publicMethod() {
try {
privateMethod1();
} catch (CheckedFooException e) {
throw new RuntimeFooException(e);
}
}
private void privateMethod1() throws CheckedFooException {
privateMethod2();
}
private void privateMethod2() throws CheckedFooException {
throw new CheckedFooException();
}
}
This approach would force me to think about CheckedFooException in all public methods. Then to check if I missed documenting one (ie. #throws RuntimeFooException), I would simply do a regex search on catch.*CheckedFooException and check for missing #throws entries. Rather unwieldy process though (and there's a lot of public api that would get peppered with try...catch statements).
Answer: There is some discussion about whether you should document (your own thrown) runtime exceptions at all (the summary so far: it depends), but as far as a direct answer to my question, the accepted answer answers it adequately; I can take that approach, implement my use case and even make a maven plugin with it, given some time and effort. I uploaded a cleaned up start project for this.
After understanding your question and researching this subject, I finally found what I thought to be one of the best tools to do this job. With this not only you can find each throws instance that you haven't documented, but you can also find where you don't throw anything but accidentally document a throw value.
The idea behind this is to parse the code into an abstract syntax tree. Then look for methods and look for throws statement in the methods. If a method have any throw statement, extract the exception name from those statements. Then get the Javadoc for that method. Check the Javadoc for all the #throw tags and get the name of the exception that been documented. After that, compare the exception throws versus the one that been documented. The last, you kind of have to figure that out on your own depend on your usage circumstance.
The tool I used for this is JavaParser. You can find them on Github at https://github.com/javaparser/javaparser. I downloaded their latest version. Their website is at https://javaparser.org/. They wrote a book on this subject and they mentioned that you can pay $0 dollar for the book. However, I didn't read that as they also have a Javadoc version for their program which can be found at https://www.javadoc.io/doc/com.github.javaparser/javaparser-core/3.15.1.
I wrote a demonstrate code below. In no mean that this code is final. It is just an example. You have to fix it into making it work for your case. I didn't take into consideration of nested classes, nested method, or methods within classes that are within a method. Also, the example code was written for class only and not interface. However, it is easy to adapt the code to change to able to handle interfaces.
For this, you would need to download javaParser, build it, and have their javaparser-core-3.15.1.jar or whichever version in your classpath.
The demonstrated code is below and the test.java is a file from a project that I wrote but you could use any. I also included comments in the example code.
import com.github.javaparser.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.comments.*;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.javadoc.*;
import java.io.IOException;
import java.nio.file.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;
class Main{
public static void main(String[] args) throws IOException {
// Set file path
Path path = Paths.get("test.java");
// Set configuration
ParserConfiguration parseConfig = new ParserConfiguration();
parseConfig.setCharacterEncoding(Charset.forName("UTF-8"));
parseConfig.setTabSize(4);
parseConfig.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8);
// Get the parser
JavaParser jvParser = new JavaParser(parseConfig);
// Parse the result
ParseResult<CompilationUnit> parseResult = jvParser.parse(path);
// Check for problem
if ( !parseResult.isSuccessful() ) {
System.out.print("Parsing java code fail with the following problems:");
List<Problem> problems = parseResult.getProblems();
for ( Problem problem : problems ){
System.out.println(problem.getMessage());
}
return;
}
// Get the compilationUnit
// No optional checking for Optional<CompilationUnit> due to already check above.
CompilationUnit compilationUnit = parseResult.getResult().get();
// Get Classes
List<ClassOrInterfaceDeclaration> classes = compilationUnit.findAll(ClassOrInterfaceDeclaration.class).stream()
.filter(c -> !c.isInterface())
.collect(Collectors.toList());
// Traverse through each class to get method
for ( ClassOrInterfaceDeclaration c : classes ) {
// Get methods
List<MethodDeclaration> methods = c.getMethods();
for ( MethodDeclaration method : methods ) {
// Get the body statement
Optional <BlockStmt> body = method.getBody();
// if no body continue
if ( !body.isPresent() ) continue;
// After getting the body of the method code
// Search for the throw statements.
List<ThrowStmt> throwStatements = body.get().findAll(ThrowStmt.class);
// No throw statements, skip
if ( throwStatements.size() == 0 ) continue;
// Storing name of exceptions thrown into this list.
List<String> exceptionsThrown = new ArrayList<String>();
for ( ThrowStmt stmt : throwStatements ){
// Convert the throw expression to object creation expression and get the type.
String exceptionName = stmt.getExpression().asObjectCreationExpr().getType().toString();
if ( !exceptionsThrown.contains(exceptionName) ) exceptionsThrown.add(exceptionName);
}
/*
* Debug block for up to this point
System.out.println(method.getName());
System.out.println(exceptionsThrown);
System.out.println();
*
**/
// Get The Javadoc
Optional<Javadoc> javadoc = method.getJavadoc();
// To store the throws Tags
List<JavadocBlockTag> throwTags;
// A list of thrown exception that been documented.
List<String> exceptionsDocumented = new ArrayList<String>();
if ( javadoc.isPresent() ) {
throwTags = javadoc.get()
.getBlockTags()
.stream()
.filter(t -> t.getType() == JavadocBlockTag.Type.THROWS)
.collect(Collectors.toList());
for ( JavadocBlockTag tag : throwTags ) {
/*
* This may be buggy as
* the code assumed #throw exception
* to be on its own line. Therefore
* it will just take the first line as the exception name.
*/
String exceptionName = tag.getContent().toText()
.split("\n")[0]; // Use system line separator or change
// line accordingly.
if ( !exceptionsDocumented.contains(exceptionName) )
exceptionsDocumented.add(exceptionName);
}
}
// getBegin can extract the line out. But evaluating the optional would take some more code
// and is just for example so this was done like this without any checking.
System.out.println("Method: " + method.getName() + " at line " + method.getBegin());
System.out.println("Throws Exceptions: ");
System.out.println(exceptionsThrown);
System.out.println("Documented Exceptions:");
System.out.println(exceptionsDocumented);
System.out.println(System.lineSeparator() + System.lineSeparator());
}
}
}
}
test.java content:
package host.fai.lib.faiNumber;
/*
* Copyright 2019 Khang Hoang Nguyen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
**/
/**
* <p>The <code>Base2Util</code> class is a final class that provides
* static methods for converting base 2 numbering system values in
* string representation to a Java's Primitive Data Type.
*
* <p>Currently this class supports converting base 2 numbers values
* in string representation to integer int values and integer
* long values.
*
* <p>This class can parse unsigned base 2 numbers to a supported
* integer signed type as if the integer type is unsigned. However,
* some of the values must be interprete properly to get the correct
* result.
*
* <p>Example for interpreting signed value as unsigned value.
*
* <p>It is possible to store the value of 18446744073709551615L
* into a long(signed) value. However, if that value is stored into a
* signed long integer type and if we were to interprete the value
* normally, we would get a -1L value. However, if the -1L value is
* pass to LongUtil.toStringAsUnsigned, we would get
* 18446744073709551615 in string format.
*
* <p>The following example is to get to -1L. First, we assign a value
* of 9223372036854775807L to an interger long variable, multiply that
* variable to 2L, and add 1L to it.
* <pre>
* long a = 9223372036854775807L * 2L + 1L;
* System.out.println(a);
* System.out.println(LongUtil.toStringAsUnsigned(a));
* </pre>
*
* <p>Example methods for interprete signed type as unsigned type
* in a decimal strings value are
* {#link IntUtil#toStringAsUnsigned(int) IntUtil.toStringAsUnsigned}
* and {#link LongUtil#toStringAsUnsigned(long) LongUtil.toStringAsUnsigned}.
* </p>
*
* #author Khang Hoang Nguyen
*
* #since 1.0.0.f
**/
public final class Base2Util{
private Base2Util(){};
/**
* Parse the input string as signed base 2 digits representation
* into an integer int value.
*
* #param input
* A string to be parsed as signed base 2 number to an
* integer int value.
*
* #return An integer int value of the signed base 2 number
* {#code input} string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid signed
* base 2 digits, if the {#code input} string contains a
* value that is smaller than the value of Integer.MIN_VALUE(
* {#value java.lang.Integer#MIN_VALUE}),
* or if the {#code input} string contains a value that
* is larger than the value of Integer.MAX_VALUE(
* {#value java.lang.Integer#MAX_VALUE}).
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final int toInt(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
final char ch1 = input.charAt(0); int start;
if ( ch1 == '-' || ch1 == '+' ){
if ( length == 1 ) throw new NumberFormatException(input);
start = 1;
} else {
start = 0;
}
int out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
final int runlen = length - start;
if ( runlen > 31 ){
if ( runlen > 32 ) throw new NumberFormatException(input);
if ( ch1 != '-' ) throw new NumberFormatException(input);
if ( input.charAt(start++) != '1') throw new NumberFormatException(input);
for ( ; start < length; start++){
if ( input.charAt(start) != '0' ) throw new NumberFormatException(input);
}
return -2147483648;
}
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1 ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
if ( ch1 == '-' ) return ~out + 1;
return out;
}
/**
* Parse the input string as unsigned base 2 number representation
* into an integer int value as if the integer int is an unsigned
* type. For values that need to be interpreted correctly, see the
* {#link IntUtil#toStringAsUnsigned(int) toStringAsUnsigned} method
* of the {#link IntUtil IntUtil} class.
*
* #param input
* A string to be parsed as unsigned base 2 number to an
* integer int value as if the integer int is an unsigned
* type.
*
* #return An int value that represents an unsigned integer int
* value of the unsigned base 2 number {#code input} string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid unsigned
* base 2 digits, if the {#code input} string contains a
* value that is beyond the capacity of the integer int
* data type.
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final int toIntAsUnsigned(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
int start = 0;
int out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
if ( length - start > 32 ) throw new NumberFormatException(input);
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1 ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
return out;
}
/**
* Parse the input string as signed base 2 number representation
* into an integer long value.
*
* #param input
* A string to be parsed as signed base 2 number to an
* integer long value.
*
* #return An integer long value of the signed base 2 number
* {#code input} string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid signed
* base 2 digits, if the {#code input} string contains a
* value that is smaller than the value of Long.MIN_VALUE(
* {#value java.lang.Long#MIN_VALUE}), or if
* the {#code input} string contains a value that is larger
* than the value of Long.MAX_VALUE(
* {#value java.lang.Long#MAX_VALUE}).
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final long toLong(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
final char ch1 = input.charAt(0); int start = 0;
if ( ch1 == '-' || ch1 == '+' ){
if ( length == 1 ) throw new NumberFormatException(input);
start = 1;
}
long out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
final int runlen = length - start;
if ( runlen > 63 ){
if ( runlen > 64 ) throw new NumberFormatException(input);
if ( ch1 != '-' ) throw new NumberFormatException(input);
if ( input.charAt(start++) != '1') throw new NumberFormatException(input);
for ( ; start < length; start++){
if ( input.charAt(start) != '0' ) throw new NumberFormatException(input);
}
return -9223372036854775808L;
}
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1L ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
if ( ch1 == '-' ) return ~out + 1L;
return out;
}
/**
* Parse the input string as unsigned base 2 number representation
* into an integer long value as if the integer long is an unsigned
* type. For values that need to be interpreted correctly, see the
* {#link LongUtil#toStringAsUnsigned(long) toStringAsUnsigned} method
* of the {#link LongUtil LongUtil} class.
*
* #param input
* A string to be parsed as unsigned base 2 number to an
* integer long value as if the integer long is an unsigned
* type.
*
* #return An integer long value represent the unsigned integer
* long value of the unsigned base 2 number {#code input}
* string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid unsigned
* base 2 digits, or if the {code input} string
* contains a value that is beyond the capacity of the
* long data type.
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final long toLongAsUnsigned(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
int start = 0;
long out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
if ( length - start > 64 ) throw new NumberFormatException(input);
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1L ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
return out;
}
}
If I understand your question correctly, you are violating the purpose of RuntimeException.
As explained in the thread here,
RuntimeException(s) are the one's that are not supposed to be handled by the client. Rather it is a situation, where the client cannot recover. In such case, all he can do is either abandon the application or throw back the error.
If you are adding documentation to cover these exceptions, that means you very well know why this exception is occurring. In such cases it should be checked exception, and not unchecked.
So Technically speaking, no library will provide the functionality you are looking for, as runtime exceptions are not expected to be documented. It's a design smell. so better you correct the design, than adding documentation.
If it is not possible, and you insist to use RuntimeException only, then I would recommend to look at this answer and build your own Findbugs/checkstyle rule that will do the trick.
Let all your exceptions inherit from one exception superclass:
public class MySuperException extends RuntimeException {
}
public class MyException extends MySuperException {
}
To validate, that all exceptions are documented, simply exchange your super class (for example by providing another version of the file at a later position of your classpath):
// temporary class, only for compile time checks
// do not export this into jar
public class MySuperException extends Exception {
}
Please check Semmle code analysis, which has a query "Missing Javadoc for thrown exception"
Semmle has plugins LGTM and QL that could be used from IDE like Eclipse.
or
as an alternative approach please use something similar to Eclipse plugin JAutodoc to complete existing Javadoc.
I am basically being asked to take the Unicode value of a string, multiply it by 10% and add whatever level the object currently has. It's frustrating because as it turns out I have the logic down including the code yet I still get an error that says: expected:<0> but was:<8>. Any suggestions, maybe it's just a slight nuance I have to make in the logic, although I'm fairly certain it's right. Take note of the getLevel method because that's where the error is
public class PouchCreature implements Battleable {
private String name;
private int strength;
private int levelUps;
private int victoriesSinceLevelUp;
/**
* Standard constructor. levelUps and victoriesSinceLevelUp start at 0.
*
* #param nameIn desired name for this PouchCreature
* #param strengthIn starting strength for this PouchCreature
*/
public PouchCreature(String nameIn, int strengthIn) {
this.name = nameIn;
this.strength = strengthIn;
this.levelUps = 0;
this.victoriesSinceLevelUp = 0;
}
/**
* Copy constructor.
*
* #param other reference to the existing object which is the basis of the new one
*/
public PouchCreature(PouchCreature other) {
this.name=other.name;
this.strength=other.strength;
this.levelUps=other.levelUps;
this.victoriesSinceLevelUp=other.victoriesSinceLevelUp;
}
/**
* Getter for skill level of the PouchCreature, which is based on the
* first character of its name and the number of levelUps it has.
* Specifically, the UNICODE value of the first character in its name
* taken %10 plus the levelUps.
*
* #return skill level of the PouchCreature
*/
public int getLevel() {
int value = (int)((int)(getName().charAt(0)) * 0.1);
return value + this.levelUps;
}
You've said you're supposed to increase the value by 10%. What you're actually doing, though, is reducing it 90% by taking just 10% of it (and then truncating that to an int). 67.0 * 0.1 = 6.7, which when truncated to an int is 6.
Change the 0.1 to 1.1 to increase it by 10%:
int value = (int)((int)(getName().charAt(0)) * 1.1);
// --------------------------------------------^
There, if getName() returns "Centaur" (for instance), the C has the Unicode value 67, and value ends up being 73.
We need to see the code you're calling the class with and that is generating your error message. Why is it expecting 0? 8 seems like a valid return value from the information you've given.
I'm compiling my java project with java 4 using GNU Make which does not support generics.
Here's my little code causing the error :
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) > 127) {
buffer.append("\"");
String charValue = asciiToNascMap.get(String.valueOf((int)text.charAt(i)));
buffer.append(String.format(";CHR$(%d);\"", charValue));
} else {
buffer.append(text.charAt(i));
}
}
private static Map<String, String> asciiToNascMap = new HashMap<String, String>();
static {
asciiToNascMap.put("232", "125");//è
asciiToNascMap.put("233", "123");//é
asciiToNascMap.put("224", "64");//à
asciiToNascMap.put("231", "92");//ç
asciiToNascMap.put("199", "180");//Ç
asciiToNascMap.put("234", "193");//ê
}
I'm getting this error :
Printer.java:319: error:Cannot find method "java/lang/String.format(java.lang.String, java.lang.String)"
Here's the signature of the String.format method :
/**
* Returns a formatted string using the specified format string and
* arguments.
*
* <p> The locale always used is the one returned by {#link
* java.util.Locale#getDefault() Locale.getDefault()}.
*
* #param format
* A format string
*
* #param args
* Arguments referenced by the format specifiers in the format
* string. If there are more arguments than format specifiers, the
* extra arguments are ignored. The number of arguments is
* variable and may be zero. The maximum number of arguments is
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
* <tt>null</tt> argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
* #throws IllegalFormatException
* If a format string contains an illegal syntax, a format
* specifier that is incompatible with the given arguments,
* insufficient arguments given the format string, or other
* illegal conditions. For specification of all possible
* formatting errors, see the <a
* href="../util/Formatter.html#detail">Details</a> section of the
* formatter class specification.
*
* #throws NullPointerException
* If the <tt>format</tt> is <tt>null</tt>
*
* #return A formatted string
*
* #see java.util.Formatter
* #since 1.5
*/
public static String format(String format, Object ... args) {
return new Formatter().format(format, args).toString();
}
The method you are trying to use is not available in Java 1.4. See the #since tag in your posted commentary. It says #since 1.5 meaning it was intoduced in Java 1.5.
You cannot use String.format in Java 1.4.
Try:
buffer.append(";CHR$(").append(Integer.valueOf(charValue)).append(");\"");
String.format is not available in Java 1.4. This is indicated in the text you posted in the #since tag. varargs support was not added until Java 5, which is why it probably wasn't added until then. People have created C printf-style libraries, however.
See these links:
http://www.sharkysoft.com/archive/printf/docs/javadocs/lava/clib/stdio/doc-files/introduction.htm
http://www.cs.ubc.ca/~lloyd/java/doc/cformat.html
I'm using varargs in a method for optional parameters. Any suggestion for how best to document the method?
Here's a wonderfully contrived example:
/**
*
* #param consumption
* liters of liquid consumed after last pee
* #param options
* urgency
* how badly you have to pee on a scale of 1-3,
* 3 being the highest (default 1)
* bribe
* what's a toilet worth to you? (default 0)
* #return waitTime
* minutes until you'll be able to relieve yourself
*/
public integer whenCanIUseTheBathroom(int consumption, int... options){
// Segment handling options, defining defaults/fallbacks
int urgency = 1;
int bribe = 0;
if(options.length > 0) {
urgency = options[0];
}
if(options.length == 2) {
bribe = options[1];
}
// Segment determining one's fate
...
}
Varargs are not usually used to implement optional parameters with different meanings because it does not support different types for the "subparams", offers poor refactoring support (want to insert a new "subparam" or remove an old one?), and is inflexible (you can't omit "urgency" while providing "bribe"). Therefore, there is no standard way to document them with javadoc, either.
Optional parameters are typically implemented using overloading (usually with delegation), or a variant of the builder pattern, which allows you to write:
new BathroomRequest(3).withBribe(2).compute();
For a more thorough discussion of that approach, see Joshua Bloch's Effective Java, item 2.