Maven plugin to restrict specific packages from being used

≡放荡痞女 提交于 2019-11-28 08:30:22
Mark O'Connor

You want to define an architectural rule for your project, which is best enforced by source code analysis.

Sonar now has the ability to specify such rules and display violations on the project's quality dashboard. If you want the build to break, this can additionally be done enabling Sonar's Build breaker plug-in.

Sonar is really easy to setup and integrates into your Maven build process with zero change to your POM.

Maciej A. Bednarz

Look at this:

<plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>macker-maven-plugin</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>macker</goal>
            </goals>
          </execution>
        </executions>      
      </plugin>

where rule is defined not to allow import of java.lang.System

<?xml version="1.0"?>
<macker>    
    <ruleset name="Testing rules">
        <pattern name="mypackage" class="org.codehaus.mojo.**" />
        <access-rule>
            <message>System out is bad. Use logging instead.</message>
            <deny>
                <to>
                    <include class="java.lang.System" />
                </to>
            </deny>
            <!--allow>
                <from pattern="blah" />
            </allow-->
        </access-rule>
    </ruleset>
</macker>

Here is plug-in I wrote for similar purposes.

Details can be seen here: https://github.com/yamanyar/restrict-maven-plugin/wiki

Restrict all access from com.ya* to java.util.regex.*

<restriction>com.ya* to java.util.regex.*</restriction>

Restrict all access from com.ya* (except com.yamanyar.core.) to java.util.regex.,

<restriction>com.ya*,!com.yamanyar.core.* to java.util.regex.*</restriction>

Restrict all access from com.ya* (except com.yamanyar.core.) and com.abc.Test to java.util.regex.

<restriction>com.ya*,com.abc.Test,!com.yamanyar.core.* to java.util.regex.*</restriction>

Restrict all access from com.ya* (except com.yamanyar.core.) and com.abc.Test to java.util.regex. ( except java.util.regex.Matcher) <restriction>com.ya*,com.abc.Test,!com.yamanyar.core.* to java.util.regex.*,!java.util.regex.Matcher</restriction>

Restrict all access from com.ya* ( except com.yamanyar.core.) and com.abc.Test to java.util.regex. ( except java.util.regex.Matcher); and also restrict com.ya* (except com.yamanyar.core.) to java.io.PrintStre.print*()

<restriction>com.ya*,com.abc.Test,!com.yamanyar.core.* to java.util.regex.*,!java.util.regex.Matcher</restriction>
<restriction>com.ya*,!com.yamanyar.core* to java.io.PrintStre*.print*()</restriction>

I'm not aware of a Maven plugin to do this, but I would imagine you could do similar with aspects (and therefore use the Maven/Aspectj plugin). Aspectj has the declare error construct that may be useful. This can raise an error if it detects a pointcut that uses your forbidden classes.

Also http://www.eclipse.org/aspectj/doc/released/progguide/semantics-declare.html#warnings-and-errors

One limitation of this approach is it is a static analysis and so won't be able to catch any 'clever' invocations of your class/package black-list.

You could check which classes are loaded in your class loader and raise an error if you find something from java.sun.Base64.

This seems to work: http://www.javaworld.com/javaworld/javaqa/2003-07/02-qa-0725-classsrc2.html

Here is a proof of concept rule code for PMD/Maven PMD plugin. (The restricted classes are hard-coded in the constructor, but it's possible to make it configurable via properties.)

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import net.sourceforge.pmd.AbstractJavaRule;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.ast.ASTName;
import net.sourceforge.pmd.ast.SimpleJavaNode;

public class PackageRestrictionRule extends AbstractJavaRule {

    private final List<String> disallowedPackages;

    public PackageRestrictionRule() {
        final List<String> disallowedPackages = new LinkedList<String>();
        disallowedPackages.add("org.apache.");
        this.disallowedPackages = Collections
                .unmodifiableList(disallowedPackages);
    }

    @Override
    public Object visit(final ASTClassOrInterfaceType node, 
            final Object data) {
        checkPackage(node, data);
        return super.visit(node, data);
    }

    @Override
    public Object visit(final ASTName node, final Object data) {
        checkPackage(node, data);
        return super.visit(node, data);
    }

    private void checkPackage(final SimpleJavaNode node, 
            final Object data) {
        final String image = node.getImage();
        if (isDisallowedPackage(image)) {
            addViolationWithMessage(data, node, 
                    "Disallowed class or package: " + image);
        }
    }

    private boolean isDisallowedPackage(final String packageName) {
        for (final String disallowedPackageName : disallowedPackages) {
            if (packageName.startsWith(disallowedPackageName)) {
                return true;
            }
        }
        return false;
    }
}

Create a new maven project for it, and use this project as a dependency of the PMD plugin in your project:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>2.5</version>
    <configuration>
        <targetJdk>1.6</targetJdk>
        <rulesets>
            <ruleset>packagerestrictionrule.xml</ruleset>
        </rulesets>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>...</groupId>
            <artifactId>PackageRestrictionRule</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</plugin>

Furthermore, the PMD plugin needs a proper ruleset XML file for the rule class. There is an example on the PMD website: http://pmd.sourceforge.net/howtowritearule.html. Just place it to the src/main/resources folder in your PackageRestrictionRule project and the plugin will find it on the classpath.

This suggestion is the opposite of "graceful"; it is a total kluge: it might be simple enough to write something to put in the process-sources phase of the build ... you could (for example) replace any cases of "sun.Base64" with some (invalid Java) text indicating the problem. This would cause the build to fail at least.

One simple option can be to use a 'parent' pom to define all your third party jars with versions in 'Dependency Management' section and use them in child poms. Even though this model does not deny the usage of a particular jar, the PM or architect will have an easy way to manage the dependencies. Once this done, we can simply tell developers to use only the dependencies used in the parent pom.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!