Java 11+Maven环境下如何禁止修改Model类并触发构建失败?
如何在Maven+Spring Boot+Java 11项目中禁止Model类属性修改/新增
可以通过以下几种方案实现,确保Model类的属性被修改或新增时Maven构建直接失败:
方案一:使用Checkstyle自定义字段校验规则
Checkstyle支持自定义检查规则,我们可以编写一个规则来校验目标Model类的字段是否与预设的完全一致,不一致则触发构建失败。
步骤:
- 编写自定义Checkstyle检查器
创建一个Java类继承AbstractCheck,重写visitToken方法,读取目标类的所有字段并与预设字段列表对比:
import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import java.util.HashSet; import java.util.Set; public class ModelFieldCheck extends AbstractCheck { // 预设的Model字段名,根据实际情况修改 private static final Set<String> EXPECTED_FIELDS = new HashSet<>(); static { EXPECTED_FIELDS.add("id"); EXPECTED_FIELDS.add("name"); EXPECTED_FIELDS.add("createTime"); } @Override public int[] getDefaultTokens() { return new int[]{TokenTypes.CLASS_DEF}; } @Override public int[] getAcceptableTokens() { return getDefaultTokens(); } @Override public int[] getRequiredTokens() { return getDefaultTokens(); } @Override public void visitToken(DetailAST ast) { // 仅检查指定的Model类,替换为你的Model类名 String className = ast.findFirstToken(TokenTypes.IDENT).getText(); if (!"YourModel".equals(className)) { return; } Set<String> actualFields = new HashSet<>(); DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK); DetailAST current = objBlock.getFirstChild(); while (current != null) { if (current.getType() == TokenTypes.VARIABLE_DEF) { DetailAST fieldNameAst = current.findFirstToken(TokenTypes.IDENT); actualFields.add(fieldNameAst.getText()); } current = current.getNextSibling(); } // 检查新增字段 for (String field : actualFields) { if (!EXPECTED_FIELDS.contains(field)) { log(current.getLineNo(), "新增未授权字段: " + field); } } // 检查删除字段 for (String expectedField : EXPECTED_FIELDS) { if (!actualFields.contains(expectedField)) { log(ast.getLineNo(), "必填字段被删除: " + expectedField); } } } }
将这个类打包成jar,放到项目的依赖中或Checkstyle的类路径下。
- 配置Checkstyle规则文件
在项目根目录创建checkstyle.xml,引入自定义检查器:
<?xml version="1.0"?> <!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd"> <module name="Checker"> <module name="TreeWalker"> <module name="com.yourpackage.checkstyle.ModelFieldCheck"/> </module> </module>
- 配置Maven Checkstyle插件
在pom.xml中引入插件,绑定到verify阶段,开启构建失败开关:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <version>3.2.0</version> <executions> <execution> <id>check-model-fields</id> <phase>verify</phase> <goals> <goal>check</goal> </goals> </execution> </executions> <configuration> <configLocation>checkstyle.xml</configLocation> <failOnError>true</failOnError> <classpathDependencyScope>compile</classpathDependencyScope> </configuration> </plugin>
方案二:使用Maven Exec插件执行自定义校验程序
如果觉得Checkstyle的自定义规则过于复杂,可以直接编写一个Java校验程序,通过Maven Exec插件在构建阶段执行,一旦校验不通过就抛出异常终止构建。
步骤:
- 编写字段校验程序
创建一个Java类,通过反射读取Model类的字段并与预设值对比:
import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class ModelFieldValidator { public static void main(String[] args) throws ClassNotFoundException { // 参数1:Model类全限定名,参数2:预设字段(格式:字段名:类型,字段名:类型) String modelClassName = args[0]; String expectedFieldsStr = args[1]; Map<String, String> expectedFields = parseExpectedFields(expectedFieldsStr); Class<?> modelClass = Class.forName(modelClassName); Field[] actualFields = modelClass.getDeclaredFields(); Map<String, String> actualFieldMap = new HashMap<>(); for (Field field : actualFields) { actualFieldMap.put(field.getName(), field.getType().getSimpleName()); } // 校验新增字段 for (String fieldName : actualFieldMap.keySet()) { if (!expectedFields.containsKey(fieldName)) { throw new IllegalStateException("Model类新增未授权字段: " + fieldName); } } // 校验字段删除或类型修改 for (Map.Entry<String, String> entry : expectedFields.entrySet()) { String fieldName = entry.getKey(); String expectedType = entry.getValue(); String actualType = actualFieldMap.get(fieldName); if (actualType == null) { throw new IllegalStateException("Model类必填字段被删除: " + fieldName); } if (!actualType.equals(expectedType)) { throw new IllegalStateException( String.format("字段%s类型不匹配,预期: %s,实际: %s", fieldName, expectedType, actualType) ); } } } private static Map<String, String> parseExpectedFields(String str) { Map<String, String> map = new HashMap<>(); String[] pairs = str.split(","); for (String pair : pairs) { String[] parts = pair.split(":"); map.put(parts[0], parts[1]); } return map; } }
- 配置Maven Exec插件
在pom.xml中配置插件,绑定到verify阶段,执行校验程序:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>validate-model-fields</id> <phase>verify</phase> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>com.yourpackage.ModelFieldValidator</mainClass> <arguments> <!-- 替换为你的Model类全限定名 --> <argument>com.yourpackage.model.YourModel</argument> <!-- 替换为预设的字段列表 --> <argument>id:Long,name:String,createTime:LocalDateTime</argument> </arguments> </configuration> </plugin>
注意事项
- 无论使用哪种方案,都需要将校验阶段绑定到
verify或更晚的Maven阶段,确保代码编译完成后再执行校验。 - 当Model类需要合法修改时,必须同步更新校验规则中的预设字段列表,否则会触发构建失败。
- 自定义校验程序需要处理反射的访问权限,
getDeclaredFields()会返回类的所有字段,包括私有字段。
内容的提问来源于stack exchange,提问作者Lokesh
相关产品推荐
相关产品推荐

