Skip to content

PmdRulesPrototype

Peter Kofler edited this page Feb 10, 2020 · 8 revisions

Prototype

Very specific rules but useless on general code. They serve as examples and prototypes to copy from.


EntityWithReferences

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

Example:

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
}

ImmutableValueObject

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

Example:

public class ValueObject { }
public class BadValueObject extends ValueObject {
   private MyString astring;
   private BetterRelationShip<MyString> bstring; // wrong
   public void changeAstring(MyString string) { // wrong
      astring = string;
   }
}

EmptyFunction

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]

Example:

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

CommitInDBLayer

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) ]]
]

Example:

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

Call4MethodNotInPackage

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)) ]]
]

Example:

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

MoreThanOneCustomLogger

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
]

Example:

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

CustomLoggerIsNotStaticFinal

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'] )
]

Example:

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

NoAttrInClass

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)]]

Example:

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

TypeNotAllowed

The use of this type is not allowed.

This rule is defined by the following XPath expression:

//ClassOrInterfaceType[@Image=$simple or @Image=$full]

Example:

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

ActionHasNoShortName

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
]

Example:

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

JUnitTestHasWrongName

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) ]]
]

Example:

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

NewEnumOnlyInside

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)
]

Example:

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