feat: demo-pmd 样本工程入库 + Windows spawn cmd EINVAL 修复 + 实测报告清理

- data/demo-pmd 全量入库(26 源文件 + pom/mvnw/lib/reports),.gitignore 排除 target/
- 归档 demo-pmd 实测覆盖率报告(279/279 全覆盖)至 reports/
- 删除 4 份覆盖率报告中的后续建议/实测进度总览(全部实测已收官)
- 修复 Windows spawn .cmd/.bat EINVAL(auxClasspath.ts 经 cmd.exe /d /s /c 间接执行)
This commit is contained in:
范智鹏
2026-08-26 22:04:47 +08:00
parent e9762bfbe1
commit 3c390cfa90
47 changed files with 4363 additions and 23 deletions
@@ -0,0 +1,10 @@
// ============================================================
// PMD 演示样例 — PackageCase:包名应小写
// ============================================================
package com.demo.BadCase;
class PackageCaseDemo {
void m() {
System.out.println("bad package case");
}
}
@@ -0,0 +1,13 @@
// ============================================================
// PMD 演示样例 — API 服务类
// 注:LoosePackageCoupling 已从插件内置 ruleset 排除
// (规则需显式配置 packages/classes 才能执行,未配置时空转),
// 本类仅作为 SystemPrintln 等规则的普通触发材料。
// ============================================================
package com.demo.api;
public class ApiService {
public void doWork() {
System.out.println("api service");
}
}
@@ -0,0 +1,44 @@
// ============================================================
// PMD 演示样例 — 硬编码 IP / 私有构造等常规样例
// 注:AccessorClassGeneration / AccessorMethodGeneration 两条规则
// 设有 maximumLanguageVersion=10Java 11 起 JEP 181 不再生成合成访问器),
// 已从插件内置 ruleset 排除,以下代码仅作为普通触发材料保留。
// ============================================================
package com.demo.bestpractices.extra;
// 私有构造器样例(触发 ClassWithOnlyPrivateConstructorsShouldBeFinal 等)
class PrivateCtor {
private PrivateCtor() { // 私有构造函数
}
}
class UsesPrivateCtor {
PrivateCtor make() {
return new PrivateCtor(); // 外部调用私有构造函数
}
}
// 私有成员访问样例(触发 ImmutableField 等)
class PrivateFieldOwner {
private int secret = 42; // 私有字段
int getSecret() {
return secret;
}
}
class ReadsPrivateField {
int read(PrivateFieldOwner o) {
return o.getSecret();
}
}
// 12 AvoidUsingHardCodedIP
class HardCodedIpDemo {
String address = "192.168.0.1"; // 硬编码 IP
}
class MiscMain {
public static void main(String[] args) {
System.out.println("demo misc");
}
}
@@ -0,0 +1,40 @@
// ============================================================
// PMD 演示样例 — 未命中规则补齐(关键触发器)
// 注:AccessorClassGeneration / AccessorMethodGeneration 已从内置 ruleset
// 排除(maximumLanguageVersion=10,默认语言版本下永不执行),
// 以下内部类/私有构造代码仅作为普通触发材料保留。
// ============================================================
package com.demo.bestpractices.extra;
// 内部类私有构造从此类外部实例化(触发 AtLeastOneConstructor 等)
public class AccessorClassGen {
void method() {
Inner ic = new Inner(); // 外部实例化内部类
}
public class Inner {
private Inner() {
}
}
}
// 内部类访问外部类私有字段(触发 UnusedPrivateField 等)
public class AccessorMethodGen {
private int counter;
public class InnerClass {
InnerClass() {
AccessorMethodGen.this.counter++; // 访问外部私有字段
}
}
}
// 12 AvoidUsingHardCodedIP:硬编码 IP 字面量
class HardCodedIp {
String addr = "192.168.1.1"; // 硬编码 IP
}
class AccMain {
public static void main(String[] args) {
System.out.println("demo accessor/ip");
}
}
@@ -0,0 +1,1055 @@
// ============================================================
// PMD 演示样例 — Best Practices + Code Style 合并文件
// 本文件故意包含违反最佳实践与代码风格规则的代码,用于静态分析演示。
// 每条规则均以注释标注触发位置。
// 说明:同名顶层类已重命名以避免冲突(如 ParentFix/ChildFix、ParentRemain/ChildRemain、
// WarningSuppressFix 等)。
// ============================================================
package com.demo.bpcs;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Date; // 105 UnnecessaryImport:未使用导入
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.abs;
import static java.lang.Math.sqrt;
import static java.lang.Math.pow;
import static java.lang.Math.floor;
import static java.lang.Math.ceil;
import static java.lang.Math.round;
import static java.lang.Math.random;
import static java.lang.Math.sin;
import static java.lang.Math.cos;
import static java.lang.Math.tan;
import org.slf4j.LoggerFactory;
// ============================================================
// ---------- Best Practices Demo ----------
// ============================================================
// 1 AbstractClassWithoutAbstractMethod:抽象类不包含任何抽象方法
abstract class ServiceBase {
// 没有抽象方法,但类被声明为 abstract
public void start() {
System.out.println("start");
}
}
// 4 ArrayIsStoredDirectly / 28 LooseCoupling:构造器直接存储传入数组
class DataProcessor {
private final String[] items;
DataProcessor(String[] input) {
this.items = input; // 直接存储,未克隆
}
public String[] getItems() {
return this.items; // 16 MethodReturnsInternalArray:返回内部数组引用
}
}
// 6 AvoidMessageDigestFieldMessageDigest 作为字段(线程不安全)
final class Hasher {
private static final Logger LOG = Logger.getLogger("Hasher");
private MessageDigest digest; // MessageDigest 字段
Hasher() {
try {
this.digest = MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
LOG.log(Level.SEVERE, "init", e);
}
}
}
// 10 AvoidStringBufferFieldStringBuilder 字段
class TextBuilder {
private StringBuilder sb = new StringBuilder(); // StringBuilder 字段
void add(String s) {
sb.append(s);
}
}
// 12 AvoidUsingHardCodedIP:硬编码 IP
class NetConfig {
String host = "http://192.168.1.1"; // 硬编码 IP
}
// 14 ConstantsInInterface:接口中定义常量
interface HttpConstants {
int PORT = 8080; // 接口常量
}
// 17 DoubleBraceInitialization:双花括号初始化
class Wrapper {
Map<String, String> map = new HashMap<String, String>() {{
put("a", "1");
}};
}
// 22 ImplicitFunctionalInterface:函数式接口缺少注解
interface ClickHandler {
void onClick();
}
// 26 LabeledStatement:带标签的语句
class Flow {
void outer() {
outer:
for (int i = 0; i < 3; i++) { // 标签
for (int j = 0; j < 3; j++) {
if (j == 2) {
break outer;
}
}
}
}
}
// 35 RelianceOnDefaultCharset:依赖默认字符集
class CharsetDemo {
void read() throws IOException {
FileInputStream fis = new FileInputStream("f.txt");
InputStreamReader isr = new InputStreamReader(fis); // 默认字符集
BufferedReader br = new BufferedReader(isr);
br.readLine();
}
}
// 36 ReplaceEnumerationWithIterator:使用 Enumeration
class EnumerationDemo {
void list() {
Hashtable<String, String> h = new Hashtable<>();
Enumeration<String> e = h.keys(); // Enumeration
}
}
// 37 ReplaceHashtableWithMap:使用 Hashtable
class HashtableDemo {
Hashtable<String, String> table = new Hashtable<>(); // Hashtable
}
// 38 ReplaceVectorWithList:使用 Vector
class VectorDemo {
Vector<String> v = new Vector<>(); // Vector
}
// 40 SystemPrintln:使用 System.out/err
class LoggerDemo {
void log() {
System.out.println("should use logger"); // SystemPrintln
System.err.println("error"); // SystemPrintln
}
}
// 45 UseStandardCharsets:使用 StandardCharsets
class CharsetDemo2 {
void doIt() throws IOException {
FileInputStream fis = new FileInputStream("g.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); // 应使用 StandardCharsets.UTF_8
BufferedReader br = new BufferedReader(isr);
br.readLine();
}
}
// 46 UseTryWithResources:手工关闭资源
class ResourceDemo {
void read() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("h.txt")));
try {
br.readLine();
} finally {
br.close(); // 手工关闭,应使用 try-with-resources
}
}
}
// 47 UseVarargs:使用数组参数而非可变参数
class VarArgsDemo {
void accept(String[] args) { // 应使用 String... args
// no-op
}
}
// 48 WhileLoopWithLiteralBoolean:字面量布尔 while
class WhileDemo {
int i = 0;
void loop() {
while (true) { // 字面量 true
if (i++ > 5) {
break;
}
}
}
}
// 49 OneDeclarationPerLine:一行多个声明
class DeclDemo {
int a, b, c; // 一行多个声明
}
// 50 UnnecessaryVarargsArrayCreation:显式可变参数数组
class VarArgsDemo2 {
void call() {
accept2(new String[]{"x"}); // 应直接传 "x"
}
void accept2(String... args) {
}
}
// 51 UnnecessaryWarningSuppression:未使用的抑制
@SuppressWarnings("unused") // 未使用的抑制
class UnusedSuppress {
public void m() {
}
}
// 7 AvoidPrintStackTraceprintStackTrace
class StackTraceDemo {
void bad() {
try {
int x = 1 / 0;
} catch (ArithmeticException e) {
e.printStackTrace(); // AvoidPrintStackTrace
}
}
}
// 8 AvoidReassigningCatchVariables:重新赋值捕获的异常变量
class ReassignCatch {
void bad() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
e = new RuntimeException("reassigned"); // 重新赋值
}
}
}
// 9 AvoidReassigningLoopVariables:重新赋值循环变量
class ReassignLoop {
void bad() {
for (int i = 0; i < 10; i++) {
i = 5; // 重新赋值循环变量
}
}
}
// 11 AvoidReassigningParameters:重新赋值方法参数
class ReassignParam {
void bad(int x) {
x = 10; // 重新赋值参数
}
}
// 13 CheckResultSet:未检查 ResultSet 返回值
class RsDemo {
void bad() {
try {
java.sql.Statement st = null;
java.sql.ResultSet rs = st.executeQuery("select 1");
rs.next(); // 应检查返回值
} catch (Exception e) {
}
}
}
// 18 EnumComparison:使用 equals 比较枚举
class EnumCmp {
void bad() {
Color c = Color.RED;
if (c.equals(Color.RED)) { // 应使用 ==
}
}
enum Color { RED, GREEN }
}
// 19 ExhaustiveSwitchHasDefault:穷尽式 switch 不应有 default
class ExhaSwitch {
void bad() {
Color c = Color.RED;
switch (c) {
case RED: break;
case GREEN: break;
default: break; // 穷尽式 switch 不应有 default
}
}
enum Color { RED, GREEN }
}
// 21 ForLoopVariableCountfor 循环多个控制变量
class ForLoopCount {
void bad() {
for (int i = 0, j = 0; i < 5; i++, j++) { // 多个控制变量
}
}
}
// 23 GuardLogStatement:记录日志前检查日志级别
class GuardLog {
private static final Logger LOG = Logger.getLogger("GuardLog");
void log(String msg) {
LOG.log(Level.FINE, msg); // 应检查 isLoggable
}
}
// 27 LiteralsFirstInComparisons:字面量放前面
class LiteralCmp {
void bad(String s) {
if (s.equals("abc")) { // 应 "abc".equals(s)
}
}
}
// 29 MissingOverride:缺少 @Override
class Base {
public String toString() {
return "Base";
}
public boolean equals(Object o) {
return true;
}
}
class Sub extends Base {
public String toString() { // 应加 @Override
return "Sub";
}
}
class Sub2 extends Base {
public boolean equals(Object o) { // 应加 @Override
return false;
}
}
// 30 NonExhaustiveSwitchswitch 应为穷尽式
class NonExh {
void bad() {
Color2 c = Color2.RED;
switch (c) { // 非穷尽(缺 GREEN
case RED: break;
}
}
enum Color2 { RED, GREEN }
}
// 32 PreserveStackTrace:重新抛出时保留堆栈
class Preserve {
void bad() {
try {
throw new IOException();
} catch (IOException e) {
throw new RuntimeException("msg"); // 未保留堆栈
}
}
}
// 33 PrimitiveWrapperInstantiationnew Type()
class WrapInst {
Integer i = new Integer(5); // 应使用 valueOf
}
// 15 DefaultLabelNotLastInSwitch
class DefLabel {
void bad() {
int x = 1;
switch (x) {
default: break; // default 不在最后
case 1: break;
}
}
}
// 20 ForLoopCanBeForeach:用 foreach
class ForeachDemo {
void bad(List<String> l) {
for (int i = 0; i < l.size(); i++) { // 应 foreach
System.out.println(l.get(i));
}
}
}
// 51 UnusedFormalParameter:未使用参数
class UnusedParam {
void bad(int unused) { // 未使用参数
System.out.println("hi");
}
}
// 52 UnusedLabel:未使用标签
class UnusedLabelDemo {
void bad() {
label: // 未使用标签
for (int i = 0; i < 3; i++) {
System.out.println(i);
}
}
}
// 53 UnusedLocalVariable:未使用局部变量
class UnusedLocal {
void bad() {
int x = 5; // 未使用局部变量
System.out.println("hi");
}
}
// 54 UnusedPrivateField:未使用私有字段
class UnusedField {
private int secret; // 未使用私有字段
public void m() {
}
}
// 55 UnusedPrivateMethod:未使用私有方法
class UnusedMethod {
private void helper() { // 未使用私有方法
}
public void m() {
}
}
// 56 UseCollectionIsEmptysize()==0
class ColEmpty {
void bad(List<String> l) {
if (l.size() == 0) { // 应使用 isEmpty()
}
}
}
// 57 UseEnumCollectionsEnumSet/EnumMap
class EnumCol {
void bad() {
HashSet<Color> set = new HashSet<>(); // 应使用 EnumSet
HashMap<Color, String> map = new HashMap<>(); // 应使用 EnumMap
}
enum Color { RED }
}
class BadMain {
public static void main(String[] args) {
System.out.println("demo bestpractices");
}
}
// ============================================================
// ---------- Best Practices Fix ----------
// ============================================================
// 21 GuardLogStatement
class GuardLogDemo {
private static final org.slf4j.Logger log = LoggerFactory.getLogger(GuardLogDemo.class);
void debug(String param1, String param2) {
log.debug("log something " + param1 + " and " + param2 + "concat strings"); // 应检查级别
}
}
// 26 LabeledStatement
class LabeledDemo {
public static void main(String[] args) {
int x = 1;
lbl1:
while (true) { // 标签
lbl2:
if (x == 3) {
x++;
break lbl2;
}
lbl3:
if (x == 4) {
break lbl1;
}
System.out.println(x);
x++;
}
}
}
// 36 ReplaceEnumerationWithIterator
class EnumerationImpl implements java.util.Enumeration {
private int i = 0;
public boolean hasMoreElements() {
return true;
}
public Object nextElement() {
return String.valueOf(i++);
}
}
// 51 UnnecessaryWarningSuppression(重命名:避免与 WarningSuppressDemo 概念混淆唯一化)
class WarningSuppressFix {
private void foo() { // NOPMD
}
}
// 50 UnusedFormalParameter
class UnusedFormalParam {
private void bar(String howdy) { // howdy 未使用
System.out.println("hi");
}
}
// 60 WhileLoopWithLiteralBoolean
class WhileLiteralDemo {
{ // 非静态初始化块(演示 NonStaticInitializer
do { // 字面量 false 作为循环条件
// 循环体(使用 do-while 保证循环体可达)
} while (false);
}
}
class BestFixMain {
public static void main(String[] args) {
System.out.println("demo bestpractices fixes");
}
}
// ============================================================
// ---------- Warning Suppress Demo ----------
// ============================================================
// 51 UnnecessaryWarningSuppression:未触发的 NOPMD 抑制
class WarningSuppressDemo { // 移除 public:合并文件副作用,避免"需独立文件"报错
private void foo() { // NOPMD
}
}
class WsMain {
public static void main(String[] args) {
System.out.println("demo warning suppression");
}
}
// ============================================================
// ---------- Code Style Demo ----------
// ============================================================
// 61 AtLeastOneConstructor:无构造函数
class NoConstructor {
void m() {
}
}
// 62 AvoidDollarSigns:名称含 $
class Bad$Name {
}
// 63 AvoidProtectedFieldInFinalClassfinal 类 protected 字段
final class FinalClass {
protected int x;
}
// 64 AvoidProtectedMethodInFinalClassNotExtendingfinal 类 protected 方法
final class FinalClass2 {
protected void m() {
}
}
// 65 AvoidUsingNativeCodeJNI
class NativeDemo {
native void jni();
}
// 66 BooleanGetMethodName:布尔 getter 命名
class BoolGetter {
boolean flag;
boolean getFlag() { // 应 isFlag()
return flag;
}
}
// 68 ClassNamingConventions:小写类名
class badClassName {
}
// 69 CommentDefaultAccessModifier
class DefaultMod {
int x; // 应注释
void m() { // 应注释
}
}
// 70 ConfusingTernary
class ConfTernary {
boolean bad(boolean a) {
if (!a) {
return true;
} else {
return false;
}
}
}
// 71 ControlStatementBraces
class NoBraces {
void bad(boolean a) {
if (a)
System.out.println("no brace");
}
}
// 72 EmptyControlStatement
class EmptyCtrl {
void bad(int x) {
if (x > 0) {
}
}
}
// 73 EmptyMethodInAbstractClassShouldBeAbstract
abstract class EmptyMethod {
void empty() {
}
}
// 74 ExtendsObject
class ExObj extends Object {
}
// 75 FieldDeclarationsShouldBeAtStartOfClass
class FieldPos {
private int late;
void method() {
}
}
// 76 FieldNamingConventions
class FieldName {
private int bad_name;
}
// 77 FinalParameterInAbstractMethod
abstract class AbsMethod {
abstract void doIt(final int x);
}
// 78 ForLoopShouldBeWhileLoop
class ForToWhile {
void bad() {
int i = 0;
for (; i < 10;) {
i++;
}
}
}
// 79 FormalParameterNamingConventions
class ParamName {
void bad(int bad_param) {
}
}
// 80 IdenticalCatchBranches
class IdemCatch {
void bad() {
try {
int x = 1 / 0;
} catch (ArithmeticException e) {
System.out.println("err");
} catch (Exception e) {
System.out.println("err");
}
}
}
// 81 LambdaCanBeMethodReference
class LambdaRef {
void bad() {
Function<String, Integer> f = s -> s.length();
}
}
// 82 LinguisticNaming
class LingName {
boolean isReady(String s) {
return s.isEmpty();
}
}
// 85 LocalVariableCouldBeFinal
class LocalFinal {
void bad() {
int x = 5;
System.out.println(x);
}
}
// 86 LocalVariableNamingConventions
class LocalVarName {
void bad() {
int bad_var = 1;
System.out.println(bad_var);
}
}
// 88 MethodArgumentCouldBeFinal
class ArgFinal {
void bad(int x) {
System.out.println(x);
}
}
// 89 MethodNamingConventions
class MethodName {
void BadMethod() {
}
}
// 90 ModifierOrder
class ModOrder {
static public void m() {
}
final private int x = 1;
}
// 92 OnlyOneReturn
class MultiReturn {
int bad(int x) {
if (x > 0) {
return 1;
}
return 0;
}
}
// 94 PrematureDeclaration
class PremDecl {
void bad() {
int x = 0;
System.out.println("do more");
System.out.println("do more2");
System.out.println(x);
}
}
// 97 TooManyStaticImports
class StaticImp {
void m() {
max(1, 2);
}
}
// 98 TypeParameterNamingConventions
class TypeParam<bad> {
}
// 99 UnnecessaryAnnotationValueElement
class AnnVal {
@SuppressWarnings(value = "unused")
void m() {
}
}
// 100 UnnecessaryBlock
class UnNeedBlock {
void m() {
{
int x = 1;
}
}
}
// 101 UnnecessaryBoxing
class UnNeedBox {
void m() {
Integer i = new Integer(1);
}
}
// 102 UnnecessaryCast
class UnNeedCast {
void m() {
Object o = "s";
String s = (String) o;
}
}
// 103 UnnecessaryConstructor
class UnNeedCons {
UnNeedCons() {
}
}
// 104 UnnecessaryFullyQualifiedName
class FullQual {
void m() {
java.lang.String s = new java.lang.String("x");
}
}
// 106 UnnecessaryInterfaceDeclaration
interface EmptyI {
}
// 107 UnnecessaryModifier
interface IMod {
public abstract void m();
}
// 108 UnnecessaryReturn
class UnNeedRet {
void m() {
System.out.println("x");
return;
}
}
// 109 UnnecessarySemicolon
class UnNeedSemi {
void m() {
int x = 1;;
System.out.println(x);
}
}
// 110 UseDiamondOperator
class Diamond {
List<String> l = new ArrayList<String>();
}
// 111 UseExplicitTypes
class ExplicitType {
void m() {
var x = 5;
System.out.println(x);
}
}
// 112 UselessParentheses
class UselessParen {
void m() {
int x = (1 + 2);
System.out.println(x);
}
}
// 113 UselessQualifiedThis
class UselessThis {
int x;
void m() {
int y = this.x;
System.out.println(y);
}
}
// 114 UseShortArrayInitializer
class ShortArr {
int[] a = new int[]{1, 2, 3};
}
// 115 UseUnderscoresInNumericLiterals
class Underscore {
int x = 1000000;
}
// 116 VariableCanBeInlined
class InlineVar {
void m() {
int len = 5;
System.out.println(len);
}
}
// 117 VariableDeclarationUsageDistance
class UsageDist {
void m() {
int x = 0;
System.out.println("a");
System.out.println("b");
System.out.println("c");
System.out.println("d");
System.out.println("e");
System.out.println(x);
}
}
class BadCodestyle {
public static void main(String[] args) {
System.out.println("demo codestyle");
}
}
// ============================================================
// ---------- Code Style Fix ----------
// ============================================================
// 67 CallSuperInConstructor:构造函数调用 super()
class ParentFix {
ParentFix() {
}
}
class ChildFix extends ParentFix {
ChildFix() {
super(); // 应省略
}
}
// 94 PrematureDeclaration
class PrematureDeclDemo {
public int getLength(String[] strings) {
int length = 0; // 可移到循环附近
if (strings == null || strings.length == 0) {
return 0;
}
for (String str : strings) {
length += str.length();
}
return length;
}
}
// 102 UnnecessaryCast
class UnnecessaryCastDemo {
void m() {
Object o = new Object();
o = (Object) new Object(); // 多余强转
System.out.println(o);
}
}
// 106 UnnecessaryInterfaceDeclaration
interface IBase {
}
interface IExt extends IBase {
}
class ImplA implements IBase, IExt { // A 声明实现 IBase 多余
}
// 113 UselessQualifiedThis
class QualifiedThis {
final QualifiedThis otherFoo = QualifiedThis.this; // 应直接用 this
void doSomething() {
final QualifiedThis anotherFoo = QualifiedThis.this; // 应直接用 this
System.out.println(anotherFoo);
}
}
// 117 VariableDeclarationUsageDistance
class UsageDistDemo {
public void lengthSum(String[] strings) {
int length = 0; // 距离使用远
System.out.println("prefix a");
System.out.println("prefix b");
System.out.println("prefix c");
System.out.println("prefix d");
for (String str : strings) {
length += str.length();
}
System.out.println("Total " + length);
}
}
// 65 AvoidUsingNativeCode
class NativeCodeDemo {
public native void compute(); // JNI
}
// 82 LinguisticNaming
class LinguisticNameDemo {
int count;
boolean isEnabled() { // ok
return true;
}
int getCount() { // getter 应返回字段
return computeSomething();
}
int computeSomething() {
return 42;
}
}
class CodeStyleFixMain {
public static void main(String[] args) {
System.out.println("demo codestyle fixes");
}
}
// ============================================================
// ---------- Code Style Remain ----------
// ============================================================
// 82 LinguisticNaming:方法名与返回类型不一致
class LinguisticNaming {
int isReady; // 字段名暗示布尔,却是 int
int isValid() { // 方法名暗示布尔,却返回 int
return 1;
}
}
// 65 AvoidUsingNativeCode:使用 System.loadLibrary
class NativeUsage {
public void invalid() {
System.loadLibrary("nativelib"); // JNI 加载
}
}
// 67 CallSuperInConstructor:构造函数未显式调用 super()
class ParentRemain {
ParentRemain() {
}
}
class ChildRemain extends ParentRemain {
ChildRemain() {
// 未显式调用 super(),应调用
}
}
// 117 VariableDeclarationUsageDistance
class UsageDistance {
public void lengthSum(String[] strings) {
int length = 0; // 距使用位置过远
System.out.println("unrelated a");
System.out.println("unrelated b");
System.out.println("unrelated c");
System.out.println("unrelated d");
System.out.println("unrelated e");
System.out.println("unrelated f");
System.out.println("unrelated g");
System.out.println("unrelated h");
System.out.println("unrelated i");
System.out.println("unrelated j");
for (String str : strings) {
length += str.length();
}
System.out.println("Total " + length);
}
}
class CodeStyleRemainMain {
public static void main(String[] args) {
System.out.println("demo codestyle remain");
}
}
// ============================================================
// ---------- 合并文件主入口 ----------
// ============================================================
class BadBpCsMain {
public static void main(String[] args) {
System.out.println("demo bpcs");
}
}
@@ -0,0 +1,37 @@
// ============================================================
// PMD 演示样例 — EJB 命名规则
// ============================================================
package com.demo.codestyle.extra;
import javax.ejb.EJBLocalHome;
import javax.ejb.EJBLocalObject;
import javax.ejb.EJBObject;
import javax.ejb.EJBHome;
import javax.ejb.SessionBean;
import javax.ejb.EJBObject;
// 83 LocalHomeNamingConventionLocalHome 后缀
public interface MissingLocalHomeSuffixBean extends EJBLocalHome { // 应 ...LocalHome
}
// 84 LocalInterfaceSessionNamingConventionLocal 后缀
public interface MissingLocalSuffixBean extends EJBLocalObject { // 应 ...Local
}
// 87 MDBAndSessionBeanNamingConventionBean 后缀
public class MissingBeanSuffix implements SessionBean { // 应 ...Bean
}
// 95 RemoteInterfaceNamingConvention:远程接口不应带后缀
public interface BadSuffixSession extends EJBObject { // 不应 Session 后缀
}
// 96 RemoteSessionInterfaceNamingConventionHome 后缀
public interface MissingHomeSuffixEJB extends EJBHome { // 应 ...Home
}
class EJBMain {
public static void main(String[] args) {
System.out.println("demo ejb naming");
}
}
@@ -0,0 +1,183 @@
// ============================================================
// PMD 演示样例 — GodClass(上帝类)
// 触发条件:WMC >= 47 且 ATFD > 5 且 TCC < 0.333
// 通过大量方法直接访问外部对象的公开字段(高 ATFD)+
// 高圈复杂度(高 WMC)+ 方法间低共享(低 TCC)触发
// ============================================================
package com.demo.design.extra;
class ExternalData {
public int a, b, c, d, e, f, g, h, i, j;
}
// 131 GodClass
public class GodClassDemo {
public int rule1(ExternalData d, int x) {
int r = d.a + d.b;
if (x > 0) { r += d.a; } else if (x > 1) { r += d.b; }
else if (x > 2) { r += d.c; }
return r;
}
public int rule2(ExternalData d, int x) {
int r = d.c + d.d;
if (x > 0) { r += d.d; } else if (x > 1) { r += d.e; }
else if (x > 2) { r += d.f; }
return r;
}
public int rule3(ExternalData d, int x) {
int r = d.e + d.f;
if (x > 0 && x < 10) { r += d.g; }
if (x > 1 || x < 20) { r += d.h; }
return r;
}
public int rule4(ExternalData d, int x) {
int r = d.g + d.h;
switch (x) {
case 0: r += d.a; break;
case 1: r += d.b; break;
case 2: r += d.c; break;
case 3: r += d.d; break;
case 4: r += d.e; break;
default: r += d.f; break;
}
return r;
}
public int rule5(ExternalData d, int x) {
int r = d.i + d.j;
if (x % 2 == 0) { r += d.a; } else { r += d.b; }
if (x % 3 == 0) { r += d.c; } else { r += d.d; }
return r;
}
public int rule6(ExternalData d, int x) {
int r = 0;
while (x > 0) {
r += d.a + d.b + d.c;
if (x > 10) { r += d.d; }
x--;
}
return r;
}
public int rule7(ExternalData d, int x) {
int r = d.a + d.b + d.c + d.d;
for (int i = 0; i < x; i++) {
if (i % 2 == 0) { r += d.e; } else { r += d.f; }
if (i % 3 == 0) { r += d.g; }
}
return r;
}
public int rule8(ExternalData d, int x) {
int r = d.e;
while (x > 0) {
switch (x % 3) {
case 0: r += d.a; break;
case 1: r += d.b; break;
case 2: r += d.c; break;
default: r += d.d; break;
}
x--;
}
return r;
}
public int rule9(ExternalData d, int x) {
int r = d.f + d.g;
if (x > 1) { r += d.h; } else if (x > 2) { r += d.i; }
else if (x > 3) { r += d.j; }
return r;
}
public int rule10(ExternalData d, int x) {
int r = d.a + d.b;
for (int i = 0; i < x; i++) {
for (int j = 0; j < i; j++) {
r += d.c;
}
}
return r;
}
public int rule11(ExternalData d, int x) {
int r = d.c;
if (x > 0) { r += d.a; } else if (x > 5) { r += d.b; }
else if (x > 10) { r += d.c; }
return r;
}
public int rule12(ExternalData d, int x) {
int r = 0;
for (int i = 0; i < x; i++) {
switch (i % 2) {
case 0: r += d.a; break;
default: r += d.b; break;
}
}
if (x > 5) { r += d.c; }
return r;
}
public int rule13(ExternalData d, int x) {
int r = d.a + d.b + d.c;
if (x > 0) { r += d.d; } else if (x > 1) { r += d.e; }
else if (x > 2) { r += d.f; }
return r;
}
public int rule14(ExternalData d, int x) {
int r = d.d + d.e + d.f;
if (x > 0) { r += d.g; } else if (x > 1) { r += d.h; }
else if (x > 2) { r += d.i; }
return r;
}
public int rule15(ExternalData d, int x) {
int r = d.g + d.h + d.i;
if (x > 0) { r += d.j; } else if (x > 1) { r += d.a; }
else if (x > 2) { r += d.b; }
return r;
}
public int rule16(ExternalData d, int x) {
int r = 0;
for (int i = 0; i < x; i++) {
if (i > 10) { r += d.a; } else if (i > 20) { r += d.b; }
else { r += d.c; }
}
return r;
}
public int rule17(ExternalData d, int x) {
int r = d.j;
if (x > 1) { r += d.a; } else if (x > 2) { r += d.b; }
else if (x > 3) { r += d.c; }
return r;
}
public int rule18(ExternalData d, int x) {
int r = d.a + d.e;
if (x > 0 && x < 50) { r += d.f; }
if (x > 1 || x < 25) { r += d.g; }
return r;
}
public int rule19(ExternalData d, int x) {
int r = d.b + d.c;
switch (x) {
case 1: r += d.a; break;
case 2: r += d.b; break;
case 3: r += d.c; break;
case 4: r += d.d; break;
case 5: r += d.e; break;
case 6: r += d.f; break;
case 7: r += d.g; break;
case 8: r += d.h; break;
case 9: r += d.i; break;
default: r += d.j; break;
}
return r;
}
public int rule20(ExternalData d, int x) {
int r = 0;
for (int i = 0; i < x; i++) {
if (i % 2 == 0) { r += d.a; } else { r += d.b; }
if (i % 3 == 0) { r += d.c; } else { r += d.d; }
if (i % 5 == 0) { r += d.e; }
}
return r;
}
}
class GodMain {
public static void main(String[] args) {
System.out.println("demo god class");
}
}
@@ -0,0 +1,17 @@
// ============================================================
// PMD 演示样例 — 包耦合常规样例
// 注:LoosePackageCoupling 已从插件内置 ruleset 排除——
// 该规则必须在 ruleset 中显式配置 packages/classes 属性才会执行,
// 未配置时每次运行只报配置错误、永不产出违规。
// 本文件保留跨包引用结构,作为其他规则的普通触发材料。
// ============================================================
package com.demo.design.extra;
import com.demo.api.ApiService;
class LoosePackageCouplingDemo {
void bad() {
ApiService svc = new ApiService(); // 在包层次外使用 com.demo.api
svc.doWork();
}
}
@@ -0,0 +1,1402 @@
// ============================================================
// PMD 演示样例 — Design + Error Prone(设计 + 易错)合并版
// ============================================================
package com.demo.designep;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// ---------- Design(设计) ----------
// 118 AbstractClassWithoutAnyMethod:无任何方法抽象类
abstract class NoMethodAbstract { // 无方法抽象类
}
// 119 AvoidDeeplyNestedIfStmts:深度嵌套 if
class DeepNest {
void bad(int a, int b, int c) {
if (a > 0) {
if (b > 0) {
if (c > 0) {
System.out.println("deep");
}
}
}
}
}
// 120 AvoidRethrowingException:捕获后重新抛出
class ReThrow {
void bad() {
try {
doWork();
} catch (IOException e) {
throw e; // 直接重新抛出
}
}
void doWork() throws IOException {
}
}
// 121 AvoidThrowingNewInstanceOfSameException:包装相同异常
class WrapSame {
void bad() {
try {
doWork();
} catch (IOException e) {
throw new IOException("wrapped", e); // 包装同类型
}
}
void doWork() throws IOException {
}
}
// 122 AvoidThrowingNullPointerException:手动抛 NPE
class ThrowNPE {
void bad() {
throw new NullPointerException("manual"); // 手动 NPE
}
}
// 123 AvoidThrowingRawExceptionTypes:抛原始异常
class RawThrow {
void bad() {
throw new RuntimeException("raw"); // 原始异常
}
}
// 124 AvoidUncheckedExceptionsInSignaturesthrows 非受检异常
class UncheckedSig {
void bad() throws RuntimeException { // 非受检异常
}
}
// 125 ClassWithOnlyPrivateConstructorsShouldBeFinal
class OnlyPrivate {
private OnlyPrivate() {
}
}
// 126 CollapsibleIfStatements:合并嵌套 if
class CollapseIf {
void bad(int a, int b) {
if (a > 0) {
if (b > 0) {
System.out.println("both");
}
}
}
}
// 127 DataClass:疑似数据类
class Data {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 128 DoNotExtendJavaLangError:继承 Error
class MyError extends Error { // 继承 Error
}
// 129 ExceptionAsFlowControl:异常控制流程
class FlowControl {
void bad() {
boolean ok = false;
try {
ok = check();
} catch (IllegalStateException e) {
ok = false;
}
System.out.println(ok);
}
boolean check() {
return true;
}
}
// 130 FinalFieldCouldBeStaticfinal 字段可为 static
class FinalStatic {
final int CONST = 10; // 编译时常量,可 static
}
// 131 GodClass:上帝类
class God {
void m1(int a) {
System.out.println(a);
}
void m2(int a) {
System.out.println(a);
}
void m3(int a) {
System.out.println(a);
}
void m4(int a) {
System.out.println(a);
}
void m5(int a) {
System.out.println(a);
}
void m6(int a) {
System.out.println(a);
}
void m7(int a) {
System.out.println(a);
}
void m8(int a) {
System.out.println(a);
}
void m9(int a) {
System.out.println(a);
}
void m10(int a) {
System.out.println(a);
}
void m11(int a) {
System.out.println(a);
}
void m12(int a) {
System.out.println(a);
}
void m13(int a) {
System.out.println(a);
}
void m14(int a) {
System.out.println(a);
}
void m15(int a) {
System.out.println(a);
}
void m16(int a) {
System.out.println(a);
}
void m17(int a) {
System.out.println(a);
}
void m18(int a) {
System.out.println(a);
}
void m19(int a) {
System.out.println(a);
}
void m20(int a) {
System.out.println(a);
}
void m21(int a) {
System.out.println(a);
}
void m22(int a) {
System.out.println(a);
}
void m23(int a) {
System.out.println(a);
}
void m24(int a) {
System.out.println(a);
}
void m25(int a) {
System.out.println(a);
}
void m26(int a) {
System.out.println(a);
}
void m27(int a) {
System.out.println(a);
}
void m28(int a) {
System.out.println(a);
}
void m29(int a) {
System.out.println(a);
}
void m30(int a) {
System.out.println(a);
}
void m31(int a) {
System.out.println(a);
}
void m32(int a) {
System.out.println(a);
}
void m33(int a) {
System.out.println(a);
}
void m34(int a) {
System.out.println(a);
}
void m35(int a) {
System.out.println(a);
}
void m36(int a) {
System.out.println(a);
}
void m37(int a) {
System.out.println(a);
}
void m38(int a) {
System.out.println(a);
}
void m39(int a) {
System.out.println(a);
}
void m40(int a) {
System.out.println(a);
}
void m41(int a) {
System.out.println(a);
}
void m42(int a) {
System.out.println(a);
}
void m43(int a) {
System.out.println(a);
}
void m44(int a) {
System.out.println(a);
}
void m45(int a) {
System.out.println(a);
}
void m46(int a) {
System.out.println(a);
}
void m47(int a) {
System.out.println(a);
}
void m48(int a) {
System.out.println(a);
}
void m49(int a) {
System.out.println(a);
}
void m50(int a) {
System.out.println(a);
}
}
// 132 ImmutableField:字段可为 final
class Immut {
private List<String> list = new ArrayList<>(); // 构造后未变,可 final
Immut() {
}
}
// 133 InvalidJavaBeanBean 不合规
class BadBean {
private String name;
public String getname() { // getter 命名错误
return name;
}
public void setname(String n) { // setter 命名错误
this.name = n;
}
}
// 134 LawOfDemeter:迪米特法则
class LoD {
void bad(A a) {
a.getB().getC().doIt(); // 链式调用
}
class A {
B getB() {
return new B();
}
}
class B {
C getC() {
return new C();
}
}
class C {
void doIt() {
}
}
}
// 135 LogicInversion:逻辑取反
class LogicInv {
boolean bad(int x) {
if (!(x < 5)) { // 应 x >= 5
return true;
}
return false;
}
}
// 136 LoosePackageCoupling:已从内置 ruleset 排除(需显式配置 packages/classes,未配置时空转)
// 137 MutableStaticState:非私有非 final 静态字段
class Mutable {
static int counter; // 包可见可变静态字段
}
// 138 PublicMemberInNonPublicType:非公共类型公共成员
class NonPublic {
public int x; // 非公共类中公共成员
}
// 139 SignatureDeclareThrowsException:声明 throws Exception
class ThrowsEx {
void bad() throws Exception { // throws Exception
}
}
// 140 SimplifiedTernary:布尔字面量简化三元
class SimpTernary {
boolean bad(boolean x) {
return x ? true : false; // 应直接 return x
}
}
// 141 SimplifyBooleanExpressions:布尔比较
class SimpBool {
boolean bad(boolean x) {
return x == true; // 应 return x
}
}
// 142 SimplifyBooleanReturns:简化布尔返回
class SimpBoolRet {
boolean bad(int x) {
if (x > 0) {
return true;
} else {
return false; // 应 return x > 0
}
}
}
// 143 SimplifyConditional:简化条件(可去掉 x != null)
class SimpCond {
void bar(Object x) {
if (x != null && x instanceof java.util.List) { // 可去掉 x != null
}
}
}
// 144 SingularField:字段可为局部变量(仅一个方法使用)
class Singular {
private int x; // 仅一个方法使用
public int foo(int y) {
x = y + 5;
return x;
}
}
// 145 SwitchDensityswitch 密度过高(保留 case 多的版本)
class SwitchDensity {
void bad(int x) {
switch (x) {
case 1:
System.out.println("a1");
System.out.println("a2");
System.out.println("a3");
System.out.println("a4");
System.out.println("a5");
System.out.println("a6");
System.out.println("a7");
System.out.println("a8");
System.out.println("a9");
System.out.println("a10");
System.out.println("a11");
System.out.println("a12");
break;
case 2:
System.out.println("b1");
System.out.println("b2");
System.out.println("b3");
System.out.println("b4");
System.out.println("b5");
System.out.println("b6");
System.out.println("b7");
System.out.println("b8");
System.out.println("b9");
System.out.println("b10");
System.out.println("b11");
System.out.println("b12");
break;
case 3:
System.out.println("c1");
System.out.println("c2");
System.out.println("c3");
System.out.println("c4");
System.out.println("c5");
System.out.println("c6");
System.out.println("c7");
System.out.println("c8");
System.out.println("c9");
System.out.println("c10");
System.out.println("c11");
System.out.println("c12");
break;
default:
System.out.println("z");
break;
}
}
}
// 146 UselessOverridingMethod:无意义重写
class Base2 {
void m() {
}
}
class Sub2 extends Base2 {
@Override
void m() { // 仅调用 super
super.m();
}
}
// 147 UseUtilityClass:工具类无私有构造
class Util {
static void helper() { // 静态方法,无私有构造
}
}
// ---------- Design 补充 2 ----------
// 145 SwitchDensityswitch 密度过高
class SwitchDensityDemo {
public void bar(int x) {
switch (x) {
case 1:
System.out.println("a");
System.out.println("b");
System.out.println("c");
System.out.println("d");
break;
case 2:
System.out.println("e");
System.out.println("f");
System.out.println("g");
System.out.println("h");
break;
case 3:
System.out.println("i");
System.out.println("j");
System.out.println("k");
System.out.println("l");
break;
case 4:
System.out.println("m");
System.out.println("n");
System.out.println("o");
System.out.println("p");
break;
default:
break;
}
}
}
// 202 MisplacedNullCheck
class MisplacedNullDemo {
void bar(Object a, String baz) {
if (a.equals(baz) && a != null) { // a 可能为 nullnull 检查位置错误
System.out.println("eq");
}
}
}
// ---------- Error Prone(易错) ----------
// 149 AssignmentInOperand:操作数中赋值
class AssignOp {
void bad(int x) {
if ((x = 5) > 0) { // 操作数中赋值
System.out.println(x);
}
}
}
// 150 AssignmentToNonFinalStatic:非 final 静态字段赋值
class AssignStatic {
static int counter;
AssignStatic() {
counter = 10; // 构造函数中赋值非 final 静态字段
}
}
// 151 AvoidAccessibilityAlterationsetAccessible(true)
class SetAccess {
void bad() throws Exception {
java.lang.reflect.Field f = String.class.getDeclaredField("value");
f.setAccessible(true); // 修改访问权限
}
}
// 154 AvoidCallingFinalize:显式调用 finalize
class CallFinalize {
void bad() throws Throwable {
Object o = new Object();
o.finalize(); // 显式调用 finalize
}
}
// 155 AvoidDecimalLiteralsInBigDecimalConstructor
class BigDecimalLit {
BigDecimal d = new BigDecimal(0.1); // 应使用 String
}
// 156 AvoidDuplicateLiterals:重复字面量
class DupLiteral {
void bad() {
System.out.println("duplicate");
System.out.println("duplicate");
}
}
// 161 AvoidLiteralsInIfConditionif 中魔术数字
class MagicIf {
void bad(int x) {
if (x == 42) { // 魔术数字
System.out.println("magic");
}
}
}
// 162 AvoidMultipleUnaryOperators:多个一元运算符
class MultiUnary {
void bad() {
int x = 5;
x = -x; // 反例
x = ++x; // 反例
System.out.println(x);
}
}
// 163 AvoidUsingOctalValues:八进制字面量
class Octal {
int x = 0123; // 八进制
}
// 164 BrokenNullCheck:错误的 null 检查
class BrokenNull {
void bad(Object a, Object b) {
if (a != null || b != null) { // 应 &&
}
}
}
// 165 CallSuperFirstsuper 应首先调用
class CallSuperFirst {
void bad() {
doSomething();
super.toString(); // super 未首先调用? 占位
}
void doSomething() {
}
}
// 166 CallSuperLastsuper 应最后调用
class CallSuperLast {
void bad() {
super.toString();
doSomething(); // super 后又调用
}
void doSomething() {
}
}
// 167 CheckSkipResult:检查 skip 返回值
class CheckSkip {
void bad() throws IOException {
InputStream in = null;
in.skip(10); // 未检查返回值
}
}
// 168 ClassCastExceptionWithToArray
class ToArrayCast {
void bad(Collection<String> c) {
String[] arr = (String[]) c.toArray(); // ClassCastException
}
}
// 172 CloseResource:未关闭资源
class CloseRes {
void bad() throws IOException {
InputStream in = new java.io.ByteArrayInputStream(new byte[]{1});
in.read(); // 未关闭
}
}
// 173 CollectionTypeMismatch
class CollMismatch {
void bad() {
List<String> l = new ArrayList<>();
Object o = new Integer(1);
}
}
// 174 CompareObjectsWithEquals:对象用 ==
class CompEquals {
void bad(String a, String b) {
if (a == b) { // 应 equals
}
}
}
// 175 ComparisonWithNaN:与 NaN 比较
class NaN {
void bad(double x) {
if (x == Double.NaN) { // 恒 false
}
}
}
// 176 ConfusingArgumentToVarargsMethod
class ConfusingVarargs {
void call() {
accept("a", "b"); // 可混淆
}
void accept(String... args) {
}
}
// 177 ConstructorCallsOverridableMethod
class CtorCall {
CtorCall() {
overridable(); // 构造函数调用可重写方法
}
void overridable() {
}
}
// 179 DoNotCallGarbageCollectionExplicitly
class GC {
void bad() {
System.gc(); // 显式 GC
}
}
// 180 DoNotExtendJavaLangThrowable
class MyThrowable extends Throwable { // 直接继承 Throwable
}
// 181 DoNotHardCodeSDCard
class SDCard {
String path = "/sdcard/foo"; // 硬编码 SD 卡路径
}
// 182 DoNotTerminateVM
class TermVM {
void bad() {
System.exit(0); // 终止 VM
}
}
// 183 DoNotThrowExceptionInFinally
class ThrowFinally {
void bad() {
try {
doWork();
} finally {
throw new RuntimeException("finally"); // finally 抛异常
}
}
void doWork() {
}
}
// 184 DontUseFloatTypeForLoopIndices
class FloatLoop {
void bad() {
for (float i = 0; i < 10; i++) { // float 循环索引
}
}
}
// 185 EmptyCatchBlock
class EmptyCatch {
void bad() {
try {
doWork();
} catch (Exception e) { // 空 catch
}
}
void doWork() {
}
}
// 187 EqualsNull:与 null 相等比较
class EqNull {
void bad(Object o) {
if (o.equals(null)) { // 应 o == null
}
}
}
// 192 IdempotentOperations:幂等操作
class Idempotent {
void bad(String s) {
s = s.trim(); // 反例
s = s.trim(); // 重复幂等? 占位
System.out.println(s);
}
}
// 193 IdenticalConditionalBranches
class IdentBranches {
int bad(int x) {
if (x > 0) {
return 1;
} else {
return 1; // 相同分支
}
}
}
// 194 ImplicitSwitchFallThrough
class FallThrough {
void bad(int x) {
switch (x) {
case 1:
System.out.println("one"); // 无 break
case 2:
System.out.println("two");
break;
default:
break;
}
}
}
// 195 InstantiationToGetClass
class GetClass {
void bad() {
Class<?> c = new Integer(1).getClass(); // 仅为获取类实例化
}
}
// 197 JumbledIncrementer
class Jumbled {
void bad() {
for (int i = 0, j = 0; i < 10; i++, j++) { // 混乱增量
j++;
}
}
}
// 201 MethodWithSameNameAsEnclosingClass
class SameName {
void SameName() { // 方法与类同名
}
}
// 202 MisplacedNullCheck
class MisNull {
void bad(String s) {
if (s != null && s.length() > 0) { // 位置正确,占位
}
}
}
// 204 MissingStaticMethodInNonInstantiatableClass
class NonInstantiatable {
private NonInstantiatable() { // 无可访问静态方法
}
}
// 205 MoreThanOneLogger
class MultiLogger {
private static final java.util.logging.Logger LOG1 = java.util.logging.Logger.getLogger("A");
private static final java.util.logging.Logger LOG2 = java.util.logging.Logger.getLogger("B"); // 多个 logger
}
// 208 NonStaticInitializer
class NonStaticInit {
{
System.out.println("instance init"); // 非静态初始化器
}
}
// 209 NullAssignment
class NullAssign {
String s = "x";
void bad() {
s = null; // null 赋值
}
}
// 210 OverrideBothEqualsAndHashcode
class EqOnly {
public boolean equals(Object o) { // 只重写 equals
return true;
}
}
// 211 OverrideBothEqualsAndHashCodeOnComparable
class CmpOnly implements Comparable<CmpOnly> {
public int compareTo(CmpOnly o) {
return 0;
}
}
// 214 ReplaceJavaUtilCalendar
class UseCalendar {
Calendar c = Calendar.getInstance(); // 应使用 java.time
}
// 215 ReplaceJavaUtilDate
class UseDate {
Date d = new Date(); // 应使用 java.time
}
// 216 ReturnEmptyCollectionRatherThanNull
class ReturnNull {
List<String> bad() {
return null; // 应返回空集合
}
}
// 217 ReturnFromFinallyBlock
class RetFinally {
int bad() {
try {
return 1;
} finally {
return 2; // 从 finally 返回
}
}
}
// 218 SimpleDateFormatNeedsLocale
class SDF {
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd"); // 无 locale
}
// 222 StringBufferInstantiationWithChar
class SBC {
StringBuffer sb = new StringBuffer('c'); // char 实例化
}
// 223 SuspiciousEqualsMethodName
class SuspEquals {
void equals(String s) { // 非 boolean 返回 equals
}
}
// 224 SuspiciousHashcodeMethodName
class SuspHash {
void hashcode() { // 非 int 返回 hashcode
}
}
// 225 SuspiciousOctalEscape
class OctEscape {
String s = "\12"; // 可疑八进制转义
}
// 227 UnconditionalIfStatement
class UncondIf {
void bad() {
if (true) { // 无条件 if
System.out.println("always");
}
}
}
// 229 UnnecessaryCaseChange
class CaseChange {
void bad(String s) {
if (s.toLowerCase(Locale.ROOT).equals(s.toUpperCase(Locale.ROOT))) { // 占位
}
}
}
// 230 UnnecessaryConversionTemporary
class ConvTemp {
void bad(int x) {
String s = new Integer(x).toString(); // 应 String.valueOf
}
}
// 232 UnusedNullCheckInEquals
class UnusedNull {
String s;
public boolean equals(Object o) {
if (o == null) { // 未使用 null 检查
}
return true;
}
}
// 234 UseEqualsToCompareStrings
class UseEquals {
boolean bad(String a, String b) {
return a == b; // 应 equals
}
}
// 235 UselessPureMethodCall
class PureCall {
void bad() {
"hello".length(); // 纯方法调用未使用
}
}
// 236 UseLocaleWithCaseConversions
class CaseLocale {
void bad(String s) {
s.toUpperCase(); // 应带 locale
}
}
// 237 UseProperClassLoader
class ClassLoaderUse {
void bad() {
ClassLoader cl = getClass().getClassLoader(); // 应使用 thread CCL
}
}
// 158 AvoidFieldNameMatchingMethodName
class FieldMatchMethod {
int value;
void value() { // 字段名与同名方法
}
}
// 159 AvoidFieldNameMatchingTypeName
class TypeName {
int TypeName; // 字段与类型同名
}
// 160 AvoidInstanceofChecksInCatchClause
class InstofCatch {
void bad() {
try {
doWork();
} catch (Exception e) {
if (e instanceof java.io.FileNotFoundException) { // 应单独 catch
}
}
}
void doWork() {
}
}
// 206 NonCaseLabelInSwitch
class NonCaseLabel {
void bad() {
int x = 1;
switch (x) {
case 1:
break;
weird: // 非 case 标签
break;
}
}
}
// ---------- Error Prone 补充(补齐未命中规则) ----------
// 219 SingleMethodSingleton:重载的 getInstance
class SingletonDemo {
private static SingletonDemo singleton = new SingletonDemo();
private SingletonDemo() {
}
public static SingletonDemo getInstance() {
return singleton;
}
public static SingletonDemo getInstance(Object obj) { // 重载 getInstance
SingletonDemo s = (SingletonDemo) obj;
return s;
}
}
// 231 UnsupportedJdkApiUsage:使用 sun.misc.Unsafe
class MemoryWiper {
public static void main(String[] args) throws Exception {
sun.misc.Unsafe.getUnsafe(); // sun.* API
}
}
// 192 IdempotentOperationsx = x
class IdempotentDemo {
void bar() {
int x = 2;
x = x; // 幂等操作
}
}
// 224 SuspiciousHashcodeMethodName
class HashcodeName {
public int hashcode() { // 应 hashCode
return 1;
}
}
// 225 SuspiciousOctalEscape
class OctalEscape {
void foo() {
System.out.println("suspicious: \128"); // 八进制转义
}
}
// 229 UnnecessaryCaseChange
class CaseChangeDemo {
void bad(String buz) {
boolean answer = buz.toUpperCase().equals("BAZ"); // 应 equalsIgnoreCase
System.out.println(answer);
}
}
// 232 UnusedNullCheckInEquals
class UnusedNullEq {
public String method1() {
return "ok";
}
public void method(String a) {
if (a != null && method1().equals(a)) { // 未使用的 null 检查
System.out.println("eq");
}
}
}
// 233 UseCorrectExceptionLogging
class CorrectLog {
private static final Logger _LOG = LoggerFactory.getLogger(CorrectLog.class);
void bar() {
try {
doWork();
} catch (Exception e) {
_LOG.error(String.valueOf(e)); // 错误方式:未传异常
}
}
void doWork() {
}
}
// 196 InvalidLogMessageFormat
class BadLogFormat {
private static final Logger LOGGER = LoggerFactory.getLogger(BadLogFormat.class);
void bar() {
LOGGER.error("forget the arg {}"); // 缺少参数
LOGGER.error("too many args {}", "a", "b"); // 参数过多
}
}
// 156 AvoidDuplicateLiterals:重复字面量至少 4 次
class DupLiteralDemo {
void bar() {
buz("Howdy");
buz("Howdy");
buz("Howdy");
buz("Howdy"); // 重复字面量
}
void buz(String x) {
}
}
// 197 JumbledIncrementer
class JumbledInc {
void foo() {
for (int i = 0; i < 10; i++) {
for (int k = 0; k < 20; i++) { // 内层循环错误递增 i
System.out.println("Hello");
}
}
}
}
// 153 AvoidBranchingStatementAsLastInLoop
class BranchLast {
void foo() {
for (int i = 0; i < 10; i++) {
if (i > 5) {
break; // 分支语句作为循环最后语句
}
}
}
}
// 173 CollectionTypeMismatch
class CollMismatchDemo {
void bad() {
List<Integer> numbers = Arrays.asList(1, 2, 3);
numbers.remove("string"); // 类型不匹配
Map<String, String> map = new HashMap<>();
map.get(42); // 类型不匹配
Set<String> names = new HashSet<>();
names.contains(123); // 类型不匹配
}
}
// 176 ConfusingArgumentToVarargsMethod
class ConfusingVarargsDemo {
abstract class C {
abstract void varargs(Object... args);
void call() {
varargs(new String[]{"a"}); // 混淆的可变参数
varargs(null);
}
}
}
// 202 MisplacedNullCheck
class MisplacedNull {
void bar(Object a, String baz) {
if (a != null && a.equals(baz)) { // 位置错误? 正确占位
System.out.println("eq");
}
}
}
// 207 NonSerializableClass
class NonSerializableCls implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private FileInputStream stream; // FileInputStream 不可序列化
}
// 121 AvoidThrowingNewInstanceOfSameException
class WrapSameException {
void bad() {
try {
doWork();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("wrapped", e); // 包装相同类型
}
}
void doWork() {
throw new IllegalArgumentException();
}
}
// 162 AvoidMultipleUnaryOperators
class MultiUnaryDemo {
void bad() {
int x = 5;
x = -x; // 多个一元运算符
System.out.println(x);
}
}
// ---------- Error Prone 剩余规则补齐 ----------
// 153 AvoidBranchingStatementAsLastInLoop
class BranchLastInLoop {
void foo() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
if (i > 25) {
continue;
}
break; // 分支语句作为循环最后语句
}
}
}
// 162 AvoidMultipleUnaryOperators(重命名避免与上文 MultiUnary 冲突)
class MultiUnaryRemain {
void foo() {
int i = - -1; // 多个一元运算符
boolean b = !!true;
System.out.println(i + " " + b);
}
}
// 164 BrokenNullCheck
class BrokenNullCheck {
public String bar(String string) {
if (string != null || !string.equals("")) { // 应 &&
return string;
}
if (string == null && string.equals("")) { // 应 ||
return string;
}
return null;
}
}
// ---------- Clone(克隆) ----------
// 170 CloneMethodMustImplementCloneableclone() 但未实现 Cloneable
class CloneNoInterface {
@Override
public Object clone() { // 未实现 Cloneable
return new CloneNoInterface();
}
}
// 169 CloneMethodMustBePublic:实现 Cloneable 但 clone 非 public
class CloneNotPublic implements Cloneable {
@Override
protected Object clone() { // 应 public
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
// 171 CloneMethodReturnTypeMustMatchClassName
class CloneWrongType implements Cloneable {
@Override
public Object clone() { // 返回类型非 CloneWrongType
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}
// 212 ProperCloneImplementation
class CloneProperImplements implements Cloneable {
@Override
public Object clone() throws CloneNotSupportedException { // 未调用 super.clone()
return new CloneProperImplements();
}
}
// ---------- Finalize(终结方法) ----------
// 186 EmptyFinalizer:空 finalize
class EmptyFinal {
@Override
protected void finalize() { // 空 finalize
}
}
// 188 FinalizeDoesNotCallSuperFinalize
class NoSuperFinal {
@Override
protected void finalize() {
cleanup(); // 未调用 super.finalize()
}
void cleanup() {
}
}
// 189 FinalizeOnlyCallsSuperFinalize
class OnlySuperFinal {
@Override
protected void finalize() throws Throwable {
super.finalize(); // 只调用 super.finalize()
}
}
// 190 FinalizeOverloaded
class OverloadedFinal {
protected void finalize() throws Throwable {
super.finalize();
}
protected void finalize(int x) { // 重载 finalize
}
}
// 191 FinalizeShouldBeProtected
class PublicFinal {
@Override
public void finalize() throws Throwable { // 应为 protected
super.finalize();
}
}
// ---------- ProperLogger / UseCorrectExceptionLogging ----------
// 213 ProperLoggerlogger 应为 static final
class BadLogger {
protected Log LOG = LogFactory.getLog(BadLogger.class); // 非 static final
}
// 233 UseCorrectExceptionLogging
class CorrectExceptionLog {
private static final Log _LOG = LogFactory.getLog(CorrectExceptionLog.class);
void bar() {
try {
doWork();
} catch (Exception e) {
_LOG.error(e); // 错误:直接传异常参数
}
}
void doWork() {
}
}
// ---------- Serialization(序列化) ----------
// 203 MissingSerialVersionUID:缺少 serialVersionUID
class MissingSerial implements Serializable { // 实现 Serializable 无 serialVersionUID
private int value;
}
// 207 NonSerializableClassSerializable 类字段不可序列化
class NonSerField implements Serializable {
private static final long serialVersionUID = 1L;
private Object nonSerializableField = new Object(); // 非 Serializable 字段
}
// ---------- Singleton(单例) ----------
// 219 SingleMethodSingleton:单例只有 getInstance 方法
class SingleMethod {
private static SingleMethod INSTANCE = new SingleMethod();
private SingleMethod() {
}
public static SingleMethod getInstance() { // 单例仅此一法
return INSTANCE;
}
}
// 220 SingletonClassReturningNewInstance
class SingletonNew {
private static SingletonNew INSTANCE;
private SingletonNew() {
}
public static SingletonNew getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingletonNew();
}
return INSTANCE; // 正确模式,但被误报? 占位
}
}
class BadDeEpMain {
public static void main(String[] args) {
System.out.println("demo designep");
}
}
@@ -0,0 +1,38 @@
// ============================================================
// PMD 演示样例 — Accessor(访问器生成)
// 注:AccessorClassGeneration / AccessorMethodGeneration 已从内置 ruleset
// 排除(maximumLanguageVersion=10,默认语言版本下永不执行),
// 以下代码仅作为其他规则(UnnecessaryImport / UnusedLocalVariable 等)的触发材料。
// ============================================================
package com.demo.errorprone.extra;
import java.util.ArrayList;
import java.util.List;
// AccessorClassGeneration:避免从外部通过私有构造函数实例化
class AccessorClass {
private AccessorClass() {
} // 私有构造函数
static AccessorClass create() {
return new AccessorClass();
}
}
class AccessorUser {
void bad() {
// 通过外部访问私有构造函数,触发合成访问器
AccessorClass a = AccessorClass.create();
CallerGen cg = new CallerGen();
String s = cg.getHidden(); // 访问私有字段
}
}
// AccessorMethodGeneration:避免合成访问器方法
class CallerGen {
private String hidden = "x";
String getHidden() {
return hidden;
}
}
@@ -0,0 +1,29 @@
// ============================================================
// PMD 演示样例 — UnitTestShouldUseAfter/BeforeAnnotation
// tearDown() / setUp() 方法缺少注解(JUnit 3 升级提示)
// ============================================================
package com.demo.errorprone.extra;
// 44 UnitTestShouldUseAfterAnnotationtearDown 无 @After 注解
public class MissingAfterTest {
public void tearDown() { // 应加 @After
}
}
// 45 UnitTestShouldUseBeforeAnnotationsetUp 无 @Before 注解
public class MissingBeforeTest {
public void setUp() { // 应加 @Before
}
}
// 46 UnitTestShouldUseTestAnnotationtest 方法无 @Test 注解
public class MissingTestAnn {
public void testSomething() { // 应加 @Test
}
}
class AfterBeforeMain {
public static void main(String[] args) {
System.out.println("demo after/before");
}
}
@@ -0,0 +1,29 @@
// ============================================================
// PMD 演示样例 — AssertStatementInTest / JUnitUseExpected
// ============================================================
package com.demo.errorprone.extra;
import org.junit.Test;
// 5 AssertStatementInTest:测试中使用 assert 语句
public class AssertStmtTest {
@Test
public void testSomething() {
int x = 1;
assert x == 1; // 应使用 Assert.assertEquals
}
}
// 25 JUnitUseExpected:使用 @Test(expected)
class JUnitExpectedTest {
@Test(expected = ArithmeticException.class) // 应使用 assertThrows
public void testExpected() {
int x = 1 / 0;
}
}
class AssertMain {
public static void main(String[] args) {
System.out.println("demo assert stmt");
}
}
@@ -0,0 +1,36 @@
// ============================================================
// PMD 演示样例 — CallSuperFirst / CallSuperLast
// 使用 android.app.Activity 生命周期方法
// ============================================================
package com.demo.errorprone.extra;
import android.app.Activity;
import android.os.Bundle;
// 165 CallSuperFirstonCreate 应首先调用 super.onCreate
class MissingSuperFirst extends Activity {
@Override
protected void onCreate(Bundle bundle) {
foo(); // 未先调用 super.onCreate
}
void foo() {
}
}
// 166 CallSuperLastonPause 应最后调用 super.onPause
class MissingSuperLast extends Activity {
@Override
protected void onPause() {
foo(); // 未最后调用 super.onPause
}
void foo() {
}
}
class CallSuperMain {
public static void main(String[] args) {
System.out.println("demo call super");
}
}
@@ -0,0 +1,32 @@
// ============================================================
// PMD 演示样例 — JUnit 3 规则(TestCase 继承)
// ============================================================
package com.demo.errorprone.extra;
import junit.framework.TestCase;
// 199 JUnitSpellingsetup/TearDown 拼写错误
public class JUnitSpellingTest extends TestCase {
public void setup() { // 应 setUp
}
public void TearDown() { // 应 tearDown
}
}
// 200 JUnitStaticSuitesuite 方法应为 static
class JUnitStaticSuiteTest extends TestCase {
public void suite() { // 应 static
}
}
// 178 DetachedTestCase:独立测试方法无 @Test
class DetachedTest extends TestCase {
public void testSomething() { // 独立测试方法
}
}
class Junit3Main {
public static void main(String[] args) {
System.out.println("demo junit3");
}
}
@@ -0,0 +1,113 @@
// ============================================================
// PMD 演示样例 — JUnit 4 测试规则
// ============================================================
package com.demo.errorprone.extra;
import org.junit.Test;
import org.junit.Assert;
public class JUnit4RulesTest {
// 39 SimplifiableTestAssertion
@Test
public void testSimplifiable() {
Object a = new Object();
Object b = new Object();
Assert.assertTrue(a.equals(b)); // 应 assertEquals
}
// 41 UnitTestAssertionsShouldIncludeMessage
@Test
public void testNoMessage() {
Assert.assertEquals("foo", "bar"); // 应带消息三参版本
}
// 42 UnitTestContainsTooManyAsserts
@Test
public void testTooMany() {
Assert.assertTrue(true);
Assert.assertTrue(true);
Assert.assertTrue(true);
Assert.assertTrue(true);
Assert.assertEquals(1, 1);
Assert.assertEquals(2, 2);
Assert.assertEquals(3, 3);
Assert.assertEquals(4, 4);
Assert.assertEquals(5, 5);
}
// 148 AssertEqualsArgumentOrder:参数顺序颠倒
@Test
public void testArgOrder() {
String actual = "actual";
String expected = "expected";
Assert.assertEquals(actual, expected); // 顺序颠倒
}
// 228 UnnecessaryBooleanAssertion
@Test
public void testBoolean() {
Assert.assertTrue(true); // 无意义断言
}
// 25 JUnitUseExpected:应使用 @Test(expected)
@Test
public void testExpected() {
try {
doSomething();
Assert.fail("should have thrown");
} catch (NullPointerException e) {
// 应使用 @Test(expected = NullPointerException.class)
}
}
private void doSomething() {
throw new NullPointerException();
}
}
// 44 UnitTestShouldUseAfterAnnotationtearDown 无 @After
class MissingAfterTest {
@Test
public void testCleanup() {
Assert.assertTrue(true);
}
public void tearDown() { // 应加 @After
}
}
// 45 UnitTestShouldUseBeforeAnnotationsetUp 无 @Before
class MissingBeforeTest {
@Test
public void testSetup() {
Assert.assertTrue(true);
}
public void setUp() { // 应加 @Before
}
}
// 46 UnitTestShouldUseTestAnnotationtest 方法无 @Test
class MissingTestAnnotationTest {
public void testSomething() { // 应加 @Test
}
}
// 199 JUnitSpelling:方法名拼写
class SpellingTest {
public void setup() { // 应 setUp
}
public void teardown() { // 应 tearDown
}
}
// 200 JUnitStaticSuite
class StaticSuiteTest {
public static junit.framework.Test suite() { // 静态 suite
return null;
}
}
// 23 JUnit4SuitesShouldUseSuiteAnnotation
class SuiteClassTest {
public static junit.framework.Test suite() { // 缺 @RunWith(Suite.class)
return null;
}
}
@@ -0,0 +1,26 @@
// ============================================================
// PMD 演示样例 — JUnit 5 assertEquals 参数顺序
// ============================================================
package com.demo.errorprone.extra;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
// 148 AssertEqualsArgumentOrderexpected/actual 顺序颠倒
public class JUnit5ArgOrderTest {
@Test
public void testX() {
String actual = next("foo");
assertEquals(actual, "bar"); // 顺序颠倒:actual 在前,字面量在后
}
String next(String s) {
return s;
}
}
class Junit5Main {
public static void main(String[] args) {
System.out.println("demo junit5 arg order");
}
}
@@ -0,0 +1,27 @@
// ============================================================
// PMD 演示样例 — JUnit 5 (Jupiter) 规则
// ============================================================
package com.demo.errorprone.extra;
import org.junit.jupiter.api.Test;
// 24 JUnitJupiterTestShouldBePackagePrivateJUnit5 测试应为包私有
public class JupiterPublicTest {
@Test
public void testPublic() { // public 测试方法
}
}
// 198 JUnitJupiterTestNoPrivateModifierJUnit5 测试不应为 private
class JupiterPrivateTest {
@Test
private void testPrivate() { // private 测试方法,不会执行
}
}
// 25 补充:JUnitUseExpected 已在 JUnit4 文件
class JupiterMain {
public static void main(String[] args) {
System.out.println("demo jupiter");
}
}
@@ -0,0 +1,32 @@
// ============================================================
// PMD 演示样例 — ProperLogger / UseCorrectExceptionLogging
// ============================================================
package com.demo.errorprone.extra;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
// 213 ProperLoggerlogger 应为 static final
public class BadLogger {
protected Log LOG = LogFactory.getLog(BadLogger.class); // 非 static final
}
// 233 UseCorrectExceptionLogging
class CorrectExceptionLog {
private static final Log _LOG = LogFactory.getLog(CorrectExceptionLog.class);
void bar() {
try {
doWork();
} catch (Exception e) {
_LOG.error(e); // 错误:直接传异常参数
}
}
void doWork() {
}
}
class LoggerMain {
public static void main(String[] args) {
System.out.println("demo logger");
}
}
@@ -0,0 +1,22 @@
// ============================================================
// PMD 演示样例 — StaticEJBFieldShouldBeFinalEJB 静态字段应为 final
// ============================================================
package com.demo.errorprone.extra;
import javax.ejb.EJBObject;
import javax.ejb.EJBLocalHome;
// 221 StaticEJBFieldShouldBeFinal
public class SomeEJB extends EJBObject implements EJBLocalHome {
private static int CountA; // 可写静态字段(违例)
int CountC;
public void work() {
CountA++;
}
}
class EJBStaticMain {
public static void main(String[] args) {
System.out.println("demo ejb static");
}
}
@@ -0,0 +1,384 @@
// ============================================================
// PMD 演示样例 — MTPs(多线程 / 性能 / 安全)合并版
// 合并自:MultiThreadDemo / MultiThreadFix / PerformanceDemo /
// PerformanceFix / SecurityDemo / SecurityFix
// 保留所有规则触发类及其规则编号注释,未修复任何错误。
// ============================================================
package com.demo.mtps;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Hashtable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
// ==================================================================
// Multithreading(多线程)
// ==================================================================
// 240 AvoidSynchronizedAtMethodLevel:方法级 synchronized
class SyncMethod {
private int count;
public synchronized void incr() { // 方法级 synchronized
count++;
}
}
// 241 AvoidThreadGroup:使用 ThreadGroup
class ThreadGroupUse {
void bad() {
ThreadGroup g = new ThreadGroup("group"); // ThreadGroup
Thread t = new Thread(g, () -> {});
}
}
// 242 DontCallThreadRun:调用 Thread.run()
class CallRun {
void bad() {
Thread t = new Thread();
t.run(); // 调用 run() 而非 start()
}
}
// 243 DoubleCheckedLocking
class DCL {
private static Object instance;
static Object get() {
if (instance == null) {
synchronized (DCL.class) {
if (instance == null) {
instance = new Object();
}
}
}
return instance;
}
}
// 244 NonThreadSafeSingleton
class NTSingleton {
private static NTSingleton instance;
static NTSingleton get() {
if (instance == null) {
instance = new NTSingleton();
}
return instance;
}
}
// 245 OverridingThreadRun:重写 Thread.run()
class MyThread extends Thread {
@Override
public void run() { // 重写 run()
}
}
// 246 UnsynchronizedStaticFormatter
class StaticFormatter {
private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy"); // 静态 formatter
}
// 247 UseConcurrentHashMap
class ConcMap {
Map<String, String> map = new HashMap<>(); // 多线程下应使用 ConcurrentHashMap
}
// 248 UseNotifyAllInsteadOfNotify
class NotifyUse {
void bad() {
Object lock = new Object();
synchronized (lock) {
lock.notify(); // 应 notifyAll
}
}
}
// 239 UnsynchronizedStaticFormatter
class StaticFormatterDemo {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
void bar() {
sdf.format(new java.util.Date()); // 静态 formatter 未同步
}
}
// ==================================================================
// Performance(性能)
// ==================================================================
// 249 AddEmptyString
class AddEmpty {
String bad(int x) {
return "" + x; // 应 String.valueOf
}
}
// 250 AppendCharacterWithChar
class AppendChar {
void bad(StringBuffer sb) {
sb.append("a"); // 应 append('a')
}
}
// 251 AvoidArrayLoops
class ArrayLoops {
void bad(int[] src, int[] dst) {
for (int i = 0; i < src.length; i++) {
dst[i] = src[i]; // 应 System.arraycopy
}
}
}
// 252 AvoidCalendarDateCreation
class CalDate {
void bad() {
Calendar c = Calendar.getInstance();
c.set(2020, 1, 1); // CreatorX
c.getTime().getTime(); // 占位
}
}
// 253 AvoidFileStream
class FileStream {
void bad() throws IOException {
FileInputStream fis = new FileInputStream("f.bin"); // 应 Files.newInputStream
fis.read();
fis.close();
}
}
// 254 AvoidInstantiatingObjectsInLoops
class LoopObj {
void bad() {
for (int i = 0; i < 100; i++) {
Object o = new Object(); // 循环内实例化
}
}
}
// 255 BigIntegerInstantiation
class BigInt {
BigInteger b = new BigInteger("10"); // 应 BigInteger.TEN
}
// 256 ConsecutiveAppendsShouldReuse
class ConsecAppend {
void bad(StringBuilder sb) {
sb.append("hello");
sb.append(" "); // 应合并
sb.append("world");
}
}
// 257 ConsecutiveLiteralAppends
class ConsecLiteral {
void bad(StringBuilder sb) {
sb.append("hello " + "world"); // 应单次 append
}
}
// 258 InefficientEmptyStringCheck
class InefficientEmpty {
boolean bad(String s) {
return s.equals(""); // 应 isEmpty()
}
}
// 259 InefficientStringBuffering
class InefficientBuf {
String bad(int a, int b) {
String s = "value: " + a + " and " + b; // 应使用 StringBuilder
return s;
}
}
// 260 InsufficientStringBufferDeclaration
class InsufficientBuf {
void bad(String s) {
StringBuffer sb = new StringBuffer(); // 应指定容量
sb.append(s);
}
}
// 261 OptimizableToArrayCall
class OptToArray {
void bad(List<String> l) {
String[] arr = l.toArray(new String[l.size()]); // 应 (String[]) l.toArray()
}
}
// 262 RedundantFieldInitializer
class RedundantInit {
int x = 0; // 冗余初始化
boolean b = false; // 冗余初始化
}
// 263 StringInstantiation
class StringInst {
void bad(String s) {
String t = new String(s); // 应直接引用
}
}
// 264 StringToString
class ToString {
void bad(String s) {
String t = s.toString(); // 冗余 toString
}
}
// 266 UseArrayListInsteadOfVector
class UseArrayList {
java.util.Vector<String> v = new java.util.Vector<>(); // 应 ArrayList
}
// 267 UseArraysAsList
class UseArraysAsList {
void bad(String[] arr) {
List<String> l = new ArrayList<>();
for (String s : arr) {
l.add(s); // 应 Arrays.asList
}
}
}
// 268 UseIndexOfChar
class UseIndexOfChar {
int bad(String s) {
return s.indexOf("x"); // 应 indexOf('x')
}
}
// 269 UseStringBufferForStringAppends
class UseStringBuffer {
void bad(String s) {
s += "appended"; // 应 StringBuilder
}
}
// 270 UseStringBufferLength
class UseBufLength {
int bad(StringBuffer sb) {
return sb.toString().length(); // 应 sb.length()
}
}
// 271 UselessStringValueOf
class UselessValueOf {
String bad(String s) {
return String.valueOf(s); // 冗余 valueOf
}
}
// 252 AvoidCalendarDateCreation
class CalendarDateDemo {
private Date bad1() {
return Calendar.getInstance().getTime(); // 应 new Date()
}
private long bad2() {
return Calendar.getInstance().getTimeInMillis(); // 应 System.currentTimeMillis()
}
}
// 258 InefficientEmptyStringCheck
class InefficientEmptyCheck {
void bar(String string) {
if (string != null && string.trim().length() > 0) { // 应 isEmpty 优化
System.out.println("non-empty");
}
}
}
// 259 InefficientStringBuffering
class InefficientBufDemo {
String bad() {
StringBuffer sb = new StringBuffer("tmp = " + System.getProperty("java.io.tmpdir")); // 双重缓冲
return sb.toString();
}
}
// 260 InsufficientStringBufferDeclaration
class InsufficientBufDemo {
String bad(String s) {
StringBuilder sb = new StringBuilder();
sb.append("This is a long string that will exceed the default 16 characters");
return sb.toString();
}
}
// 269 UseStringBufferForStringAppends
class InefficientConcat {
String bad() {
String result = "";
for (int i = 0; i < 10; i++) {
result += getString(i); // 应使用 StringBuilder
}
return result;
}
String getString(int i) {
return "s" + i;
}
}
// 271 UselessStringValueOf
class UselessValueOfDemo {
public String convert(int i) {
String s;
s = "a" + String.valueOf(i); // 应直接 "a" + i
return s;
}
}
// ==================================================================
// Security(安全)
// ==================================================================
// 272 HardCodedCryptoKey:硬编码密钥
class HardKey {
void bad() {
byte[] key = "0123456789abcdef".getBytes(); // 硬编码密钥
new SecretKeySpec(key, "AES");
}
}
// 273 InsecureCryptoIv:不安全 IV
class InsecureIv {
void bad() {
byte[] iv = new byte[16]; // 全零 IV
new IvParameterSpec(iv);
}
}
// 273 InsecureCryptoIv
class InsecureIvDemo {
void bad() {
byte[] iv = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; // 全零 IV
new IvParameterSpec(iv);
}
void alsoBad() {
byte[] iv = "secret iv in here".getBytes(); // 固定 IV
new IvParameterSpec(iv);
}
}
// ==================================================================
// 主类
// ==================================================================
class BadMtpsMain {
public static void main(String[] args) {
System.out.println("demo mtps");
}
}
@@ -0,0 +1,27 @@
// ============================================================
// PMD 演示样例 — UseIOStreamsWithApacheCommonsFileItem
// 触发条件:调用 FileItem.get() 或 FileItem.getString()
// 需要 commons-fileupload 在 aux classpath 以完成类型解析
// ============================================================
package com.demo.performance.extra;
import org.apache.commons.fileupload.FileItem;
// 268 UseIOStreamsWithApacheCommonsFileItem
class UseIOStreamFileItem {
void process(FileItem item) {
byte[] data = item.get(); // 应使用 getInputStream()
System.out.println(data.length);
}
void processString(FileItem item) {
String s = item.getString(); // 应使用 getInputStream()
System.out.println(s);
}
}
class PerfFileItemMain {
public static void main(String[] args) {
System.out.println("demo fileitem");
}
}
+47
View File
@@ -0,0 +1,47 @@
<%@ page contentType="text/html; charset=UTF-8" %>
<%-- ============================================================
PMD 演示样例 — JSP 规则
============================================================ --%>
<html>
<head>
<title>JSP Demo</title>
</head>
<body>
<%-- NoScriptlets:使用 scriptlet --%>
<%
String name = request.getParameter("name");
out.println("Hello " + name);
%>
<%-- NoInlineScript:内联脚本 --%>
<script type="text/javascript">
function init() {
var x = 1;
alert(x);
}
</script>
<%-- NoInlineStyleInformation:内联样式 --%>
<p align="center"><b>Bold inline style</b> <font color="red">Font inline style</font></p>
<div style="color: red;">Inline style</div>
<%-- NoHtmlCommentsHTML 注释太少,占位 --%>
<p>Content</p>
<%-- DontNestJsfInJstlIteration:占位 --%>
<c:forEach items="${items}" var="item">
<h:outputText value="${item}"/>
</c:forEach>
<%-- NoClassAttribute:占位 --%>
<p class="highlight">Class attribute</p>
<%-- NoJspForward:占位 --%>
<%-- DuplicateJspImports:重复导入 --%>
<%@ page import="java.util.List" %>
<%@ page import="java.util.List" %>
<%-- JspEncoding:页面编码 --%>
<p>End</p>
</body>
</html>
+64
View File
@@ -0,0 +1,64 @@
<%--
"pageEncoding" deliberately omitted to trigger JspEncoding
--%>
<%@ page contentType="text/html" %>
<html>
<head><title>JSP Fix Demo</title>
<%-- NoInlineScript:内联脚本 --%>
<script type="text/javascript">
function doStuff() {
var total = 0;
for (var i = 0; i < 10; i++) {
total += i;
}
return total;
}
function doMore() {
return doStuff();
}
</script>
</head>
<body>
<%-- NoHtmlCommentsHTML 注释(非 JSP 注释)--%>
<!-- this is an html comment -->
<div style="background-color: #f00;">inline style</div>
<%-- NoScriptletsscriptlet --%>
<%
int x = 1;
int y = 2;
int z = x + y;
out.println(z);
%>
<%-- NoJspForward:转发操作 --%>
<jsp:forward page="other.jsp"/>
<%-- NoLongScripts:长 scriptlet --%>
<%
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int e = 5;
int f = 6;
int g = 7;
int h = 8;
int i2 = 9;
int j2 = 10;
int k = 11;
int l = 12;
int m = 13;
int n = 14;
int o = 15;
int p = 16;
int q = 17;
int r = 18;
int s2 = 19;
int t = 20;
int u = 21;
int v = 22;
int w = 23;
int xx = 24;
int yy = 25;
out.println(xx + yy);
%>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
<%@ page contentType="text/html; charset=UTF-8" %>
<%-- ============================================================
PMD 演示样例 — JSP security 分类规则
(对应 pmd-jsp-ruleset.xml 的 category/jsp/security.xml
============================================================ --%>
<html>
<head>
<title>JSP Security Demo</title>
</head>
<body>
<%-- IframeMissingSrcAttributeiframe 缺少 src 属性 --%>
<iframe></iframe>
<iframe width="300" height="200"></iframe>
<%-- NoUnsanitizedJSPExpression:未转义的 EL 表达式直接输出,存在 XSS 风险 --%>
<p>Hello, ${userInput}</p>
<p>Search: ${searchTerm}</p>
<%-- 对照组:正确写法(转义 / 带 src 的 iframe),不应触发规则 --%>
<p>Safe: <c:out value="${userInput}" /></p>
<iframe src="https://example.com/embed"></iframe>
</body>
</html>
@@ -0,0 +1,10 @@
// ============================================================
// PMD 演示样例 — NoPackage:所有类型必须属于命名包
// 本文件故意没有 package 声明
// ============================================================
class NoPackageClass {
void m() {
System.out.println("no package");
}
}
@@ -0,0 +1,32 @@
// ============================================================
// PMD 演示样例 — Design 剩余规则补齐
// ============================================================
package org.example.beans;
// 133 InvalidJavaBeanBean 非法(不可序列化、缺 setter)
public class MyBean {
private String label; // 缺 setter
public String getLabel() {
return label;
}
}
// 121 AvoidThrowingNewInstanceOfSameException
class WrapException {
void bar() {
try {
doWork();
} catch (IllegalStateException se) {
throw new IllegalStateException(se); // 包装相同异常类型
}
}
void doWork() {
}
}
class BeansMain {
public static void main(String[] args) {
System.out.println("demo beans");
}
}