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:
@@ -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=10(Java 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 AvoidMessageDigestField:MessageDigest 作为字段(线程不安全)
|
||||
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 AvoidStringBufferField:StringBuilder 字段
|
||||
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 AvoidPrintStackTrace:printStackTrace
|
||||
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 ForLoopVariableCount:for 循环多个控制变量
|
||||
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 NonExhaustiveSwitch:switch 应为穷尽式
|
||||
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 PrimitiveWrapperInstantiation:new 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 UseCollectionIsEmpty:size()==0
|
||||
class ColEmpty {
|
||||
void bad(List<String> l) {
|
||||
if (l.size() == 0) { // 应使用 isEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 57 UseEnumCollections:EnumSet/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 AvoidProtectedFieldInFinalClass:final 类 protected 字段
|
||||
final class FinalClass {
|
||||
protected int x;
|
||||
}
|
||||
|
||||
// 64 AvoidProtectedMethodInFinalClassNotExtending:final 类 protected 方法
|
||||
final class FinalClass2 {
|
||||
protected void m() {
|
||||
}
|
||||
}
|
||||
|
||||
// 65 AvoidUsingNativeCode:JNI
|
||||
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 LocalHomeNamingConvention:LocalHome 后缀
|
||||
public interface MissingLocalHomeSuffixBean extends EJBLocalHome { // 应 ...LocalHome
|
||||
}
|
||||
|
||||
// 84 LocalInterfaceSessionNamingConvention:Local 后缀
|
||||
public interface MissingLocalSuffixBean extends EJBLocalObject { // 应 ...Local
|
||||
}
|
||||
|
||||
// 87 MDBAndSessionBeanNamingConvention:Bean 后缀
|
||||
public class MissingBeanSuffix implements SessionBean { // 应 ...Bean
|
||||
}
|
||||
|
||||
// 95 RemoteInterfaceNamingConvention:远程接口不应带后缀
|
||||
public interface BadSuffixSession extends EJBObject { // 不应 Session 后缀
|
||||
}
|
||||
|
||||
// 96 RemoteSessionInterfaceNamingConvention:Home 后缀
|
||||
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 AvoidUncheckedExceptionsInSignatures:throws 非受检异常
|
||||
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 FinalFieldCouldBeStatic:final 字段可为 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 InvalidJavaBean:Bean 不合规
|
||||
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 SwitchDensity:switch 密度过高(保留 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 SwitchDensity:switch 密度过高
|
||||
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 可能为 null,null 检查位置错误
|
||||
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 AvoidAccessibilityAlteration:setAccessible(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 AvoidLiteralsInIfCondition:if 中魔术数字
|
||||
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 CallSuperFirst:super 应首先调用
|
||||
class CallSuperFirst {
|
||||
void bad() {
|
||||
doSomething();
|
||||
super.toString(); // super 未首先调用? 占位
|
||||
}
|
||||
void doSomething() {
|
||||
}
|
||||
}
|
||||
|
||||
// 166 CallSuperLast:super 应最后调用
|
||||
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 IdempotentOperations:x = 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 CloneMethodMustImplementCloneable:clone() 但未实现 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 ProperLogger:logger 应为 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 NonSerializableClass:Serializable 类字段不可序列化
|
||||
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 UnitTestShouldUseAfterAnnotation:tearDown 无 @After 注解
|
||||
public class MissingAfterTest {
|
||||
public void tearDown() { // 应加 @After
|
||||
}
|
||||
}
|
||||
|
||||
// 45 UnitTestShouldUseBeforeAnnotation:setUp 无 @Before 注解
|
||||
public class MissingBeforeTest {
|
||||
public void setUp() { // 应加 @Before
|
||||
}
|
||||
}
|
||||
|
||||
// 46 UnitTestShouldUseTestAnnotation:test 方法无 @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 CallSuperFirst:onCreate 应首先调用 super.onCreate
|
||||
class MissingSuperFirst extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
foo(); // 未先调用 super.onCreate
|
||||
}
|
||||
|
||||
void foo() {
|
||||
}
|
||||
}
|
||||
|
||||
// 166 CallSuperLast:onPause 应最后调用 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 JUnitSpelling:setup/TearDown 拼写错误
|
||||
public class JUnitSpellingTest extends TestCase {
|
||||
public void setup() { // 应 setUp
|
||||
}
|
||||
public void TearDown() { // 应 tearDown
|
||||
}
|
||||
}
|
||||
|
||||
// 200 JUnitStaticSuite:suite 方法应为 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 UnitTestShouldUseAfterAnnotation:tearDown 无 @After
|
||||
class MissingAfterTest {
|
||||
@Test
|
||||
public void testCleanup() {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
public void tearDown() { // 应加 @After
|
||||
}
|
||||
}
|
||||
|
||||
// 45 UnitTestShouldUseBeforeAnnotation:setUp 无 @Before
|
||||
class MissingBeforeTest {
|
||||
@Test
|
||||
public void testSetup() {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
public void setUp() { // 应加 @Before
|
||||
}
|
||||
}
|
||||
|
||||
// 46 UnitTestShouldUseTestAnnotation:test 方法无 @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 AssertEqualsArgumentOrder:expected/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 JUnitJupiterTestShouldBePackagePrivate:JUnit5 测试应为包私有
|
||||
public class JupiterPublicTest {
|
||||
@Test
|
||||
public void testPublic() { // public 测试方法
|
||||
}
|
||||
}
|
||||
|
||||
// 198 JUnitJupiterTestNoPrivateModifier:JUnit5 测试不应为 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 ProperLogger:logger 应为 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 演示样例 — StaticEJBFieldShouldBeFinal:EJB 静态字段应为 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");
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
<%-- NoHtmlComments:HTML 注释太少,占位 --%>
|
||||
<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>
|
||||
@@ -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>
|
||||
<%-- NoHtmlComments:HTML 注释(非 JSP 注释)--%>
|
||||
<!-- this is an html comment -->
|
||||
<div style="background-color: #f00;">inline style</div>
|
||||
<%-- NoScriptlets:scriptlet --%>
|
||||
<%
|
||||
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>
|
||||
@@ -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>
|
||||
<%-- IframeMissingSrcAttribute:iframe 缺少 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 InvalidJavaBean:Bean 非法(不可序列化、缺 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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user