Packagraph is a lightweight tool designed to generate customizable package dependency diagrams for Java source code. It reads configurations from a Human JSON file and outputs diagrams in formats supported by GraphViz.
Below is an example diagram of packagraph
itself, created using the
for_manual_testing.hjson configuration:
Packagraph provides a simple way to visualize Java package dependencies, filling the void left by tools like ObjectAid (discontinued - see WebArchive). It focuses specifically on package-level diagrams, making it ideal for understanding high-level architecture.
Packagraph scans Java files in the specified directories, extracting package-level dependencies based on import
statements.
Packagraph uses the GraphViz library to create and export the dependency diagrams, styled according to your configuration.
Packagraph can be used as a command-line tool:
java -jar packagraph.jar -o myOptions.hjson
A typical HJSON configuration might look like:
{
directories: [ // Source directories
"./module1/src/main/java",
"./module2/src/main/java"
],
output: {
path: "./output/diagram.png", // Output file path
overwrite: true, // Overwrite existing file
graphStyle: MAIN_GRAPH
},
definitions: [
{
packages: "com.example.service.*",
as: "Service Layer",
nodeStyle: {
fillcolor: "lightblue"
}
},
{
packages: "com.example.repository.*",
as: "Repository Layer",
nodeStyle: {
fillcolor: "lightgray"
}
},
{
packages: "java.*",
as: "" // Exclude standard Java packages completely
}
],
clusters: [
{
packages: "Service Layer,com.example.dao.*",
graphStyle: {
label: "Application Core"
}
}
],
nodeStyles: {
default: {
//Default node style inherited by all other node styles.
shape: "rectangle"
}
},
graphStyles: {
default: {
fontsize: 18,
fontcolor: "gray"
},
MAIN_GRAPH: {
label: "My Project",
fontsize: 24,
fontcolor: "blue"
}
}
}
Below is all the properties that can be defined in the HJson file and supported by packagraph (* required):
Property | Type | Description | Example Value |
---|---|---|---|
directories* | String[] | Base directories that contain (source code) java packages. Could be as simple as "src/main/java" or directories of multiple modules. |
"directories": [ "./myModule1/src/main/java", "./myModule2/src/main/java" ] |
output.path | String | Defines the output file path and file type. Please see the GraphViz output formats. |
"output": { //PNG output "path": "./packagraph.png", "overwrite": true, "graphStyle": { "label": "MyLabel", "fontsize": 24, "fontcolor": "purple", "dpi": 96 } } |
output.overwrite | boolean | Whether to overwrite the output file if it already exists. | |
output.graphStyle | Object | The style of the main graph (read below). See also graph attributes. | |
includeOnlyFromDirectories | boolean | If true, only packages sourced from the directories will be included in the graph. |
"includeOnlyFromDirectories": true |
definitions | Object[] | Definitions can be used to re-name (or group into one) some of the packages. For example, you could define that packages javax.persistence.* and org.springframework.jpa.* will be exported as a single JPA package. |
"definitions": [ { "packages": "org.spring.data.*", "as": "Spring Data", "nodeStyle": { // Database has 'green' node "fillcolor": "green" }, "edgeInStyle": { // Database node has 'green' edges "color": "green" } }, { "packages": "java.*", //JDK standards "as": "" //exclude from the graph }, { //Trim the 'com.smth.' prefix //com.smth.pack1 and com.smth.pack2 //will become just 'pack1' and 'pack2' "packages": "com.smth\\.(.*)", "as": "$1", "nodeStyle": { "shape": "rectangle" } } ] |
definition(s).packages* | String | The packages that this definition refers to. You can use comma for multiple packages and regular expressions. | |
definition(s).as* | String | The name of the re-defined package. In other words, how the package will be shown in the output graph. If this value is empty, the package is completely excluded from the graph. | |
definition(s).nodeStyle | Object | Each package is exported to the graph as an individual node. nodeStyle
defines the style of this node. It can be either a named style (defined in nodeStyles ) or an inner object. See also node attributes. |
|
definition(s).edgeInStyle | Object | Customize the edges (that point to) of a single package.
It can be either a named style (defined in edgeStyles ) or an inner object.
Please see the GraphViz attributes that can be applied to an edge. |
|
clusters | Object[] | Clusters allow you to group several packages into a single type of sub-graph. More information on GraphViz clusters. |
"definitions": [ { "packages": "org.hibernate.*", "as": "Hibernate" }, { "packages": "jakarta.persistence.*", "as": "JPA" } ], "clusters": [ { "packages": "JPA,Hibernate, org.springframework.data.*", "graphStyle": { "label": "Database Access Layer", "fontsize": 18, "fontcolor": "gray" } } ] |
cluster(s).packages* | String | A comma-separated list of packages that will be grouped within the cluster.
Please note that at this stage, you have to refer to the packages based in their re-defined
names specified indefinitions . |
|
cluster(s).name | String | The name of the cluster, to be used as an identifier. Does not have any impact on the output. | |
cluster(s).graphStyle | Object | The style of the cluster graph. By default, all cluster graphs have the same graphStyle
as the main graph (output.graphStyle ). It can be either a named style (defined in graphStyles ) or an inner object.
See also graph attributes. |
|
nodeStyles | Object[] | A list of named styles to be used in definitions . All nodes have the
default style by default. All other styles inherit the properties of the default style.
If you want to prevent the inheritance, use "inheritDefault": false |
"nodeStyles": { "default": { "shape": "rectangle" }, "BLUE_RECTANGLE": { "color": "blue" }, "BLUE_CIRCLE": { "inheritDefault": false "color": "blue" }, } "definitions": [ { "packages": "org.spring.data.*", "as": "Spring Data", "nodeStyle": "BLUE_RECTANGLE" } ] |
edgeInStyles | Object[] | A list of named styles to be used in definitions . All edges have the
default style by default. All other styles inherit the properties of the default style.
If you want to prevent the inheritance, use "inheritDefault": false . |
"edgeInStyles": { "default": { "style": "solid" }, "DASHED_RED": { "color": "red", "style": "dashed" }, "SOLID_BLUE": { "inheritDefault": false, "color": "blue", "style": "solid" } }, "definitions": [ { "packages": "org.spring.data.*", "as": "Spring Data", "edgeInStyle": "SOLID_BLUE" } ] |
graphStyles | Object[] | A list of named styles to be used by clusters or the main graph. All clusters have the
default style by default. All other styles inherit the properties of the default style.
If you want to prevent the inheritance, use "inheritDefault": false . |
"graphStyles": { "default": { "dpi": "96" }, "BASIC_CLUSTER": { "color": "red" } } "clusters": [ { "packages": "org.spring.data.*", "graphStyle": "BASIC_CLUSTER" } ] |
constants | Object[] | A list of "key-value" pairs defined as constants within the Hjson file.
Use the ${MY_CONSTANT} syntax to refer to a constant. |
"constants": [ { "name": "EDGE_CUSTOM_BLUE", "value": "#258fc4" } ], "nodeStyles": { "default":{ "color": "${EDGE_CUSTOM_BLUE}" } }, |
constant(s).name* | String | The name of the constant | |
constant(s).value* | String | The value of the constant |
More examples of packagraph's usage can be found within the examples folder. You can use skeleton.hjson as a starting point for your own Human JSON files.