-
Notifications
You must be signed in to change notification settings - Fork 0
PmdRulesPrototype
Very specific rules but useless on general code. They serve as examples and prototypes to copy from.
In a specific Rich Domain Model all Entities (subclasses of Entity) must define their attributes as (subclasses of) `RelationShip`s. Simple attributes are not allowed. To fix this rule, wrap all simple attributes with a `RelationShip` of proper type accordingly.
This rule is defined by the following Java class: org.codecop.pmd.prototype.EntityWithReferences
public class RelationShip<T> { }
public class BetterRelationShip<T> extends RelationShip<T> { }
public class Entity { }
public class BetterEntity extends Entity { }
public class BadEntity extends BetterEntity {
private RelationShip<MyString> astring; // ok
private MyString bstring; // wrong
private int bint; // wrong
}
In a specific Rich Domain Model all Value Objects (subclasses of `ValueObject`s) must not define their attributes as (subclasses of) `RelationShip`s. Just simple attributes are allowed.
This rule is defined by the following Java class: org.codecop.pmd.prototype.ImmutableValueObject
public class ValueObject { }
public class BadValueObject extends ValueObject {
private MyString astring;
private BetterRelationShip<MyString> bstring; // wrong
public void changeAstring(MyString string) { // wrong
astring = string;
}
}
Some methods, e.g. toString or getName() in subclasses of Action, must not just return null. If they will never be called, throw a `OperationNotSupportedException`.
This rule is defined by the following XPath expression:
//MethodDeclaration
[MethodDeclarator[@Image=$method or @Image='toString']]
[Block//ReturnStatement//NullLiteral]
public class FooAction {
public String getName() {
return null; // should return some string for statistics.
}
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| method | 'getName' | Name of the method to check |
Services are responsible for maintaining transactions, so classes in the DB layer are not allowed to call Connection.commit. commit is a reserved word and should also not be used as identifier.
This rule is defined by the following XPath expression:
//PrimaryExpression[ ( PrimaryPrefix/Name[ends-with(@Image, $method)] or PrimarySuffix[@Image=$method] ) and //PackageDeclaration[Name[ends-with(@Image, $package) ]] ]
package some.resultlist;
public class CommitInDBLayerExample {
public void methodOne() {
Connection con = getConnection();
con.commit();
System.out.println("we did it");
}
public void methodTwo() {
getConnection().commit();
System.out.println("we did it again");
}
public void methodThree() {
// would be ok, but may warn as well
other.commit(bla);
}
public void okOne() {
int commit;
// commit = 3; - false positive
// other.Somecommit(); - false positive
}
public void okTwo() {
long commit = 3L;
other.commitIt(bla);
other.commit2();
}
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| method | 'commit' | Name of the commit method |
| package | '.resultlist' | Suffix of the db layer package name |
Only certain classes in $package packages are allowed to call special methods on objects, which are suffixed by $method.
This rule is defined by the following XPath expression:
//PrimaryExpression[ ( PrimaryPrefix/Name[ends-with(@Image, $method)] or PrimarySuffix[ends-with(@Image, $method)] ) and //PackageDeclaration[Name[ not (ends-with(@Image, $package)) ]] ]
package some.notjunit;
public class BadGuy {
public void method() {
Object con = getObject();
con.run4Test();
int result = con.run4Test(params);
System.out.println("we did it");
getObject().run4Test();
int res = getObject().run4Test(params);
System.out.println("we did it again");
}
public void method4Test() { } // is allowed
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| method | '4Test' | Suffix of the method name |
| package | '.junit' | Suffix of the allowed package name |
Normally only one logger is used in each class.
This rule is defined by the following XPath expression:
//ClassOrInterfaceBody[ count(//VariableDeclarator[parent::FieldDeclaration][../Type/ReferenceType/ClassOrInterfaceType[@Image=$logger]]) > 1 ]
class Foo {
LoggerImpl logger = LoggerUtil.getLogger(Foo.class);
// It is very rare to see two loggers on a class, normally
// log information is multiplexed by levels
LoggerImpl log2 = LoggerUtil.getLogger(Foo.class.getName());
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| logger | 'LoggerImpl' | Name of the logger type |
In most cases, the Logger can be declared private, static and final.
This rule is defined by the following XPath expression:
//VariableDeclarator[parent::FieldDeclaration][ ../Type/ReferenceType/ClassOrInterfaceType[@Image=$logger] and ( ..[@Final='false'] or ..[@Static='false'] or .. [@Private='false'] ) ]
class Foo {
LoggerImpl logger = LoggerUtil.getLogger(Foo.class);
// It is much better to declare the logger as follows
// static final LoggerImpl logger = LoggerUtil.getLogger(Foo.class);
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| logger | 'LoggerImpl' | Name of the logger type |
This class is shared by threads but not threadsafe. Therefore it must only have final members.
This rule is defined by the following XPath expression:
//FieldDeclaration[@Final='false' and ../../..[ends-with(@Image,$suffix)]]
public class AdWorxChannelPolicy {
private final String channel; // ok
private boolean showIfSearchedInRegion; // not ok
}
// other class
public class AdWorxChannelPolicyKey {
private final String channel; // ok
private boolean showIfSearchedInRegion; // ok
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| suffix | 'Policy' | Class name suffix |
The use of this type is not allowed.
This rule is defined by the following XPath expression:
//ClassOrInterfaceType[@Image=$simple or @Image=$full]
class MyClass extends OtherClass {
public void myMethod() {
try {
// ...
throw new org.codecop.HBDException("..."); // "throw new HBDException" is not allowed!
} catch(HBDException e) { // "catch HBDException" is not allowed!
// ...
}
}
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| simple | 'HBDException' | Forbidden type simple name |
| full | 'org.codecop.HBDException' | Forbidden type full name |
Certain classes need to define and redefine a method on their own regardless of superclasses have provided it or not.
This rule is defined by the following XPath expression:
//ClassOrInterfaceDeclaration[ ends-with(@Image, $suffix) and not (ends-with(@Image,'HelperAction')) and @Abstract='false' and count(//MethodDeclarator[@Image=$method])=0 ]
public class FooAction {
public String getXActionShortName() { // typo occured
return "abc";
}
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| suffix | 'Action' | Class name suffix |
| method | 'getActionShortName' | Name of the method to implement |
All concrete JUnit tests must be named to the sheme of ending with Test to be identified and run automatically.
This rule is defined by the following XPath expression:
//ClassOrInterfaceDeclaration[ not (ends-with(@Image, $suffix)) and not (ends-with(@Image, 'TestManuell')) and not (@Image='TCInit') and @Abstract='false' and //PackageDeclaration[Name[ ends-with(@Image, $package) ]] ]
package some.junit;
class BadTestClass {
// this does not end with Test
}
abstract class GoodAbstract {
// is abstract, name as it likes
}
class GoodTest {
// ok
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| package | '.junit' | Suffix of the package name |
| suffix | 'Test' | Mandatory suffix of the class name |
Enums are special instances and not meant to be created by other classes, instead use a getEnumFor(value) on the Enum itself.
This rule is defined by the following XPath expression:
//AllocationExpression[ ends-with(ClassOrInterfaceType/@Image, $suffix) and (count(ArrayDimsAndInits)=0) and not (//ClassOrInterfaceDeclaration/@Image=ClassOrInterfaceType/@Image) ]
class MyEnum {
public void foo() {
new MyEnum(); // is ok
}
}
class OtherEnum {
public void foo() {
new MyEnum(); // is forbidden
}
}
class OtherClass {
public void foo() {
new MyEnum[0]; // array is ok
}
}
This rule has the following properties:
| Name | Default value | Description |
|---|---|---|
| suffix | 'Enum' | Enum type name suffix |