The XWiki project is following a specific coding style for Java code. We're using Checkstyle (checkstyle.xml) to ensure compliance of the code. Our build (the Maven2 one) is configured to fail on violations. However the decision to follow this code style and enforce it was only made recently and not all the code base has been moved to this new code style. Hence:
- We're only enforcing the code style in the code that has been moved to the new code style. The checked files are defined in xwiki/core/pom.xml (bottom of file).
- We're asking new code to follow the new style and then once a Java file is compliant, to edit xwiki/core/pom.xml and add it there so that we cannot regress...
For examples of "clean" class see the following example and its unit tests:
Configuring your IDE to use the XWiki code style
Eclipse 3.x
Download codestyle-eclipse-java.xml.
After this, select Window > Preferences, and open up the configuration for Java > Code Style > Code Formatter. Click on the button labeled Import... and select the file you downloaded. Give the style a name, and click OK.
To reformat a file, press Ctrl+Shift+F while inside that file. To format only a portion of the file, select it and press the same key combination.
In recent versions of Eclipse (>3.3) there is the possibility to configure Eclipse to automatically format a file when saving it. To do this, open Window > Preferences, select Java > Editor > Save Actions and enable Perform the selected actions on save and Format source code.
Download codetemplates-eclipse.xml.
After this, select Window > Preferences, and open up the configuration for Java > Code Style > Code Templates. Click on the button labeled Import... and select the file you downloaded. You can enable "Automatically add comments for new methods and types" if you want.
To generate a javadoc, press Meta+Shift+J while on the element you want to document.
IntelliJ IDEA 4.5+
Download codestyle-idea.xml.
Close IntelliJ IDEA. Place the file in your IntelliJ IDEA user configuration directory:
- For example for Windows Vista users of IntelliJ IDEA v6.x, it's in C:\Users\username\.IntelliJIdea60\config\codestyles. Then open IntelliJ IDEA again, select File > Project Settings > Project Code Style, select Use per-project code style scheme, click on Import... and select XWiki.
- On Mac it's in ~/Library/Preferences/IntelliJIdeaXX/codestyles
Interface best practices
Do not use 'public' in interfaces
Public is always implied in interfaces. Do not write:
public interface Page
{
public String getParentSpaceKey();
}
But instead, write
public interface Page
{
String getParentSpaceKey();
}
Javadoc Best Practices
We are following the Oracle Javadoc coding conventions. Please make sure you're familiar with them when you write javadoc.
Do not repeat the name of the method or any useless information. For example, if you have:
/**
* @return the id
*/
public String getId()
{
return this.id;
}
Instead, write:
/**
* @return the attachment id (the id is the filename of the XWikiAttachment object used to construct this Attachment object)
*/
public String getId()
{
return this.id;
}
Do not duplicate Javadoc
If you inherit from an interface/class then you shouldn't copy the Javadoc from the super type. Instead you should reference it or add more fine-tuned explanations. For example if getSomething() is the implementation of a method defined in an inherited Something interface or parent class, you shouldn't write:
/**
* Do something blah blah.
*/
public void doSomething()
{
[...]
Instead, write either the following:
/**
* {@inheritDoc}
*
* <p>Optionally add here javadoc additional to the one inherited from the parent javadoc.</p>
*/
@Override
public void doSomething()
{
[...]
or (it you don't have anything else to add in the javadoc):
@Override
public void doSomething()
{
[...]
Don't forget the @Override annotation!
Instead of writing:
/**
* Returns the key of the space to which this page belongs to.
*
* @return - Parent space's key as String.
*/
public String getParentSpaceKey();
Write:
/**
* @return the key of the space to which this page belongs to. For example "Main".
*/
public String getParentSpaceKey();
For example:
/**
* Something, blah blah...
*
* @version $Id: $
* @since 1.6M1
*/
Do not use author javadoc tags!
Trailing Whitespace
Trailing whitespace is prohibited except for one case.
In empty lines in a javadoc comment, a single trailing space character is acceptable but not required.
/**
* The Constructor.
*
* $param something...
*/
The trailing whitespace in the center line in that comment is permissible. See this proposal for more information.
Class/Interface names
- Prefix class names with Abstract for abstract classes
- Class names should start with an uppercase letter
- The interface name should be as short and expressive as possible with no technical prefix or suffix. For example "Parser".
- As a consequence interfaces shouldn't be prefixed with "I" (as in "IParser") or suffixed with "Interface" (as in "ParserInterface"), nor suffixed with "IF" (as in "ParserIF).
- Classes implementing interfaces should extend the interface name by prefixing it with a characteristic of the implementation. For example "XWikiParser".
- As a consequence implementation classes shouldn't be suffixed with "Impl", "Implementation", etc.
- Default implementation classes where there's only one implementation provided by XWiki should be prefixed with "Default". As in "DefaultParser".
Members and fields names
- All methods and fields names should be camelCase, starting with a lower letter (someProperty, getSomeProperty())
- The names should be understandable and short, avoiding abbreviations (parentDocument instead of pdoc, for example)
- Constants should all be uppercase, with underscores as word separators, and no prefix letter (WIKI_PAGE_CREATOR instead of WIKIPAGECREATOR)
- Constants should be public/private static final in classes (public static final String CONTEXT_KEY = "theKey") and without any modifiers in interfaces, since public, static and final are implied and enforced (String PREFERENCES_DOCUMENT_NAME = "XWiki.XWikiPreferences")
Package names
- All code that is not located in the oldcore module should use org.xwiki.
- The package name for code using the component-based architecture must be of the format org.xwiki.(module name).*. For example org.xwiki.rendering.
- Non user-public code must be located in an internal package just after the module name. For example: org.xwiki.rendering.internal.parser.. General rule is org.xwiki.(module name).internal.
Logging Best Practices
- Your component must get a Logger using the following construct:
import org.slf4j.Logger;
...
@Inject
private Logger logger;
- You should use the severity according to the following rules:
- info: used for logs that should be printed by default (default logging configuration)
- debug: logs that are informational but that shouldn't be printed by default should be debug logs
- warning: they are for not critical problems but raised so that the users see them and remedy the problem, shown by default too
- error: they are for critical problems that cause the application to misbehave and should most of the time have an associated stack trace
- If you need to perform computations for passing parameters to the logging calls you should instead use the appropriate SLF4J signature to not incur performance penalty. For example:
this.logger.debug("Test message with {} and {}", param1, param2);
Imports
- imports should be added individually for each class/interface
- individual imports should be grouped together and separated by blank lines following this model:
import java.*
import javax.*
import org.*
import com.*
import <any other imports>
import static <any static imports>
- The default configuration of Eclipse, and the above code style settings for IntelliJ IDEA will automatically follow these rules, so you usually do not have to take care (Be careful that the default configuration for IntelliJ IDEA is not appropriate).
Equals/HashCode and ToString implementations
We've decided to standardize on using Apache Commons Lang HashCodeBuilder, EqualsBuilder and ToStringBuilder.
For example:
...
@Override
public boolean equals(Object object)
{
if (object == null) {
return false;
}
if (object == this) {
return true;
}
if (object.getClass() != getClass()) {
return false;
}
WikiBotListenerData rhs = (WikiBotListenerData) object;
return new EqualsBuilder()
.appendSuper(super.equals(object))
.append(getReference(), rhs.getReference())
.isEquals();
}
@Override
public int hashCode()
{
return new HashCodeBuilder(3, 17)
.appendSuper(super.hashCode())
.append(getReference())
.toHashCode();
}
...
XWiki provides a custom ToStringBuilder implementation named XWikiToStringBuilder that uses a custom XWiki's toString style (see the Text Module for information).
For example:
...
@Override
public String toString()
{
ToStringBuilder builder = new XWikiToStringBuilder(this);
builder = builder.append("Typed", isTyped())
.append("Type", getType().getScheme());
if (getReference() != null) {
builder = builder.append("Reference", getReference());
}
if (!getBaseReferences().isEmpty()) {
builder = builder.append("Base References", getBaseReferences());
}
Map<String, String> params = getParameters();
if (!params.isEmpty()) {
builder = builder.append("Parameters", params);
}
return builder.toString();
}
...
This example would generate the following:
...
ResourceReference reference = new ResourceReference("reference", ResourceType.DOCUMENT);
Assert.assertEquals("Typed = [true] Type = [doc] Reference = [reference]", reference.toString());
reference.addBaseReference("baseref1");
reference.addBaseReference("baseref2");
Assert.assertEquals("Typed = [true] Type = [doc] Reference = [reference] "
+ "Base References = [[baseref1], [baseref2]]", reference.toString());
reference.setParameter("name1", "value1");
reference.setParameter("name2", "value2");
Assert.assertEquals("Typed = [true] Type = [doc] Reference = [reference] "
+ "Base References = [[baseref1], [baseref2]] "
+ "Parameters = [[name1] = [value1], [name2] = [value2]]", reference.toString());
...