Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Checkstyle ignore missing JavaDoc whenever there is a specific annotation

I want to customize the Checkstyle JavadocVariable rule, so that it does not complain about a field that is has a @FindBy annotation.

class Demo{

    @FindBy(id = "new-button")
    public WebElement createButton;  //<- no JavaDoc required because it is a field "injected" by selenium

    public String otherField;    //<- complain about missing Java doc
}

But I do not have a clue how to specify this in the checkstyle.xml file. Does anybody have an idea?

Things that does not work in this use case:

  • Modifyng the checked class is also no solution!
  • SuppressWithNearbyCommentFilter will not work, because it is a annotation but not a comment
like image 272
Ralph Avatar asked Feb 06 '15 07:02

Ralph


1 Answers

I know several solutions but all of them requires additional work to do.

  1. Implementing own JavadocVariableCheck with possibility to skip check in case annotation is provided.
  2. Implementing checkstyle filter (like SuppressWarningsHolder + SuppressWarningsFilter but with annotation support)
  3. Or implement simple filter which scans for @FindBy and ignores two lines after it.

My solution (the simplest one):

package org.aap.checks;

import com.google.common.collect.Lists;
import com.puppycrawl.tools.checkstyle.api.AuditEvent;
import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
import com.puppycrawl.tools.checkstyle.api.FileContents;
import com.puppycrawl.tools.checkstyle.api.Filter;
import com.puppycrawl.tools.checkstyle.checks.FileContentsHolder;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class SuppressWithAnnotationFilter
        extends AutomaticBean
        implements Filter {

    public class Tag implements Comparable<Tag> {
        private final int firstLine;
        private final int lastLine;

        public Tag(int firstLine, int lastLine) {
            this.firstLine = firstLine;
            this.lastLine = lastLine;
        }

        @Override
        public int compareTo(Tag other) {
            if (firstLine == other.firstLine) {
                return lastLine - other.lastLine;
            }
            return (firstLine - other.firstLine);
        }

        public boolean isMatch(AuditEvent event) {
            final int line = event.getLine();
            return line >= firstLine && line <= lastLine;
        }

        @Override
        public final String toString() {
            return "Tag[lines=" + firstLine + " to " + lastLine + "]";
        }
    }

    private final List<Tag> tags = Lists.newArrayList();
    private WeakReference<FileContents> fileContentsReference =
            new WeakReference<FileContents>(null);

    public FileContents getFileContents() {
        return fileContentsReference.get();
    }

    public void setFileContents(FileContents fileContents) {
        fileContentsReference = new WeakReference<FileContents>(fileContents);
    }

    @Override
    public boolean accept(AuditEvent event) {
        if (event.getLocalizedMessage() == null) {
            return true;        // A special event.
        }

        final FileContents currentContents = FileContentsHolder.getContents();
        if (currentContents == null) {
            return true;
        }
        if (getFileContents() != currentContents) {
            setFileContents(currentContents);
            tagSuppressions();
        }
        for (final Iterator<Tag> iter = tags.iterator(); iter.hasNext(); ) {
            final Tag tag = iter.next();
            if (tag.isMatch(event)) {
                return false;
            }
        }
        return true;
    }

    private void tagSuppressions() {
        tags.clear();
        final FileContents contents = getFileContents();

        String[] contentsLines = contents.getLines();
        for (int i = 0; i < contentsLines.length; i++) {
            if (contentsLines[i].contains("@FindBy")) {
                tags.add(new Tag(i+1, i+2));
            }
        }

        Collections.sort(tags);
    }
}

Add resulting class into classpath of the checkstyle task then in checkstyle.xml specify filter:

<?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">
    ....
    <!-- your Check goes here -->
    <module name="org.aap.checks.SuppressWithAnnotationFilter"/>
    ....
  </module>
</module>
like image 176
4ndrew Avatar answered Oct 19 '22 13:10

4ndrew