How Refactoring an IDEA YAML Inspection Plugin Boosted Code Quality
This article examines the refactoring of an IntelliJ IDEA plugin for YAML file validation, comparing the original and improved implementations across structure, naming, readability, comments, method abstraction, conditional logic, and error handling, and demonstrates how these changes enhance maintainability and robustness.
Background
Develop an IntelliJ IDEA plugin to perform customized format checks on YAML files.
Verify that the specified classpath is correct.
Check whether YAML keys match the field names in the class.
Ensure values can be converted to the field types.
Code Comparison
1 Structure Design
After refactoring, an abstract class method celtVisitMapping was added to provide a unified proxy for multiple inspection modules, enabling centralized error handling, logging, and parameter tagging for easier extension.
2 Code Readability
2.1 Naming
A good name conveys purpose and usage. The original class name YamlBaseInspection was vague, while the new name CeltClassInspection clearly indicates that it handles YAML class inspections.
2.2 Functions
Original function compareNameAndValue did not reflect its purpose. It was renamed to compareKeyAndValue, making it clear that the method validates the correspondence between a key and its value.
2.3 Variables
// before
ASTNode node = mapping.getNode().findChildByType(YAMLTokenTypes.TAG);
String className = node.getText().substring(2);
// after
ASTNode node = mapping.getNode().findChildByType(YAMLTokenTypes.TAG);
String tagClassName = node.getText().substring(2);The new variable name tagClassName immediately reveals that the value originates from the YAML tag, reducing cognitive load.
3 Comments
3.1 Comment Format
Before: missing or non‑standard comments. After: JavaDoc‑style comments added to methods, providing clear @param and @return descriptions.
// before
private boolean checkSimpleValue(PsiClass psiClass, PsiElement value)
/**
* @param psiClass
* @param value
* @return true if normal; false if abnormal
*/
private boolean checkSimpleValue(PsiClass psiClass, PsiElement value, ProblemsHolder holder)3.2 Comment Placement
// simpleValue is null or "null"
if (YamlUtil.isNull(value)) {
return;
}
// simple type: check key and value format
checkSimpleValue(psiClass, value, holder);Inline comments are now placed inside the code block they explain.
4 Method Abstraction
Before, compareNameAndValue was long and handled type discrimination, complex logic, and error registration in one method, making it hard to read. After refactoring, the complex comparison logic was extracted to a separate method, and the original method now only determines the type and delegates the work.
public void compareKeyAndValue(PsiClass psiClass, YAMLValue value, ProblemsHolder holder) {
if (YamlUtil.isNull(value)) {
return;
}
if (PsiClassUtil.isSimpleType(psiClass)) {
// simple type: check key and value format
checkSimpleValue(psiClass, value, holder);
} else if (PsiClassUtil.isGenericType(psiClass)) {
// generic, Object, whitelist: no check
} else {
checkComplexValue(psiClass, value, holder);
}
}5 Complex Conditional Logic
Before the code contained deeply nested if statements, making the logic hard to follow. After refactoring, the nesting was reduced, improving readability and maintainability.
6 Robustness
6.1 Precise Error Messages
// before
holder.registerProblem(value, "类型无法转换", ProblemHighlightType.GENERIC_ERROR);
// after
String errorMsg = String.format("cannot find field:%s in class:%s", yamlKeyValue.getName(), psiClass.getQualifiedName());
holder.registerProblem(yamlKeyValue.getKey(), errorMsg, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);The new message specifies which field and class are missing, helping users locate the issue quickly.
6.2 Exception Handling
Before, null pointers could occur (e.g., deleteSqlList might be null). After refactoring, each potential null is checked, and appropriate error registration is performed.
@Override
public void doVisitMapping(@NotNull YAMLMapping mapping, @NotNull ProblemsHolder holder) {
ASTNode node = mapping.getNode().findChildByType(YAMLTokenTypes.TAG);
if (YamlUtil.isNull(node)) {
return;
}
if (node.getText() == null || !node.getText().startsWith("!!")) {
holder.registerProblem(node.getPsi(), "yaml plugin error: text is null or does not start with !!", ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
return;
}
String tagClassName = node.getText().substring(2);
PsiClass[] psiClasses = ProjectService.findPsiClasses(tagClassName, mapping.getProject());
if (ArrayUtils.isEmpty(psiClasses)) {
String errorMsg = String.format("cannot find className = %s", tagClassName);
holder.registerProblem(node.getPsi(), errorMsg, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
return;
}
if (psiClasses.length == 1) {
compareKeyAndValue(psiClasses[0], mapping, holder);
}
}6.3 Switch Default Handling
// before
switch (className) {
case "java.lang.Boolean":
break;
case "java.lang.Character":
break;
case "java.math.BigDecimal":
break;
case "java.util.Date":
break;
default:
}
// after
switch (className) {
case "java.lang.Boolean":
break;
case "java.lang.Character":
break;
case "java.math.BigDecimal":
break;
case "java.util.Date":
break;
case "java.lang.String":
return true;
default:
holder.registerProblem(value, "Unrecognized className: " + className, ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
return false;
}The revised switch adds explicit handling for String and registers an error for unknown classes, making the logic clearer and more robust.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
