All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.jqassistant-rules.spring-injection.xml Maven / Gradle / Ivy

Go to download

Plugin for jQAssistant to be able to scan and to analyze Spring related artifacts.

There is a newer version: 1.7.0-MS3
Show newest version
<jqassistant-rules xmlns="http://schema.jqassistant.org/rule/v1.10"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://schema.jqassistant.org/rule/v1.10 https://schema.jqassistant.org/plugin/jqassistant-rule-v1.10.xsd">

    <group id="spring-injection:Default">
        <includeConstraint refId="spring-injection:InjectablesMustNotBeInstantiated"/>
        <includeConstraint refId="spring-injection:BeanProducerMustBeDeclaredInConfigurationComponent"/>
        <includeConstraint refId="spring-injection:BeanProducerMustNotBeInvokedDirectly"/>
        <includeConstraint refId="spring-injection:FieldsOfInjectablesMustNotBeManipulated"/>
        <includeConstraint refId="spring-injection:AvoidInitializingBean"/>
        <includeConstraint refId="spring-injection:AvoidDisposableBean"/>
        <includeConstraint refId="spring-injection:AvoidAwareInterfacesInFavorOfInjection"/>
        <includeConstraint refId="spring-injection:InjectablesMustNotBeHeldInStaticVariables"/>
        <includeConstraint refId="spring-injection:InjectablesMustNotBeAccessedStatically"/>
    </group>

    <group id="spring-injection:Strict">
        <includeConstraint refId="spring-injection:FieldInjectionIsNotAllowed"/>
        <includeConstraint refId="spring-injection:InjectablesShouldBeHeldInFinalFields"/>
        <includeConstraint refId="spring-injection:JdkClassesMustNotBeInjectables"/>
        <includeConstraint refId="spring-injection:InjectablesMustOnlyBeHeldInInjectables"/>
    </group>

    <concept id="spring-injection:Injectable">
        <description>Returns all injectables.</description>
        <cypher><![CDATA[
            MATCH
              (injectable:Spring:Injectable)
            RETURN
              injectable as Injectable
        ]]></cypher>
    </concept>

    <concept id="spring-injection:BeanProducer">
        <providesConcept refId="spring-injection:Injectable"/>
        <description>Labels methods which are annotated with "@org.springframework.context.annotation.Bean" with
            "BeanProducer" and their return types with "Spring" and "Injectable".
        </description>
        <cypher><![CDATA[
           MATCH
              (:Type)-[:DECLARES]->(beanProducer:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(annotationType:Type),
              (beanProducer)-[:RETURNS]->(injectable:Type)
            WHERE
              annotationType.fqn = "org.springframework.context.annotation.Bean"
            SET
              injectable:Spring:Injectable,
              beanProducer:Spring:BeanProducer
            RETURN
              injectable as Injectable, collect(beanProducer) as BeanProducers
        ]]></cypher>
    </concept>

    <constraint id="spring-injection:InjectablesMustNotBeInstantiated">
        <requiresConcept refId="spring-injection:Injectable"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>If the constructor of an Injectable is called from another Injectable, then the caller must be a BeanProducer.</description>
        <cypher><![CDATA[
            MATCH
              (injectable:Injectable:Type)-[:DECLARES]->(constructor:Constructor),
              (artifact:Artifact)-[:CONTAINS]->(type:Injectable:Type)-[:DECLARES]->(method:Method),
              shortestPath((method)-[:INVOKES*]->(constructor))
            WHERE NOT (
              artifact:Test
              OR type:Generated
              OR method:Spring:BeanProducer
              OR (
                method:Constructor
                AND (type)-[:EXTENDS*0..]->(injectable)
              )
            )
            RETURN
              type as Type, method as Method, injectable as Injectable
        ]]></cypher>
        <report primaryColumn="Method"/>
    </constraint>

    <constraint id="spring-injection:BeanProducerMustBeDeclaredInConfigurationComponent">
        <requiresConcept refId="spring-injection:BeanProducer"/>
        <requiresConcept refId="spring-component:Configuration"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Bean producer methods must be declared in configuration components.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:DECLARES]->(beanProducer:Method:BeanProducer)-[:RETURNS]->(injectable:Injectable)
            WHERE NOT (
              artifact:Test
              OR type:Generated
              OR type:Spring:Configuration
            )
            RETURN
              type as Type, beanProducer as BeanProducer, injectable as Injectable
        ]]></cypher>
        <report primaryColumn="BeanProducer"/>
    </constraint>

    <constraint id="spring-injection:BeanProducerMustNotBeInvokedDirectly">
        <requiresConcept refId="spring-injection:BeanProducer"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Bean producer methods must not be invoked directly by the application.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:DECLARES]->(method:Method),
              (beanType:Type)-[:DECLARES]->(beanProducer:Spring:BeanProducer),
              (method)-[invokes:INVOKES]->(beanProducer)
            WHERE NOT (
              artifact:Test
              OR type:Generated
            )
            RETURN
              type as Type, invokes as Invocation, beanType as BeanProducerType, beanProducer as BeanProducer
        ]]></cypher>
        <report primaryColumn="Invocation"/>
    </constraint>

    <concept id="spring-injection:InjectionPoint">
        <description>
            Labels all type members annotated with "@org.springframework.beans.factory.annotation.Autowired",
            "javax.inject.Inject" or "javax.annotation.Resource" with "Spring" and "InjectionPoint".
        </description>
        <cypher><![CDATA[
            MATCH
              (injectionPoint:Member)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(annotationType:Type)
            WHERE
              annotationType.fqn in [
                "org.springframework.beans.factory.annotation.Autowired",
                "javax.inject.Inject",
                "javax.annotation.Resource"
              ]
            SET
              injectionPoint:Spring:InjectionPoint
            RETURN
              injectionPoint as InjectionPoint
        ]]></cypher>
    </concept>

    <constraint id="spring-injection:FieldInjectionIsNotAllowed">
        <requiresConcept refId="spring-injection:InjectionPoint"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Field injection is not allowed, use constructor injection instead.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:DECLARES]->(field:Field:InjectionPoint)
            WHERE NOT (
              artifact:Test
              OR type:Generated
            )
            RETURN
              type as Type, field as Field
        ]]></cypher>
        <report primaryColumn="Field"/>
    </constraint>

    <constraint id="spring-injection:InjectablesShouldBeHeldInFinalFields">
        <requiresConcept refId="spring-injection:Injectable"/>
        <requiresConcept refId="spring-injection:InjectionPoint"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Fields holding injectables should be declared final.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type:Injectable)-[declares:DECLARES]->(field:Field)-[:OF_TYPE]->(injectedType:Type:Injectable)
            WHERE NOT (
              artifact:Test
              OR type:Generated
              OR (exists(field.final) AND field.final = true)
              OR (exists(field.synthetic) AND field.synthetic) // synthetic fields, e.g. generated by Groovy
            )
            RETURN
              type AS Type, field AS Field
            ]]></cypher>
        <report primaryColumn="Field"/>
    </constraint>

    <constraint id="spring-injection:FieldsOfInjectablesMustNotBeManipulated">
        <requiresConcept refId="spring-injection:Injectable"/>
        <requiresConcept refId="java:TypeAssignableFrom"/>
        <requiresConcept refId="java:PostConstruct"/>
        <requiresConcept refId="java:PreDestroy"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Fields of injectable types must not be manipulated, except from constructors.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(injectable:Type:Injectable),
              (injectable)-[:DECLARES]->(field:Field)-[:OF_TYPE]->(fieldType:Type),
              (injectable)-[:DECLARES]->(method:Method),
              (method)-[writes:WRITES]->(field)
            WHERE
              (fieldType)-[:ASSIGNABLE_FROM*0..]->(:Injectable)
              AND NOT (
                artifact:Test
                OR injectable:Generated
                OR method:Constructor // method is a constructor
                OR method:PostConstruct
                OR method:PreDestroy
                OR (exists(field.synthetic) AND field.synthetic) // synthetic fields, e.g. generated by Groovy
              )
            RETURN
               injectable as Injectable, writes as WriteToInjectableField, field as Field
        ]]></cypher>
        <report primaryColumn="WriteToInjectableField"/>
    </constraint>

    <constraint id="spring-injection:AvoidInitializingBean">
        <requiresConcept refId="java:GeneratedType"/>
        <description>Prefer to use @PostConstruct over implementing InitializingBean.
        </description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:IMPLEMENTS]->(otherType:Type)
            WHERE
              NOT (
                artifact:Test
                OR type:Generated
              )
              AND otherType.fqn = "org.springframework.beans.factory.InitializingBean"
            RETURN
              type as Type
        ]]></cypher>
    </constraint>

    <constraint id="spring-injection:AvoidDisposableBean">
        <requiresConcept refId="java:GeneratedType"/>
        <description>Prefer to use @PreDestroy over implementing DisposableBean.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:IMPLEMENTS]->(otherType:Type)
            WHERE
              NOT (
                artifact:Test
                OR type:Generated
              )
              AND otherType.fqn = "org.springframework.beans.factory.DisposableBean"
            RETURN
              type as Type
        ]]></cypher>
    </constraint>

    <constraint id="spring-injection:AvoidAwareInterfacesInFavorOfInjection">
        <requiresConcept refId="java:GeneratedType"/>
        <description>Prefer to inject framework components over implementing '…Aware' interfaces.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:IMPLEMENTS]->(otherType:Type)
            WHERE
              NOT (
                artifact:Test
                OR type:Generated
              )
              AND otherType.fqn in [
                "org.springframework.beans.factory.BeanFactoryAware",
                "org.springframework.context.ApplicationContextAware",
                "org.springframework.context.ApplicationEventPublisherAware"
              ]
            RETURN
              type as Type, otherType as ImplementedInterface
        ]]></cypher>
    </constraint>

    <constraint id="spring-injection:InjectablesMustNotBeHeldInStaticVariables">
        <requiresConcept refId="spring-injection:Injectable"/>
        <requiresConcept refId="java:TypeAssignableFrom"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Injectable components must not be held in static variables.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(type:Type)-[:DECLARES]->(field:Field)-[:OF_TYPE]->(fieldType:Type)
            WHERE
              (fieldType)-[:ASSIGNABLE_FROM*0..]->(:Injectable)
              AND field.static
              AND NOT (
               artifact:Test
                OR type:Generated
              )
            RETURN
              type as Type, field as Field
        ]]></cypher>
        <report primaryColumn="Field"/>
    </constraint>

    <constraint id="spring-injection:InjectablesMustNotBeAccessedStatically">
        <requiresConcept refId="spring-injection:Injectable"/>
        <requiresConcept refId="java:TypeAssignableFrom"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Injectable components must not be accessed from static variables.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(:Type)-[:DECLARES]->(field:Field)-[:OF_TYPE]->(fieldType:Type),
              (type:Type)-[:DECLARES]->(method:Method)-[:WRITES|READS]->(field)
            WHERE
              (fieldType)-[:ASSIGNABLE_FROM*0..]->(:Injectable)
              AND field.static
              AND NOT (
               artifact:Test
                OR type:Generated
              )
            RETURN
              type as Type, method as Method, field as Field
        ]]></cypher>
        <report primaryColumn="Method"/>
    </constraint>

    <constraint id="spring-injection:JdkClassesMustNotBeInjectables">
        <requiresConcept refId="spring-injection:Injectable"/>
        <description>JDK classes must not be injectables.</description>
        <cypher><![CDATA[
            MATCH
              (type:Type:Spring:Injectable)
            WHERE
              type.fqn STARTS WITH "java."
            RETURN
              type AS Injectable
        ]]></cypher>
    </constraint>

    <constraint id="spring-injection:InjectablesMustOnlyBeHeldInInjectables">
        <requiresConcept refId="spring-injection:Injectable"/>
        <requiresConcept refId="java:GeneratedType"/>
        <description>Injectable classes must not be held as fields in non-injectable classes.</description>
        <cypher><![CDATA[
            MATCH
              (artifact:Artifact)-[:CONTAINS]->(t:Type)-[:DECLARES]->(f:Field)-[:OF_TYPE]->(fType:Type:Spring:Injectable)
            WHERE NOT (
              artifact:Test
              or t:Generated
              or t:Spring:Injectable
              or exists(f.synthetic) // exclude synthetic inner class field referencing the outer class
            )
            WITH
              t, collect(DISTINCT fType.fqn) AS fields
            OPTIONAL MATCH
              (t)<-[:EXTENDS|IMPLEMENTS*]-(injectableImpl:Type:Spring:Injectable)
            WITH
              t, fields, count(DISTINCT injectableImpl) AS injectableImplCnt
            WHERE
              NOT exists(t.abstract) OR injectableImplCnt = 0
            RETURN
              t AS NonInjectableHavingInjectablesAsField, fields AS Fields
        ]]></cypher>
    </constraint>
</jqassistant-rules>




© 2015 - 2025 Weber Informatics LLC | Privacy Policy