इस उत्तर का अधिकांश उत्तर Checkstyle's "Writing Checks" article से प्रेरित था। अधिकांश काम AnnotationSameLineCheck
में किया जाता है।
AnnotationSameLineCheck.java
यह जावा फ़ाइल "लेखन चेकों" लेख के "Visitor In Action" section से प्रेरित था।
getDefaultTokens
परिभाषित करता है कि जावा फ़ाइल के कौन से हिस्सों (ए.के.ए. टोकन) में रुचि है। पहले व्यक्ति को लगता है कि हमें TokenTypes.ANNOTATION
में रुचि होगी, लेकिन ऐसा नहीं है। हमें TokenTypes.ANNOTATION
में रुचि नहीं है क्योंकि हम सभी एनोटेशन का निरीक्षण नहीं करना चाहते हैं; हम वास्तव में TokenTypes.PARAMETER_DEF
की उपेक्षा करना चाहते हैं।
तब हमें क्या रूचि है? हम वास्तव में जावा फ़ाइल के उन हिस्सों में रूचि रखते हैं जिन्हें एनोटेट किया जा सकता है (यानी, कक्षा परिभाषा TokenTypes.CLASS_DEF
, विधि परिभाषा TokenTypes.METHOD_DEF
, आदि)। सुविधाजनक रूप से, चेकस्टाइल के एपीआई में एक तरीका है जो हमें बता सकता है कि टोकन एनोटेट किया गया है या नहीं। वह विधि AnnotationUtility.containsAnnotation
है, जिसका उपयोग visitToken
में किया जाता है।
अगर एक एनोटेशन एक ही लाइन पर है के रूप में एक जावा फ़ाइल के अन्य भागों प्रकार है का निर्धारण किया जाता एल्गोरिथ्म:
- निर्धारित करें कि एक विशेष टोकन एक एनोटेशन शामिल हैं। यदि नहीं, तो कुछ भी मत करो।
- एनोटेशन टोकन खोजें।
- एनोटेशन टोकन से पहले टोकन खोजें।
- एनोटेशन टोकन के बाद टोकन खोजें।
- यदि एनोटेशन टोकन पिछले टोकन के समान लाइन पर है, तो एक त्रुटि लॉग करें।
- यदि एनोटेशन टोकन अगले टोकन के समान लाइन पर है, तो एक त्रुटि लॉग करें।
यह एल्गोरिदम visitToken
में पाया गया है।
package example;
import com.puppycrawl.tools.checkstyle.api.AnnotationUtility;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
public class AnnotationSameLineCheck extends Check {
@Override
public int[] getDefaultTokens() {
// PACKAGE_DEF and PARAMETER_DEF were left out of the list
return new int[] { TokenTypes.ANNOTATION_DEF, //
TokenTypes.ANNOTATION_FIELD_DEF, //
TokenTypes.CLASS_DEF, //
TokenTypes.CTOR_DEF, //
TokenTypes.ENUM_DEF, //
TokenTypes.ENUM_CONSTANT_DEF, //
TokenTypes.INTERFACE_DEF, //
TokenTypes.METHOD_DEF, //
TokenTypes.VARIABLE_DEF };
}
@Override
public void visitToken(DetailAST ast) {
if (AnnotationUtility.containsAnnotation(ast)) {
final DetailAST holder = AnnotationUtility.getAnnotationHolder(ast);
final DetailAST annotation = getAnnotationAst(holder);
final DetailAST prev = getPreviousSibling(annotation, holder, ast);
final DetailAST next = getNextSibling(annotation, holder, ast);
if (isPreviousSiblingOnSameLine(prev, annotation) || //
isNextSiblingOnSameLine(annotation, next)) {
log(annotation.getLineNo(), //
annotation.getColumnNo(), //
"Annotations must exist on their own line");
}
}
}
private static boolean isPreviousSiblingOnSameLine(DetailAST prev, DetailAST annotation) {
if (prev == null) {
return false;
} else if (prev.getLastChild() == null) {
return prev.getLineNo() == annotation.getLineNo();
}
return prev.getLastChild().getLineNo() == annotation.getLineNo();
}
private static boolean isNextSiblingOnSameLine(DetailAST annotation, DetailAST next) {
if (next == null) {
return false;
}
return annotation.getLineNo() == next.getLineNo();
}
private static DetailAST getAnnotationAst(DetailAST aHolderAst) {
if (aHolderAst.getType() == TokenTypes.ANNOTATIONS) {
return aHolderAst;
} else if (aHolderAst.getType() == TokenTypes.MODIFIERS) {
return aHolderAst.findFirstToken(TokenTypes.ANNOTATION);
}
throw new AssertionError("aHolder must be one of TokenTypes.ANNOTATIONS or TokenTypes.MODIFIERS but was " + aHolderAst);
}
private static DetailAST getPreviousSibling(DetailAST annotation, DetailAST holder, DetailAST ast) {
if (annotation.getPreviousSibling() != null) {
return annotation.getPreviousSibling();
} else if (holder.getPreviousSibling() != null) {
return holder.getPreviousSibling();
}
return ast.getPreviousSibling();
}
private static DetailAST getNextSibling(DetailAST annotation, DetailAST holder, DetailAST ast) {
if (annotation.getNextSibling() != null) {
return annotation.getNextSibling();
} else if (holder.getNextSibling() != null) {
return holder.getNextSibling();
}
return ast.getNextSibling();
}
}
checks.xml
इस एक्सएमएल फ़ाइल "लेखन चेकों" लेख के "Integrate Your Check" section से प्रेरित था। इसका उपयोग यह जांचने के लिए चेकस्टाइल द्वारा किया जाता है कि जावा फाइलों के सेट पर कौन से चेक प्रदर्शन करते हैं। ध्यान दें कि AnnotationSameLineCheck
पूरी तरह योग्य है (यानी, इसका पैकेज नाम में निर्दिष्ट है)। checks.xml
का उल्लेख build.xml
फ़ाइल में किया गया है।
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="TreeWalker">
<module name="example.AnnotationSameLineCheck"/>
</module>
</module>
बिल्ड।xml
यह चींटी बिल्ड फ़ाइल Checkstyle's "Ant Task" article से प्रेरित थी। चींटी का उपयोग करना केवल स्टाइलस्टाइल निष्पादित करने का एक तरीका है। कमांड लाइन का उपयोग करना एक और विकल्प है।
<project default="example">
<taskdef resource="checkstyletask.properties" classpath="target/classes:lib/checkstyle-5.5-all.jar" />
<target name="example">
<checkstyle config="checks.xml">
<fileset dir="src/main/java" includes="**/AnnotatedClass.java" />
<formatter type="plain" />
</checkstyle>
</target>
</project>
AnnotationClass.java
एक AnnotationSameLineCheck
परीक्षण करने के लिए निम्नलिखित वर्ग का उपयोग कर सकते हैं। इसका उल्लेख build.xml
फ़ाइल में किया गया है। इंटरफ़ेस, कक्षा, एनम, सदस्य-चर, विधि, पैरामीटर, और स्थानीय-चरणीय घोषणाओं के परीक्षण पर ध्यान दें।
package example;
@Deprecated
class CorrectClassDefA {}
@Deprecated class IncorrectClassDefA {}
abstract
@Deprecated
class CorrectClassDefB {}
abstract @SuppressWarnings(value = "unused") class IncorrectClassDefB0 {}
abstract
@Deprecated class IncorrectClassDefB1 {}
[email protected]
class IncorrectClassDefB2 {}
@Deprecated abstract class IncorrectClassDefB3 {}
@Deprecated
abstract class CorrectClassDefB4 {}
@SuppressWarnings(value = "unused")
interface CorrectInterfaceDefA {}
@Deprecated interface IncorrectInterfaceDefA {}
abstract
@Deprecated
interface CorrectInterfaceDefB {}
abstract @Deprecated interface IncorrectInterfaceDefB0 {}
abstract
@Deprecated interface IncorrectInterfaceDefB1 {}
abstract @SuppressWarnings(value = "unused")
interface IncorrectInterfaceDefB2 {}
@SuppressWarnings(value = "unused") abstract interface IncorrectInterfaceDefB3 {}
@SuppressWarnings(value = "unused")
abstract
interface CorrectInterfaceDefB4 {}
@Deprecated
enum CorrectEnumA {
@SuppressWarnings(value = "unused")
CORRECT,
@Deprecated INCORRECT }
@Deprecated enum
IncorrectEnumA {
@Deprecated
CORRECT,
@SuppressWarnings(value = "unused") INCORRECT }
public class AnnotatedClass { @Deprecated // incorrect
public AnnotatedClass() {}
@Deprecated
AnnotatedClass(int correct) {}
public
@SuppressWarnings(value = "unused")
AnnotatedClass(boolean correct, boolean correct0) {}
@SuppressWarnings(value = "unused")
AnnotatedClass(int correct, int correct0, int correct1) {}
public @SuppressWarnings(value = "unused")
AnnotatedClass(@Deprecated int bad, int bad0, int bad1, int bad2) {}
@SuppressWarnings(value = "unused") AnnotatedClass(@Deprecated int bad, int bad0, int bad1, int bad2, int bad3) {}
@Deprecated private int incorrectB;
transient @Deprecated
private int incorrectC;
transient
@Deprecated
private
int correctD;
private
@SuppressWarnings(value = "unused")
Object correctA; @SuppressWarnings(value = "dog")
public void incorrectA(final Object baz) {
}
public void correctB(@SuppressWarnings(value = "dog") final Object good) {
@Deprecated
int correctA;
final @Deprecated int incorrectB;
final
@Deprecated
Object
correctC;
}
@SuppressWarnings(value = "dog") public
void incorrectC(final Object bad) {
}
public
@SuppressWarnings(value = "dog") void incorrectD(final Object bad) {
}
}
चेकस्टाइल में काफी लचीला एपीआई प्रतीत होता है, इसलिए मुझे लगता है कि यह संभव होगा। आपने क्या प्रयास किया है –
मैंने regexp बनाने का प्रयास किया, लेकिन इसे सही नहीं लिखा –
क्या आप अपने प्रश्न में अपना regexp लिख सकते हैं, इसलिए हम यह गलत कर सकते हैं कि क्या गलत है? – zmo