public class VisibilityModifierCheck extends AbstractCheck
Public members are not flagged if the name matches the public member regular expression (contains "^serialVersionUID$" by default).
Rationale: Enforce encapsulation.Check also has options making it less strict:
ignoreAnnotationCanonicalNames - the list of annotations canonical names which ignore variables in consideration, if user will provide short annotation name that type will match to any named the same type without consideration of package, list by default:
For example such public field will be skipped by default value of list above:
@org.junit.Rule
public TemporaryFolder publicJUnitRule = new TemporaryFolder();
allowPublicFinalFields - which allows public final fields. Default value is false.
allowPublicImmutableFields - which allows immutable fields to be declared as public if defined in final class. Default value is false
Field is known to be immutable if:
Classes known to be immutable are listed in immutableClassCanonicalNames by their canonical names. List by default:
User can override this list via adding canonical class names to immutableClassCanonicalNames, if user will provide short class name all that type will match to any named the same type without consideration of package.
Rationale: Forcing all fields of class to have private modified by default is good in most cases, but in some cases it drawbacks in too much boilerplate get/set code. One of such cases are immutable classes.
Restriction: Check doesn't check if class is immutable, there's no checking if accessory methods are missing and all fields are immutable, we only check if current field is immutable by matching a name to user defined list of immutable classes and defined in final class
Star imports are out of scope of this Check. So if one of type imported via star import collides with user specified one by its short name - there won't be Check's violation.
Examples:The check will rise 3 violations if it is run with default configuration against the following code example:
public class ImmutableClass
{
public int intValue; // violation
public java.lang.String notes; // violation
public BigDecimal value; // violation
public ImmutableClass(int intValue, BigDecimal value, String notes)
{
this.intValue = intValue;
this.value = value;
this.notes = notes;
}
}
To configure the Check passing fields of type com.google.common.collect.ImmutableSet and java.util.List:
<module name="VisibilityModifier"> <property name="allowPublicImmutableFields" value="true"/> <property name="immutableClassCanonicalNames" value="java.util.List, com.google.common.collect.ImmutableSet"/> </module>
public final class ImmutableClass
{
public final ImmutableSet<String> includes; // No warning
public final ImmutableSet<String> excludes; // No warning
public final BigDecimal value; // Warning here, type BigDecimal isn't specified as immutable
public ImmutableClass(Collection<String> includes, Collection<String> excludes,
BigDecimal value)
{
this.includes = ImmutableSet.copyOf(includes);
this.excludes = ImmutableSet.copyOf(excludes);
this.value = value;
this.notes = notes;
}
}
To configure the Check passing fields annotated with
@com.annotation.CustomAnnotation:
<module name="VisibilityModifier"> <property name="ignoreAnnotationCanonicalNames" value=" com.annotation.CustomAnnotation"/> </module>
@com.annotation.CustomAnnotation String customAnnotated; // No warning
@CustomAnnotation String shortCustomAnnotated; // No warning
To configure the Check passing fields annotated with short annotation name
@CustomAnnotation:
<module name="VisibilityModifier"> <property name="ignoreAnnotationCanonicalNames" value="CustomAnnotation"/> </module>
@CustomAnnotation String customAnnotated; // No warning
@com.annotation.CustomAnnotation String customAnnotated1; // No warning
@mypackage.annotation.CustomAnnotation String customAnnotatedAnotherPackage; // another package but short name matches // so no violation
Modifier and Type | Field and Description |
---|---|
private boolean |
allowPublicFinalFields
Allows final fields to be declared as public.
|
private boolean |
allowPublicImmutableFields
Allows immutable fields of final classes to be declared as public.
|
private static java.util.List<java.lang.String> |
DEFAULT_IGNORE_ANNOTATIONS
Default ignore annotations canonical names.
|
private static java.util.List<java.lang.String> |
DEFAULT_IMMUTABLE_TYPES
Default immutable types canonical names.
|
private static java.lang.String[] |
EXPLICIT_MODS
Contains explicit access modifiers.
|
private static java.lang.String |
FINAL_KEYWORD
Name for 'final' keyword.
|
private java.util.List<java.lang.String> |
ignoreAnnotationCanonicalNames
List of ignore annotations canonical names.
|
private java.util.List<java.lang.String> |
ignoreAnnotationShortNames
List of ignore annotations short names.
|
private java.util.List<java.lang.String> |
immutableClassCanonicalNames
List of immutable classes canonical names.
|
private java.util.List<java.lang.String> |
immutableClassShortNames
List of immutable classes short names.
|
static java.lang.String |
MSG_KEY
A key is pointing to the warning message text in "messages.properties"
file.
|
private static java.lang.String |
PACKAGE_ACCESS_MODIFIER
Name for implicit 'package' access modifier.
|
private boolean |
packageAllowed
Whether package visible members are allowed.
|
private static java.lang.String |
PRIVATE_ACCESS_MODIFIER
Name for 'private' access modifier.
|
private static java.lang.String |
PROTECTED_ACCESS_MODIFIER
Name for 'protected' access modifier.
|
private boolean |
protectedAllowed
Whether protected members are allowed.
|
private static java.lang.String |
PUBLIC_ACCESS_MODIFIER
Name for 'public' access modifier.
|
private java.util.regex.Pattern |
publicMemberPattern
Regexp for public members that should be ignored.
|
private static java.lang.String |
STATIC_KEYWORD
Name for 'static' keyword.
|
Constructor and Description |
---|
VisibilityModifierCheck() |
Modifier and Type | Method and Description |
---|---|
private boolean |
areImmutableTypeArguments(java.util.List<java.lang.String> typeArgsClassNames)
Checks whether all of generic type arguments are immutable.
|
void |
beginTree(DetailAST rootAst)
Called before the starting to process a tree.
|
private DetailAST |
findMatchingAnnotation(DetailAST variableDef)
Checks whether the AST is annotated with
an annotation containing the passed in regular
expression and return the AST representing that
annotation.
|
int[] |
getAcceptableTokens()
The configurable token set.
|
private static java.lang.String |
getCanonicalName(DetailAST type)
Gets canonical type's name from given
TYPE node. |
private static java.lang.String |
getClassShortName(java.lang.String canonicalClassName)
Gets the short class name from given canonical name.
|
private static java.util.List<java.lang.String> |
getClassShortNames(java.util.List<java.lang.String> canonicalClassNames)
Gets the list with short names classes.
|
int[] |
getDefaultTokens()
Returns the default token a check is interested in.
|
private static DetailAST |
getGenericTypeArgs(DetailAST type,
boolean isCanonicalName)
Returns generic type arguments token.
|
private static java.util.Set<java.lang.String> |
getModifiers(DetailAST defAST)
Returns the set of modifier Strings for a VARIABLE_DEF or CLASS_DEF AST.
|
private static DetailAST |
getNextSubTreeNode(DetailAST currentNodeAst,
DetailAST subTreeRootAst)
Gets the next node of a syntactical tree (child of a current node or
sibling of a current node, or sibling of a parent of a current node).
|
int[] |
getRequiredTokens()
The tokens that this check must be registered for.
|
private static java.util.List<java.lang.String> |
getTypeArgsClassNames(DetailAST typeArgs)
Returns a list of type parameters class names.
|
private static java.lang.String |
getTypeName(DetailAST type,
boolean isCanonicalName)
Gets the name of type from given ast
TYPE node. |
private static java.lang.String |
getVisibilityScope(DetailAST variableDef)
Returns the visibility scope for the variable.
|
private boolean |
hasIgnoreAnnotation(DetailAST variableDef)
Checks if variable def has ignore annotation.
|
private boolean |
hasProperAccessModifier(DetailAST variableDef,
java.lang.String variableName)
Checks if current variable has proper access modifier according to Check's options.
|
private boolean |
isAllowedPublicField(DetailAST variableDef)
Checks whether the variable satisfies the public field check.
|
private static boolean |
isAnonymousClassVariable(DetailAST variableDef)
Checks if current variable definition is definition of an anonymous class.
|
private static boolean |
isCanonicalName(DetailAST type)
Checks whether type definition is in canonical form.
|
private static boolean |
isFinalField(DetailAST variableDef)
Checks whether current field is final.
|
private boolean |
isIgnoredPublicMember(java.lang.String variableName,
java.lang.String variableScope)
Checks whether variable belongs to public members that should be ignored.
|
private boolean |
isImmutableField(DetailAST variableDef)
Checks if current field is immutable:
has final modifier and either a primitive type or instance of class
known to be immutable (such as String, ImmutableCollection from Guava and etc).
|
private boolean |
isImmutableFieldDefinedInFinalClass(DetailAST variableDef)
Checks whether immutable field is defined in final class.
|
private static boolean |
isPrimitive(DetailAST type)
Checks if current type is primitive type (int, short, float, boolean, double, etc.).
|
private static boolean |
isStarImport(DetailAST importAst)
Checks if current import is star import.
|
private static boolean |
isStaticFinalVariable(DetailAST variableDef)
Checks whether variable has static final modifiers.
|
void |
setAllowPublicFinalFields(boolean allow)
Sets whether public final fields are allowed.
|
void |
setAllowPublicImmutableFields(boolean allow)
Sets whether public immutable fields are allowed.
|
void |
setIgnoreAnnotationCanonicalNames(java.lang.String... annotationNames)
Set the list of ignore annotations.
|
void |
setImmutableClassCanonicalNames(java.lang.String... classNames)
Set the list of immutable classes types names.
|
void |
setPackageAllowed(boolean packageAllowed)
Set whether package visible members are allowed.
|
void |
setProtectedAllowed(boolean protectedAllowed)
Set whether protected members are allowed.
|
void |
setPublicMemberPattern(java.util.regex.Pattern pattern)
Set the pattern for public members to ignore.
|
private void |
visitImport(DetailAST importAst)
Checks imported type.
|
void |
visitToken(DetailAST ast)
Called to process a token.
|
private void |
visitVariableDef(DetailAST variableDef)
Checks access modifier of given variable.
|
destroy, finishTree, getClassLoader, getFileContents, getLine, getLines, getTabWidth, getTokenNames, init, isCommentNodesRequired, leaveToken, log, log, setClassLoader, setFileContents, setMessages, setTabWidth, setTokens
getCustomMessages, getId, getMessageBundle, getSeverity, getSeverityLevel, log, setId, setSeverity
configure, contextualize, finishLocalSetup, getConfiguration, setupChild
public static final java.lang.String MSG_KEY
private static final java.util.List<java.lang.String> DEFAULT_IMMUTABLE_TYPES
private static final java.util.List<java.lang.String> DEFAULT_IGNORE_ANNOTATIONS
private static final java.lang.String PUBLIC_ACCESS_MODIFIER
private static final java.lang.String PRIVATE_ACCESS_MODIFIER
private static final java.lang.String PROTECTED_ACCESS_MODIFIER
private static final java.lang.String PACKAGE_ACCESS_MODIFIER
private static final java.lang.String STATIC_KEYWORD
private static final java.lang.String FINAL_KEYWORD
private static final java.lang.String[] EXPLICIT_MODS
private java.util.regex.Pattern publicMemberPattern
private final java.util.List<java.lang.String> ignoreAnnotationShortNames
private final java.util.List<java.lang.String> immutableClassShortNames
private java.util.List<java.lang.String> ignoreAnnotationCanonicalNames
private boolean protectedAllowed
private boolean packageAllowed
private boolean allowPublicImmutableFields
private boolean allowPublicFinalFields
private java.util.List<java.lang.String> immutableClassCanonicalNames
public void setIgnoreAnnotationCanonicalNames(java.lang.String... annotationNames)
annotationNames
- array of ignore annotations canonical names.public void setProtectedAllowed(boolean protectedAllowed)
protectedAllowed
- whether protected members are allowedpublic void setPackageAllowed(boolean packageAllowed)
packageAllowed
- whether package visible members are allowedpublic void setPublicMemberPattern(java.util.regex.Pattern pattern)
pattern
- pattern for public members to ignore.public void setAllowPublicImmutableFields(boolean allow)
allow
- user's value.public void setAllowPublicFinalFields(boolean allow)
allow
- user's value.public void setImmutableClassCanonicalNames(java.lang.String... classNames)
classNames
- array of immutable types canonical names.public int[] getDefaultTokens()
AbstractCheck
getDefaultTokens
in class AbstractCheck
TokenTypes
public int[] getAcceptableTokens()
AbstractCheck
getAcceptableTokens
in class AbstractCheck
TokenTypes
public int[] getRequiredTokens()
AbstractCheck
getRequiredTokens
in class AbstractCheck
TokenTypes
public void beginTree(DetailAST rootAst)
AbstractCheck
beginTree
in class AbstractCheck
rootAst
- the root of the treepublic void visitToken(DetailAST ast)
AbstractCheck
visitToken
in class AbstractCheck
ast
- the token to processprivate static boolean isAnonymousClassVariable(DetailAST variableDef)
variableDef
- VARIABLE_DEF
private void visitVariableDef(DetailAST variableDef)
variableDef
- variable to check.private boolean hasIgnoreAnnotation(DetailAST variableDef)
variableDef
- VARIABLE_DEF
private void visitImport(DetailAST importAst)
importAst
- Import
private static boolean isStarImport(DetailAST importAst)
import java.util.*;
importAst
- Import
private boolean hasProperAccessModifier(DetailAST variableDef, java.lang.String variableName)
variableDef
- Variable definition node.variableName
- Variable's name.private static boolean isStaticFinalVariable(DetailAST variableDef)
variableDef
- Variable definition node.private boolean isIgnoredPublicMember(java.lang.String variableName, java.lang.String variableScope)
variableName
- Variable's name.variableScope
- Variable's scope.private boolean isAllowedPublicField(DetailAST variableDef)
variableDef
- Variable definition node.private boolean isImmutableFieldDefinedInFinalClass(DetailAST variableDef)
variableDef
- Variable definition node.private static java.util.Set<java.lang.String> getModifiers(DetailAST defAST)
defAST
- AST for a variable or class definition.private static java.lang.String getVisibilityScope(DetailAST variableDef)
variableDef
- Variable definition node.private boolean isImmutableField(DetailAST variableDef)
immutableClassCanonicalNames
variableDef
- Field in consideration.private static boolean isCanonicalName(DetailAST type)
type
- type definition token.private static DetailAST getGenericTypeArgs(DetailAST type, boolean isCanonicalName)
type
- type token.isCanonicalName
- whether type name is in canonical form.private static java.util.List<java.lang.String> getTypeArgsClassNames(DetailAST typeArgs)
typeArgs
- type arguments token.private boolean areImmutableTypeArguments(java.util.List<java.lang.String> typeArgsClassNames)
typeArgsClassNames
- type arguments class names.private static boolean isFinalField(DetailAST variableDef)
variableDef
- field in consideration.private static java.lang.String getTypeName(DetailAST type, boolean isCanonicalName)
TYPE
node.
If type is specified via its canonical name - canonical name will be returned,
else - short type's name.type
- TYPE
node.isCanonicalName
- is given name canonical.private static boolean isPrimitive(DetailAST type)
IDENT
token - it's a
primitive type.type
- Ast TYPE
node.private static java.lang.String getCanonicalName(DetailAST type)
TYPE
node.type
- DetailAST TYPE
node.private static DetailAST getNextSubTreeNode(DetailAST currentNodeAst, DetailAST subTreeRootAst)
currentNodeAst
- Current node in consideringsubTreeRootAst
- SubTree rootprivate static java.util.List<java.lang.String> getClassShortNames(java.util.List<java.lang.String> canonicalClassNames)
canonicalClassNames
- canonical class names.private static java.lang.String getClassShortName(java.lang.String canonicalClassName)
canonicalClassName
- canonical class name.private DetailAST findMatchingAnnotation(DetailAST variableDef)
This method will not look for imports or package statements to detect the passed in annotation.
To check if an AST contains a passed in annotation taking into account fully-qualified names (ex: java.lang.Override, Override) this method will need to be called twice. Once for each name given.
variableDef
- variable def node
.