Skip to content

Instantly share code, notes, and snippets.

@jexp
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jexp/9359595 to your computer and use it in GitHub Desktop.
Save jexp/9359595 to your computer and use it in GitHub Desktop.
jQAssistant Documentation GraphGist

jQAssistant Data model

logo 600px

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

Here are some examples to illustrate the possibilities:

  • define technical layers (e.g. presentation, business logic, persistence) and/or business components (e.g. shopping cart, user management) and validate dependencies between them

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

  • separate APIs and implementation classes (e.g. a component must only have dependencies to API classes of other components) detect common problems, e.g cyclic package dependencies, dead code

The documentation can be found on the GitHub project wiki.

Meta Model

The Meta Model represents (Java) source code structures, it has nodes annotated with:

  • ARTIFACT

  • PACKAGE, TYPE, CLASS, ANNOTATION

  • FIELD, METHOD, PARAMETER, CONSTRUCTOR

And relationships like

  • CONTAINS, DECLARES, ANNOTATED_BY, EXTENDS, IMPLEMENTS, OF_TYPE, HAS, DEPENDS_ON

DataModel

Sample Model

A sample model is taken from the jqassistant-workshop-project.

create (_31:`ARTIFACT` {`FQN`:"com.buschmais.jqassistant.workshop:jqassistant.workshop:jar:1.0.0-SNAPSHOT", `GROUP`:"com.buschmais.jqassistant.workshop", `NAME`:"jqassistant.workshop", `TYPE`:"jar", `VERSION`:"1.0.0-SNAPSHOT"})
create (_32:`PACKAGE` {`FQN`:"", `NAME`:""})
create (_33:`PACKAGE` {`FQN`:"com", `NAME`:"com"})
create (_34:`PACKAGE` {`FQN`:"com.buschmais", `NAME`:"buschmais"})
create (_35:`PACKAGE` {`FQN`:"com.buschmais.workshop", `NAME`:"workshop"})
create (_36:`PACKAGE` {`FQN`:"com.buschmais.workshop.dataimport", `NAME`:"dataimport"})
create (_37:`CLASS`:`TYPE`:`PUBLIC` {`FQN`:"com.buschmais.workshop.dataimport.ImportService", `NAME`:"ImportService"})
create (_38:`PACKAGE` {`FQN`:"java", `NAME`:"java"})
create (_39:`PACKAGE` {`FQN`:"java.lang", `NAME`:"lang"})
create (_40:`TYPE` {`FQN`:"java.lang.Object", `NAME`:"Object"})
create (_41:`PUBLIC`:`METHOD`:`CONSTRUCTOR` {`NAME`:"<init>", `SIGNATURE`:"void <init>()"})
create (_42:`TYPE` {`FQN`:"void", `NAME`:"void"})
create (_43:`METHOD`:`CONSTRUCTOR` {`SIGNATURE`:"void <init>()"})
create (_44:`PACKAGE` {`FQN`:"com.buschmais.workshop.shoppingcart", `NAME`:"shoppingcart"})
create (_45:`CLASS`:`TYPE`:`PUBLIC` {`FQN`:"com.buschmais.workshop.shoppingcart.CartService", `NAME`:"CartService"})
create (_46:`FIELD`:`PRIVATE` {`NAME`:"userService", `SIGNATURE`:"com.buschmais.workshop.usermanagement.UserService userService", `TRANSIENT`:false, `VOLATILE`:false})
create (_47:`PACKAGE` {`FQN`:"com.buschmais.workshop.usermanagement", `NAME`:"usermanagement"})
create (_48:`CLASS`:`TYPE`:`PUBLIC` {`FQN`:"com.buschmais.workshop.usermanagement.UserService", `NAME`:"UserService"})
create (_49:`PUBLIC`:`METHOD`:`CONSTRUCTOR` {`NAME`:"<init>", `SIGNATURE`:"void <init>()"})
create (_50:`PACKAGE` {`FQN`:"com.buschmais.workshop.shoppingcart.model", `NAME`:"model"})
create (_51:`CLASS`:`TYPE`:`PUBLIC`:`JPA`:`ENTITY` {`FQN`:"com.buschmais.workshop.shoppingcart.model.Cart", `NAME`:"Cart"})
create (_52:`PACKAGE` {`FQN`:"javax", `NAME`:"javax"})
create (_53:`PACKAGE` {`FQN`:"javax.persistence", `NAME`:"persistence"})
create (_54:`TYPE` {`FQN`:"javax.persistence.Entity", `NAME`:"Entity"})
create (_55:`ANNOTATION`:`VALUE`)
create (_56:`PUBLIC`:`METHOD`:`CONSTRUCTOR` {`NAME`:"<init>", `SIGNATURE`:"void <init>()"})
create (_57:`PACKAGE` {`FQN`:"com.buschmais.workshop.usermanagement.model", `NAME`:"model"})
create (_58:`CLASS`:`TYPE`:`PUBLIC`:`JPA`:`ENTITY` {`FQN`:"com.buschmais.workshop.usermanagement.model.User", `NAME`:"User"})
create (_59:`ANNOTATION`:`VALUE`)
create (_60:`PUBLIC`:`METHOD`:`CONSTRUCTOR` {`NAME`:"<init>", `SIGNATURE`:"void <init>()"})
create (_61:`PUBLIC`:`METHOD`:`CONSTRUCTOR` {`NAME`:"<init>", `SIGNATURE`:"void <init>()"})
create _31-[:`CONTAINS`]->_48
create _31-[:`CONTAINS`]->_58
create _31-[:`CONTAINS`]->_57
create _31-[:`CONTAINS`]->_47
create _31-[:`CONTAINS`]->_51
create _31-[:`CONTAINS`]->_50
create _31-[:`CONTAINS`]->_45
create _31-[:`CONTAINS`]->_44
create _31-[:`CONTAINS`]->_37
create _31-[:`CONTAINS`]->_36
create _31-[:`CONTAINS`]->_35
create _31-[:`CONTAINS`]->_34
create _31-[:`CONTAINS`]->_33
create _31-[:`CONTAINS`]->_32
create _32-[:`CONTAINS`]->_52
create _32-[:`CONTAINS`]->_42
create _32-[:`CONTAINS`]->_38
create _32-[:`CONTAINS`]->_33
create _33-[:`CONTAINS`]->_34
create _34-[:`CONTAINS`]->_35
create _35-[:`CONTAINS`]->_47
create _35-[:`CONTAINS`]->_44
create _35-[:`CONTAINS`]->_36
create _36-[:`CONTAINS`]->_37
create _37-[:`EXTENDS`]->_40
create _37-[:`DECLARES`]->_41
create _38-[:`CONTAINS`]->_39
create _39-[:`CONTAINS`]->_40
create _40-[:`DECLARES`]->_43
create _41-[:`RETURNS`]->_42
create _41-[:`INVOKES`]->_43
create _41-[:`DEPENDS_ON`]->_42
create _44-[:`CONTAINS`]->_50
create _44-[:`CONTAINS`]->_45
create _45-[:`EXTENDS`]->_40
create _45-[:`DECLARES`]->_49
create _45-[:`DECLARES`]->_46
create _46-[:`OF_TYPE`]->_48
create _47-[:`CONTAINS`]->_57
create _47-[:`CONTAINS`]->_48
create _48-[:`EXTENDS`]->_40
create _48-[:`DECLARES`]->_61
create _49-[:`RETURNS`]->_42
create _49-[:`INVOKES`]->_43
create _49-[:`DEPENDS_ON`]->_42
create _50-[:`CONTAINS`]->_51
create _51-[:`EXTENDS`]->_40
create _51-[:`DECLARES`]->_56
create _51-[:`ANNOTATED_BY`]->_55
create _52-[:`CONTAINS`]->_53
create _53-[:`CONTAINS`]->_54
create _55-[:`OF_TYPE`]->_54
create _56-[:`RETURNS`]->_42
create _56-[:`INVOKES`]->_43
create _56-[:`DEPENDS_ON`]->_42
create _57-[:`CONTAINS`]->_58
create _58-[:`EXTENDS`]->_40
create _58-[:`DECLARES`]->_60
create _58-[:`ANNOTATED_BY`]->_59
create _59-[:`OF_TYPE`]->_54
create _60-[:`RETURNS`]->_42
create _60-[:`INVOKES`]->_43
create _60-[:`DEPENDS_ON`]->_42
create _61-[:`RETURNS`]->_42
create _61-[:`INVOKES`]->_43
create _61-[:`DEPENDS_ON`]->_42

jQAssistant can be run as maven plugin, if you don’t want to provide the prefix, check the docs for pluginGroup configuration.

mvn com.buschmais.jqassistant.maven:jqassistant-maven-plugin:scan
mvn com.buschmais.jqassistant.maven:jqassistant-maven-plugin:server

Here are some sample use-cases

Number of Types

MATCH (t:TYPE)
RETURN COUNT(t) AS NumberOfTypes

Classes with highest Method Count

MATCH (c:CLASS)-[:DECLARES]->(e)
WHERE e:METHOD OR e:FIELD
RETURN c.NAME, COUNT(*) AS elements
ORDER BY elements DESC
LIMIT 10

Enrich your model with Concepts

jQAssistant allows you to enrich your model with concepts, like

  • TEST, ENTITY, MODULE, etc.

by allowing queries to be specified that label matched nodes with node labels.

It comes with a lot of concepts out of the box, supporting

  • J2EE, JPA, JSF

  • JUnit

  • Spring

Declare Constraints, Rules

Constraints and rules check your project data for certain rules. They can depend on concepts that they use to check rules. So only concepts that you actually need are applied to the graph data.

Mark Test Methods

MATCH (method:METHOD)-[:ANNOTATED_BY]->(t:ANNOTATION)-[:OF_TYPE]->(:TYPE {FQN:"org.junit.Test"}),
      (method)<-[:DECLARES]-(test:CLASS)
SET method:TEST SET test:TEST
RETURN distinct test.NAME, labels(test)

Check Test Class Naming

MATCH (c:TEST:CLASS)
WHERE NOT c.NAME =~ ".*Tests?$"
RETURN c.NAME

Provided Concepts

TODO

Move Maven Rules

# list maven goals with short desc
mvn jqassistant:help

# list available rules
mvn jqassistant:available-rules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment