# Manual

jQAssistant Team
info@jqassistant.org

The powerful Quality Assurance Tool for your Java application.

This document describes the concepts of jQAssistant and usage information.

## Overview

jQAssistant is a QA tool which allows the definition and validation of project specific rules on a structural level. It is built upon the graph database Neo4j and can easily be plugged into the build process to automate detection of constraint violations and generate reports about user defined concepts and metrics.

Example use cases:

- Enforce naming conventions, e.g. EJBs, JPA entities, test classes, packages, maven modules etc.

- Validate dependencies between modules of your project

- Separate API and implementation packages

- Detect common problems like cyclic dependencies or tests without assertions

The rules are expressed in Cypher - the easy-to-learn query language of Neo4j:

    MATCH
      (t:Test:Method)
    WHERE NOT
      (t)-[:INVOKES]->(:Assert:Method)
    RETURN
      t AS TestWithoutAssertion

## License

jQAssistant is contributed under GNU General Public License, v3.

## Quickstart

### Command Line

#### Installation

- Download and unpack the distribution, a directory ${project.artifactId}-${project.version} will be created.

#### Scan

Windows

    bin/jqassistant.cmd scan -f lib

Linux

    bin/jqassistant.sh scan -f lib

- The JAR files contained in the lib/ folder will be scanned.

##### Explore

Windows

    bin/jqassistant.cmd server

Linux

    bin/jqassistant.sh server

- Open a browser and navigate to http://localhost:7474

- Enter the follwoing query in the top level area and hit Ctrl-Enter:

    MATCH
      (t:Type)-[:DECLARES]->(m:Method)
    RETURN
      t.fqn AS Type, count(t) AS DeclaredMethods
    ORDER BY
      DeclaredMethods DESC
    LIMIT 20

### Maven

#### Add the plugin

Add the following lines to the parent pom.xml file of your project:

    <build>
        <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>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    <build>

    <reporting>
        <plugins>
            <plugin>
                <groupId>com.buschmais.jqassistant.scm</groupId>
                <artifactId>jqassistant-maven-plugin</artifactId>
                <reportSets>
                    <reportSet>
                        <reports>
                            <report>report</report>
                        </reports>
                    </reportSet>
                </reportSets>
            </plugin>
        </plugins>
    </reporting>

#### Add a rule

Within your parent module create a directory "jqassistant" and a rules file in it:

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

        <group id="default">
            <includeConstraint refId="my-rules:TestClassName" />
        </group>

        <constraint id="my-rules:TestClassName">
            <requiresConcept refId="junit4:TestClass" />
            <description>All JUnit test classes must have a name with suffix "Test".</description>
            <cypher><![CDATA[
                MATCH
                    (t:Junit4:Test:Class)
                WHERE NOT
                    t.name =~ ".*Test"
                RETURN
                    t AS InvalidTestClass
            ]]></cypher>
        </constraint>

    </jqa:jqassistant-rules>

#### Run the build

Execute the following command from your parent module:

    mvn install

The build will fail with the message specified by your rule if it is violated. If everything is fine you can also create a report as part of your Maven site:

    mvn site

#### Explore your application

jQAssistant comes with an integrated Neo4j server, you can run it using

    mvn jqassistant:server

- Open a browser and navigate to http://localhost:7474

- Enter the follwoing query in the top level area and hit Ctrl-Enter:

    MATCH
      (t:Type)-[:DECLARES]->(m:Method)
    RETURN
      t.fqn AS Type, count(t) AS DeclaredMethods
    ORDER BY
      DeclaredMethods DESC
    LIMIT 20

## Introduction

This chapter provides an introduction to the concepts of jQAssistant.

### How it works

The basic idea behind jQAssistant is to integrate the following steps into the build process of a software system:

1. Scan the generated artifacts and store structural information about them into a database

2. Analyze the structures using rules which are represented by queries

3. Report violations

jQAssistant itself is a plugin based framework. It comes with a pre-defined set of plugins containing scanners, rules and reports but can be easily extended by custom rules or implementations.

As database an embedded instance of Neo4j Community Edition is managed and used by jQAssistant. This means that no setup or configuration of a dedicated server is required. Neo4j has been chosen because:

- it is a mature open source graph database

- it allows easy modelling of structural elements of a software and their relations

- it comes with a very expressive and easy to learn query language (Cypher)

### Rules

Rules are expressed as Cypher queries and are specified in XML-files:

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

        <group id="default">
            <includeConstraint refId="my-rules:MyConstraint"/>
        </group>

        <constraint id="my-rules:MyConcept">
            <description>A human readable description of the concept.</description>
            <cypher><![CDATA[
                MATCH
                  ...
                WHERE
                  ...
                SET
                  ...
                CREATE
                  ...
                RETURN
                  ...
            ]]></cypher>
        </constraint>

        <constraint id="my-rules:MyConstraint">
            <requiresConcept refId="my-rules:MyConcept" />
            <description>A human readable description of the constraint.</description>
            <cypher><![CDATA[
                MATCH
                    ...
                WHERE
                    ...
                RETURN
                    ...
            ]]></cypher>
        </constraint>

    </jqa:jqassistant-rules>

Each rule comes with an unique id (e.g. "my-rules:MyConstraint") which can be referenced by other rules. jQAssistant will take care about executing the rules in the correct order. Furthermore a human readable description shall help developers to understand the rationale behind them.

A rule can optionally define the severity level. jQAssistant allows to break the build if there are violations in the configured severity level (or higher). For example, if the severity is set to critical, and if there are violated constraints with blocker and/or critical severity; the build will break. This feature allows projects to pay down their technical debt in an iterative manner.

Following severity levels are supported:

- info

- minor

- major

- critical

- blocker

#### Groups

A group is a set of rules that shall be executed together. This allows to adjust analysis depth for different types of builds, e.g. a Continuous Integration build (CI) can be configured to only execute rules with low costs (i.e. execution times) whereas a report build is allowed to run for a longer time with more expensive checks.

#### Concepts

The information created by the scanner represents the structure of a software project on a raw level. Concept rules allow enriching the database with higher level information to ease the process of writing queries that check for violations (i.e. constraints) . This typically means adding labels, properties or relations.

jQAssistant comes with language and framework plugins which include general technical concepts, e.g.

- "java:Entity" provided by the JPA2 plugin adds a label "Entity" to a node if it represents a class which is annotated by "@javax.persistence.Entity".

- "java:MethodOverrides" provided by the Java plugin adds a relation "OVERRIDES" between a method of a sub class to the super class methods it overrides.

It is recommended to use concepts to enrich the database with information which is specific for the concrete project, e.g. labels can be added to

- package nodes representing modules of the application ("Module")

- package nodes that represent technical layers ("UI", "EJB")

- class nodes representing elements with a specific role ("Controller", "Model")

NOTE Even if the primary intention of a concept is to enrich data it still must provide a return clause. If a concept returns an empty result a warning will be generated by jQAssistant. The rationale is that in such case the concept does not match the structure of the application and other rules which depend on it will probably not work as expected. The return clause of the concept shall preferably return a node/relation itself instead of an attribute of it. Similarly, return clauses with only count of matching nodes shall be avoided. With this, XML and HTML reports can provide additional information about the concept.

#### Constraints

A Constraint is a query which detects violations, e.g.

- classes with specific roles (e.g. entity, controller, etc.) that are either located in the wrong packages or have names that do not fit defined conventions

- invocations of methods which are deprecated and/or forbidden (e.g. constructors of java.util.Date)

- dependencies to other modules which are not allowed

A constraint can depend on one or more concepts and usually is referenced by one or more groups.

NOTE If a constraint returns a result jQAssistant will report an error including the provided description and information about the returned elements. This information shall help the developer to understand and fix the problem.

## Command Line

Shell scripts are provided for executing jQAssistant from the command line of Microsoft Windows® or Unix compatible systems. They are located in the bin/ directory of the distribution:

- jqassistant.cmd

- jqassistant.sh

The command line accepts tasks and their specific options:

    jqassistant.sh <task1> <task2> <task3> -<option1> -<option2>

The following example will scan the content of the directories classes/ and test-classes/:

    jqassistant.sh scan -f classes,test-classe

### Tasks

- scan

- analyze

- available-rules

- effective-rules

- report

- effective-rules

#### scan

##### Description

Scans files or directories and stores the gathered information in database.

##### Options

- -s, --storeDirectory <directory>

- -f <file1>,<file2> or --files <file1>,<file2>

  - specifies a list of files or directories to scan

- -u <url1>,<url2> or --urls <url1>,<url2>

  - specifies a list of URLs to scan

- -reset

  - reset the database before scanning

#### analyze

##### Description

Executes an analysis.

##### Options

- -concepts <concept1>,<concept2>

- -constraints <constraint1>,<constraint2>

- -groups <group1>,<group2>

- -s, --storeDirectory <directory>

- -r, --ruleDirectory <directory>

- -reportDirectory

- -severity <severity>

  - specifies the severity of a problem for the analysis to fail. The program will return with exit code 2.

  - values: 'info', 'minor', 'major', 'critical' or 'blocker'

  - default: 'minor'

#### available-rules

##### Description

List all available rules.

##### Options

- -r, --ruleDirectory <directory>

#### effective-rules

##### Description

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

##### Options

- -concepts <concept1>,<concept2>

- -constraints <constraint1>,<constraint2>

- -groups <group1>,<group2>

- -r, --ruleDirectory <directory>

#### report

##### Description

Transforms an XML report into HTML.

##### Options

- -reportDirectory

#### effective-rules

##### Description

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

##### Options

- -s, --storeDirectory <directory>

#### Common options

##### -s, --storeDirectory <directory>

- specifies the location of the database to use

- default: './jqassistant/store'

##### -concepts <concept1>,<concept2>

- specifies the ids of the concepts to be applied

##### -constraints <constraint1>,<constraint2>

- specifies the ids of the constraints to be validated

##### -groups <group1>,<group2>

- specifies the ids of the groups to be executed

- default: 'default'

##### -r, --ruleDirectory <directory>

- specifies the directory where reports (XML, HTML) will be stored

- default: './jqassistant/rules'

##### -reportDirectory

- specifies the directory where reports (XML, HTML) will be stored

- default: './jqassistant/report'

## 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

Software projects often consist of several modules which are assembled 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 "{project.build.directory}/jqassistant/store"

- the generated native report, default: "{project.build.directory}/jqassistant/jqassistant-report.xml")

- and the generated HTML report, default "{project.build.directory}/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-M4</version>
                    <executions>
                        <execution>
                            <id>scan</id>
                            <goals>
                                <goal>scan</goal>
                            </goals>
                            <!--
                            <configuration>
                                <scanIncludes>
                                    <scanInclude>
                                        <path>config</path>
                                    </scanInclude>
                                </scanIncludes>
                                <scanProperties>
                                    <customScanner.property>value</customScanner.property>
                                </scanProperties>
                            </configuration>
                            -->
                        </execution>
                        <execution>
                            <id>analyze</id>
                            <goals>
                                <goal>analyze</goal>
                            </goals>
                            <!--
                            <configuration>
                                <concepts>
                                    <concept>junit4:TestClass</concept>
                                </concepts>
                                <constraints>
                                    <constraint>junit4:TestMethodWithoutAssertion</constraints>
                                </constraints>
                                <groups>
                                    <group>default</group>
                                </groups>
                                <failOnViolations>true</failOnViolations>
                                <severity>critical</severity>
                            </configuration>
                             -->
                        </execution>
                    </executions>
                    <!--
                    <configuration>
                        <skip>false</skip>
                        <storeLifecycle>REACTOR</storeLifecycle>
                        <rulesDirectory>jqassistant</rulesDirectory>
                        <rulesDirectories>
                            <rulesDirectory>target/generated-rules</rulesDirectory>
                        </rulesDirectories>
                        <xmlReportFile>target/jqassistant/jqassistant-report.xml</xmlReportFile>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>com.buschmais.jqassistant.plugin</groupId>
                            <artifactId>jqassistant.plugin.jpa2</artifactId>
                            <version>1.0.0-M4</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-M4</version>
                    <reportSets>
                        <reportSet>
                            <reports>
                                <report>report</report>
                            </reports>
                        </reportSet>
                    </reportSets>
                    <!--
                    <configuration>
                        <reportProperties>
                            <customReport.fileName>target/customReport.txt</customReport.fileName>
                        </reportProperties>
                    </configuration>
                    -->
                </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

- jqassistant:reset

- jqassistant:server

- jqassistant:analyze

- jqassistant:effective-rules

- jqassistant:available-rules

- jqassistant:report

#### jqassistant:scan

##### Description

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

##### Configuration

- skip

- storeDirectory (-Djqassistant.store.directory)

- storeLifecycle (-Djqassistant.store.lifecycle)

- scanIncludes

  - add directories or files to be included while scanning

  - wildcards are not supported

- scanProperties

  - allows passing properties to scanner plugins.

#### jqassistant:reset

##### Description

Resets the database by deleting all nodes and relationships.

##### Configuration

- skip

- storeDirectory (-Djqassistant.store.directory)

- storeLifecycle (-Djqassistant.store.lifecycle)

#### jqassistant:server

##### Description

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

##### Configuration

- skip

- storeDirectory (-Djqassistant.store.directory)

- storeLifecycle (-Djqassistant.store.lifecycle)

#### jqassistant:analyze

##### Description

Executes an analysis.

##### Configuration

- skip

- storeDirectory (-Djqassistant.store.directory)

- storeLifecycle (-Djqassistant.store.lifecycle)

- concepts (-Djqassistant.concepts)

- constraints (-Djqassistant.constraints)

- groups (-Djqassistant.groups)

- rulesDirectory (-Djqassistant.rules.directory)

- rulesDirectories (-Djqassistant.rules.directories)

- xmlReportFile (-Djqassistant.report.xml)

- failOnViolations

  - determines if jQAssistant shall break the build if violations are detected (see also severity)

  - default: 'false'

- severity

  - determines if jQAssistant shall break the build when constraint with higher severity level are violated and failOnViolations is set to true

  - default: 'info'

#### jqassistant:effective-rules

##### Description

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

##### Configuration

- skip

- concepts (-Djqassistant.concepts)

- constraints (-Djqassistant.constraints)

- groups (-Djqassistant.groups)

- rulesDirectory (-Djqassistant.rules.directory)

- rulesDirectories (-Djqassistant.rules.directories)

#### jqassistant:available-rules

##### Description

List all available rules.

##### Configuration

- skip

- rulesDirectory (-Djqassistant.rules.directory)

- rulesDirectories (-Djqassistant.rules.directories)

#### jqassistant:report

##### Description

Transforms the XML report into HTML (i.e. for generating a Maven site).

##### Configuration

- xmlReportFile (-Djqassistant.report.xml)

### Common Configuration Properties

#### Execution

##### skip

- skip execution of the plugin

- default: 'false'

#### Store

##### storeDirectory (-Djqassistant.store.directory)

- specifies the location of the database

- default: '{rootModule}/target/jqassistant/store'

##### storeLifecycle (-Djqassistant.store.lifecycle)

- specifies the lifecycle of the data store

  - 'REACTOR': cache the store for the execution time of the reactor for fast operations

  - 'MODULE': open and close the store for each module

- default: 'REACTOR'

#### Analysis And Report

##### 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'

##### rulesDirectory (-Djqassistant.rules.directory)

- specifies the name of the directory which contains rules

- this directory is also used to identify the root module of a project, see Project Scope

- default: 'jqassistant'

##### rulesDirectories (-Djqassistant.rules.directories)

- specifies a list of directory names relative to the root module containing additional rules

##### xmlReportFile (-Djqassistant.report.xml)

- specifes the target file for writing the XML report

- default: '{rootModule}/target/jqassistant/jqassistant-report.xml'

## 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 Scanner Plugin

A custom scanner plugin allows extending the functionality of jQAssistant to read arbitrary structures (e.g. from files) and create the corresponding information in the database. The following example demonstrates this for CSV files.

The plugin is an artifact which contains the scanner implementation, model classes and a plugin descriptor. The project needs to declare the following dependencies:

pom.xml

            <dependency>
                <groupId>com.buschmais.jqassistant.core</groupId>
                <artifactId>jqassistant.core.scanner</artifactId>
                <version>1.0.0-M4</version>
            </dependency>
            <dependency>
                <groupId>com.buschmais.jqassistant.plugin</groupId>
                <artifactId>jqassistant.plugin.common</artifactId>
                <version>1.0.0-M4</version>
            </dependency>
            <dependency>
                <groupId>au.com.bytecode</groupId>
                <artifactId>opencsv</artifactId>
                <version>2.4</version>
            </dependency>
        </dependencies>

The artifact 'jqassistant.core.scanner' provides the scanner plugin API, 'jqassistant.plugin.common' contains common functionality shared by plugins, the library 'opencsv' is used to read CSV files.

The model to be stored in the database is defined using the approach provided by eXtended Objects. It is based on annotated interfaces declaring methods representing properties and relations.

First a label "CSV" is defined which is going to be used for all nodes created by the scanner:

com.buschmais.jqassistant.examples.plugins.scanner.model.CSVDescriptor

    @Label("CSV")
    public interface CSVDescriptor extends Descriptor {
    }

A CSV file is represented by CSVFileDescriptor which inherits from CSVDescriptor and FileDescriptor (part of the scanner API). Thus a node of this type will carry the labels "CSV" and "File". Furthermore a list of "HAS_ROW" relations is defined by the property "rows".

com.buschmais.jqassistant.examples.plugins.scanner.model.CSVFileDescriptor

    public interface CSVFileDescriptor extends CSVDescriptor, FileDescriptor {

        @Relation("HAS_ROW")
        List<CSVRowDescriptor> getRows();

    }

A single row is a node defined by the type CSVRowDescriptor which inherits the label "CSV" from CSVDescriptor and provides its own label "Row", a property "lineNumber" and a list of "HAS_COLUMN" relations.

com.buschmais.jqassistant.examples.plugins.scanner.model.CSVRowDescriptor

    @Label("Row")
    public interface CSVRowDescriptor extends CSVDescriptor {

        int getLineNumber();

        void setLineNumber(int lineNumber);

        @Relation("HAS_COLUMN")
        List<CSVColumnDescriptor> getColumns();
    }

CSVColumnDescriptor finally defines a column of a row following the principles explained above:

com.buschmais.jqassistant.examples.plugins.scanner.model.CSVColumnDescriptor

    @Label("Column")
    public interface CSVColumnDescriptor extends CSVDescriptor {

        String getValue();

        void setValue(String value);

        int getIndex();

        void setIndex(int index);

    }

The implementation of the plugin itself inherits from AbstractScannerPlugin which requires generic type parameters for the item type it handles and the descriptor type it creates. In the example FileResource is used which represents a file contained in a directory or archive. This allows plugins to be independent of the source where files or directories are picked up by the scanner.

The method accepts is called by the scanner to determine if the plugin can handle the given item. The example matches the value of the parameter path against the file extension ".csv". The scope parameter may be used to further restrict executions of the plugin, e.g. by checking equality against JavaScope.CLASSPATH.

The scan method actually reads the CSV file and stores the gathered data into the database using the interface Store provided by the scanner context.

com.buschmais.jqassistant.examples.plugins.scanner.CSVFileScannerPlugin

    public class CSVFileScannerPlugin extends AbstractScannerPlugin<FileResource, CSVFileDescriptor> {

        @Override
        public boolean accepts(FileResource item, String path, Scope scope) throws IOException {
            return path.toLowerCase().endsWith(".csv");
        }

        @Override
        public CSVFileDescriptor scan(FileResource item, String path, Scope scope, Scanner scanner) throws IOException {
            // Open the input stream for reading the file.
            try (InputStream stream = item.createStream()) {
                // Create the node for a CSV file.
                final Store store = scanner.getContext().getStore();
                final CSVFileDescriptor fileDescriptor = store.create(CSVFileDescriptor.class);
                // Parse the stream using OpenCSV.
                CSV csv = CSV.create();
                csv.read(stream, new CSVReadProc() {

                    @Override
                    public void procRow(int rowIndex, String... values) {
                        // Create the node for a row
                        CSVRowDescriptor rowDescriptor = store.create(CSVRowDescriptor.class);
                        fileDescriptor.getRows().add(rowDescriptor);
                        rowDescriptor.setLineNumber(rowIndex);
                        for (int i = 0; i < values.length; i++) {
                            // Create the node for a column
                            CSVColumnDescriptor columnDescriptor = store.create(CSVColumnDescriptor.class);
                            rowDescriptor.getColumns().add(columnDescriptor);
                            columnDescriptor.setIndex(i);
                            columnDescriptor.setValue(values[i]);
                        }
                    }

                });
                return fileDescriptor;
            }
        }
    }

Finally the model and 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>Provides a scanner for CSV file.</description>
        <model>
            <class>com.buschmais.jqassistant.examples.plugins.scanner.model.CSVFileDescriptor</class>
            <class>com.buschmais.jqassistant.examples.plugins.scanner.model.CSVRowDescriptor</class>
            <class>com.buschmais.jqassistant.examples.plugins.scanner.model.CSVColumnDescriptor</class>
        </model>
        <scanner>
            <class>com.buschmais.jqassistant.examples.plugins.scanner.CSVFileScannerPlugin</class>
        </scanner>
    </jqa-plugin:jqassistant-plugin>

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

#### Custom Rule Plugin

Rules (i.e. concepts, constraints or groups) can be shared between projects by packaging their rule descriptors in JAR artifacts as a classpath resources under /META-INF/jqassistant-rules/, e.g.

/META-INF/jqassistant-rules/common.xml

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

        <constraint id="common:TopLevelPackage">
            <description>All types defined in a project must use "com.buschmais" as top level package.</description>
            <cypher><![CDATA[
                MATCH
                  (:Artifact)-[:CONTAINS]->(type:Type)
                WHERE
                  NOT type.fqn =~ "com\\.buschmais\\..*"
                RETURN
                  type AS TypeInWrongPackage
            ]]></cypher>
        </constraint>

    </jqa:jqassistant-rules>

Furthermore these resources must be declared in the jQAssistant plugin descriptor /META-INF/jqassistant-plugin.xml:

/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 set of custom rules.</description>
        <rules>
            <resource>common.xml</resource>
        </rules>
    </jqa-plugin:jqassistant-plugin>

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

#### Custom Report Plugin

A custom report plugin may be implemented to create custom representations of analysis results. Such a plugin must be provided as an artifact which contains a Java class and a plugin descriptor. Therefore a project is required which declares the required dependencies:

pom.xml

            <dependency>
                <groupId>com.buschmais.jqassistant.core</groupId>
                <artifactId>jqassistant.core.report</artifactId>
                <version>1.0.0-M4</version>
            </dependency>
            <dependency>
                <groupId>com.buschmais.jqassistant.plugin</groupId>
                <artifactId>jqassistant.plugin.java</artifactId>
                <version>1.0.0-M4</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

            <plugins>
                <plugin>
                    <groupId>com.buschmais.jqassistant.scm</groupId>
                    <artifactId>jqassistant-maven-plugin</artifactId>
                    <version>1.0.0-M4</version>
                    <configuration>
                        <reportProperties>
                            <customReport.fileName>target/customReport.txt</customReport.fileName>
                        </reportProperties>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>com.buschmais.jqassistant.examples</groupId>
                            <artifactId>jqassistant.examples.plugins.scanner</artifactId>
                            <version>1.0.0-M4</version>
                        </dependency>
                        <dependency>
                            <groupId>com.buschmais.jqassistant.examples</groupId>
                            <artifactId>jqassistant.examples.plugins.rule</artifactId>
                            <version>1.0.0-M4</version>
                        </dependency>
                        <dependency>
                            <groupId>com.buschmais.jqassistant.examples</groupId>
                            <artifactId>jqassistant.examples.plugins.report</artifactId>
                            <version>1.0.0-M4</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </build>

### 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.

The plugin is available from the standalone distribution in the folder "sonar/" and must be copied to the directory "extensions/plugins" of the SonarQube server. After startup a repository 'jQAssistant' is available in the view 'Coding rules' providing all rules which are distributed with jQAssistant.

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 custom rule extension (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>
                                        <failOnViolations>true</failOnViolations>
                                        <severity>critical</severity>
                                    </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 break if a violation is detected, therefore 'failOnViolations' is set to 'true'.

- The build shall break only if violation is detected with severity equal to or higher than critical, therefore severity is set to critical

#### Custom Rule Extension

A custom rule extension can be implemented to make user defined jQAssistant rules available for SonarQube. It is a Maven project which declares packaging 'sonar-plugin':

pom.xml

    <project ...>
    ...

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

        <build>
            <plugins>
                <plugin>
                    <groupId>com.buschmais.jqassistant.scm</groupId>
                    <artifactId>jqassistant-maven-plugin</artifactId>
                </plugin>
                <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-M4</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" severity="critical">
            <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.cdi

Provides rules for CDI.

cdi.xml decorator.xml interceptor.xml

Scanner for beans.xml files

#### Scanner for beans.xml files

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

##### :File:Cdi:Beans

Represents a beans.xml file.

Table 1. Properties of :File:Cdi:Beans
Name | Description
--- | ---
fileName | The file name
version | The version of the CDI specification this descriptor represents, e.g. '1.0'
beanDiscoveryMode | The bean discovery mode, i.e. "all", "annotated" or "none"

Table 2. Relations of :File:Cdi:Beans
Name | Target label(s) | Cardinality | Description
--- | --- | --- | ---
HAS_INTERCEPTOR | :Type | 0..n | References an interceptor type which is activated
HAS_DECORATOR | :Type | 0..n | References a decorator type which is activated
HAS_ALTERNATIVE | :Type | 0..n | References an alternative type (class or stereotype annotation) which is activated

#### cdi.xml

##### Concepts

###### cdi:Alternative

Labels all types annotated by @javax.enterprise.inject.Alternative with "Cdi" and "Alternative".

                MATCH
                  (alternative:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(alternativeType:Type)
                WHERE
                  alternativeType.fqn="javax.enterprise.inject.Alternative"
                SET
                  alternative:Cdi:Alternative
                RETURN
                  alternative AS Alternative

###### cdi:Any

Labels all elements annotated by "javax.enterprise.inject.Any" with "Cdi" and "Any".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(anyType:Type)
                WHERE
                  anyType.fqn = "javax.enterprise.inject.Any"
                SET
                  e:Cdi:Any
                RETURN
                  e AS Any

###### cdi:ApplicationScoped

Labels all beans, fields or methods annotated by @javax.enterprise.context.ApplicationScoped with "Cdi" and "ApplicationScoped".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(scopeType:Type)
                WHERE
                  (e:Type or e:Method or e:Field)
                  and scopeType.fqn="javax.enterprise.context.ApplicationScoped"
                SET
                  e:Cdi:ApplicationScoped
                RETURN
                  e AS ApplicationScopedElement

###### cdi:ConversationScoped

Labels all beans, fields or methods annotated by @javax.enterprise.context.ConversationScoped with "Cdi" and "ConversationScoped".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(scopeType:Type)
                WHERE
                  (e:Type or e:Method or e:Field)
                  and scopeType.fqn="javax.enterprise.context.ConversationScoped"
                SET
                  e:Cdi:ConversationScoped
                RETURN
                  e AS ConversationScopedElement

###### cdi:Decorator

Requires concepts:

- cdi:Delegate

Labels all types annotated by @javax.decorator.Decorator with "Cdi" and "Decorator".

                MATCH
                  (decorator:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(decoratorType:Type)
                WHERE
                  decoratorType.fqn="javax.decorator.Decorator"
                SET
                  decorator:Cdi:Decorator
                RETURN
                  decorator AS Decorator

###### cdi:Default

Labels all elements annotated by "javax.enterprise.inject.Default" with "Cdi" and "Default".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(defaultType:Type)
                WHERE
                  defaultType.fqn = "javax.enterprise.inject.Default"
                SET
                  e:Cdi:Default
                RETURN
                  e AS Default

###### cdi:Delegate

Labels all fields annotated annotated by @javax.decorator.Delegate with "Cdi" and "Delegate".

                MATCH
                  (delegate:Field)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(delegateType:Type)
                WHERE
                  delegateType.fqn="javax.decorator.Delegate"
                SET
                  delegate:Cdi:Delegate
                RETURN
                  delegate AS Delegate

###### cdi:Dependent

Labels all beans, fields or methods annotated by @javax.enterprise.context.Dependent with "Cdi" and "Dependent".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(scopeType:Type)
                WHERE
                  (e:Type or e:Method or e:Field)
                  and scopeType.fqn="javax.enterprise.context.Dependent"
                SET
                  e:Cdi:Dependent
                RETURN
                  e AS DependentElement

###### cdi:Disposes

Creates a relation DISPOSES between a parameter and its type if the parameter is annotated by @javax.enterprise.inject.Disposes.

                MATCH
                  (:Type)-[:DECLARES]->(disposeMethod:Method)-[:HAS]->(parameter:Parameter),
                  (parameter)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(disposesType:Type),
                  (parameter)-[:OF_TYPE]->(type)
                WHERE
                  disposesType.fqn="javax.enterprise.inject.Disposes"
                CREATE UNIQUE
                  (parameter)-[:DISPOSES]->(type)
                RETURN
                  disposeMethod AS DisposeMethod

###### cdi:EventConsumer

Requires concepts:

- cdi:InjectionPoint

Labels all beans declaring method that has parameter of type "javax.enterprise.event.Observes" with "Cdi" and "EventConsumer".

                MATCH
                  (a:Type)-[:DECLARES]->(member:Method)-[:HAS]->(param:Parameter),
                  (param)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(injectType:Type)
                WHERE
                  injectType.fqn = "javax.enterprise.event.Observes"
                SET
                  a:Cdi:EventConsumer
                RETURN
                  DISTINCT a.fqn AS cdiEventConsumer

###### cdi:EventProducer

Requires concepts:

- cdi:InjectionPoint

Labels all beans declaring "InjectionPoint" of type "javax.enterprise.event.Event" with "Cdi" and "EventProducer".

                MATCH
                  (a:Type)-[:DECLARES]->(member:Field:Cdi:InjectionPoint),
                  (member)-[:OF_TYPE]->(injectType:Type)
                WHERE
                  injectType.fqn = "javax.enterprise.event.Event"
                SET
                  a:Cdi:EventProducer
                RETURN
                  DISTINCT a.fqn AS cdiEventProducers

###### cdi:InjectionPoint

Labels all fields or methods annotated by @javax.inject.Inject with "Cdi" and "InjectionPoint".

                MATCH
                  (:Type)-[:DECLARES]->(member),
                  (member)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(injectType:Type)
                WHERE
                  (member:Field or member:Method)
                  and injectType.fqn="javax.inject.Inject"
                SET
                  member:Cdi:InjectionPoint
                RETURN
                  member AS InjectionPoint

###### cdi:Named

Labels all types or methods annotated by "javax.inject.Named" with "Cdi" and "Named".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(namedType:Type)
                WHERE
                  namedType.fqn = "javax.inject.Named"
                SET
                  e:Cdi:Named
                RETURN
                  e AS Named

###### cdi:New

Labels all elements annotated by "javax.enterprise.inject.New" with "Cdi" and "New".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(newType:Type)
                WHERE
                  newType.fqn = "javax.enterprise.inject.New"
                SET
                  e:Cdi:New
                RETURN
                  e AS New

###### cdi:Produces

Creates a relation PRODUCES between a field and its type or a method and its return type if the parameter is annotated by @javax.enterprise.inject.Disposes.

                MATCH
                  (:Type)-[:DECLARES]->(member),
                  (member)-[:OF_TYPE|RETURNS]->(type),
                  (member)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(producesType:Type)
                WHERE
                  (member:Field or member:Method)
                  and producesType.fqn="javax.enterprise.inject.Produces"
                CREATE UNIQUE
                  (member)-[:PRODUCES]->(type)
                RETURN
                  member AS Producer

###### cdi:Qualifier

Labels all annotation types annotated by @javax.inject.Qualifier with "Cdi" and "Qualifier" and adds the labels "Cdi" and "Nonbinding" to all non-binding annotation values (i.e. which are annotated by @javax.enterprise.util.Nonbinding).

                MATCH
                  (qualifier:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(qualifierType:Type)
                WHERE
                  qualifierType.fqn = "javax.inject.Qualifier"
                SET
                  qualifier:Cdi:Qualifier
                WITH
                  qualifier
                MATCH
                  (qualifier)-[:DECLARES]->(attribute:Method),
                  (attribute)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(nonbindingType:Type)
                WHERE
                  nonbindingType.fqn = "javax.enterprise.util.Nonbinding"
                SET
                  attribute:Cdi:Nonbinding
                RETURN
                  distinct qualifier AS Qualifier

###### cdi:RequestScoped

Labels all beans, fields or methods annotated by @javax.enterprise.context.RequestScoped with "Cdi" and "RequestScoped".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(scopeType:Type)
                WHERE
                  (e:Type or e:Method or e:Field)
                  and scopeType.fqn="javax.enterprise.context.RequestScoped"
                SET
                  e:Cdi:RequestScoped
                RETURN
                  e AS RequestScopedElement

###### cdi:SessionScoped

Labels all beans, fields or methods annotated by @javax.enterprise.context.SessionScoped with "Cdi" and "SessionScoped".

                MATCH
                  (e)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(scopeType:Type)
                WHERE
                  (e:Type or e:Method or e:Field)
                  and scopeType.fqn="javax.enterprise.context.SessionScoped"
                SET
                  e:Cdi:SessionScoped
                RETURN
                  e AS SessionScopedElement

###### cdi:SingletonScoped

Labels all beans annotated by @javax.inject.Singleton with "Cdi" and "SingletonScoped".

                MATCH
                  (t:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
                WHERE
                  a.fqn = "javax.inject.Singleton"
                SET
                  t:Cdi:SingletonScoped
                RETURN
                  t AS cdiSingleton

###### cdi:Specializes

Labels all types and methods annotated by @javax.enterprise.inject.Specializes with "Cdi" and "Specializes".

                MATCH
                  (specializes)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(specializesType:Type)
                WHERE
                  (specializes:Type or specializes:Method)
                  and specializesType.fqn="javax.enterprise.inject.Specializes"
                SET
                  specializes:Cdi:Specializes
                RETURN
                  specializes AS Specialization

###### cdi:Stereotype

Labels all annotation types annotated by @javax.enterprise.inject.Stereotype with "Cdi" and "Stereotype".

                MATCH
                  (stereotype:Type:Annotation)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(stereotypeType:Type)
                WHERE
                  stereotypeType.fqn="javax.enterprise.inject.Stereotype"
                SET
                  stereotype:Cdi:Stereotype
                RETURN
                  stereotype AS Stereotype

##### Constraints

###### cdi:BeansMustNotUseFieldInjection

Requires concepts:

- cdi:InjectionPoint

CDI beans shall not use field injection (constructor and setter injections are fine.).

                MATCH
                  (a:Type)-[:DECLARES]->(member:Field:Cdi:InjectionPoint)
                RETURN
                  DISTINCT a.fqn AS invalidBean

###### cdi:BeansMustUseConstructorInjection

Requires concepts:

- cdi:InjectionPoint

All CDI beans must use constructor injection.

                MATCH
                  (a:Type)-[:DECLARES]->(member:Cdi:InjectionPoint)
                WHERE
                  NOT member:Constructor
                RETURN
                  DISTINCT a.fqn AS invalidBean

#### decorator.xml

##### Concepts

###### decorator:Decorator

Requires concepts:

- decorator:Delegate

Labels all types annotated by @javax.decorator.Decorator with "Decorator".

                MATCH
                  (decorator:Type)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(decoratorType:Type)
                WHERE
                  decoratorType.fqn="javax.decorator.Decorator"
                SET
                  decorator:Decorator
                RETURN
                  decorator AS Decorator

###### decorator:Delegate

Labels all fields annotated annotated by @javax.decorator.Delegate with "Decorator" and "Delegate".

                MATCH
                  (delegate:Field)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(delegateType:Type)
                WHERE
                  delegateType.fqn="javax.decorator.Delegate"
                SET
                  delegate:Decorator:Delegate
                RETURN
                  delegate AS Delegate

#### interceptor.xml

##### Concepts

###### interceptor:Binding

Labels all annotations annotated by "javax.interceptor.InterceptorBinding" with "Interceptor" and "Binding".

                MATCH
                  (binding:Type:Annotation)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(bindingType:Type)
                WHERE
                  bindingType.fqn = "javax.interceptor.InterceptorBinding"
                SET
                  binding:Interceptor:Binding
                RETURN
                  binding AS InterceptorBinding

###### interceptor:Interceptor

Labels all classes annotated by "javax.interceptor.Interceptor" with "Interceptor".

                MATCH
                  (interceptor:Type:Class)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(interceptorType:Type)
                WHERE
                  interceptorType.fqn = "javax.interceptor.Interceptor"
                SET
                  interceptor:Interceptor
                RETURN
                  interceptor AS Interceptor

### jqassistant.plugin.ejb3

Provides rules for EJB3.

ejb3.xml

#### 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 jaxrs-provider.xml

#### jaxrs-resource.xml

##### Concepts

###### jaxrs:DeleteResourceMethod

Requires concepts:

- jaxrs:ResourceMethod

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:

- jaxrs:ResourceMethod

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:

- jaxrs:ResourceMethod

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:

- jaxrs:ResourceMethod

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:

- jaxrs:ResourceMethod

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:

- jaxrs:ResourceMethod

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:

- jaxrs:RequestMethodDesignator

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:

- jaxrs:Resource

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:

- jaxrs:RequestMethodDesignator

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.

dependency.xml java.xml metric.xml

Package Scanner Class Scanner Manifest File Scanner Property File Scanner Service Loader File Scanner

#### Package Scanner

Imports Java packages.

##### :Package

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

Table 3. Properties of :Package
Name | Description
--- | ---
fqn | Fully qualified name, e.g. 'java.lang'
name | The local name, e.g. 'lang'

Table 4. 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:

:Type :Field :Method :Parameter :Value

NOTE Some of these labels may be further qualified with other labels, see the description below.

NOTE The full set of information is only available for class files which have actually been scanned. Types which are only referenced (i.e. from external libraries not included in the scan) are represented by ':TYPE' nodes with a property 'fqn' and 'DECLARES' relations to their members. These are ':FIELD' or ':METHOD' labeled nodes which only provide the property 'signature'.

##### :Type

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

Table 5. 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 6. 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)

NOTE Types which are referenced by scanned classes but have not been scanned themselves will only provide the property "fqn" and the relation "DECLARES".

NOTE Inheritance between interfaces (i.e. "public interface A extends B { …​ }") is represented using IMPLEMENTS relations, i.e. queries must use (a:Type:Interface)-[:IMPLEMENTS]→(b:Type:Interface) for pattern matching.

##### :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 7. Properties of :Field
Name | Description
--- | ---
name | The field name, e.g. 'id'
signature | The raw signature of the field, e.g. 'int id', 'java.lang.String toString()'
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 8. 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)

NOTE Fields which are referenced by scanned classes but have not been scanned themselves will only provide the property "signature".

##### :Method

A method declared in a Java type.

Table 9. Properties of :Method
Name | Description
--- | ---
name | The method name, e.g. 'getId'
signature | The raw signature of the method, e.g. 'int getId()', 'java.lang.String concat(java.lang.String,java.lang.String)'
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 10. 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)

NOTE Methods which are referenced by scanned classes but have not been scanned themselves will only provide the property "signature".

##### :Method:Constructor

Qualifies a method as constructor.

##### :Parameter

A method parameter.

Table 11. Properties of :Parameter
Name | Description
--- | ---
index | The index of the parameter according to the method signature (starting with 0)

Table 12. 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 13. Properties of :Value
Name | Description
--- | ---
name | The method name, e.g. 'value'

##### :Value:Primitive

A primitive value.

Table 14. Properties of :Value:Primitive
Name | Description
--- | ---
value | The value

##### :Value:Annotation

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

Table 15. 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 16. Relations of :Value:Class:
Name | Target label(s) | Cardinality | Description
--- | --- | --- | ---
IS | :Type | 1 | References the type

##### :Value:Enum

Represents an enum value.

Table 17. 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 18. 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 19. Properties of :File:Manifest
Name | Description
--- | ---
fileName | The file name

Table 20. Relations of :Manifest
Name | Target label(s) | Cardinality | Description
--- | --- | --- | ---
DECLARES | :ManifestSection | 0..n | References a manifest section

##### :ManifestSection

A manifest section.

Table 21. 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 22. 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 23. Properties of :File:Properties
Name | Description
--- | ---
fileName | The file name

Table 24. 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 25. 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 26. Properties of :File:ServiceLoader
Name | Description
--- | ---
fileName | The file name

Table 27. 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
                    e AS AnnotatedType, COUNT(DISTINCT vt) as Elements

###### dependency:Artifact

Requires concepts:

- dependency:Type

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
                    m AS method, COUNT(DISTINCT ft) AS FieldAccesseCount

###### dependency:MethodInvocation

Requires concepts:

- dependency:MethodParameter

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
                    m AS Method, COUNT(DISTINCT rt) AS MethodInvocations

###### dependency:MethodParameter

Requires concepts:

- dependency:Annotation

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
                    m AS Method, COUNT(DISTINCT t) as Parameters

###### dependency:Package

Requires concepts:

- dependency:Type

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
                    p1 AS package, COUNT(DISTINCT p2) AS PackageDependencyCount

###### dependency:Type

Requires concepts:

- dependency:TypeBody

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
                    t1 AS Type, COUNT(DISTINCT t2) AS DependencyCount

###### dependency:TypeBody

Requires concepts:

- dependency:Annotation

- dependency:MethodParameter

- dependency:MethodInvocation

- dependency:FieldAccess

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
                    t1 AS Type, COUNT(DISTINCT t2) AS DependencyCount

##### Constraints

###### dependency:ArtifactCycles

Requires concepts:

- dependency:Artifact

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:

- dependency:Package

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:

- dependency:Package

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:

- java:InnerType

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
                  innerType AS AnonymousInnerType

###### 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
                  e AS DeprecatedElement

###### java:Error

Labels types deriving from java.lang.Error as "Error".

                MATCH
                  (throwable)-[:EXTENDS*]->(t:Type)
                WHERE
                  t.fqn = 'java.lang.Error'
                SET
                  throwable:Error
                RETURN
                  throwable AS Error

###### java:Exception

Labels types deriving from java.lang.Exception as "Exception".

                MATCH
                  (exception)-[:EXTENDS*]->(t:Type)
                WHERE
                  t.fqn = 'java.lang.Exception'
                SET
                  exception:Exception
                RETURN
                  exception AS Exception

###### java:InnerType

Sets a label "Inner" on inner types.

                MATCH
                  (:Type)-[:DECLARES]->(innerType:Type)
                SET
                  innerType:Inner
                RETURN
                  innerType AS InnerType

###### java:InvokesOverriddenMethod

Requires concepts:

- java:MethodOverrides

- java:TypeAssignableFrom

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 r AS OverridingInvocation

###### 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 method AS OverloadedMethod, type AS DeclaringType

###### java:MethodOverrides

Requires concepts:

- java:TypeAssignableFrom

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 method AS OverriddenMethod, type AS DeclaringType, superType AS SuperType

###### java:RuntimeException

Labels types deriving from java.lang.RuntimeException as "RuntimeException".

                MATCH
                  (runtimeException)-[:EXTENDS*]->(t:Type)
                WHERE
                  t.fqn = 'java.lang.RuntimeException'
                SET
                  runtimeException:RuntimeException
                RETURN
                  runtimeException AS RuntimeException

###### java:Throwable

Labels types deriving from java.lang.Throwable as "Throwable".

                MATCH
                  (throwable)-[:EXTENDS*]->(t:Type)
                WHERE
                  t.fqn = 'java.lang.Throwable'
                SET
                  throwable:Throwable
                RETURN
                  throwable AS Throwable

###### 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 type AS AssignableType, superType AS AssignableFrom

#### metric.xml

##### Concepts

###### metric:Top10FieldsPerType

Requires concepts:

- dependency:Type

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

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

###### metric:Top10MethodsPerType

Requires concepts:

- dependency:Type

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

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

###### metric:Top10TypeFanIn

Requires concepts:

- dependency:Type

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

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

###### metric:Top10TypeFanOut

Requires concepts:

- dependency:Type

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

                MATCH
                    (t:Type:File)-[: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:File)-[:CONTAINS]->(t:Type:File)
                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:File)-[:CONTAINS]->(t:Type:File)
                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

#### 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
                  defaultMethod AS DefaultMethod, type AS Interface

###### 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
                  functionalInterface AS FunctionalInterface

### jqassistant.plugin.jpa2

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

jpa2.xml

Scanner for persistence.xml files

#### 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 28. 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 29. 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 30. 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 31. 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:

- jpa2:Entity

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).

junit3.xml junit4.xml

Scanner for JUnit4 test suite results

#### 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 32. 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 33. Relations of :File:TestSuite
Name | Target label(s) | Cardinality | Description
--- | --- | --- | ---
CONTAINS | :TestCase | 0..n | References a test case

##### :TestCase

A test case.

Table 34. 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'

#### junit3.xml

##### Concepts

###### junit3:SetUpMethod

Requires concepts:

- junit3:TestClass

Labels all setUp methods declared by a test class with "SetUp" and "Junit3".

                MATCH
                  (c:Class:Test:Junit3)-[:DECLARES]->(m:Method)
                WHERE
                  m.signature = "void setUp()"
                SET
                  m:SetUp:Junit3
                RETURN
                  m AS SetUpMethod, c AS TestClass

###### junit3:TearDownMethod

Requires concepts:

- junit3:TestClass

Labels all tearDown methods declared by a test class with "TearDown" and "Junit3".

                MATCH
                  (c:Class:Test:Junit3)-[:DECLARES]->(m:Method)
                WHERE
                  m.signature = "void tearDown()"
                SET
                  m:TearDown:Junit3
                RETURN
                  m AS TearDownMethod, c AS TestClass

###### junit3:TestClass

Labels all non-abstract classes extending from junit.framework.TestCase "Test" and "Junit3".

                MATCH
                  (c:Type:Class)-[:EXTENDS*]->(testCaseType:Type)
                WHERE
                  testCaseType.fqn = "junit.framework.TestCase"
                SET
                  c:Test:Junit3
                RETURN
                  c AS TestClass

###### junit3:TestMethod

Requires concepts:

- junit3:TestClass

Labels all test methods declared by a test class with "Test" and "Junit3".

                MATCH
                  (c:Class:Test:Junit3)-[:DECLARES]->(m:Method)
                WHERE
                  m.signature =~ "void test.*\\(.*\\)"
                SET
                  m:Test:Junit3
                RETURN
                  m AS Test, c AS TestClass

#### junit4.xml

##### Concepts

###### junit4:AfterClassMethod

Labels all methods annotated by "@org.junit.AfterClass" with "Junit4" and "AfterClass".

                MATCH
                  (c:Type:Class)-[:DECLARES]->(m:Method),
                  (m:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
                WHERE
                  a.fqn="org.junit.AfterClass"
                SET
                  m:Junit4:AfterClass
                RETURN
                  m AS AfterClassMethod, c AS TestClass

###### junit4:AfterMethod

Labels all methods annotated by "@org.junit.After" with "Junit4" and "After".

                MATCH
                  (c:Type:Class)-[:DECLARES]->(m:Method),
                  (m:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
                WHERE
                  a.fqn="org.junit.After"
                SET
                  m:Junit4:After
                RETURN
                  m AS AfterMethod, c AS TestClass

###### junit4:AssertMethod

Labels all assertion methods declared by org.junit.Assert with "Junit4" and "Assert".

                MATCH
                  (assertType:Type)-[:DECLARES]->(assertMethod)
                WHERE
                  assertType.fqn = 'org.junit.Assert'
                  and assertMethod.signature =~ 'void assert.*'
                SET
                  assertMethod:Junit4:Assert
                RETURN
                  assertMethod

###### junit4:BeforeClassMethod

Labels all methods annotated by "@org.junit.BeforeClass" with "Junit4" and "BeforeClass".

                MATCH
                  (c:Type:Class)-[:DECLARES]->(m:Method),
                  (m:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
                WHERE
                  a.fqn="org.junit.BeforeClass"
                SET
                  m:Junit4:BeforeClass
                RETURN
                  m AS BeforeClassMethod, c AS TestClass

###### junit4:BeforeMethod

Labels all methods annotated by "@org.junit.Before" with "Junit4" and "Before".

                MATCH
                  (c:Type:Class)-[:DECLARES]->(m:Method),
                  (m:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(a:Type)
                WHERE
                  a.fqn="org.junit.Before"
                SET
                  m:Junit4:Before
                RETURN
                  m AS BeforeMethod, c AS TestClass

###### 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
                  testcase AS TestCase

###### junit4:TestClass

Requires concepts:

- junit4:TestMethod

Labels all classes containing test methods with "Test" and "Junit4".

                MATCH
                  (c:Type:Class)-[:DECLARES]->(m:Method:Junit4:Test)
                SET
                  c:Test:Junit4
                RETURN
                  c AS TestClass, COLLECT(m) AS TestMethods

###### junit4:TestClassOrMethod

    _The rule is deprecated: This concept has been replaced by "junit4:TestMethod" and "junit4:TestClass"._

Requires concepts:

- junit4:TestMethod

- junit4:TestClass

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:Junit4:Test)
                RETURN
                  c AS TestClass, COLLECT(m) AS TestMethods

###### junit4:TestMethod

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

                MATCH
                  (m:Method)-[:ANNOTATED_BY]-()-[:OF_TYPE]->(a:Type)
                WHERE
                  a.fqn="org.junit.Test"
                SET
                  m:Test:Junit4
                RETURN
                  m AS Test

##### Constraints

###### junit4:AssertionMustProvideMessage

Requires concepts:

- junit4:AssertMethod

All assertions must provide a message.

                MATCH
                  (testType:Type)-[:DECLARES]->(testMethod:Method),
                  (testMethod)-[invocation:INVOKES]->(assertMethod:Assert:Method)
                WHERE
                  NOT assertMethod.signature =~ 'void assert.*\\(java.lang.String,.*\\)'
                RETURN
                  invocation AS Invocation,
                  testType AS DeclaringType,
                  testMethod AS Method

###### junit4:IgnoreWithoutMessage

All @Ignore annotations must provide a message.

                MATCH
                  (e)-[:ANNOTATED_BY]->(ignore:Annotation)-[:OF_TYPE]->(ignoreType:Type)
                WHERE
                  ignoreType.fqn= "org.junit.Ignore"
                  AND NOT (ignore)-[:HAS]->(:Value{name:"value"})
                RETURN
                  e AS IgnoreWithoutMessage

###### junit4:TestMethodWithoutAssertion

Requires concepts:

- junit4:TestMethod

- junit4:AssertMethod

All test methods must perform assertions (within a call hierarchy of max. 3 steps).

                MATCH
                  (testType:Type)-[:DECLARES]->(testMethod:Test:Method)
                WHERE
                  NOT (testMethod)-[:INVOKES*..3]->(:Method:Assert)
                RETURN
                  testType AS DeclaringType,
                  testMethod AS Method

### jqassistant.plugin.maven3

Provides a scanner for Maven 3 modules.

maven3.xml

Scanner for Maven projects

#### Scanner for Maven projects

Imports information from Maven projects.

##### :Maven:Project:File

A pom.xml file describing a single Maven project.

Table 35. 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 36. 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 37. 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 38. 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 39. Properties of :DEPENDS_ON
Name | Description
--- | ---
scope | The declared scope, e.g. "compile"
optional | "true" indicates that this dependency is optional.

#### maven3.xml

##### Constraints

###### maven3:HierarchicalParentModuleRelation

If a parent Maven project declares a module then the parent project must also be declared as the parent of the module (i.e. to keep the project hierarchy consistent).

                match
                  (parent:Maven:Project)-[:HAS_MODULE]->(module:Maven:Project)
                where
                  not (module)-[:HAS_PARENT]->(parent)
                return
                  module as InvalidModule

### jqassistant.plugin.osgi

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

osgi-bundle.xml

#### osgi-bundle.xml

##### Concepts

###### osgi-bundle:Activator

Requires concepts:

- osgi-bundle:Bundle

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:

- osgi-bundle:Bundle

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:

- osgi-bundle:Bundle

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:

- osgi-bundle:ExportPackage

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:

- dependency:Type

- osgi-bundle:InternalType

- osgi-bundle:Activator

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:

- dependency:Type

- osgi-bundle:InternalType

- osgi-bundle:Activator

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

#### Scanner for Tycho projects

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