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