Your Software. Your Structures. Your Rules.

This document describes the concepts of jQAssistant and usage information.

Introduction

jQAssistant is a tool supporting the process for developing Java applications. It is based on the graph database Neo4j and can be plugged into the Maven build process to break the build on detection of constraint violations and generate reports about user defined concepts and metrics.

Here are some examples:

  • Enforce naming conventions, e.g. EJBs, JPA entities, test classes, package names etc.

  • Define business modules (e.g. shopping cart, user management) and technical modules (e.g. presentation, business logic, persistence) and validate dependencies between them

  • separate APIs and implementation classes (e.g. a module must only have dependencies to API classes of other components)

  • detect common problems, e.g cyclic package dependencies, dead code

License

jQAssistant is contributed under Apache License 2.0.

Maven Plugin

jQAssistant provides a plugin for Apache Maven which can be used to provide either fully automated scanning and analysis during the build process or manual execution from a command line.

Setup

Project Scope Definition

Software projects often consist of several modules which are combined to executable or deployable artifacts. In a Maven project these modules are usually organized hierarchically with a common parent module which is referenced directly or indirectly by all sub-modules. For each project jQAssistant uses a separate database with its own set of rules. Thus if a goal is executed within a Maven structure jQAssistant first determines the project scope, i.e. the root module, by searching within the tree starting from the current module following the parent relation until either a module is found where a directory "jqassistant/" exists or no parent is defined. The determined root module defines the location of

  • the set of rules to apply (from the directory "jqassistant/")

  • the database, default "C:\Development\Temp\jqassistant\target\checkout\scm\jqassistant-maven-plugin\target/jqassistant/store"

  • the generated native report, default: "C:\Development\Temp\jqassistant\target\checkout\scm\jqassistant-maven-plugin\target/jqassistant/jqassistant-report.xml")

  • and the generated HTML report, default "C:\Development\Temp\jqassistant\target\checkout\scm\jqassistant-maven-plugin\target/site/jqassistant.html")

The following examples demonstrate different scenarios, the root modules as detected by jQAssistant are marked using asterisks.

Single project consisting of two modules
root*
   |-pom.xml
   |
   |-jqassistant
   |           |-rules.xml
   |
   |-module1
   |       |-pom.xml
   |
   |-module2
           |-pom.xml
Multiple projects, each consisting of two modules
root
   |-pom.xml
   |
   |-project1*
   |        |-jqassistant
   |        |           |-rules1.xml
   |        |
   |        |-pom.xml
   |        |-module1
   |        |       |-pom.xml
   |        |
   |        |-module2
   |                |-pom.xml
   |
   |-project2*
   |        |-jqassistant
   |        |           |-rules2.xml
   |        |-pom.xml
   |        |-module1
   |        |       |-pom.xml
   |        |
   |        |-module2
                    |-pom.xml

Plugin Configuration

The jQAssistant Maven plugin must be configured in the pom.xml of the root module, it should not be overwritten by sub-modules.

Setup of the jQAssistant Maven plugin
<project ...>
    ...
    <build>
        <plugins>
            <plugin>
            <groupId>com.buschmais.jqassistant.scm</groupId>
                <artifactId>jqassistant-maven-plugin</artifactId>
                <version>1.0.0-M3</version>
                <executions>
                    <execution>
                        <id>scan</id>
                        <goals>
                            <goal>scan</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>analyze</id>
                        <goals>
                            <goal>analyze</goal>
                        </goals>
                        <!--
                        <configuration>
                            <groups>
                                <group>default</group>
                            </groups>
                            <failOnConstraintViolations>true</failOnConstraintViolations>
                        </configuration>
                         -->
                    </execution>
                </executions>
                <!--
                <dependencies>
                    <dependency>
                        <groupId>com.buschmais.jqassistant.plugin</groupId>
                        <artifactId>jqassistant.plugin.jpa2</artifactId>
                        <version>1.0.0-M3</version>
                    </dependency>
                </dependencies>
                -->
            </plugin>
        </plugins>
    </build>

    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-project-info-reports-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.buschmais.jqassistant.scm</groupId>
                <artifactId>jqassistant-maven-plugin</artifactId>
                <version>1.0.0-M3</version>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>report</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
        </plugins>
    </reporting>
    ...
</project>

Command Line

Goals may also be executed from the command line:

mvn com.buschmais.jqassistant.scm:jqassistant-maven-plugin:available-rules

Adding the following lines to the file settings.xml (usually located in the $HOME/.m2) eases execution of jQAssistant goals from the command line:

<pluginGroups>
    <pluginGroup>com.buschmais.jqassistant.scm</pluginGroup>
</pluginGroups>

The same goal can now be executed using the following command line statement:

mvn jqassistant:available-rules

Goals

jqassistant:scan

Description

Scans the directories of compiled classes and test classes and stores the gathered information in database.

Configuration
  • storeDirectory (-Djqassistant.store.directory)

    • specifies the location of the database

    • default: {rootmodule}/target/jqassistant/store

jqassistant:reset

Description

Resets the database by deleting all nodes and relationships.

Configuration
  • storeDirectory (-Djqassistant.store.directory)

    • specifies the location of the database

    • default: {rootmodule}/target/jqassistant/store

jqassistant:server

Description

Starts the integrated Neo4j web server (http://localhost:7474).

Configuration
  • storeDirectory (-Djqassistant.store.directory)

    • specifies the location of the database

    • default: {rootmodule}/target/jqassistant/store

jqassistant:analyze

Description

Executes an analysis.

Configuration
  • storeDirectory (-Djqassistant.store.directory)

    • specifies the location of the database

    • default: {rootmodule}/target/jqassistant/store

  • concepts (-Djqassistant.concepts)

    • specifies the ids of the concepts to be applied

  • constraints (-Djqassistant.constraints)

    • specifies the ids of the constraints to be validated

  • groups (-Djqassistant.groups)

    • specifies the ids of the groups to be executed

    • default: default

  • xmlReportFile (-Djqassistant.report.xml)

    • specifes the target file for writing the XML report

    • default: {rootmodule}/target/jqassistant/jqassistant-report.xml

  • failOnConstraintViolations (-Djqassistant.failOnConstraintViolations)

    • determines the jQAssistant shall break the build if constraint violations are detected

    • default: true

jqassistant:effective-rules

Description

List the rules which would be executed for an analysis and the given concepts, constraints or groups.

Configuration
  • concepts (-Djqassistant.concepts)

    • specifies the ids of the concepts to be applied

  • constraints (-Djqassistant.constraints)

    • specifies the ids of the constraints to be validated

  • groups (-Djqassistant.groups)

    • specifies the ids of the groups to be executed

    • default: default

jqassistant:available-rules

Description

List all available rules.

jqassistant:report

Description

Transforms an XML report into HTML.

Configuration
  • xmlReportFile (-Djqassistant.report.xml)

    • specifes the file containing the XML report from an analysis

    • default: {rootmodule}/target/jqassistant/jqassistant-report.xml

  • htmlReportFile (-Djqassistant.report.html)

    • specifes the target file for writing the HTML report

    • default: {rootmodule}/target/site/jqassistant.html

Examples

Rules

Forbidden Method

Demonstrates a constraint to define methods which must not be invoked by the application. The example denies usage of all constructors of java.util.Date.

jqassistant/default.xml
<jqa:jqassistant-rules xmlns:jqa="http://www.buschmais.com/jqassistant/core/analysis/rules/schema/v1.0">

    <constraint id="example:ConstructorOfDateMustNotBeUsed">
        <description>Constructors of java.util.Date must not be used.</description>
        <cypher><![CDATA[
            match
                (dateType:Type)-[:DECLARES]->(forbiddenMethod:Method),
                (type:Type)-[:DECLARES]->(method:Method)-[:INVOKES]->(forbiddenMethod)
            where
                dateType.fqn = 'java.util.Date'
                and forbiddenMethod:Constructor
            return
                method as Method
        ]]></cypher>
    </constraint>

    <group id="default">
        <includeConstraint refId="example:ConstructorOfDateMustNotBeUsed"/>
    </group>

</jqa:jqassistant-rules>

Naming

The following rules demonstrate concepts and constraints to enforce names and locations of classes with dedicated roles. These are identified either by an implemented interface or an annotation.

Interface
jqassistant/controller.xml
<jqa:jqassistant-rules xmlns:jqa="http://www.buschmais.com/jqassistant/core/analysis/rules/schema/v1.0">

    <concept id="controller:ControllerClass">
        <description>Labels all classes implementing the Controller interface as "Controller".</description>
        <cypher><![CDATA[
            match
                (controllerClass:Type:Class)-[:IMPLEMENTS*]->(controllerType:Type)
            where
                controllerType.fqn = "com.buschmais.jqassistant.examples.rules.naming.Controller"
            set
                controllerClass:Controller
            return
                controllerClass
        ]]></cypher>
    </concept>

    <constraint id="controller:ClassNameMustHaveControllerSuffix">
        <requiresConcept refId="controller:ControllerClass"/>
        <description>All controller implementations must have a name suffix "Controller".</description>
        <cypher><![CDATA[
            match
                (controllerClass:Class:Controller)
            where
                not controllerClass.name =~ ".*Controller"
            return
                controllerClass as ControllerClass
        ]]></cypher>
    </constraint>

    <constraint id="controller:ClassesMustBeLocatedInControllerPackage">
        <requiresConcept refId="controller:ControllerClass"/>
        <description>All controller implementations must be located in the package "model".</description>
        <cypher><![CDATA[
            match
                (package:PACKAGE)-[:CONTAINS]->(controllerClass:Class:Controller)
            where
                not package.name = "controller"
            return
                controllerClass as ControllerClass, package as InvalidPackage
        ]]></cypher>
    </constraint>

</jqa:jqassistant-rules>
Annotation
jqassistant/model.xml
<jqa:jqassistant-rules xmlns:jqa="http://www.buschmais.com/jqassistant/core/analysis/rules/schema/v1.0">

    <concept id="model:ModelClass">
        <description>Labels all classes annotated with @Model as "Model".</description>
        <cypher><![CDATA[
            match
                (modelClass:Type:Class)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(modelAnnotationType:Type)
            where
                modelAnnotationType.fqn = "com.buschmais.jqassistant.examples.rules.naming.Model"
            set
                modelClass:Model
            return
                modelClass as ModelClass
        ]]></cypher>
    </concept>

    <constraint id="model:ClassNameMustHaveModelSuffix">
        <requiresConcept refId="model:ModelClass"/>
        <description>All model classes must have a name suffix "Model".</description>
        <cypher><![CDATA[
            match
                (modelClass:Class:Model)
            where
                not modelClass.name =~ ".*Model"
            return
                modelClass as ModelClass
        ]]></cypher>
    </constraint>

    <constraint id="model:ClassesMustBeLocatedInModelPackage">
        <requiresConcept refId="model:ModelClass"/>
        <description>All model classes must be located in the package "model".</description>
        <cypher><![CDATA[
            match
                (package:PACKAGE)-[:CONTAINS]->(modelClass:Class:Model)
            where
                not package.name = "model"
            return
                modelClass as ModelClass, package as InvalidPackage
        ]]></cypher>
    </constraint>

</jqa:jqassistant-rules>

Plugins

Custom Report Plugin

A custom report plugin can be provided as an artifact which contains a Java class and a plugin descriptor. Therefore a project must be created which declares the required dependencies:

pom.xml
        <dependency>
            <groupId>com.buschmais.jqassistant.core</groupId>
            <artifactId>jqassistant.core.report</artifactId>
            <version>1.0.0-M3</version>
        </dependency>
        <dependency>
            <groupId>com.buschmais.jqassistant.plugin</groupId>
            <artifactId>jqassistant.plugin.java</artifactId>
            <version>1.0.0-M3</version>
        </dependency>
    </dependencies>

The artifact jqassistant.core.report provides the report plugin API, jqassistant.plugin.java provides interfaces representing Java types which might be used by the plugin implementation:

com.buschmais.jqassistant.examples.plugins.report.CustomReportPlugin
import com.buschmais.jqassistant.core.report.api.ReportPlugin;
import com.buschmais.jqassistant.plugin.java.api.model.TypeDescriptor;

public class CustomReportPlugin implements ReportPlugin {

    private static final String PROPERTY_FILENAME = "customReport.fileName";

    private String fileName;

    @Override
    public void initialize(Map<String, Object> properties) throws ReportException {
        this.fileName = (String) properties.get(PROPERTY_FILENAME);
        if (this.fileName == null) {
            throw new ReportException("Property " + PROPERTY_FILENAME + " is not specified.");
        }
    }

    @Override
    public void begin() throws ReportException {
    }

    @Override
    public void end() throws ReportException {
    }

    @Override
    public void beginConcept(Concept concept) throws ReportException {
    }

    @Override
    public void endConcept() throws ReportException {
    }

    @Override
    public void beginGroup(Group group) throws ReportException {
    }

    @Override
    public void endGroup() throws ReportException {
    }

    @Override
    public void beginConstraint(Constraint constraint) throws ReportException {
    }

    @Override
    public void endConstraint() throws ReportException {
    }

    @Override
    public void setResult(Result<? extends Rule> result) throws ReportException {
        Rule rule = result.getRule();
        if (rule instanceof Concept && "example:MethodsPerType".equals(rule.getId())) {
            try {
                PrintWriter writer = new PrintWriter(new FileWriter(fileName));
                writer.println("Methods per Type");
                writer.println("================");
                for (Map<String, Object> row : result.getRows()) {
                    TypeDescriptor type = (TypeDescriptor) row.get("Type");
                    Long methodCount = (Long) row.get("MethodCount");
                    writer.println(type.getFullQualifiedName() + ":" + methodCount);
                }
                writer.close();
            } catch (IOException e) {
                throw new ReportException("Cannot write custom report.", e);
            }
        }
    }
}

The plugin implementation must be declared in the jQAssistant plugin descriptor:

/META-INF/jqassistant-plugin.xml
<jqa-plugin:jqassistant-plugin xmlns:jqa-plugin="http://www.buschmais.com/jqassistant/core/plugin/schema/v1.0">
    <description>Example plugin defining a custom report.</description>
    <report>
        <class>com.buschmais.jqassistant.examples.plugins.report.CustomReportPlugin</class>
    </report>
</jqa-plugin:jqassistant-plugin>

The plugin is automatically loaded by the analyzer if it can be found on the classpath, e.g. by adding it as dependency to the maven plugin.

Maven Project Using Custom Plugins

Custom plugins containing rules, scanners or reporters must be specified as dependency of the Maven plugin. It is also possible to specify plugin specific properties:

pom.xml
                <groupId>com.buschmais.jqassistant.scm</groupId>
                <artifactId>jqassistant-maven-plugin</artifactId>
                <version>1.0.0-M3</version>
                <configuration>
                    <reportProperties>
                        <customReport.fileName>customReport.txt</customReport.fileName>
                    </reportProperties>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>com.buschmais.jqassistant.examples</groupId>
                        <artifactId>jqassistant.examples.plugins.report</artifactId>
                        <version>1.0.0-M3</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>

SonarQube

jQAssistant Plugin

Projects may retrieve jQAssistant rules from a SonarQube instance using a permalink. Furthermore a sensor is provided which will create issues on violated constraints. As a pre-condition the jQAssistant SonarQube plugin must be downloaded. It is together with several extensions available from Maven Central Repository using group id "com.buschmais.jqassistant.sonar". For analyzing Java projects the plugin itself (jqassistant.sonar.plugin) and the Java extension (jqassistant.sonar.extension.java) are required.

The JAR files must be deployed in the directory "extensions/plugins" of the SonarQube server. This makes a repository jQAssistant and the rules defined in the deployed extensions available in the Coding rules view of quality profiles. New rules can be added or created in the following ways:

  • by creating new concepts and constraints from the pre-defined templates (i.e. "Concept Template" and "Constraint Template")

  • by deploying a pre-defined rule extension available from Maven Central (see above)

  • by deploying a custom rule extension, this is demonstrated by the example "Custom Rule Extension"

Next the following settings must be applied to the jQAssistant Maven plugin in the pom.xml of the project to be analyzed:

pom.xml
                <plugins>
                    <plugin>
                        <groupId>com.buschmais.jqassistant.scm</groupId>
                        <artifactId>jqassistant-maven-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>scan</id>
                                <goals>
                                    <goal>scan</goal>
                                </goals>
                            </execution>
                            <execution>
                                <id>analyze</id>
                                <goals>
                                    <goal>analyze</goal>
                                </goals>
                                <configuration>
                                    <rulesUrl>http://localhost:9000/profiles/export?format=jqassistant&amp;language=java&amp;name=MyQualityProfile</rulesUrl>
                                    <groups>
                                        <group>MyQualityProfile</group>
                                    </groups>
                                    <failOnConstraintViolations>false</failOnConstraintViolations>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
  • Rules are retrieved from the SonarQube server using the URL specified in rulesUrl. The value is the jQAssistant permalink available within the quality profile from the SonarQube UI. Note that special characters must be replaced by XML entities.

  • The specified group must be the name of the quality profile used to analyze the project.

  • The build shall not be broken if a violation is detected, therefore failOnConstraintViolations is set to false.

Custom Rule Extension

A custom rule extension makes user defined jQAssistant rules available for SonarQube. It is a Maven project which declares packaging sonar-plugin:

pom.xml
<project ...>
...

    <packaging>sonar-plugin</packaging>

    <properties>
        <org.codehaus.sonar_version>3.7.4</org.codehaus.sonar_version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.sonar</groupId>
                <artifactId>sonar-packaging-maven-plugin</artifactId>
                <version>1.9</version>
                <extensions>true</extensions>
                <configuration>
                    <basePlugin>jqassistant</basePlugin>
                    <pluginClass>com.buschmais.jqassistant.examples.sonar.ruleextension.MyJQAssistantExtension</pluginClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>native2ascii-maven-plugin</artifactId>
                <version>1.0-beta-1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>native2ascii</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.buschmais.jqassistant.sonar</groupId>
            <artifactId>jqassistant.sonar.plugin</artifactId>
            <version>1.0.0-M3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.sonar</groupId>
            <artifactId>sonar-plugin-api</artifactId>
            <version>3.7.4</version>
        </dependency>
    </dependencies>


...
</project>

Notes on the sonar plugin configuration:

  • basePlugin must be set to jQAssistant to indicate which plugin shall be extended.

  • The implementation of pluginClass (i.e. MyJQAssistantExtension) returns an empty list of extensions. It must be specified as this is required by SonarQube.

MyJQAssistantExtension.java
package com.buschmais.jqassistant.examples.sonar.ruleextension;

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

import org.sonar.api.SonarPlugin;

/**
 * Defines a sonar extension.
 */
public class MyJQAssistantExtension extends SonarPlugin {

    @SuppressWarnings("rawtypes")
    @Override
    public List getExtensions() {
        return Collections.emptyList();
    }

}

The rules itself are packaged according to the following structure:

/META-INF/jqassistant-plugin.xml
<v1:jqassistant-plugin xmlns:v1="http://www.buschmais.com/jqassistant/core/plugin/schema/v1.0">
    <description>An example plugin.</description>
    <rules>
        <resource>example.xml</resource>
    </rules>
</v1:jqassistant-plugin>
  • example.xml specifies the path to a jQAssistant rule file relative to /META-INF/jqassistant-rules

/META-INF/jqassistant-rules/example.xml
<jqa:jqassistant-rules xmlns:jqa="http://www.buschmais.com/jqassistant/core/analysis/rules/schema/v1.0">

    <!-- Don't take these constraints serious - they are just here to illustrate integration with SonarQube -->

    <constraint id="example:AllClassesMustBeNamedFoo">
        <description>All classes must be named 'Foo'.</description>
        <cypher><![CDATA[
            match
              (type:Class)
            where not
              type.name = 'Foo'
            return
              type as InvalidClass
        ]]></cypher>
    </constraint>

    <constraint id="example:FieldsMustBeReadOnly">
        <description>All declared fields must be read-only (i.e. not be written).</description>
        <cypher><![CDATA[
                        match
                          (m:Method)-[w:WRITES]->(f:Field)
                        return
                           w as WriteAccess
        ]]></cypher>
    </constraint>
</jqa:jqassistant-rules>

The created JAR archive and the jQAssistant must be copied to the folder extensions/plugins of the SonarQube installation. The defined rules will be visible in the repository "jQAssistant".

Plugins

This section provides detailed descriptions of all distributed plugins.

jqassistant.plugin.ejb3

Provides rules for EJB3.

ejb3.xml

Concepts
ejb3:Local

Labels all types annotated with @javax.ejb.Local with "Ejb" and "Local".


            MATCH (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE a.fqn="javax.ejb.Local"
            SET t:Ejb:Local
            RETURN t AS LocalBean
ejb3:MessageDrivenBean

Labels all types annotated with @javax.ejb.MessageDriven with "Ejb" and "MessageDriven".


            MATCH (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE a.fqn="javax.ejb.MessageDriven"
            SET t:Ejb:MessageDriven
            RETURN t AS MessageDrivenBean
ejb3:Remote

Labels all types annotated with @javax.ejb.Remote with "Ejb" and "Remote".


            MATCH (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE a.fqn="javax.ejb.Remote"
            SET t:Ejb:Remote
            RETURN t AS RemoteBean
ejb3:SingletonBean

Labels all classes annotated with @javax.ejb.Singleton with "Ejb" and "Singleton".


            MATCH (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE a.fqn="javax.ejb.Singleton"
            SET t:Ejb:Singleton
            RETURN t AS SingletonEjb
ejb3:StatefulSessionBean

Labels all types annotated with @javax.ejb.Stateful with "Ejb" and "Stateful".


            MATCH (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE a.fqn="javax.ejb.Stateful"
            SET t:Ejb:Stateful
            RETURN t AS StatefulEjb
ejb3:StatelessSessionBean

Labels all types annotated with @javax.ejb.Stateless with "Ejb" and "Stateless".


            MATCH (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE a.fqn="javax.ejb.Stateless"
            SET t:Ejb:Stateless
            RETURN t AS StatelessEjb

jqassistant.plugin.jaxrs

Provides rules for JAX-RS.

jaxrs-resource.xml

Concepts
jaxrs:DeleteResourceMethod

Requires concepts:

Finds resource methods annotated with "@javax.ws.rs.DELETE" and labels them with DeleteResourceMethod.


            MATCH
              (m:JaxRS:ResourceMethod)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            WHERE
              a.fqn = "javax.ws.rs.DELETE"
            SET
              m:DeleteResourceMethod
            RETURN
              m as DeleteMethod
jaxrs:GetResourceMethod

Requires concepts:

Finds resource methods annotated with "@javax.ws.rs.GET" and labels them with GetResourceMethod.


            MATCH
              (m:JaxRS:ResourceMethod)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            WHERE
              a.fqn = "javax.ws.rs.GET"
            SET
              m:GetResourceMethod
            RETURN
              m as GetMethod
jaxrs:HeadResourceMethod

Requires concepts:

Finds resource methods annotated with "@javax.ws.rs.HEAD" and labels them with HeadResourceMethod.


            MATCH
              (m:JaxRS:ResourceMethod)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            WHERE
              a.fqn = "javax.ws.rs.HEAD"
            SET
              m:HeadResourceMethod
            RETURN
              m as HeadMethod
jaxrs:OptionsResourceMethod

Requires concepts:

Finds resource methods annotated with "@javax.ws.rs.OPTIONS" and labels them with OptionsResourceMethod.


            MATCH
              (m:JaxRS:ResourceMethod)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            WHERE
              a.fqn = "javax.ws.rs.OPTIONS"
            SET
              m:OptionsResourceMethod
            RETURN
              m as OptionsMethod
jaxrs:PostResourceMethod

Requires concepts:

Finds resource methods annotated with "@javax.ws.rs.POST" and labels them with PostResourceMethod.


            MATCH
              (m:JaxRS:ResourceMethod)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            WHERE
              a.fqn = "javax.ws.rs.POST"
            SET
              m:PostResourceMethod
            RETURN
              m as PostMethod
jaxrs:PutResourceMethod

Requires concepts:

Finds resource methods annotated with "@javax.ws.rs.PUT" and labels them with PutResourceMethod.


            MATCH
              (m:JaxRS:ResourceMethod)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            WHERE
              a.fqn = "javax.ws.rs.PUT"
            SET
              m:PutResourceMethod
            RETURN
              m as PutMethod
jaxrs:RequestMethodDesignator

Finds request method designator annotations (i.e. @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS) and labels them with JaxRS and RequestMethodDesignator


            MATCH
              (a:Type)
            WHERE
              a.fqn IN ["javax.ws.rs.GET", "javax.ws.rs.POST", "javax.ws.rs.PUT", "javax.ws.rs.DELETE", "javax.ws.rs.HEAD", "javax.ws.rs.OPTIONS"]
            SET
              a:JaxRS:RequestMethodDesignator
            RETURN
              a as RequestMethodDesignator
jaxrs:Resource

Requires concepts:

Finds classes or interfaces with atleast one method annotated with "@javax.ws.rs.Path" or with request method designator (i.e. @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS) and labels them with JaxRS and Resource.


            MATCH
              (t:Type)-[:DECLARES]->(m:Method)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:Type)
                        WHERE
              (a:JaxRS:RequestMethodDesignator OR a.fqn="javax.ws.rs.Path")
                        AND
              (t:Class OR t:Interface)
            SET
              t:JaxRS:Resource
            RETURN
              DISTINCT t as RestResource
jaxrs:ResourceMethod

Requires concepts:

Finds methods that belong to resource class or interface and annotated with request method designator (i.e. @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS) and labels them with JaxRS and ResourceMethod.


            MATCH
              (c:JaxRS:Resource)-[:DECLARES]->(m:Method)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:JaxRS:RequestMethodDesignator)
            SET
              m:JaxRS:ResourceMethod
            RETURN
              m as ResourceMethod
jaxrs:SubResourceLocator

Requires concepts:

Finds classes or interfaces with method annotated with "@javax.ws.rs.Path" but no request method designator and no entity parameters and labels the methods with JaxRS and SubResourceLocator.


            MATCH
              (t:Type)-[:DECLARES]->(m:Method)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:Type)
                        WHERE
              a.fqn = "javax.ws.rs.Path"
                        AND
              (t:Class OR t:Interface)
                        AND
              NOT (m)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(:JaxRS:RequestMethodDesignator)
                        AND
              (m)-[:HAS]->(:Parameter)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(:Type)
            SET
              m:JaxRS:SubResourceLocator
            RETURN
              DISTINCT m as RestSubResourceLocator

jaxrs-provider.xml

Concepts
jaxrs:ContextProvider

Finds classes that implement "javax.ws.rs.ext.ContextResolver" and labels them with JaxRS and ContextProvider


            MATCH
              (c:Type:Class)-[:IMPLEMENTS]->(a:Type)
                        WHERE
              a.fqn = "javax.ws.rs.ext.ContextResolver"
            SET
              c:JaxRS:ContextProvider
            RETURN
              DISTINCT c as ContextProvider
jaxrs:EntityProvider

Finds classes that implement "javax.ws.rs.ext.MessageBodyReader" or "javax.ws.rs.ext.MessageBodyWriter" and labels them with JaxRS and EntityProvider


            MATCH
              (c:Type:Class)-[:IMPLEMENTS]->(a:Type)
                        WHERE
              a.fqn IN ["javax.ws.rs.ext.MessageBodyReader", "javax.ws.rs.ext.MessageBodyWriter"]
            SET
              c:JaxRS:EntityProvider
            RETURN
              DISTINCT c as EntityProvider
jaxrs:ExceptionMappingProvider

Finds classes that implement "javax.ws.rs.ext.ExceptionMapper" and labels them with JaxRS and ExceptionMappingProvider


            MATCH
              (c:Type:Class)-[:IMPLEMENTS]->(a:Type)
                        WHERE
              a.fqn = "javax.ws.rs.ext.ExceptionMapper"
            SET
              c:JaxRS:ExceptionMappingProvider
            RETURN
              DISTINCT c as ExceptionMappingProvider

jqassistant.plugin.java

Provides scanner for Java elements (e.g. packages, classes, manifest and property files) and rules for common language concepts (e.g. Deprecation), dependencies and metrics.

Package Scanner

Imports Java packages.

:Package

A Java package, i.e. a directory containing .class files or other directories.

Table 1. Properties of :Package
Name Description

fqn

Fully qualified name, e.g. java.lang

name

The local name, e.g. lang

Table 2. Relations of :Package
Name Target label(s) Cardinality Description

CONTAINS

:Type

0..n

References a type located in the package

CONTAINS

:Package

0..n

References a package located in the package

Class Scanner

Imports Java classes, i.e. all scanned files having a .class suffix. Nodes with following labels will be created:

Note: Some of these labels may be further qualified.

:Type

A Java type. Can be qualified by either :Class, :Interface, :Enum or :Annotation

Table 3. Properties of :Type
Name Description

fqn

Fully qualified name, e.g. java.lang.Object

name

The local name, e.g. Object

visibility

optional, the visibility of the type, can be either public, protected, default or private

abstract

optional, true indicates that the type is abstract, e.g. public abstract class …

static

optional, true indicates that the type has the static modifier, e.g. private static class …

final

optional, true indicates that the type is final, e.g. public final class…

synthetic

optional, true indicates that the type is synthetic, i.e. it has been generated

Table 4. Relations of :Type
Name Target label(s) Cardinality Description

DECLARES

:Type

0..n

Declares an inner type of the type

DECLARES

:Method

0..n

Declares a method of the type

DECLARES

:Field

0..n

Declares a field of the type

EXTENDS

:Type

0..1

References a type this type extends from

IMPLEMENTS

:Type

0..1

References an "Interface" type this type implements

ANNOTATED_BY

:Value:Annotation

0..n

References an annotation which is present on the type

DEPENDS_ON

:Type

0..n

References a type which this type depends on according to its signature (e.g. due to generic type parameters)

:Type:Class

Qualifies a Java type as class.

:Type:Interface

Qualifies a Java type node as interface.

:Type:Enum

Qualifies a Java type as enumeration.

:Type:Annotation

Qualifies a Java type as annotation.

:Field

A field declared in a Java type.

Table 5. Properties of :Field
Name Description

name

The field name, e.g. id

signature

The raw signature of the field, e.g. int id

visibility

optional, The visibility of the field, can be either public, protected, default or private

static

optional, true indicates that the field has the static modifier, e.g. static int id;

final

optional, true indicates that the field is final, e.g. final int id;

transient

optional, true indicates that the field is transient, e.g. transient int id;

volatile

optional, true indicates that the field is volatile, e.g. volatile int id;

synthetic

optional, true indicates that the field is synthetic, i.e. it has been generated

Table 6. Relations of :Field
Name Target label(s) Cardinality Description

OF_TYPE

:Type

1

References the type of the field

ANNOTATED_BY

:Value:Annotation

0..n

References an annotation which is present on the field

DEPENDS_ON

:Type

0..n

References a type which this field depends on according to its signature (e.g. generic type parameters)

:Method

A method declared in a Java type.

Table 7. Properties of :Method
Name Description

name

The method name, e.g. getId

signature

The raw signature of the method, e.g. int getId()

visibility

optional, The visibility of the method, can be either public, protected, default or private

static

optional, true indicates that the method has the static modifier, e.g. static int getId();

final

optional, true indicates that the method is final, e.g. final int getId();

native

optional, true indicates that the method is native, e.g. native int getId();

synthetic

optional, true indicates that the method is synthetic, i.e. it has been generated

Table 8. Relations of :Method
Name Target label(s) Cardinality Description

HAS

:Parameter

0..n

References a parameter of the method

THROWS

:Type

0..n

References the exception type thrown by the method

RETURNS

:Type

0..n

References the return type of the method

ANNOTATED_BY

:Value:Annotation

0..n

References an annotation which is present on the method declaration

READS

:Field

0..n

References a field which is read by the method

WRITES

:Field

0..n

References a field which is written by the method

INVOKES

:Method

0..n

References a method which is invoked by the method

DEPENDS_ON

:Type

0..n

References a type which this method depends on (e.g. generic type parameters, dependencies from the method body)

:Method:Constructor

Qualifies a method as constructor.

:Parameter

A method parameter.

Table 9. Properties of :Parameter
Name Description

index

The index of the parameter according to the method signature (starting with 0)

Table 10. Properties of :Parameter
Name Target label(s) Cardinality Description

OF_TYPE

:Type

1

References the type of the parameter

ANNOTATED_BY

:Value:Annotation

0..n

References an annotation which is present on the parameter

DEPENDS_ON

:Type

0..n

References a type which this parameter depends on according to its signature (e.g. generic type parameters)

:Value

A value, can be qualified by either :Primitive, :Annotation, :Class, :Enum or :Array.

Table 11. Properties of :Value
Name Description

name

The method name, e.g. value

:Value:Primitive

A primitive value.

Table 12. Properties of :Value:Primitive
Name Description

value

The value

:Value:Annotation

Represents a annotation on a Java element, e.g. @Entity public class …

Table 13. Relations of :Value:Annotation:
Name Target label(s) Cardinality Description

OF_TYPE

:Type

1

References the type of the annotation

HAS

:Value

0..n

References an attribute of the annotation, e.g. @Entity(name="MyEntity")

:Value:Class

Represents a class instance, e.g. as specified by annotation attribute.

Table 14. Relations of :Value:Class:
Name Target label(s) Cardinality Description

IS

:Type

1

References the type

:Value:Enum

Represents an enum value.

Table 15. Relations of :Value:Enum:
Name Target label(s) Cardinality Description

IS

:Field

1

References the field representing the enumeration value

:Value:Array

Represents an array value, i.e. a node referencing value nodes.

Table 16. Relations of :Value:Array:
Name Target label(s) Cardinality Description

CONTAINS

:Value

0..n

References a value contained in the array

Manifest File Scanner

Imports manifest descriptors from META-INF/MANIFEST.MF files.

:File:Manifest

A MANIFEST.MF file containing sections.

Table 17. Properties of :File:Manifest
Name Description

fileName

The file name

Table 18. Relations of :Manifest
Name Target label(s) Cardinality Description

DECLARES

:ManifestSection

0..n

References a manifest section

:ManifestSection

A manifest section.

Table 19. Relations of :ManifestSection
Name Target label(s) Cardinality Description

HAS

:Value:ManifestEntry

0..n

References a manifest entry in the section

:Value:ManifestEntry

A manifest entry.

Table 20. Properties of :Value:ManifestEntry
Name Description

name

The name of the entry, e.g. Main-Class

value

The value of the entry, e.g. com.buschmais.jqassistant.scm.cli.Main

Property File Scanner

Imports property files, i.e. all files having a suffix .properties.

:File:Properties

A property file containing key/value pairs.

Table 21. Properties of :File:Properties
Name Description

fileName

The file name

Table 22. Relations of :File:Properties
Name Target label(s) Cardinality Description

HAS

:Value:Property

0..n

References a property value

:Value:Property

A key value/pair.

Table 23. Properties of :Value:Property
Name Description

name

The name of the property

value

The value of the property

Service Loader File Scanner

Imports service loader descriptors from "META-INF/services" directories.

:File:ServiceLoader

A file containing the implementation class names for a service interface

Table 24. Properties of :File:ServiceLoader
Name Description

fileName

The file name

Table 25. Relations of :File:ServiceLoader
Name Target label(s) Cardinality Description

OF_TYPE

:Type

1

The type representing the service interface

CONTAINS

:Type

0..n

References a type which implements the service interface

dependency.xml

Concepts
dependency:Annotation

Creates a DEPENDS_ON relationship between an annotated element and the types of the annotation and its values.


            match
                (e)-[:ANNOTATED_BY]->(a:Annotation)-[:OF_TYPE]->(at:Type)
            where
                e:Type
                or e:Method
                or e:Parameter
                or e:Field
            create unique
                (e)-[:DEPENDS_ON]->(at)
            with
                e, a
            match
                (a)-[:HAS|IS|CONTAINS|OF_TYPE*0..]->(vt:Type)
            create unique
                (e)-[:DEPENDS_ON]->(vt)
            return
                count(distinct e) as Elements
dependency:Artifact

Requires concepts:

Creates a DEPENDS_ON relationship between artifacts if there are type dependencies between them.


            match
                (a1:Artifact)-[:CONTAINS]->(t1:Type)-[:DEPENDS_ON]->(t2:Type)<-[:CONTAINS]-(a2:Artifact)
            where
                a1<>a2
            create unique
                (a1)-[:DEPENDS_ON]->(a2)
            return
                a1 as Artifact, collect(distinct a2.name) as Dependencies
dependency:FieldAccess

Creates a DEPENDS_ON relationship between a method and all fields types it reads and writes.


            match
                (m:Method)-[:READS|WRITES]->(target:Field),
                (dt:Type)-[:DECLARES]->(target)
            create unique
                (m)-[:DEPENDS_ON]->(dt)
            with
                m, target
            match
                  (target)-[:OF_TYPE|DEPENDS_ON]->(ft)
            create unique
                (m)-[:DEPENDS_ON]->(ft)
            return
                count(distinct m) as FieldAccesses
dependency:MethodInvocation

Requires concepts:

Creates a DEPENDS_ON relationship between a method and the dependencies of the method signature it invokes.


            match
                (m:Method)-[:INVOKES]->(target:Method),
                (dt:Type)-[:DECLARES]->(target)
            create unique
                (m)-[:DEPENDS_ON]->(dt)
            with
                m, target
            match
                (target)-[:HAS]->(:PARAMETER)-[:DEPENDS_ON]->(pt)
            create unique
                (m)-[:DEPENDS_ON]->(pt)
            with
                m, target
            match
                (target)-[:RETURNS]->(rt)
            create unique
                (m)-[:DEPENDS_ON]->(rt)
            return
                count(distinct m) as MethodInvocations
dependency:MethodParameter

Requires concepts:

Creates a DEPENDS_ON relationship between a method and the types of its parameters.


            match
                (m:Method)-[:HAS]->(p:Parameter)-[:OF_TYPE|DEPENDS_ON]->(t:Type)
            create unique
                (m)-[:DEPENDS_ON]->(t)
            return
                count(distinct p) as Parameters
dependency:Package

Requires concepts:

Creates a DEPENDS_ON relationship between a packages if there are type dependencies between them.


            match
                (p1:Package)-[:CONTAINS]->(t1:Type)-[:DEPENDS_ON]->(t2:Type)<-[:CONTAINS]-(p2:Package)
            where
                p1<>p2
            create unique
                (p1)-[:DEPENDS_ON]->(p2)
            return
                count(distinct p1) as Packages
dependency:Type

Requires concepts:

Creates a DEPENDS_ON relationship between a type and all types its signature and body depends on.


            match
                (t1:Type)-[:EXTENDS|IMPLEMENTS]->(t2:Type)
            where
                t1<>t2
            create unique
                (t1)-[:DEPENDS_ON]->(t2)
            return
                count(distinct t1) as Types
dependency:TypeBody

Requires concepts:

Creates a DEPENDS_ON relationship between a type and all types its body (i.e. methods and fields) depends on.


            match
                (t1:Type)-[:DECLARES*0..1]->(fieldOrMethod)-[:OF_TYPE|RETURNS|DEPENDS_ON|THROWS]->(t2:Type)
            where
                t1<>t2
                and (fieldOrMethod:Field OR fieldOrMethod:Method)
            create unique
                (t1)-[:DEPENDS_ON]->(t2)
            return
                count(distinct t1) as Types
Constraints
dependency:ArtifactCycles

Requires concepts:

There must be no cyclic artifact dependencies.


            match
                (a1:Artifact)-[:DEPENDS_ON]->(a2:Artifact),
                path=shortestPath((a2)-[:DEPENDS_ON*]->(a1))
            where
                a1<>a2
            return
                a1 as Artifact, extract(a in nodes(path) | a.fqn) AS Cycle
            order by
                Artifact.FQN
dependency:PackageCycles

Requires concepts:

There must be no cyclic package dependencies.


            match
                (p1:Package)-[:DEPENDS_ON]->(p2:Package),
                path=shortestPath((p2)-[:DEPENDS_ON*]->(p1))
            where
                p1<>p2
            return
                p1 as Package, extract(p in nodes(path) | p.fqn) as Cycle
            order by
                Package.fqn
dependency:TypeCycles

Requires concepts:

There must be no cyclic type dependencies.


            match
                (p1:Package)-[:DEPENDS_ON*0..1]->(p2:Package),
                shortestPath((p2)-[:DEPENDS_ON*]->(p1))
            with
                p1, p2
            match
                (p1)-[:CONTAINS]->(t1:Type),
                (p2)-[:CONTAINS]->(t2:Type),
                (t1)-[:DEPENDS_ON]->(t2),
                path=shortestPath((t2)-[:DEPENDS_ON*]->(t1))
            where
                not (
                  t1 = t2 or (t1)-[:DECLARES]-(t2)
                )
            return
                length(path) as Length, extract(p in nodes (path) | p.fqn) as Cycle

java.xml

Concepts
java:AnonymousInnerType

Requires concepts:

Sets a label "Anonymous" on anonymous inner types, i.e. types without a name.


            match
              (innerType:Inner:Type)
            where
              innerType.name =~ ".*\\$[0-9]*"
            set
              innerType:Anonymous
            return
              count(innerType) as AnonymousInnerTypes
java:Deprecated

Labels all nodes representing deprecated elements (types, fields, methods, packages or parameters) with "Deprecated".


            match
              (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(dt:Type)
            where
              dt.fqn='java.lang.Deprecated'
            SET
              e:Deprecated
            return
              count(e) AS DeprecatedElements
java:InnerType

Sets a label "Inner" on inner types.


            match
              (:Type)-[:DECLARES]->(innerType:Type)
            set
              innerType:Inner
            return
              count(innerType) as InnerTypes
java:InvokesOverriddenMethod

Requires concepts:

Propagates INVOKES relationships to methods which implement or override the invoked method.


            match
              (method:Method)-[:INVOKES]->(invokedMethod:Method),
              (overridingMethod:Method)-[:OVERRIDES]->(invokedMethod)
            create unique
              (method)-[r:INVOKES]->(overridingMethod)
            return count(r) AS OverridingInvocations
java:MethodOverloads

Creates a relationship OVERLOADS between two "Method" labeled nodes if one method overloads another one from the same type (i.e. the methods have the same name but not the same signature).


            match
              (type:Type)-[:DECLARES]->(method:Method),
              (type)-[:DECLARES]->(otherMethod:Method)
            where
              method <> otherMethod
              AND method.name = otherMethod.name
              AND method.signature <> otherMethod.signature
            create unique
                (method)-[:OVERLOADS]->(otherMethod)
            return count(method) AS OverloadedMethods
java:MethodOverrides

Requires concepts:

Creates a relationship OVERRIDES between two "Method" labeled nodes if one method overrides another one from a super type (i.e. the methods have the same signature).


            match
              (type:Type)-[:DECLARES]->(method:Method),
              (superType:Type)-[:DECLARES]->(otherMethod:Method),
              (superType)-[:ASSIGNABLE_FROM]->(type)
            where
              method.name = otherMethod.name
              AND method.signature = otherMethod.signature
              AND method.visibility <> 'private'
            create unique
              (method)-[:OVERRIDES]->(otherMethod)
            return count(method) as OverriddenMethods
java:TypeAssignableFrom

Creates a relationship ASSIGNABLE_FROM between two "Type" labeled nodes if one type is assignable from the other (i.e. a super class or interface).


            match
              (type:Type)
            create unique
              (type)-[:ASSIGNABLE_FROM]->(type)
            with
              type
            match
              (type)-[:IMPLEMENTS|EXTENDS*]->(superType:Type)
            create unique
              (superType)-[:ASSIGNABLE_FROM]->(type)
            return count(type) as AssignableTypes

package.xml

Constraints
package:PackageNameMustContainArtifactName

Verifies that all package names within an artifact contain the artifact name.


            MATCH
                (artifact:ARTIFACT)-[:CONTAINS]->(t:Type),
                (package:PACKAGE)-[:CONTAINS]->(t)
            WHERE NOT
                package.FQN =~ (".*" + artifact.NAME + ".*")
            RETURN DISTINCT
                artifact, package
            ORDER BY
                artifact.FQN, package.FQN
package:PackageNameMustStartWithArtifactGroup

Verifies that all package names within an artifact start with the group name.


            MATCH
                (artifact:ARTIFACT)-[:CONTAINS]->(t:Type),
                (package:PACKAGE)-[:CONTAINS]->(t)
            WHERE NOT
                package.FQN =~ (artifact.GROUP + ".*")
            RETURN DISTINCT
                artifact, package
            ORDER BY
                artifact.FQN, package.FQN

metric.xml

Concepts
metric:Top10FieldsPerType

Requires concepts:

Returns the top 10 types regarding to the number of declared fields.


            MATCH
                (t:Type)-[:DECLARES]->(f:Field)
            RETURN
                t.fqn as Type, COUNT(f) as FieldCount
            ORDER BY
                FieldCount DESC
            LIMIT 10
metric:Top10MethodsPerType

Requires concepts:

Returns the top 10 types regarding to the number of declared methods (including constructors).


            MATCH
                (t:Type)-[:DECLARES]->(m:Method)
            RETURN
                t.fqn as Type, COUNT(m) as MethodCount
            ORDER BY
                MethodCount DESC
            LIMIT 10
metric:Top10TypeFanIn

Requires concepts:

Returns the top 10 types regarding the number of other types depending on them.


            MATCH
                (t:Type)<-[:DEPENDS_ON]-(dependent:Type)
            RETURN
                t.fqn as Type, COUNT(dependent) as Dependents
            ORDER BY
                Dependents DESC
            LIMIT 10
metric:Top10TypeFanOut

Requires concepts:

Returns the top 10 types regarding the number of other types they depend on.


            MATCH
                (t:Type)-[:DEPENDS_ON]->(dependency:Type)
            RETURN
                t.fqn as Type, COUNT(dependency) as Dependencies
            ORDER BY
                Dependencies DESC
            LIMIT 10
metric:Top10TypesPerArtifact

Returns the top 10 artifacts regarding the number of contained types.


            MATCH
                (a:Artifact)-[:CONTAINS]->(t:Type)
            RETURN
                a.fqn as Artifact, COUNT(t) as Types
            ORDER BY
                Types DESC
            LIMIT 10
metric:Top10TypesPerPackage

Returns the top 10 packages regarding the number of contained types.


            MATCH
                (p:Package)-[:CONTAINS]->(t:Type)
            RETURN
                p.fqn as Package, COUNT(t) as Types
            ORDER BY
                Types DESC
            LIMIT 10

jqassistant.plugin.java8

Provides Java 8 specific rules, e.g. concepts for functional interfaces and default methods.

java8.xml

Concepts
java8:DefaultMethod

Labels default methods of interfaces with "Default".


            MATCH
              (type:Type:Interface)-[:DECLARES]->(defaultMethod:Method)
            WHERE NOT
              has(defaultMethod.abstract)
            SET
              defaultMethod:Default
            RETURN
              count(defaultMethod) AS DefaultMethods
java8:FunctionalInterface

Labels functional interfaces (i.e. to be used as lambda expressions) with "FunctionalInterface".


            MATCH
              (functionalInterface:Interface)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(functionalInterfaceType)
            WHERE
              functionalInterfaceType.fqn = 'java.lang.FunctionalInterface'
            SET
              functionalInterface:FunctionalInterface
            RETURN
              count(functionalInterface) AS FunctionalInterfaces

jqassistant.plugin.jpa2

Provides a scanner for persistence.xml descriptors and rules for JPA2 specific elements (e.g. entities).

Scanner for persistence.xml files

Imports persistence descriptors from META-INF/persistence.xml or WEB-INF/persistence.xml files.

:File:Jpa:Persistence

A persistence.xml file containing persistence units.

Table 26. Properties of :File:Jpa:Persistence
Name Description

fileName

The file name

version

The version of the JPA specification this descriptor represents, e.g. 2.0

Table 27. Relations of :File:Jpa:Persistence
Name Target label(s) Cardinality Description

CONTAINS

:Jpa:PersistenceUnit

0..n

References a contained persistence unit

:Jpa:PersistenceUnit

A persistence unit.

Table 28. Properties of :Jpa:PersistenceUnit
Name Description

description

The description of the persistence unit.

transactionType

The transaction type, can be RESOURCE_LOCAL or JTA

provider

The class name of the JPA provider.

jtaDatasource

The JNDI name of the transactional datasource

nonJtaDatasource

The JNDI name of the non-transactional datasource

validationMode

The validation mode, can be NONE, CALLBACK or AUTO

sharedCacheMode

The shared cache mode, e.g. NONE

Table 29. Relations of :Jpa:PersistenceUnit
Name Target label(s) Cardinality Description

CONTAINS

:Type

0..n

References a persistent type (entity) contained in the persistence unit

HAS

:Value:Property

0..n

References a property of the persistence unit

jpa2.xml

Concepts
jpa2:Embeddable

Labels all types annotated with @javax.persistence.Embeddable with "Jpa" and "Embeddable".


            MATCH
              (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE
              a.fqn="javax.persistence.Embeddable"
            SET
              t:Jpa:Embeddable
            RETURN
              t AS JpaEmbeddable
jpa2:Embedded

Labels all fields or methods annotated with @javax.persistence.Embedded with "Jpa" and "Embedded".


            MATCH
              (t:Type)-[:DECLARES]->(member),
              (member)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE
              (member:Field or member:Method)
              and a.fqn="javax.persistence.Embedded"
            SET
              member:Jpa:Embedded
            RETURN
              member AS JpaEmbedded
jpa2:EmbeddedId

Labels all fields or methods annotated with @javax.persistence.EmbeddedId with "Jpa" and "Embedded".


            MATCH
              (t:Type)-[:DECLARES]->(member),
              (member)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE
              (member:Field or member:Method)
              and a.fqn="javax.persistence.EmbeddedId"
            SET
              member:Jpa:EmbeddedId
            RETURN
              member AS EmbeddedId
jpa2:Entity

Labels all types annotated with @javax.persistence.Entity with "Jpa" and "Entity".


            MATCH
              (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            WHERE
              a.fqn="javax.persistence.Entity"
            SET
              t:Jpa:Entity
            RETURN
              t AS JpaEntity
jpa2:NamedQuery

Requires concepts:

Creates a node labeled with "Jpa" and "NamedQuery" for each @NamedQuery defined for an entity. Furthermore a relation DEFINES is created between the entity and the named query.


            MATCH
              (entity:Jpa:Entity)-[:ANNOTATED_BY]->(namedQueries)-[:OF_TYPE]->(namedQueriesType:Type),
              (namedQueries)-[:HAS]->(:Value:Array)-[:CONTAINS]->(namedQuery:Value:Annotation)-[:OF_TYPE]->(namedQueryType:Type),
              (namedQuery)-[:HAS]->(nameAttribute:Value),
              (namedQuery)-[:HAS]->(queryAttribute:Value)
            WHERE
              namedQueriesType.fqn = 'javax.persistence.NamedQueries'
              and namedQueryType.fqn = 'javax.persistence.NamedQuery'
              and nameAttribute.name = 'name'
              and queryAttribute.name = 'query'
            CREATE UNIQUE
              (entity)-[:DEFINES]->(n:Jpa:NamedQuery {name:nameAttribute.value, query:queryAttribute.value})
            RETURN
              entity as Entity, n.name as Name, n.query as Query
Constraints
jpa2:ValidationModeMustBeExplicitlySpecified

The validation mode of all persistence units must be explicitly specified and either set to CALLBACK or NONE.


            MATCH
              (pu:PersistenceUnit)
            WHERE
              not has(pu.validationMode)
              OR NOT (
                pu.validationMode='CALLBACK'
                OR pu.validationMode='NONE'
              )
            RETURN
              pu as PersistenceUnit

jqassistant.plugin.junit4

Provides scanner for JUnit test reports and rules (e.g. for test classes/methods and ignored tests).

Scanner for JUnit4 test suite results

Imports results from JUnit4 test suites matching the file name TEST-.xml.

:File:TestSuite

A file containing results of a JUnit4 test suite.

Table 30. Properties of :File:TestSuite
Name Description

fileName

The file name

name

The name of the test suite, e.g. the name of the class defining the suite

tests

The number of executed tests

failures

The number of failed tests

errors

The number of tests in error

skipped

The number of skipped tests

time

The time it took to run the suite

Table 31. Relations of :File:TestSuite
Name Target label(s) Cardinality Description

CONTAINS

:TestCase

0..n

References a test case

:TestCase

A test case.

Table 32. Properties of :TestCase
Name Description

name

The name of the test, e.g. the name of the test method

className

The name of the class containing the test

time

The time it took to run the test

result

The result of the test, either SUCCESS, FAILURE, ERROR or SKIPPED

junit4.xml

Concepts
junit4:IgnoreTestClassOrMethod

Labels all classes or methods annotated with "@org.junit.Ignore" with "Junit4" and "Ignore".


            match
              (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
            where
              a.fqn="org.junit.Ignore"
            set
              e:Junit4:Ignore
            return
              e as IgnoredElement
junit4:TestCaseImplementedByMethod

Creates a relation IMPLEMENTED_BY between all test cases from test reports and their implementing methods.


            match
              (testcase:TestCase)
            with
              testcase
            match
              (testclass:Type)-[:DECLARES]->(testmethod:Method)
            where
              testclass.fqn = testcase.className
              and testmethod.name = testcase.name
            create unique
              (testcase)-[:IMPLEMENTED_BY]->(testmethod)
            return
              count(testcase) as TestCases
junit4:TestClassOrMethod

Finds test methods (i.e. annotated with "@org.junit.Test") and labels them and their containing classes with "Test" and "Junit4".


            match
              (c:Type:Class)-[:DECLARES]->(m:Method)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:Type)
            where
              a.fqn="org.junit.Test"
            set
              c:Test:Junit4, m:Test:Junit4
            return
              c as TestClass, collect(m) as TestMethods

jqassistant.plugin.maven3

Provides a scanner for Maven 3 modules.

Scanner for Maven projects

Imports information from Maven projects.

:Maven:Project:File

A pom.xml file describing a single Maven project.

Table 33. Properties of :Maven:Project:File
Name Description

fileName

The directory of the project.

name

The name

groupId

The group id

artifactId

The artifact id

packaging

The packaging type, e.g. "jar"

version

The version

Table 34. Relations of :Maven:Project:File
Name Target label(s) Cardinality Description

CREATES

:Artifact

0..n

References an artifact created by the project

HAS_PARENT

:Maven:Project:File

0..1

References the parent project (optional)

HAS_MODULE

:Maven:Project:File

0..n

References modules of this project (optional)

:Artifact

Represents an artifact, e.g. a JAR-File.

Table 35. Properties of :Artifact
Name Description

groupId

The group id

artifactId

The artifact id

type

The type, e.g. "jar"

classifier

The classifiert

version

The version

Table 36. Relations of :Artifact
Name Target label(s) Cardinality Description

CONTAINS

:File

0..n

References a file contained in the artifact

DEPENDS_ON

:Artifact

0..n

References a artifact which is a declared dependency

Table 37. Properties of :DEPENDS_ON
Name Description

scope

The declared scope, e.g. "compile"

optional

"true" indicates that this dependency is optional.

jqassistant.plugin.osgi

Provides rules for OSGi bundles (e.g. Bundles, Activator).

osgi-bundle.xml

Concepts
osgi-bundle:Activator

Requires concepts:

Creates an ACTIVATES relation between a class and the bundle artifact if the class is declared as "Bundle-Activator" in the bundle manifest.


            match
              (bundle:Osgi:Bundle)-[:CONTAINS]->(manifest:File:Manifest),
              (manifest)-[:DECLARES]->(section:ManifestSection),
              (section)-[:HAS]->(entry:ManifestEntry),
              (bundle)-[:CONTAINS]->(activator:Class)
            where
              entry.name = "Bundle-Activator"
              and entry.value = activator.fqn
            create unique
              (activator)-[:ACTIVATES]->(bundle)
            return
              activator as Activator, bundle as Bundle
osgi-bundle:Bundle

Labels all artifacts with a manifest declaring a bundle name as "Osgi" and "Bundle" and adds the properties "bundleSymbolicName" and "bundleVersion".


            MATCH
              (bundle:Artifact)-[:CONTAINS]->(manifest:Manifest:File),
              (manifest)-[DECLARES]->(section:ManifestSection),
              (section)-[:HAS]->(nameEntry:ManifestEntry),
              (section)-[:HAS]->(versionEntry:ManifestEntry)
            WHERE
              nameEntry.name = "Bundle-SymbolicName"
              AND versionEntry.name = "Bundle-Version"
            SET
              bundle:Osgi:Bundle,
              bundle.bundleSymbolicName = nameEntry.value,
              bundle.bundleVersion = versionEntry.value
            RETURN
              bundle as Bundle, bundle.BundleSymbolicName as BundleSymbolicName, bundle.BundleVersion as BundleVersion
osgi-bundle:ExportPackage

Requires concepts:

Creates an EXPORTS relation from a bundle artifact to all packages which are declared as "Export-Package" in the bundle manifest.


            match
             (bundle:Osgi:Bundle)-[:CONTAINS]->(package:Package)
            with
              bundle, package, "(^|.*,)\\s*"+ replace(package.fqn, ".", "\\.")+"\\s*((;|,).*|$)" as pattern
            match
              (bundle)-[:CONTAINS]->(manifest:File:Manifest),
              (manifest)-[:DECLARES]->(section:ManifestSection),
              (section)-[:HAS]->(entry:ManifestEntry)
            where
              entry.name = "Export-Package"
              AND entry.value=~ pattern
            create unique
              (bundle)-[:EXPORTS]->(package)
            return
              bundle as Bundle, collect(package) as ExportedPackages
osgi-bundle:ImportPackage

Requires concepts:

Creates an IMPORTS relation from a bundle artifact to all packages which are declared as "Import-Package" in the bundle manifest.


            match
             (package:Package)
            with
              package, "(^|.*,)\\s*"+ replace(package.fqn, ".", "\\.")+"\\s*((;|,).*|$)" as pattern
            match
              (bundle:Osgi:Bundle)-[:CONTAINS]->(manifest:File:Manifest),
              (manifest)-[:DECLARES]->(section:ManifestSection),
              (section)-[:HAS]->(entry:ManifestEntry)
            where
              entry.name = "Import-Package"
              and entry.value =~ pattern
            create unique
              (bundle)-[:IMPORTS]->(package)
            return
              bundle as Bundle, collect(package) as ImportedPackages
osgi-bundle:InternalType

Requires concepts:

Labels all internal types (i.e. which are not located in an exported package) as "Internal".


            match
              (bundle:Bundle:Osgi)-[:CONTAINS]->(internalPackage:Package),
              (bundle)-[:CONTAINS]->(internalType:Type),
              (internalPackage)-[:CONTAINS]->(internalType:Type)
            where not
                (bundle)-[:EXPORTS]->(internalPackage)
            set
              internalType:Internal
            return bundle as Bundle, collect(internalType) as InternalTypes
Constraints
osgi-bundle:InternalTypeMustNotBePublic

Requires concepts:

Internal types must not be public if no depending types exist in other packages of the bundle.


            match
              (bundle:Osgi:Bundle)-[:CONTAINS]->(internalType:Type:Internal),
              (internalPackage:Package)-[:CONTAINS]->(internalType)
            optional match
              (bundle)-[:CONTAINS]->(otherPackage:Package),
              (otherPackage)-[:CONTAINS]->()-[:DEPENDS_ON]->(internalType)
            where
              internalType.visibility='public'
            with
              bundle, internalPackage, internalType, collect(otherPackage) as otherPackages
            where
              all(otherPackage in otherPackages where internalPackage = otherPackage)
              and not
                (internalType)-[:ACTIVATES]->(bundle)
            return
              bundle as Bundle, internalType as InternalType
osgi-bundle:UnusedInternalType

Requires concepts:

A bundle must not contain internal types which are not used by other types in the bundle.


            match
              (bundle:Osgi:Bundle)-[:CONTAINS]->(internalType:Type:Internal)
            where not (
                (internalType)-[:ACTIVATES]->(bundle)
              or
                (bundle)-[:CONTAINS]->(:Type)-[:DEPENDS_ON]->(internalType)
            )
            return
              bundle as Bundle, internalType as InternalType

jqassistant.plugin.tycho

Provides a scanner for tycho modules.

Scanner for Tycho projects

Adds Tycho specific resources to be scanned to the file system scanner.