Showing preview only (1,181K chars total). Download the full file or copy to clipboard to get everything.
Repository: refactorfirst/RefactorFirst
Branch: main
Commit: 559631f04db0
Files: 187
Total size: 1.1 MB
Directory structure:
gitextract_nn926aoz/
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── codesee-arch-diagram.yml
│ ├── maven-pr.yml
│ ├── maven.yml
│ └── release.yml
├── .gitignore
├── CITATIONS.md
├── LICENSE
├── README.md
├── change-proneness-ranker/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── git/
│ │ ├── ChangePronenessRanker.java
│ │ ├── GitLogReader.java
│ │ └── ScmLogInfo.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ └── git/
│ ├── ChangePronenessRankerTest.java
│ └── GitLogReaderTest.java
├── cli/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── hjug/
│ └── refactorfirst/
│ ├── Main.java
│ ├── ReportCommand.java
│ └── ReportType.java
├── codebase-graph-builder/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── graphbuilder/
│ │ ├── CodebaseGraphDTO.java
│ │ ├── DependencyCollector.java
│ │ ├── GraphBuilderConfig.java
│ │ ├── GraphDependencyCollector.java
│ │ ├── JavaGraphBuilder.java
│ │ └── visitor/
│ │ ├── BaseCodebaseVisitor.java
│ │ ├── BaseTypeProcessor.java
│ │ ├── FqnCapturingProcessor.java
│ │ ├── JavaClassDeclarationVisitor.java
│ │ ├── JavaFqnCapturingVisitor.java
│ │ ├── JavaMethodDeclarationVisitor.java
│ │ ├── JavaVariableTypeVisitor.java
│ │ ├── JavaVisitor.java
│ │ └── TypeDependencyExtractor.java
│ └── test/
│ ├── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── graphbuilder/
│ │ ├── JavaGraphBuilderTest.java
│ │ └── visitor/
│ │ ├── JavaClassDeclarationVisitorTest.java
│ │ ├── JavaFqnCapturingVisitorTest.java
│ │ ├── JavaInitializerBlockVisitorTest.java
│ │ ├── JavaLambdaVisitorTest.java
│ │ ├── JavaMethodDeclarationVisitorTest.java
│ │ ├── JavaMethodInvocationVisitorTest.java
│ │ ├── JavaNewClassVisitorFullTest.java
│ │ ├── JavaNewClassVisitorTest.java
│ │ ├── JavaVariableTypeVisitorTest.java
│ │ ├── JavaVisitorTest.java
│ │ └── testclasses/
│ │ ├── A.java
│ │ ├── B.java
│ │ ├── C.java
│ │ ├── D.java
│ │ ├── E.java
│ │ ├── F.java
│ │ ├── G.java
│ │ ├── H.java
│ │ ├── MyAnnotation.java
│ │ ├── MyOtherAnnotation.java
│ │ ├── initializers/
│ │ │ ├── ComplexInitializerClass.java
│ │ │ └── InitializerBlockTestClass.java
│ │ ├── lambda/
│ │ │ ├── DataProcessor.java
│ │ │ ├── HelperClass.java
│ │ │ ├── LambdaTestClass.java
│ │ │ └── NestedLambdaTestClass.java
│ │ ├── methodInvocation/
│ │ │ ├── A.java
│ │ │ ├── B.java
│ │ │ ├── C.java
│ │ │ └── D.java
│ │ └── newClass/
│ │ ├── A.java
│ │ ├── B.java
│ │ └── C.java
│ └── resources/
│ └── javaSrcDirectory/
│ └── com/
│ └── ideacrest/
│ └── parser/
│ └── testclasses/
│ ├── A.java
│ ├── B.java
│ ├── C.java
│ ├── D.java
│ └── E.java
├── cost-benefit-calculator/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── cbc/
│ │ ├── CostBenefitCalculator.java
│ │ ├── CycleNode.java
│ │ ├── CycleRanker.java
│ │ ├── RankedCycle.java
│ │ └── RankedDisharmony.java
│ └── test/
│ ├── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── cbc/
│ │ └── CostBenefitCalculatorTest.java
│ └── resources/
│ ├── hudson/
│ │ └── model/
│ │ └── User.java
│ └── org/
│ └── apache/
│ └── myfaces/
│ └── tobago/
│ └── facelets/
│ ├── AttributeHandler.java
│ ├── AttributeHandler2.java
│ └── AttributeHandlerAndSorter.java
├── coverage/
│ └── pom.xml
├── effort-ranker/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── metrics/
│ │ ├── CBOClass.java
│ │ ├── Disharmony.java
│ │ ├── GodClass.java
│ │ ├── GodClassRanker.java
│ │ └── rules/
│ │ └── CBORule.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ └── metrics/
│ ├── CBOClassParsingTest.java
│ ├── GodClassParsingTest.java
│ └── GodClassRankerTest.java
├── graph-algorithms/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ ├── dsm/
│ │ │ ├── CircularReferenceChecker.java
│ │ │ ├── DSM.java
│ │ │ ├── EdgeRemovalCalculator.java
│ │ │ ├── EdgeToRemoveInfo.java
│ │ │ ├── OptimalBackEdgeRemover.java
│ │ │ ├── SparseGraphCircularReferenceChecker.java
│ │ │ └── SparseIntDWGEdgeRemovalCalculator.java
│ │ └── feedback/
│ │ ├── SuperTypeToken.java
│ │ ├── arc/
│ │ │ ├── EdgeInfo.java
│ │ │ ├── EdgeInfoCalculator.java
│ │ │ ├── approximate/
│ │ │ │ ├── FeedbackArcSetResult.java
│ │ │ │ └── FeedbackArcSetSolver.java
│ │ │ ├── exact/
│ │ │ │ ├── FeedbackArcSetResult.java
│ │ │ │ └── MinimumFeedbackArcSetSolver.java
│ │ │ └── pageRank/
│ │ │ ├── DIAGRAM.md
│ │ │ ├── LineDigraph.java
│ │ │ └── PageRankFAS.java
│ │ └── vertex/
│ │ ├── approximate/
│ │ │ ├── FeedbackVertexSetResult.java
│ │ │ └── FeedbackVertexSetSolver.java
│ │ └── kernelized/
│ │ ├── DIAGRAM.md
│ │ ├── DirectedFeedbackVertexSetResult.java
│ │ ├── DirectedFeedbackVertexSetSolver.java
│ │ ├── EnhancedParameterComputer.java
│ │ ├── FeedbackVertexSetComputer.java
│ │ ├── ModulatorComputer.java
│ │ ├── ParameterComputer.java
│ │ └── TreewidthComputer.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ ├── dsm/
│ │ ├── CircularReferenceCheckerTests.java
│ │ ├── DSMTest.java
│ │ ├── EdgeRemovalCalculatorTest.java
│ │ └── OptimalBackEdgeRemoverTest.java
│ └── feedback/
│ ├── SuperTypeTokenTest.java
│ ├── arc/
│ │ ├── approximate/
│ │ │ ├── FeedbackArcSetBenchmarkTest.java
│ │ │ ├── FeedbackArcSetExample.java
│ │ │ └── FeedbackArcSetSolverTest.java
│ │ ├── exact/
│ │ │ ├── MinimumFeedbackArcSetBenchmarkTest.java
│ │ │ ├── MinimumFeedbackArcSetExample.java
│ │ │ └── MinimumFeedbackArcSetSolverTest.java
│ │ └── pageRank/
│ │ ├── PageRankFASExample.java
│ │ └── PageRankFASTest.java
│ └── vertex/
│ ├── approximate/
│ │ ├── FeedbackVertexSetBenchmarkTest.java
│ │ ├── FeedbackVertexSetExample.java
│ │ └── FeedbackVertexSetSolverTest.java
│ └── kernelized/
│ ├── DirectedFeedbackVertexSetBenchmarkTest.java
│ ├── DirectedFeedbackVertexSetExample.java
│ ├── DirectedFeedbackVertexSetSolverTest.java
│ ├── ModulatorComputerTest.java
│ ├── ParameterComputerExample.java
│ └── ParameterComputerTest.java
├── graph-data-generator/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── gdg/
│ │ └── GraphDataGenerator.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ └── gdg/
│ └── GraphDataGeneratorTest.java
├── jreleaser.yml
├── lombok.config
├── pom.xml
├── refactor-first-gradle-plugin/
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── pom.xml
│ ├── settings.gradle
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── hjug/
│ └── gradlereport/
│ └── RefactorFirstPlugin.java
├── refactor-first-maven-plugin/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── hjug/
│ └── mavenreport/
│ ├── RefactorFirstHtmlReport.java
│ ├── RefactorFirstMavenCsvReport.java
│ ├── RefactorFirstMavenJsonReport.java
│ ├── RefactorFirstMavenReport.java
│ └── RefactorFirstSimpleHtmlReport.java
├── report/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── refactorfirst/
│ │ └── report/
│ │ ├── CsvReport.java
│ │ ├── HtmlReport.java
│ │ ├── ReportWriter.java
│ │ ├── SimpleHtmlReport.java
│ │ └── json/
│ │ ├── JsonReport.java
│ │ ├── JsonReportDisharmonyEntry.java
│ │ └── JsonReportExecutor.java
│ └── test/
│ ├── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── refactorfirst/
│ │ └── report/
│ │ ├── HtmlReportTest.java
│ │ └── SimpleHtmlReportTest.java
│ └── resources/
│ ├── highlight.html
│ ├── sigmaPlayground.html
│ └── spriteText.html
├── spring-petclinic-rest-report.html
└── test-resources/
├── pom.xml
└── src/
└── main/
└── resources/
├── AttributeHandler.java
├── AttributeHandler2.java
├── AttributeHandlerAndSorter.java
├── AttributeHandlerJavaEleven.java
├── Attributes.java
└── Console.java
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: jimbethancourt
#open_collective: RefactorFirst
#ko_fi: jimbethancourt
#liberapay: jimbethancourt
#patreon: jimbethancourt
================================================
FILE: .github/workflows/codesee-arch-diagram.yml
================================================
# This workflow was added by CodeSee. Learn more at https://codesee.io/
# This is v2.0 of this workflow file
on:
push:
branches:
- main
pull_request_target:
types: [opened, synchronize, reopened]
name: CodeSee
permissions: read-all
jobs:
codesee:
runs-on: ubuntu-latest
continue-on-error: true
name: Analyze the repo with CodeSee
steps:
- uses: Codesee-io/codesee-action@v2
with:
codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
================================================
FILE: .github/workflows/maven-pr.yml
================================================
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven (PR)
on:
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: 11
distribution: 'zulu'
- name: Build With Maven
run: mvn -B verify
# Comment "Build With Maven" and uncomment the below when you want a snapshot build to be deployed
# *********Don't forget to switch to Java 1.8 as well********
# - name: Publish Maven snapshot
# uses: samuelmeuli/action-maven-publish@v1
# with:
# gpg_private_key: ${{ secrets.gpg_private_key }}
# gpg_passphrase: ${{ secrets.gpg_passphrase }}
# nexus_username: ${{ secrets.nexus_username }}
# nexus_password: ${{ secrets.nexus_password }}
# maven_profiles: snapshot-release
================================================
FILE: .github/workflows/maven.yml
================================================
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: 11
distribution: 'zulu'
- name: Build With Maven
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
run: mvn -B verify
# Comment "Build With Maven" and uncomment the below when you want a snapshot build to be deployed
# *********Don't forget to switch to Java 1.8 as well********
# - name: Publish Maven snapshot
# uses: samuelmeuli/action-maven-publish@v1
# with:
# gpg_private_key: ${{ secrets.gpg_private_key }}
# gpg_passphrase: ${{ secrets.gpg_passphrase }}
# nexus_username: ${{ secrets.nexus_username }}
# nexus_password: ${{ secrets.nexus_password }}
# maven_profiles: snapshot-release
================================================
FILE: .github/workflows/release.yml
================================================
# Based on https://github.com/jagodevreede/semver-check/blob/c9353fa86eb9ae8f6b309057748672a6c1e0f435/.github/workflows/release.yml
# From https://foojay.io/today/how-to-publish-a-java-maven-project-to-maven-central-using-jreleaser-and-github-actions-2025-guide/
# If this doesn't work, try https://jreleaser.org/guide/latest/continuous-integration/github-actions.html
name: Release
on:
workflow_dispatch:
inputs:
version:
description: 'Release version'
required: true
nextVersion:
description: 'Next version after release (-SNAPSHOT will be added automatically)'
required: true
jobs:
build:
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: maven
- name: Set release version
run: mvn --no-transfer-progress --batch-mode versions:set -DnewVersion=${{ github.event.inputs.version }}
- name: Commit & Push changes
uses: actions-js/push@master
with:
github_token: ${{ secrets.JRELEASER_GITHUB_TOKEN }}
message: "build: Releasing version ${{ github.event.inputs.version }}"
- name: Stage release
run: mvn --no-transfer-progress --batch-mode -Ppublish clean deploy -DaltDeploymentRepository=local::default::file://`pwd`/target/staging-deploy
- name: Run JReleaser
uses: jreleaser/release-action@v2
with:
setup-java: false
version: 1.20.0
env:
JRELEASER_PROJECT_VERSION: ${{ github.event.inputs.version }}
JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
JRELEASER_DEPLOY_MAVEN_MAVENCENTRAL_RELEASE_DEPLOY_USERNAME: ${{ secrets.JRELEASER_MAVENCENTRAL_SONATYPE_USERNAME }}
JRELEASER_DEPLOY_MAVEN_MAVENCENTRAL_RELEASE_DEPLOY_PASSWORD: ${{ secrets.JRELEASER_MAVENCENTRAL_SONATYPE_PASSWORD }}
- name: Set release version
run: mvn --no-transfer-progress --batch-mode versions:set -DnewVersion=${{ github.event.inputs.nextVersion }}-SNAPSHOT
- name: Commit & Push changes
uses: actions-js/push@master
with:
github_token: ${{ secrets.JRELEASER_GITHUB_TOKEN }}
message: "build: Setting SNAPSHOT version ${{ github.event.inputs.nextVersion }}-SNAPSHOT"
tags: false
- name: JReleaser release output
if: always()
uses: actions/upload-artifact@v4
with:
name: jreleaser-release
path: |
out/jreleaser/trace.log
out/jreleaser/output.properties
================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/java,maven,intellij,eclipse
# Edit at https://www.toptal.com/developers/gitignore?templates=java,maven,intellij,eclipse
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
build/
.gradle/
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
.idea/*
.idea
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
*.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# End of https://www.toptal.com/developers/gitignore/api/java,maven,intellij,eclipse
./jreleaser-cli.jar
================================================
FILE: CITATIONS.md
================================================
# Research Citations
## Directed Feedback Arc Set
**Title:** Computing a Feedback Arc Set Using PageRank
**Authors:** Geladaris, Lionakis, and Tollis
**Year:** 2023
**Publication:** International Symposium on Graph Drawing and Network Visualization
**Links:**
https://arxiv.org/abs/2208.09234
https://doi.org/10.1007/978-3-031-22203-0_14
**Summary:** The new technique produces solutions that are better than the ones produced by the best previously known heuristics, often reducing the FAS size by more than 50%.
## Directed Feedback Vertex Set
**Title:** Wannabe Bounded Treewidth Graphs Admit a Polynomial Kernel for Directed Feedback Vertex Set
**Authors:** Authors: Daniel Lokshtanov, Maadapuzhi-Sridharan Ramanujan, Saket Saurabh, Roohani Sharma, Meirav Zehavi
**Year:** 2025
**Publication:** ACM Transactions on Computation Theory, Volume 17, Issue 1
**Links:** https://doi.org/10.1145/3711669
## Tech Debt Prioritization
**Title:** Prioritizing Design Debt Investment Opportunities
**Authors:** Nico Zazworka, Carolyn Seaman, and Forrest Shull
**Year:** 2011
**Publication:** MTD '11: Proceedings of the 2nd Workshop on Managing Technical Debt
**Links:** https://dl.acm.org/doi/10.1145/1985362.1985372
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# RefactorFirst
This tool for Java codebases will help you identify what you should refactor first:
- God Classes
- Highly Coupled classes
- Class Cycles (with cycle images!)
It scans your Git repository generates a single page application by runing:
- Cycle analysis on your source code using the [OpenRewrite](https://github.com/openrewrite/rewrite) Java parser and [JGraphT](https://jgrapht.org/)
- What-if analysis to identify the most optimal relationships in a class cycle to remove
- PMD's God Class Rule
- PMD's Coupling Between Objects
Code map viewers are powered by [3D Force Graph](https://vasturiano.github.io/3d-force-graph), [sigma.js](https://www.sigmajs.org/), and [GraphViz DOT](https://graphviz.org/docs/layouts/dot/)
<br>If there are more than 4000 classes + relationships, a simplified 3D viewer will be used to avoid slowdowns. Features will be toggleable in the 3D UI in a future release.
## Decomposing and Removing Cycles
Cycle analysis is performed with cutting-edge [Directed Feedback Vertex Set](https://dl.acm.org/doi/10.1145/3711669) and [Directed Feedback Arc Set](https://arxiv.org/abs/2208.09234)
algorithms to identify the optimal classes and relationships between classes for removal to get rid of cycles in your codebase.
These algorithms are powerful and will push your CPU to its limits for large codebases, though it does play nice and shouldn't slow your computer down.
These graph algorithms can be used outside RefactorFirst.
See [DIAGRAM.md](./graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/DIAGRAM.md) for the flow of the vertex kernelized algorithm.
See [DIAGRAM.md](./graph-algorithms/src/main/java/org/hjug/feedback/arc/pageRank/DIAGRAM.md) for more details on the arc kernelized algorithm.
### How to understand the Relationship Removal Priority table
The Relationship Removal Priority table shows the most optimal relationships to remove from your codebase to remove all cycles.
The table is sorted by the number of cycles that a relationship exists in and then the change proneness of the classes in the relationship.
- Classes that should be broken apart / removed from the codebase are bold.
- If only one class is bold, the shared functionality should be moved to the non-bold class.
- If neither class or both classes are bold, examine both classes and reassess the responsibilities of the classes and refactor to remove the relationship.
Take a look at the [Spring Petclinic REST project sample report](https://rawcdn.githack.com/refactorfirst/RefactorFirst/c46d26211a91ffbe08d4089e04a85ff31eb093c0/spring-petclinic-rest-report.html)!
The graphs generated in the report will look similar to this one:

## Please Note: Java 11 (or newer) required to run RefactorFirst
**Java 21 codebase analysis is supported!**
The change to require Java 11 is needed to address vulnerability CVE-2023-4759 in JGit
Please use a recent JDK release of the Java version you are using.
If you use an old JDK release of your chosen Java version, you may encounter issues during analysis.
## There are several ways to run the analysis on your codebase:
### From The Command Line As an HTML Report
Run the following command from the root of your project (the source code does not need to be built):
```bash
mvn org.hjug.refactorfirst.plugin:refactor-first-maven-plugin:0.8.0:htmlReport
```
View the report at ```target/site/refactor-first-report.html```
### [As Part of GitHub Actions Output](https://github.blog/news-insights/product-news/supercharging-github-actions-with-job-summaries/)
This will generate a simplified HTML report (no graphs or images) as the output of a GitHub Action step
```bash
mvn -B clean test \
org.hjug.refactorfirst.plugin:refactor-first-maven-plugin:0.8.0:simpleHtmlReport \
&& echo "$(cat target/site/refactor-first-report.html)" >> $GITHUB_STEP_SUMMARY
```
### As Part of a Build
Add the following to your project in the build section. **showDetails** will show God Class metrics and rankings in the generated table.
```xml
<build>
<plugins>
...
<plugin>
<groupId>org.hjug.refactorfirst.plugin</groupId>
<artifactId>refactor-first-maven-plugin</artifactId>
<version>0.8.0</version>
<!-- optional -->
<configuration>
<showDetails>false</showDetails>
</configuration>
</plugin>
...
</plugins>
</build>
```
### As a Maven Report
Add the following to your project in the reports section.
A RefactorFirst report will show up in the site report when you run ```mvn site```
```xml
<reporting>
<plugins>
...
<plugin>
<groupId>org.hjug.refactorfirst.plugin</groupId>
<artifactId>refactor-first-maven-plugin</artifactId>
<version>0.8.0</version>
</plugin>
...
</plugins>
</reporting>
```
## Configuraiton Options
Care has been taken to use sensible defaults, though if you wish to override these defaults you can specify the following parameters.
Specify with -D if running on the command line. e.g. ```-DbackEdgeAnalysisCount=0 `DanalyzeCycles=false``` or in the configuration section (as in the above examples) if including in a Maven build.
|Option|Action| Default |
|------|------|-----------------------------------------------------------|
|showDetails|Shows God Class metrics| false |
|backEdgeAnalysisCount|Number of back edges in a cycle to analyze. <br>If total number of back edges is greater than the value specified, it analyzes the number of minimum weight edges specified.<br>**If 0 is specified, all back edges will be analyzed**| 50 |
|analyzeCycles|Analyzes the 10 largest cycles (will be configurable in the future)| true |
|minifyHtml|Minifies the generated HTML report. Only available on ```htmlReport``` and ```simpleHtmlReport``` goals. May cause issues with large reports.| false |
|excludeTests|Exclude test classes from analysis| true |
|testSrcDirectory|Excludes classes containing this pattern from analysis| ```src/test``` and ```src\test``` |
|projectName|The name of your project to be displayed on the report| Your Maven project name |
|projectVersion|The version of your project to be displayed on the report| Your Maven project version |
|outputDirectory|The location the project report will be written| ```${projectDir}/target/site/refactor-first-report.html```
### Seeing Errors?
If you see an error similar to
```
Execution default-site of goal org.apache.maven.plugins:maven-site-plugin:3.3:site failed: A required class was missing while executing org.apache.maven.plugins:maven-site-plugin:3.3:site: org/apache/maven/doxia/siterenderer/DocumentContent
```
you will need to add the following to your pom.xml:
```xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.12.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.4.5</version>
</plugin>
</plugins>
</build>
```
## But I'm using Gradle / my project layout isn't typical!
I would like to create a Gradle plugin and (possibly) support non-conventional projects in the future, but in the meantime you can create a dummy POM file in the same directory as your .git directory:
```xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
```
and then (assuming Maven is installed) run
```bash
mvn org.hjug.refactorfirst.plugin:refactor-first-maven-plugin:0.8.0:htmlReport
```
## Viewing the Report
View the report at ```target/site/refactor-first-report.html```
Once the plugin finishes executing (it may take a while for a large / old codebase), open the file **target/site/refactor-first-report.html** in the root of the project. It will contain a graph similar to the one above, and a table that lists God classes in the recommended order that they should be refactored. The classes in the top left of the graph are the easiest to refactor while also having the biggest positive impact to team productivity.
If highly coupled classes are detected, a graph and table listing Highly Coupled Classes in will be generated.
## I have the report. Now What???
Work with your Product Owner to prioritize the technical debt that has been identified. It may help to explain it as hidden negative value that is slowing team porductivity.
If you have IntelliJ Ultimate, you can install the [Method Reference Diagram](https://plugins.jetbrains.com/plugin/7996-java-method-reference-diagram) plugin to help you determine how the identified God classes and Highly Coupled classes can be refactored.
## Additional Details
This plugin will work on both single module and multi-module Maven projects that have a typical Maven project layout.
This tool is based on the paper **[Prioritizing Design Debt Investment Opportunities](https://dl.acm.org/doi/10.1145/1985362.1985372)** by Nico Zazworka, Carolyn Seaman, and Forrest Shull. The presentation based on the paper is available at https://resources.sei.cmu.edu/asset_files/Presentation/2011_017_001_516911.pdf
## Limitations
* My time. This is a passion project and is developed in my spare time.
## Feedback and Collaboration Welcome
There is still much to be done. Your feedback and collaboration would be greatly appreciated in the form of feature requests, bug submissions, and PRs.
If you find this plugin useful, please star this repository and share with your friends & colleagues and on social media.
## Future Plans
* Improve class cycle analysis
* Add a Gradle plugin.
* Incorporate Unit Test coverage metrics to quickly identify the safety of refactoring classes.
* Incorporate bug counts per class to the Impact (Y-Axis) calculation.
* Incorporate more disharmonies from Object Oriented Metrics In Practice (Lanza and Marinescu, 2004).
## Note:
If you are a user of Version 0.1.0 or 0.1.1, you may notice that the list of God classes found by the plugin has changed. This is due to changes in PMD.
# Thank You! Enjoy!
================================================
FILE: change-proneness-ranker/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hjug.refactorfirst</groupId>
<artifactId>refactor-first</artifactId>
<version>0.8.1-SNAPSHOT</version>
</parent>
<groupId>org.hjug.refactorfirst.changepronenessranker</groupId>
<artifactId>change-proneness-ranker</artifactId>
<name>RefactorFirst Change Proneness Ranker</name>
<build>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.testresources</groupId>
<artifactId>test-resources</artifactId>
</dependency>
</dependencies>
</project>
================================================
FILE: change-proneness-ranker/src/main/java/org/hjug/git/ChangePronenessRanker.java
================================================
package org.hjug.git;
import java.io.IOException;
import java.util.*;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.errors.GitAPIException;
@Slf4j
public class ChangePronenessRanker {
private final TreeMap<Integer, Integer> changeCountsByTimeStamps = new TreeMap<>();
private final Map<String, ScmLogInfo> cachedScmLogInfos = new HashMap<>();
public ChangePronenessRanker(GitLogReader repositoryLogReader) {
try {
log.info("Capturing change count based on commit timestamps");
changeCountsByTimeStamps.putAll(repositoryLogReader.captureChangeCountByCommitTimestamp());
} catch (IOException | GitAPIException e) {
log.error("Error reading from repository: {}", e.getMessage());
}
}
public void rankChangeProneness(List<ScmLogInfo> scmLogInfos) {
for (ScmLogInfo scmLogInfo : scmLogInfos) {
if (!cachedScmLogInfos.containsKey(scmLogInfo.getPath())) {
int commitsInRepositorySinceCreation =
changeCountsByTimeStamps.tailMap(scmLogInfo.getEarliestCommit()).values().stream()
.mapToInt(i -> i)
.sum();
scmLogInfo.setChangeProneness((float) scmLogInfo.getCommitCount() / commitsInRepositorySinceCreation);
cachedScmLogInfos.put(scmLogInfo.getPath(), scmLogInfo);
} else {
scmLogInfo.setChangeProneness(
cachedScmLogInfos.get(scmLogInfo.getPath()).getChangeProneness());
}
}
scmLogInfos.sort(Comparator.comparing(ScmLogInfo::getChangeProneness));
int rank = 0;
for (ScmLogInfo scmLogInfo : scmLogInfos) {
scmLogInfo.setChangePronenessRank(++rank);
}
}
}
================================================
FILE: change-proneness-ranker/src/main/java/org/hjug/git/GitLogReader.java
================================================
package org.hjug.git;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.IntStream;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.lib.*;
import org.eclipse.jgit.revwalk.*;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.io.NullOutputStream;
@Slf4j
public class GitLogReader implements AutoCloseable {
static final String JAVA_FILE_TYPE = ".java";
private Repository gitRepository;
private Git git;
public GitLogReader() {}
public GitLogReader(File basedir) throws IOException {
FileRepositoryBuilder repositoryBuilder = new FileRepositoryBuilder().findGitDir(basedir);
String gitIndexFileEnvVariable = System.getenv("GIT_INDEX_FILE");
if (Objects.nonNull(gitIndexFileEnvVariable)
&& !gitIndexFileEnvVariable.trim().isEmpty()) {
log.debug("Setting Index File based on Env Variable GIT_INDEX_FILE {}", gitIndexFileEnvVariable);
repositoryBuilder = repositoryBuilder.setIndexFile(new File(gitIndexFileEnvVariable));
}
git = Git.open(repositoryBuilder.getGitDir());
gitRepository = git.getRepository();
}
GitLogReader(Git git) {
this.git = git;
gitRepository = git.getRepository();
}
@Override
public void close() throws Exception {
git.close();
}
public File getGitDir(File basedir) {
FileRepositoryBuilder repositoryBuilder = new FileRepositoryBuilder().findGitDir(basedir);
return repositoryBuilder.getGitDir();
}
// log --follow implementation may be worth adopting in the future
// https://github.com/spearce/jgit/blob/master/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/RevWalkTextBuiltin.java
/**
* Returns the number of commits and earliest commit for a given path
* TODO: Move to a different class???
*
* @param path
* @return a LogInfo object
* @throws GitAPIException
*/
public ScmLogInfo fileLog(String path) throws GitAPIException, IOException {
ObjectId branchId = gitRepository.resolve("HEAD");
Iterable<RevCommit> revCommits = git.log().add(branchId).addPath(path).call();
int commitCount = 0;
int earliestCommit = Integer.MAX_VALUE;
int mostRecentCommit = 0;
for (RevCommit revCommit : revCommits) {
int commitTime = revCommit.getCommitTime();
if (commitCount == 0) {
mostRecentCommit = commitTime;
}
if (commitTime < earliestCommit) {
earliestCommit = commitTime;
}
commitCount++;
}
if (commitCount == 0) {
return new ScmLogInfo(path, null, earliestCommit, earliestCommit, commitCount);
}
return new ScmLogInfo(path, null, earliestCommit, mostRecentCommit, commitCount);
}
// based on https://stackoverflow.com/questions/27361538/how-to-show-changes-between-commits-with-jgit
public TreeMap<Integer, Integer> captureChangeCountByCommitTimestamp() throws IOException, GitAPIException {
TreeMap<Integer, Integer> changesByCommitTimestamp = new TreeMap<>();
ObjectId branchId = gitRepository.resolve("HEAD");
List<RevCommit> commitList = new ArrayList<>();
git.log().add(branchId).call().forEach(commitList::add);
if (commitList.isEmpty()) {
return changesByCommitTimestamp;
}
// Handle first / initial commit
changesByCommitTimestamp.putAll(walkFirstCommit(commitList.get(commitList.size() - 1)));
if (commitList.size() < 2) {
return changesByCommitTimestamp;
}
// Process adjacent commit pairs in parallel; each pair is independent
ConcurrentMap<Integer, Integer> concurrentResults = new ConcurrentHashMap<>();
IntStream.range(0, commitList.size() - 1).parallel().forEach(i -> {
RevCommit newer = commitList.get(i);
RevCommit older = commitList.get(i + 1);
try {
int count = 0;
for (DiffEntry entry : getDiffEntries(newer, older)) {
if (entry.getNewPath().endsWith(JAVA_FILE_TYPE)
|| entry.getOldPath().endsWith(JAVA_FILE_TYPE)) {
count++;
}
}
if (count > 0) {
concurrentResults.put(newer.getCommitTime(), count);
}
} catch (IOException e) {
log.error("Error getting diff entries: {}", e.getMessage());
}
});
changesByCommitTimestamp.putAll(concurrentResults);
return changesByCommitTimestamp;
}
private List<DiffEntry> getDiffEntries(RevCommit newCommit, RevCommit oldCommit) throws IOException {
try (ObjectReader reader = gitRepository.newObjectReader();
DiffFormatter df = new DiffFormatter(NullOutputStream.INSTANCE)) {
df.setRepository(gitRepository);
CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
oldTreeIter.reset(reader, newCommit.getTree());
CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
newTreeIter.reset(reader, oldCommit.getTree());
return df.scan(oldTreeIter, newTreeIter);
}
}
Map<Integer, Integer> walkFirstCommit(RevCommit firstCommit) throws IOException {
Map<Integer, Integer> changesByCommitTimestamp = new TreeMap<>();
int firstCommitCount = 0;
ObjectId treeId = firstCommit.getTree();
try (TreeWalk treeWalk = new TreeWalk(gitRepository)) {
treeWalk.setRecursive(false);
treeWalk.reset(treeId);
while (treeWalk.next()) {
if (treeWalk.isSubtree()) {
treeWalk.enterSubtree();
} else {
if (treeWalk.getPathString().endsWith(JAVA_FILE_TYPE)) {
firstCommitCount++;
}
}
}
}
if (firstCommitCount > 0) {
changesByCommitTimestamp.put(firstCommit.getCommitTime(), firstCommitCount);
}
return changesByCommitTimestamp;
}
}
================================================
FILE: change-proneness-ranker/src/main/java/org/hjug/git/ScmLogInfo.java
================================================
package org.hjug.git;
import lombok.Data;
@Data
public class ScmLogInfo {
private String path;
private String className;
private int earliestCommit;
private int mostRecentCommit;
private int commitCount;
private float changeProneness;
private int changePronenessRank;
public ScmLogInfo(String path, String className, int earliestCommit, int mostRecentCommit, int commitCount) {
this.path = path;
this.className = className;
this.earliestCommit = earliestCommit;
this.mostRecentCommit = mostRecentCommit;
this.commitCount = commitCount;
}
}
================================================
FILE: change-proneness-ranker/src/test/java/org/hjug/git/ChangePronenessRankerTest.java
================================================
package org.hjug.git;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.*;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class ChangePronenessRankerTest {
private ChangePronenessRanker changePronenessRanker;
private GitLogReader repositoryLogReader;
@BeforeEach
public void setUp() {
repositoryLogReader = mock(GitLogReader.class);
}
// TODO: this should probably be a cucumber test
@Test
void testChangePronenessCalculation() throws IOException, GitAPIException {
ScmLogInfo scmLogInfo = new ScmLogInfo("path", null, 1595275997, 0, 1);
TreeMap<Integer, Integer> commitsWithChangeCounts = new TreeMap<>();
commitsWithChangeCounts.put(scmLogInfo.getEarliestCommit(), scmLogInfo.getCommitCount());
commitsWithChangeCounts.put(scmLogInfo.getEarliestCommit() + 5 * 60, 3);
commitsWithChangeCounts.put(scmLogInfo.getEarliestCommit() + 10 * 60, 3);
when(repositoryLogReader.captureChangeCountByCommitTimestamp()).thenReturn(commitsWithChangeCounts);
changePronenessRanker = new ChangePronenessRanker(repositoryLogReader);
List<ScmLogInfo> scmLogInfos = new ArrayList<>();
scmLogInfos.add(scmLogInfo);
changePronenessRanker.rankChangeProneness(scmLogInfos);
// 1 commit of a class we're interested in, 6 commits of other files after it
Assertions.assertEquals((float) 1 / 7, scmLogInfo.getChangeProneness(), 0.1);
}
@Test
void testRankChangeProneness() throws IOException, GitAPIException {
// more recent commit
ScmLogInfo newerCommit = new ScmLogInfo("file1", null, 1595275997, 0, 1);
TreeMap<Integer, Integer> commitsWithChangeCounts = new TreeMap<>();
commitsWithChangeCounts.put(newerCommit.getEarliestCommit(), newerCommit.getCommitCount());
commitsWithChangeCounts.put(newerCommit.getEarliestCommit() + 5 * 60, 3);
commitsWithChangeCounts.put(newerCommit.getEarliestCommit() + 10 * 60, 3);
// older commit
ScmLogInfo olderCommit = new ScmLogInfo("file2", null, 1595175997, 0, 1);
commitsWithChangeCounts.put(olderCommit.getEarliestCommit(), olderCommit.getCommitCount());
commitsWithChangeCounts.put(olderCommit.getEarliestCommit() + 5 * 60, 5);
commitsWithChangeCounts.put(olderCommit.getEarliestCommit() + 10 * 60, 5);
when(repositoryLogReader.captureChangeCountByCommitTimestamp()).thenReturn(commitsWithChangeCounts);
changePronenessRanker = new ChangePronenessRanker(repositoryLogReader);
List<ScmLogInfo> scmLogInfos = new ArrayList<>();
scmLogInfos.add(newerCommit);
scmLogInfos.add(olderCommit);
changePronenessRanker.rankChangeProneness(scmLogInfos);
// ranks higher since fewer commits since initial commit
Assertions.assertEquals(2, newerCommit.getChangePronenessRank());
// ranks lower since there have been more commits since initial commit
Assertions.assertEquals(1, olderCommit.getChangePronenessRank());
}
}
================================================
FILE: change-proneness-ranker/src/test/java/org/hjug/git/GitLogReaderTest.java
================================================
package org.hjug.git;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.*;
import java.util.*;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
public class GitLogReaderTest {
// Borrowed bits and pieces from
// https://gist.github.com/rherrmann/0c682ea327862cb6847704acf90b1d5d
@TempDir
public File tempFolder;
private Git git;
private Repository repository;
@BeforeEach
public void setUp() throws GitAPIException {
git = Git.init().setDirectory(tempFolder).call();
repository = git.getRepository();
}
@AfterEach
public void tearDown() {
repository.close();
}
@Test
void testFileLog() throws IOException, GitAPIException, InterruptedException {
// This path works when referencing the full Tobago repository
// String filePath = "tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/AttributeHandler.java";
GitLogReader gitLogReader = new GitLogReader(git);
String attributeHandler = "AttributeHandler.java";
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(attributeHandler);
writeFile(attributeHandler, convertInputStreamToString(resourceAsStream));
git.add().addFilepattern(".").call();
RevCommit firstCommit = git.commit().setMessage("message").call();
// Sleeping for one second to guarantee commits have different time stamps
Thread.sleep(1000);
// write contents of updated file to original file
InputStream resourceAsStream2 = getClass().getClassLoader().getResourceAsStream("AttributeHandler2.java");
writeFile(attributeHandler, convertInputStreamToString(resourceAsStream2));
git.add().addFilepattern(".").call();
RevCommit secondCommit = git.commit().setMessage("message").call();
ScmLogInfo scmLogInfo = gitLogReader.fileLog(attributeHandler);
Assertions.assertEquals(2, scmLogInfo.getCommitCount());
Assertions.assertEquals(firstCommit.getCommitTime(), scmLogInfo.getEarliestCommit());
Assertions.assertEquals(secondCommit.getCommitTime(), scmLogInfo.getMostRecentCommit());
}
@Test
void testWalkFirstCommit() throws IOException, GitAPIException {
GitLogReader gitLogReader = new GitLogReader(git);
String attributeHandler = "AttributeHandler.java";
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(attributeHandler);
writeFile(attributeHandler, convertInputStreamToString(resourceAsStream));
git.add().addFilepattern(".").call();
RevCommit commit = git.commit().setMessage("message").call();
Map<Integer, Integer> result = gitLogReader.walkFirstCommit(commit);
Assertions.assertTrue(result.containsKey(commit.getCommitTime()));
Assertions.assertEquals(1, result.get(commit.getCommitTime()).intValue());
}
@Test
void testCaptureChangCountByCommitTimestamp() throws Exception {
GitLogReader gitLogReader = new GitLogReader(git);
String attributeHandler = "AttributeHandler.java";
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(attributeHandler);
writeFile(attributeHandler, convertInputStreamToString(resourceAsStream));
git.add().addFilepattern(".").call();
RevCommit firstCommit = git.commit().setMessage("message").call();
// Sleeping for one second to guarantee commits have different time stamps
Thread.sleep(1000);
// write contents of updated file to original file
InputStream resourceAsStream2 = getClass().getClassLoader().getResourceAsStream("AttributeHandler2.java");
writeFile(attributeHandler, convertInputStreamToString(resourceAsStream2));
InputStream resourceAsStream3 = getClass().getClassLoader().getResourceAsStream("Attributes.java");
writeFile("Attributes.java", convertInputStreamToString(resourceAsStream3));
git.add().addFilepattern(".").call();
RevCommit secondCommit = git.commit().setMessage("message").call();
Map<Integer, Integer> commitCounts = gitLogReader.captureChangeCountByCommitTimestamp();
Assertions.assertEquals(1, commitCounts.get(firstCommit.getCommitTime()).intValue());
Assertions.assertEquals(
2, commitCounts.get(secondCommit.getCommitTime()).intValue());
}
private void writeFile(String name, String content) throws IOException {
File file = new File(git.getRepository().getWorkTree(), name);
try (FileOutputStream outputStream = new FileOutputStream(file)) {
outputStream.write(content.getBytes(UTF_8));
}
}
private String convertInputStreamToString(InputStream inputStream) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
return result.toString("UTF-8");
}
}
================================================
FILE: cli/.gitignore
================================================
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
================================================
FILE: cli/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hjug.refactorfirst</groupId>
<artifactId>refactor-first</artifactId>
<version>0.8.1-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<groupId>org.hjug.refactorfirst.report</groupId>
<artifactId>cli</artifactId>
<name>RefactorFirst CLI</name>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.7.4</version>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.report</groupId>
<artifactId>report</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<!-- Needed to suppress CVE-2023-2976 in maven-core:3.9.9 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.hjug.refactorfirst.Main</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.skife.maven</groupId>
<artifactId>really-executable-jar-maven-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<programFile>rf</programFile>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>really-executable-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: cli/src/main/java/org/hjug/refactorfirst/Main.java
================================================
package org.hjug.refactorfirst;
import picocli.CommandLine;
public class Main {
public static void main(String[] args) {
int exitCode = new CommandLine(new ReportCommand())
.setCaseInsensitiveEnumValuesAllowed(true)
.execute(args);
System.exit(exitCode);
}
}
================================================
FILE: cli/src/main/java/org/hjug/refactorfirst/ReportCommand.java
================================================
package org.hjug.refactorfirst;
import static picocli.CommandLine.Option;
import java.io.File;
import java.io.FileReader;
import java.util.concurrent.Callable;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.project.MavenProject;
import org.hjug.refactorfirst.report.CsvReport;
import org.hjug.refactorfirst.report.HtmlReport;
import org.hjug.refactorfirst.report.SimpleHtmlReport;
import org.hjug.refactorfirst.report.json.JsonReportExecutor;
import picocli.CommandLine.Command;
@Command(mixinStandardHelpOptions = true, description = "Generate a report")
@Slf4j
public class ReportCommand implements Callable<Integer> {
@Option(
names = {"-d", "--details"},
defaultValue = "false",
description = "Show detailed report")
private boolean showDetails;
@Option(
names = {"-eac", "--edge-analysis-count"},
defaultValue = "50",
description = "Back Edge Analysis Count")
protected int backEdgeAnalysisCount;
@Option(
names = {"-c", "--analyze-cycles"},
defaultValue = "true",
description = "Analyze Cycles")
private boolean analyzeCycles;
@Option(
names = {"-m", "--minify-html"},
defaultValue = "false",
description = "Minify HTML output")
private boolean minifiyHtml;
@Option(
names = {"-xt", "--exclude-tests"},
defaultValue = "true",
description = "Exclude tests from analysis")
private boolean excludeTests;
/**
* The test source directory containing test class sources.
*/
@Option(
names = {"-tsd", "--output"},
description =
"Test source directory. Defaults to test/src or test\\src based on your OS. Default is intentionally generic.")
private String testSourceDirectory;
@Option(
names = {"-p", "--project"},
description = "Project name")
private String projectName;
@Option(
names = {"-v", "--version"},
description = "Project version")
private String projectVersion;
@Option(
names = {"-o", "--output"},
defaultValue = ".",
description = "Output directory")
private String outputDirectory;
@Option(
names = {"-b", "--base-dir"},
defaultValue = ".",
description = "Base directory of the project")
private File baseDir;
@Option(
names = {"-t", "--type"},
description = "Report type: ${COMPLETION-CANDIDATES}",
defaultValue = "HTML")
private ReportType reportType;
@Override
public Integer call() {
// TODO: add support for inferring arguments from gradle properties
inferArgumentsFromMavenProject();
populateDefaultArguments();
switch (reportType) {
case SIMPLE_HTML:
SimpleHtmlReport simpleHtmlReport = new SimpleHtmlReport();
simpleHtmlReport.execute(
backEdgeAnalysisCount,
analyzeCycles,
showDetails,
minifiyHtml,
excludeTests,
testSourceDirectory,
projectName,
projectVersion,
baseDir,
outputDirectory);
return 0;
case HTML:
HtmlReport htmlReport = new HtmlReport();
htmlReport.execute(
backEdgeAnalysisCount,
analyzeCycles,
showDetails,
minifiyHtml,
excludeTests,
testSourceDirectory,
projectName,
projectVersion,
baseDir,
outputDirectory);
return 0;
case JSON:
JsonReportExecutor jsonReportExecutor = new JsonReportExecutor();
jsonReportExecutor.execute(baseDir, outputDirectory);
return 0;
case CSV:
CsvReport csvReport = new CsvReport();
csvReport.execute(showDetails, projectName, projectVersion, outputDirectory, baseDir);
return 0;
}
return 0;
}
private void populateDefaultArguments() {
if (projectName == null || projectName.isEmpty()) {
projectName = "my-project";
}
if (projectVersion == null || projectVersion.isEmpty()) {
projectVersion = "0.0.0";
}
}
private void inferArgumentsFromMavenProject() {
if (baseDir.isDirectory()) {
File[] potentialPomFiles = baseDir.listFiles(f -> f.getName().equals("pom.xml"));
File pomFile = null;
if (potentialPomFiles != null && potentialPomFiles.length > 0) {
pomFile = potentialPomFiles[0];
}
if (pomFile != null) {
Model model;
FileReader reader;
MavenXpp3Reader mavenreader = new MavenXpp3Reader();
try {
reader = new FileReader(pomFile);
model = mavenreader.read(reader);
model.setPomFile(pomFile);
} catch (Exception ex) {
log.info("Unable to infer arguments from pom file");
return;
}
MavenProject project = new MavenProject(model);
// only override project name and version if they are not set
if (projectName == null || projectName.isEmpty()) {
projectName = project.getName();
}
if (projectVersion == null || projectVersion.isEmpty()) {
projectVersion = project.getVersion();
}
}
}
}
}
================================================
FILE: cli/src/main/java/org/hjug/refactorfirst/ReportType.java
================================================
package org.hjug.refactorfirst;
public enum ReportType {
SIMPLE_HTML,
HTML,
JSON,
CSV;
}
================================================
FILE: codebase-graph-builder/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hjug.refactorfirst</groupId>
<artifactId>refactor-first</artifactId>
<version>0.8.1-SNAPSHOT</version>
</parent>
<groupId>org.hjug.refactorfirst.codebasegraphbuilder</groupId>
<artifactId>codebase-graph-builder</artifactId>
<name>RefactorFirst Codebase Graph Builder</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-recipe-bom</artifactId>
<version>3.4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-21</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-17</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java-11</artifactId>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-java</artifactId>
</dependency>
<!--gizmo 1.0.11, used by rewrite-core has a CVSS score > 8.0 -->
<dependency>
<groupId>io.quarkus.gizmo</groupId>
<artifactId>gizmo</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite</groupId>
<artifactId>rewrite-core</artifactId>
</dependency>
</dependencies>
</project>
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/CodebaseGraphDTO.java
================================================
package org.hjug.graphbuilder;
import java.util.Map;
import lombok.Data;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
@Data
public class CodebaseGraphDTO {
private final Graph<String, DefaultWeightedEdge> classReferencesGraph;
private final Graph<String, DefaultWeightedEdge> packageReferencesGraph;
// used for looking up files where classes reside
private final Map<String, String> classToSourceFilePathMapping;
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/DependencyCollector.java
================================================
package org.hjug.graphbuilder;
public interface DependencyCollector {
/**
* Records a dependency from one class to another
*
* @param fromClassFqn The fully qualified name of the class that depends on another
* @param toClassFqn The fully qualified name of the class being depended upon
*/
void addClassDependency(String fromClassFqn, String toClassFqn);
/**
* Records a dependency from one package to another
*
* @param fromPackageName The package that depends on another
* @param toPackageName The package being depended upon
*/
void addPackageDependency(String fromPackageName, String toPackageName);
/**
* Records the source file location for a class
*
* @param classFqn The fully qualified name of the class
* @param sourceFilePath The path to the source file containing the class
*/
void recordClassLocation(String classFqn, String sourceFilePath);
/**
* Registers a package as being part of the codebase
*
* @param packageName The package name to register
*/
void registerPackage(String packageName);
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphBuilderConfig.java
================================================
package org.hjug.graphbuilder;
import lombok.Builder;
import lombok.Value;
@Value
@Builder
public class GraphBuilderConfig {
@Builder.Default
boolean excludeTests = true;
@Builder.Default
String testSourceDirectory = "src/test";
public static GraphBuilderConfig defaultConfig() {
return GraphBuilderConfig.builder().build();
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphDependencyCollector.java
================================================
package org.hjug.graphbuilder;
import java.util.HashSet;
import java.util.Set;
import lombok.Getter;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
public class GraphDependencyCollector implements DependencyCollector {
@Getter
private final Graph<String, DefaultWeightedEdge> classReferencesGraph;
@Getter
private final Graph<String, DefaultWeightedEdge> packageReferencesGraph;
@Getter
private final Set<String> packagesInCodebase = new HashSet<>();
public GraphDependencyCollector(
Graph<String, DefaultWeightedEdge> classReferencesGraph,
Graph<String, DefaultWeightedEdge> packageReferencesGraph) {
this.classReferencesGraph = classReferencesGraph;
this.packageReferencesGraph = packageReferencesGraph;
}
@Override
public void addClassDependency(String fromClassFqn, String toClassFqn) {
if (fromClassFqn.equals(toClassFqn)) {
return;
}
classReferencesGraph.addVertex(fromClassFqn);
classReferencesGraph.addVertex(toClassFqn);
if (!classReferencesGraph.containsEdge(fromClassFqn, toClassFqn)) {
classReferencesGraph.addEdge(fromClassFqn, toClassFqn);
} else {
DefaultWeightedEdge edge = classReferencesGraph.getEdge(fromClassFqn, toClassFqn);
classReferencesGraph.setEdgeWeight(edge, classReferencesGraph.getEdgeWeight(edge) + 1);
}
}
@Override
public void addPackageDependency(String fromPackageName, String toPackageName) {
if (fromPackageName.equals(toPackageName)) {
return;
}
packageReferencesGraph.addVertex(fromPackageName);
packageReferencesGraph.addVertex(toPackageName);
if (!packageReferencesGraph.containsEdge(fromPackageName, toPackageName)) {
packageReferencesGraph.addEdge(fromPackageName, toPackageName);
} else {
DefaultWeightedEdge edge = packageReferencesGraph.getEdge(fromPackageName, toPackageName);
packageReferencesGraph.setEdgeWeight(edge, packageReferencesGraph.getEdgeWeight(edge) + 1);
}
}
@Override
public void recordClassLocation(String classFqn, String sourceFilePath) {
// This will be handled by JavaVisitor which maintains the mapping
}
@Override
public void registerPackage(String packageName) {
packagesInCodebase.add(packageName);
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/JavaGraphBuilder.java
================================================
package org.hjug.graphbuilder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import org.hjug.graphbuilder.visitor.JavaMethodDeclarationVisitor;
import org.hjug.graphbuilder.visitor.JavaVariableTypeVisitor;
import org.hjug.graphbuilder.visitor.JavaVisitor;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
@Slf4j
public class JavaGraphBuilder {
/**
* Given a java source directory, return a CodebaseGraphDTO using default configuration
*
* @param srcDirectory The source directory to analyze
* @param excludeTests Whether to exclude test files
* @param testSourceDirectory The test source directory pattern to exclude
* @return CodebaseGraphDTO
* @throws IOException
*/
public CodebaseGraphDTO getCodebaseGraphDTO(String srcDirectory, boolean excludeTests, String testSourceDirectory)
throws IOException {
GraphBuilderConfig config = GraphBuilderConfig.builder()
.excludeTests(excludeTests)
.testSourceDirectory(testSourceDirectory)
.build();
return getCodebaseGraphDTO(srcDirectory, config);
}
/**
* Given a java source directory and configuration, return a CodebaseGraphDTO
*
* @param srcDirectory The source directory to analyze
* @param config The configuration for the graph builder
* @return CodebaseGraphDTO
* @throws IOException
*/
public CodebaseGraphDTO getCodebaseGraphDTO(String srcDirectory, GraphBuilderConfig config) throws IOException {
if (srcDirectory == null || srcDirectory.isEmpty()) {
throw new IllegalArgumentException("Source directory cannot be null or empty");
}
return processWithOpenRewrite(srcDirectory, config);
}
private CodebaseGraphDTO processWithOpenRewrite(String srcDir, GraphBuilderConfig config) throws IOException {
File srcDirectory = new File(srcDir);
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
final Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
final Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
final GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
final JavaVisitor<ExecutionContext> javaVisitor = new JavaVisitor<>(dependencyCollector);
final JavaVariableTypeVisitor<ExecutionContext> javaVariableTypeVisitor =
new JavaVariableTypeVisitor<>(dependencyCollector);
final JavaMethodDeclarationVisitor<ExecutionContext> javaMethodDeclarationVisitor =
new JavaMethodDeclarationVisitor<>(dependencyCollector);
try (Stream<Path> pathStream = Files.walk(Paths.get(srcDirectory.getAbsolutePath()))) {
List<Path> list;
if (config.isExcludeTests()) {
list = pathStream
.filter(file -> !file.toString().contains(config.getTestSourceDirectory()))
.collect(Collectors.toList());
} else {
list = pathStream.collect(Collectors.toList());
}
javaParser
.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx)
.forEach(cu -> {
javaVisitor.visit(cu, ctx);
javaVariableTypeVisitor.visit(cu, ctx);
javaMethodDeclarationVisitor.visit(cu, ctx);
});
}
removeClassesNotInCodebase(dependencyCollector.getPackagesInCodebase(), classReferencesGraph);
return new CodebaseGraphDTO(
classReferencesGraph, packageReferencesGraph, javaVisitor.getClassToSourceFilePathMapping());
}
// remove node if package not in codebase
void removeClassesNotInCodebase(
Set<String> packagesInCodebase, Graph<String, DefaultWeightedEdge> classReferencesGraph) {
// collect nodes to remove
Set<String> classesToRemove = new HashSet<>();
for (String classFqn : classReferencesGraph.vertexSet()) {
if (!packagesInCodebase.contains(getPackage(classFqn))) {
classesToRemove.add(classFqn);
}
}
classReferencesGraph.removeAllVertices(classesToRemove);
}
String getPackage(String fqn) {
// handle no package
if (!fqn.contains(".")) {
return "";
}
int lastIndex = fqn.lastIndexOf(".");
return fqn.substring(0, lastIndex);
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/BaseCodebaseVisitor.java
================================================
package org.hjug.graphbuilder.visitor;
import lombok.Getter;
import org.hjug.graphbuilder.DependencyCollector;
import org.openrewrite.java.JavaIsoVisitor;
@Getter
public abstract class BaseCodebaseVisitor<P> extends JavaIsoVisitor<P> {
protected final DependencyCollector dependencyCollector;
protected BaseCodebaseVisitor(DependencyCollector dependencyCollector) {
this.dependencyCollector = dependencyCollector;
}
protected abstract String getCurrentOwnerFqn();
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/BaseTypeProcessor.java
================================================
package org.hjug.graphbuilder.visitor;
import lombok.extern.slf4j.Slf4j;
import org.hjug.graphbuilder.DependencyCollector;
import org.openrewrite.Cursor;
import org.openrewrite.java.service.AnnotationService;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.TypeTree;
@Slf4j
public abstract class BaseTypeProcessor {
private final TypeDependencyExtractor typeDependencyExtractor = new TypeDependencyExtractor();
protected abstract DependencyCollector getDependencyCollector();
protected void processType(String ownerFqn, JavaType javaType) {
if (javaType == null || javaType instanceof JavaType.Unknown) {
return;
}
for (String dependency : typeDependencyExtractor.extractDependencies(javaType)) {
getDependencyCollector().addClassDependency(ownerFqn, dependency);
}
}
protected void processAnnotation(String ownerFqn, J.Annotation annotation, Cursor cursor) {
if (annotation.getType() instanceof JavaType.Unknown) {
return;
}
JavaType.Class type = (JavaType.Class) annotation.getType();
if (null != type) {
String annotationFqn = type.getFullyQualifiedName();
log.debug("Variable Annotation FQN: {}", annotationFqn);
getDependencyCollector().addClassDependency(ownerFqn, annotationFqn);
if (null != annotation.getArguments()) {
for (Expression argument : annotation.getArguments()) {
processType(ownerFqn, argument.getType());
}
}
}
}
protected void processTypeParameter(String ownerFqn, J.TypeParameter typeParameter, Cursor cursor) {
if (null != typeParameter.getBounds()) {
for (TypeTree bound : typeParameter.getBounds()) {
processType(ownerFqn, bound.getType());
}
}
if (!typeParameter.getAnnotations().isEmpty()) {
for (J.Annotation annotation : typeParameter.getAnnotations()) {
processAnnotation(ownerFqn, annotation, cursor);
}
}
}
protected void processAnnotations(String ownerFqn, Cursor cursor) {
AnnotationService annotationService = new AnnotationService();
for (J.Annotation annotation : annotationService.getAllAnnotations(cursor)) {
processAnnotation(ownerFqn, annotation, cursor);
}
}
protected String getPackageFromFqn(String fqn) {
if (!fqn.contains(".")) {
return "";
}
int lastIndex = fqn.lastIndexOf(".");
return fqn.substring(0, lastIndex);
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/FqnCapturingProcessor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openrewrite.java.tree.J;
public interface FqnCapturingProcessor {
default J.ClassDeclaration captureClassDeclarations(
J.ClassDeclaration classDecl, Map<String, Map<String, String>> fqns) {
// get class fqn (including "$")
String fqn = classDecl.getType().getFullyQualifiedName();
String currentPackage = getPackage(fqn);
String className = getClassName(fqn);
Map<String, String> classesInPackage = fqns.getOrDefault(currentPackage, new HashMap<>());
if (className.contains("$")) {
String normalizedClassName = className.replace('$', '.');
List<String> parts = Arrays.asList(normalizedClassName.split("\\."));
for (int i = 0; i < parts.size(); i++) {
String key = String.join(".", parts.subList(i, parts.size()));
classesInPackage.put(key, currentPackage + "." + normalizedClassName);
}
} else {
classesInPackage.put(className, fqn);
}
fqns.put(currentPackage, classesInPackage);
return classDecl;
}
default String getPackage(String fqn) {
// handle no package
if (!fqn.contains(".")) {
return "";
}
int lastIndex = fqn.lastIndexOf(".");
return fqn.substring(0, lastIndex);
}
/**
*
* @param fqn
* @return Class name (including "$") after last period in FQN
*/
default String getClassName(String fqn) {
// handle no package
if (!fqn.contains(".")) {
return fqn;
}
int lastIndex = fqn.lastIndexOf(".");
return fqn.substring(lastIndex + 1);
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaClassDeclarationVisitor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.hjug.graphbuilder.DependencyCollector;
import org.openrewrite.java.tree.*;
@Slf4j
public class JavaClassDeclarationVisitor<P> extends BaseCodebaseVisitor<P> {
private final BaseTypeProcessor typeProcessor;
private String currentOwnerFqn;
public JavaClassDeclarationVisitor(DependencyCollector dependencyCollector) {
super(dependencyCollector);
this.typeProcessor = new BaseTypeProcessor() {
@Override
protected DependencyCollector getDependencyCollector() {
return dependencyCollector;
}
};
}
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, P p) {
JavaType.FullyQualified type = classDecl.getType();
if (type == null) {
log.warn("ClassDeclaration has null type, skipping: {}", classDecl.getSimpleName());
return classDecl;
}
String owningFqn = type.getFullyQualifiedName();
String previousOwner = currentOwnerFqn;
currentOwnerFqn = owningFqn;
try {
typeProcessor.processType(owningFqn, type);
TypeTree extendsTypeTree = classDecl.getExtends();
if (null != extendsTypeTree) {
typeProcessor.processType(owningFqn, extendsTypeTree.getType());
}
List<TypeTree> implementsTypeTree = classDecl.getImplements();
if (null != implementsTypeTree) {
for (TypeTree typeTree : implementsTypeTree) {
typeProcessor.processType(owningFqn, typeTree.getType());
}
}
for (J.Annotation leadingAnnotation : classDecl.getLeadingAnnotations()) {
typeProcessor.processAnnotation(owningFqn, leadingAnnotation, getCursor());
}
if (null != classDecl.getTypeParameters()) {
for (J.TypeParameter typeParameter : classDecl.getTypeParameters()) {
typeProcessor.processTypeParameter(owningFqn, typeParameter, getCursor());
}
}
return super.visitClassDeclaration(classDecl, p);
} finally {
currentOwnerFqn = previousOwner;
}
}
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, P p) {
J.MethodInvocation methodInvocation = super.visitMethodInvocation(method, p);
if (currentOwnerFqn == null) {
return methodInvocation;
}
JavaType.Method methodType = methodInvocation.getMethodType();
if (null != methodType && null != methodType.getDeclaringType()) {
typeProcessor.processType(currentOwnerFqn, methodType.getDeclaringType());
}
if (null != methodInvocation.getTypeParameters()
&& !methodInvocation.getTypeParameters().isEmpty()) {
for (Expression typeParameter : methodInvocation.getTypeParameters()) {
typeProcessor.processType(currentOwnerFqn, typeParameter.getType());
}
}
return methodInvocation;
}
@Override
public J.NewClass visitNewClass(J.NewClass newClass, P p) {
J.NewClass result = super.visitNewClass(newClass, p);
if (currentOwnerFqn != null) {
typeProcessor.processType(currentOwnerFqn, newClass.getType());
}
return result;
}
@Override
public J.Lambda visitLambda(J.Lambda lambda, P p) {
if (currentOwnerFqn != null && lambda.getType() != null) {
typeProcessor.processType(currentOwnerFqn, lambda.getType());
}
// Recursively visit the lambda body to capture method invocations and type references
// The super.visitLambda call will traverse into the lambda's body and parameters
return super.visitLambda(lambda, p);
}
@Override
public J.If visitIf(J.If iff, P p) {
return super.visitIf(iff, p);
}
@Override
public J.ForLoop visitForLoop(J.ForLoop forLoop, P p) {
return super.visitForLoop(forLoop, p);
}
@Override
public J.ForEachLoop visitForEachLoop(J.ForEachLoop forEachLoop, P p) {
return super.visitForEachLoop(forEachLoop, p);
}
@Override
public J.WhileLoop visitWhileLoop(J.WhileLoop whileLoop, P p) {
return super.visitWhileLoop(whileLoop, p);
}
@Override
public J.DoWhileLoop visitDoWhileLoop(J.DoWhileLoop doWhileLoop, P p) {
return super.visitDoWhileLoop(doWhileLoop, p);
}
@Override
public J.Switch visitSwitch(J.Switch switchStatement, P p) {
return super.visitSwitch(switchStatement, p);
}
@Override
public J.Try visitTry(J.Try tryStatement, P p) {
J.Try result = super.visitTry(tryStatement, p);
if (currentOwnerFqn != null && tryStatement.getCatches() != null) {
for (J.Try.Catch catchClause : tryStatement.getCatches()) {
if (catchClause.getParameter().getTree() instanceof J.VariableDeclarations) {
J.VariableDeclarations varDecl =
(J.VariableDeclarations) catchClause.getParameter().getTree();
if (varDecl.getTypeExpression() != null) {
typeProcessor.processType(
currentOwnerFqn, varDecl.getTypeExpression().getType());
}
}
}
}
return result;
}
@Override
public J.InstanceOf visitInstanceOf(J.InstanceOf instanceOf, P p) {
J.InstanceOf result = super.visitInstanceOf(instanceOf, p);
if (currentOwnerFqn != null && instanceOf.getClazz() != null && instanceOf.getClazz() instanceof TypeTree) {
typeProcessor.processType(currentOwnerFqn, ((TypeTree) instanceOf.getClazz()).getType());
}
return result;
}
@Override
public J.TypeCast visitTypeCast(J.TypeCast typeCast, P p) {
J.TypeCast result = super.visitTypeCast(typeCast, p);
if (currentOwnerFqn != null && typeCast.getClazz() != null) {
typeProcessor.processType(
currentOwnerFqn, typeCast.getClazz().getTree().getType());
}
return result;
}
@Override
public J.MemberReference visitMemberReference(J.MemberReference memberRef, P p) {
J.MemberReference result = super.visitMemberReference(memberRef, p);
if (currentOwnerFqn != null && memberRef.getType() != null) {
typeProcessor.processType(currentOwnerFqn, memberRef.getType());
}
return result;
}
@Override
public J.NewArray visitNewArray(J.NewArray newArray, P p) {
J.NewArray result = super.visitNewArray(newArray, p);
if (currentOwnerFqn != null && newArray.getType() != null) {
typeProcessor.processType(currentOwnerFqn, newArray.getType());
}
return result;
}
@Override
protected String getCurrentOwnerFqn() {
return currentOwnerFqn;
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaFqnCapturingVisitor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.*;
import lombok.Getter;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.J;
/**
* Captures Fully Qualified Names (FQN) of classes as they will be imported in import statements.
* fqns map that is populated by this visitor is used to resolve Generic types.
*
* @param <P>
*/
@Getter
public class JavaFqnCapturingVisitor<P> extends JavaIsoVisitor<P> {
// consider using ConcurrentHashMap to scale performance
// package -> name, FQN
private final Map<String, Map<String, String>> fqnMap = new HashMap<>();
private final Set<String> fqns = new HashSet<>();
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, P p) {
captureClassDeclarations(classDecl, fqnMap);
return classDecl;
}
J.ClassDeclaration captureClassDeclarations(J.ClassDeclaration classDecl, Map<String, Map<String, String>> fqnMap) {
String fqn = classDecl.getType().getFullyQualifiedName();
fqns.add(fqn);
return classDecl;
}
String getPackage(String fqn) {
// handle no package
if (!fqn.contains(".")) {
return "";
}
int lastIndex = fqn.lastIndexOf(".");
return fqn.substring(0, lastIndex);
}
/**
*
* @param fqn
* @return Class name (including "$") after last period in FQN
*/
String getClassName(String fqn) {
// handle no package
if (!fqn.contains(".")) {
return fqn;
}
int lastIndex = fqn.lastIndexOf(".");
return fqn.substring(lastIndex + 1);
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaMethodDeclarationVisitor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.hjug.graphbuilder.DependencyCollector;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.NameTree;
import org.openrewrite.java.tree.TypeTree;
@Slf4j
public class JavaMethodDeclarationVisitor<P> extends BaseCodebaseVisitor<P> {
private final BaseTypeProcessor typeProcessor;
public JavaMethodDeclarationVisitor(DependencyCollector dependencyCollector) {
super(dependencyCollector);
this.typeProcessor = new BaseTypeProcessor() {
@Override
protected DependencyCollector getDependencyCollector() {
return dependencyCollector;
}
};
}
@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, P p) {
J.MethodDeclaration methodDeclaration = super.visitMethodDeclaration(method, p);
JavaType.Method methodType = methodDeclaration.getMethodType();
if (null == methodType) {
log.warn("MethodDeclaration has null methodType, skipping: {}", methodDeclaration.getSimpleName());
return methodDeclaration;
}
if (methodType.getDeclaringType() == null) {
log.warn("MethodDeclaration has null declaring type, skipping: {}", methodDeclaration.getSimpleName());
return methodDeclaration;
}
String owner = methodType.getDeclaringType().getFullyQualifiedName();
TypeTree returnTypeExpression = methodDeclaration.getReturnTypeExpression();
if (returnTypeExpression != null) {
JavaType returnType = returnTypeExpression.getType();
if (!(returnType instanceof JavaType.Primitive)) {
typeProcessor.processType(owner, returnType);
}
}
for (J.Annotation leadingAnnotation : methodDeclaration.getLeadingAnnotations()) {
typeProcessor.processAnnotation(owner, leadingAnnotation, getCursor());
}
if (null != methodDeclaration.getTypeParameters()) {
for (J.TypeParameter typeParameter : methodDeclaration.getTypeParameters()) {
typeProcessor.processTypeParameter(owner, typeParameter, getCursor());
}
}
List<NameTree> throwz = methodDeclaration.getThrows();
if (null != throwz && !throwz.isEmpty()) {
for (NameTree thrown : throwz) {
typeProcessor.processType(owner, thrown.getType());
}
}
return methodDeclaration;
}
@Override
protected String getCurrentOwnerFqn() {
return null;
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaVariableTypeVisitor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.hjug.graphbuilder.DependencyCollector;
import org.openrewrite.java.tree.*;
@Slf4j
public class JavaVariableTypeVisitor<P> extends BaseCodebaseVisitor<P> {
private final BaseTypeProcessor typeProcessor;
public JavaVariableTypeVisitor(DependencyCollector dependencyCollector) {
super(dependencyCollector);
this.typeProcessor = new BaseTypeProcessor() {
@Override
protected DependencyCollector getDependencyCollector() {
return dependencyCollector;
}
};
}
@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, P p) {
J.VariableDeclarations variableDeclarations = super.visitVariableDeclarations(multiVariable, p);
List<J.VariableDeclarations.NamedVariable> variables = variableDeclarations.getVariables();
if (null == variables || variables.isEmpty() || null == variables.get(0).getVariableType()) {
log.debug("Skipping variable declaration with null variable type");
return variableDeclarations;
}
JavaType owner = variables.get(0).getVariableType().getOwner();
String ownerFqn = "";
if (owner instanceof JavaType.Method) {
JavaType.Method m = (JavaType.Method) owner;
if (m.getDeclaringType() == null) {
log.warn("Method owner has null declaring type, skipping variable declaration");
return variableDeclarations;
}
ownerFqn = m.getDeclaringType().getFullyQualifiedName();
} else if (owner instanceof JavaType.Class) {
JavaType.Class c = (JavaType.Class) owner;
ownerFqn = c.getFullyQualifiedName();
} else {
log.debug("Unknown owner type: {}", owner != null ? owner.getClass() : "null");
return variableDeclarations;
}
log.debug("Processing variable declaration in: {}", ownerFqn);
TypeTree typeTree = variableDeclarations.getTypeExpression();
JavaType javaType;
if (null != typeTree) {
javaType = typeTree.getType();
} else {
return variableDeclarations;
}
typeProcessor.processAnnotations(ownerFqn, getCursor());
if (javaType instanceof JavaType.Primitive) {
return variableDeclarations;
}
typeProcessor.processType(ownerFqn, javaType);
return variableDeclarations;
}
@Override
protected String getCurrentOwnerFqn() {
return null;
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaVisitor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.*;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.hjug.graphbuilder.DependencyCollector;
import org.openrewrite.java.tree.*;
@Slf4j
public class JavaVisitor<P> extends BaseCodebaseVisitor<P> {
@Getter
private final Map<String, String> classToSourceFilePathMapping = new HashMap<>();
private final JavaClassDeclarationVisitor<P> javaClassDeclarationVisitor;
public JavaVisitor(DependencyCollector dependencyCollector) {
super(dependencyCollector);
javaClassDeclarationVisitor = new JavaClassDeclarationVisitor<>(dependencyCollector);
}
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, P p) {
return javaClassDeclarationVisitor.visitClassDeclaration(classDecl, p);
}
// Map each class to its source file
@Override
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, P p) {
J.CompilationUnit compilationUnit = super.visitCompilationUnit(cu, p);
J.Package packageDeclaration = compilationUnit.getPackageDeclaration();
if (null == packageDeclaration) {
return compilationUnit;
}
dependencyCollector.registerPackage(packageDeclaration.getPackageName());
for (J.ClassDeclaration aClass : compilationUnit.getClasses()) {
String classFqn = aClass.getType().getFullyQualifiedName();
String sourcePath = compilationUnit.getSourcePath().toUri().toString();
classToSourceFilePathMapping.put(classFqn, sourcePath);
dependencyCollector.recordClassLocation(classFqn, sourcePath);
}
return compilationUnit;
}
@Override
protected String getCurrentOwnerFqn() {
return null;
}
}
================================================
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/TypeDependencyExtractor.java
================================================
package org.hjug.graphbuilder.visitor;
import java.util.HashSet;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.openrewrite.java.tree.JavaType;
@Slf4j
public class TypeDependencyExtractor {
/**
* Extracts all type dependencies from a JavaType
*
* @param javaType The type to extract dependencies from
* @return Set of fully qualified type names that the given type depends on
*/
public Set<String> extractDependencies(JavaType javaType) {
Set<String> dependencies = new HashSet<>();
if (javaType == null) {
return dependencies;
}
extractDependenciesRecursive(javaType, dependencies);
return dependencies;
}
private void extractDependenciesRecursive(JavaType javaType, Set<String> dependencies) {
if (javaType instanceof JavaType.Class) {
extractFromClass((JavaType.Class) javaType, dependencies);
} else if (javaType instanceof JavaType.Parameterized) {
extractFromParameterized((JavaType.Parameterized) javaType, dependencies);
} else if (javaType instanceof JavaType.GenericTypeVariable) {
extractFromGenericTypeVariable((JavaType.GenericTypeVariable) javaType, dependencies);
} else if (javaType instanceof JavaType.Array) {
extractFromArray((JavaType.Array) javaType, dependencies);
}
}
private void extractFromClass(JavaType.Class classType, Set<String> dependencies) {
log.debug("Class type FQN: {}", classType.getFullyQualifiedName());
dependencies.add(classType.getFullyQualifiedName());
extractAnnotations(classType, dependencies);
}
private void extractFromParameterized(JavaType.Parameterized parameterized, Set<String> dependencies) {
log.debug("Parameterized type FQN: {}", parameterized.getFullyQualifiedName());
dependencies.add(parameterized.getFullyQualifiedName());
extractAnnotations(parameterized, dependencies);
log.debug("Nested Parameterized type parameters: {}", parameterized.getTypeParameters());
for (JavaType parameter : parameterized.getTypeParameters()) {
extractDependenciesRecursive(parameter, dependencies);
}
}
private void extractFromArray(JavaType.Array arrayType, Set<String> dependencies) {
log.debug("Array Element type: {}", arrayType.getElemType());
extractDependenciesRecursive(arrayType.getElemType(), dependencies);
}
private void extractFromGenericTypeVariable(JavaType.GenericTypeVariable typeVariable, Set<String> dependencies) {
log.debug("Type parameter type name: {}", typeVariable.getName());
for (JavaType bound : typeVariable.getBounds()) {
if (bound instanceof JavaType.Class) {
dependencies.add(((JavaType.Class) bound).getFullyQualifiedName());
} else if (bound instanceof JavaType.Parameterized) {
dependencies.add(((JavaType.Parameterized) bound).getFullyQualifiedName());
} else {
log.debug("Unknown type bound: {}", bound);
}
}
}
private void extractAnnotations(JavaType.FullyQualified fullyQualified, Set<String> dependencies) {
if (!fullyQualified.getAnnotations().isEmpty()) {
for (JavaType.FullyQualified annotation : fullyQualified.getAnnotations()) {
String annotationFqn = annotation.getFullyQualifiedName();
log.debug("Annotation FQN: {}", annotationFqn);
dependencies.add(annotationFqn);
}
}
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/JavaGraphBuilderTest.java
================================================
package org.hjug.graphbuilder;
import static org.junit.jupiter.api.Assertions.*;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class JavaGraphBuilderTest {
JavaGraphBuilder javaGraphBuilder = new JavaGraphBuilder();
@DisplayName("When source directory input param is empty or null throw IllegalArgumentException.")
@Test
void parseSourceDirectoryEmptyTest() {
Assertions.assertThrows(
IllegalArgumentException.class, () -> javaGraphBuilder.getCodebaseGraphDTO("", false, ""));
Assertions.assertThrows(
IllegalArgumentException.class, () -> javaGraphBuilder.getCodebaseGraphDTO(null, false, ""));
}
@DisplayName("Given a valid source directory input parameter return a valid graph.")
@Test
void parseSourceDirectoryTest() throws IOException {
File srcDirectory = new File("src/test/resources/javaSrcDirectory");
CodebaseGraphDTO dto = javaGraphBuilder.getCodebaseGraphDTO(srcDirectory.getAbsolutePath(), false, "");
Graph<String, DefaultWeightedEdge> classReferencesGraph = dto.getClassReferencesGraph();
assertNotNull(classReferencesGraph);
assertEquals(5, classReferencesGraph.vertexSet().size());
assertEquals(7, classReferencesGraph.edgeSet().size());
assertTrue(classReferencesGraph.containsVertex("com.ideacrest.parser.testclasses.A"));
assertTrue(classReferencesGraph.containsVertex("com.ideacrest.parser.testclasses.B"));
assertTrue(classReferencesGraph.containsVertex("com.ideacrest.parser.testclasses.C"));
assertTrue(classReferencesGraph.containsVertex("com.ideacrest.parser.testclasses.D"));
assertTrue(classReferencesGraph.containsVertex("com.ideacrest.parser.testclasses.E"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.A", "com.ideacrest.parser.testclasses.B"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.B", "com.ideacrest.parser.testclasses.C"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.C", "com.ideacrest.parser.testclasses.A"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.C", "com.ideacrest.parser.testclasses.E"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.D", "com.ideacrest.parser.testclasses.A"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.D", "com.ideacrest.parser.testclasses.C"));
assertTrue(classReferencesGraph.containsEdge(
"com.ideacrest.parser.testclasses.E", "com.ideacrest.parser.testclasses.D"));
// confirm edge weight calculations
assertEquals(
1,
getEdgeWeight(
classReferencesGraph,
"com.ideacrest.parser.testclasses.A",
"com.ideacrest.parser.testclasses.B"));
assertEquals(
2,
getEdgeWeight(
classReferencesGraph,
"com.ideacrest.parser.testclasses.E",
"com.ideacrest.parser.testclasses.D"));
}
private static double getEdgeWeight(
Graph<String, DefaultWeightedEdge> classReferencesGraph, String sourceVertex, String targetVertex) {
return classReferencesGraph.getEdgeWeight(classReferencesGraph.getEdge(sourceVertex, targetVertex));
}
@Test
void removeClassesNotInCodebase() throws IOException {
File srcDirectory = new File("src/test/resources/javaSrcDirectory");
CodebaseGraphDTO dto = javaGraphBuilder.getCodebaseGraphDTO(srcDirectory.getAbsolutePath(), false, "");
Graph<String, DefaultWeightedEdge> classReferencesGraph = dto.getClassReferencesGraph();
classReferencesGraph.addVertex("org.favioriteoss.FunClass");
classReferencesGraph.addVertex("org.favioriteoss.AnotherFunClass");
DefaultWeightedEdge edge1 =
classReferencesGraph.addEdge("com.ideacrest.parser.testclasses.A", "org.favioriteoss.FunClass");
DefaultWeightedEdge edge2 =
classReferencesGraph.addEdge("com.ideacrest.parser.testclasses.A", "org.favioriteoss.AnotherFunClass");
assertTrue(classReferencesGraph.containsVertex("org.favioriteoss.FunClass"));
assertTrue(classReferencesGraph.containsVertex("org.favioriteoss.AnotherFunClass"));
Set<String> packagesInCodebase = new HashSet<>();
packagesInCodebase.add("com.ideacrest.parser.testclasses");
javaGraphBuilder.removeClassesNotInCodebase(packagesInCodebase, classReferencesGraph);
assertFalse(classReferencesGraph.containsVertex("org.favioriteoss.FunClass"));
assertFalse(classReferencesGraph.containsVertex("org.favioriteoss.AnotherFunClass"));
assertFalse(classReferencesGraph.containsEdge(edge1));
assertFalse(classReferencesGraph.containsEdge(edge2));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaClassDeclarationVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaClassDeclarationVisitorTest {
@Test
void visitClasses() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses");
org.openrewrite.java.JavaParser javaParser =
JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> javaVariableCapturingVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
javaVariableCapturingVisitor.visit(cu, ctx);
});
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.A"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.B"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.C"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.D"));
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.MyAnnotation"));
Assertions.assertFalse(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.E"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.F"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.G"));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaFqnCapturingVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
@Disabled
class JavaFqnCapturingVisitorTest {
@Test
void visitClasses() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses");
org.openrewrite.java.JavaParser javaParser =
JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
JavaFqnCapturingVisitor<ExecutionContext> javaFqnCapturingVisitor = new JavaFqnCapturingVisitor();
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
javaFqnCapturingVisitor.visit(cu, ctx);
});
Map<String, Map<String, String>> fqns = javaFqnCapturingVisitor.getFqnMap();
Map<String, String> processed = fqns.get("org.hjug.graphbuilder.visitor.testclasses");
Assertions.assertEquals("org.hjug.graphbuilder.visitor.testclasses.A", processed.get("A"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass", processed.get("A.InnerClass"));
Assertions.assertEquals("org.hjug.graphbuilder.visitor.testclasses.A.InnerClass", processed.get("InnerClass"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner",
processed.get("A.InnerClass.InnerInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner",
processed.get("InnerClass.InnerInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner", processed.get("InnerInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner.MegaInner",
processed.get("A.InnerClass.InnerInner.MegaInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner.MegaInner",
processed.get("InnerClass.InnerInner.MegaInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner.MegaInner",
processed.get("InnerInner.MegaInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.InnerClass.InnerInner.MegaInner",
processed.get("MegaInner"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.StaticInnerClass", processed.get("A.StaticInnerClass"));
Assertions.assertEquals(
"org.hjug.graphbuilder.visitor.testclasses.A.StaticInnerClass", processed.get("StaticInnerClass"));
Assertions.assertEquals("org.hjug.graphbuilder.visitor.testclasses.NonPublic", processed.get("NonPublic"));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaInitializerBlockVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaInitializerBlockVisitorTest {
@Test
void visitInstanceInitializerBlocks() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> classDeclarationVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
classDeclarationVisitor.visit(cu, ctx);
});
// Verify that the test class is in the graph
Assertions.assertTrue(
classReferencesGraph.containsVertex(
"org.hjug.graphbuilder.visitor.testclasses.initializers.InitializerBlockTestClass"),
"InitializerBlockTestClass should be in the graph");
// Verify ArrayList is captured from instance initializer block: new ArrayList<>()
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.util.ArrayList"),
"ArrayList should be captured from instance initializer block");
// Verify edge from InitializerBlockTestClass to ArrayList exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.initializers.InitializerBlockTestClass",
"java.util.ArrayList"),
"Should have edge from InitializerBlockTestClass to ArrayList from initializer block");
// Verify HashMap is captured from instance initializer block: new HashMap<>()
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.util.HashMap"),
"HashMap should be captured from instance initializer block");
// Verify edge from InitializerBlockTestClass to HashMap exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.initializers.InitializerBlockTestClass",
"java.util.HashMap"),
"Should have edge from InitializerBlockTestClass to HashMap from initializer block");
// Verify StringBuilder is captured from instance initializer block: new StringBuilder()
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.lang.StringBuilder"),
"StringBuilder should be captured from instance initializer block");
// Verify edge from InitializerBlockTestClass to StringBuilder exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.initializers.InitializerBlockTestClass",
"java.lang.StringBuilder"),
"Should have edge from InitializerBlockTestClass to StringBuilder from initializer block");
}
@Test
void visitStaticInitializerBlocks() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> classDeclarationVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
classDeclarationVisitor.visit(cu, ctx);
});
// Verify that the complex test class is in the graph
Assertions.assertTrue(
classReferencesGraph.containsVertex(
"org.hjug.graphbuilder.visitor.testclasses.initializers.ComplexInitializerClass"),
"ComplexInitializerClass should be in the graph");
// Verify ConcurrentHashMap is captured from static initializer block
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.util.concurrent.ConcurrentHashMap"),
"ConcurrentHashMap should be captured from static initializer block");
// Verify edge from ComplexInitializerClass to ConcurrentHashMap exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.initializers.ComplexInitializerClass",
"java.util.concurrent.ConcurrentHashMap"),
"Should have edge from ComplexInitializerClass to ConcurrentHashMap from static initializer");
// Verify AtomicInteger is captured from static initializer block
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.util.concurrent.atomic.AtomicInteger"),
"AtomicInteger should be captured from static initializer block");
// Verify edge from ComplexInitializerClass to AtomicInteger exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.initializers.ComplexInitializerClass",
"java.util.concurrent.atomic.AtomicInteger"),
"Should have edge from ComplexInitializerClass to AtomicInteger from static initializer");
// Verify nested classes are captured from instance initializer
Assertions.assertTrue(
classReferencesGraph.containsVertex(
"org.hjug.graphbuilder.visitor.testclasses.initializers.ComplexInitializerClass$DataProcessor"),
"DataProcessor nested class should be captured from instance initializer");
Assertions.assertTrue(
classReferencesGraph.containsVertex(
"org.hjug.graphbuilder.visitor.testclasses.initializers.ComplexInitializerClass$HelperService"),
"HelperService nested class should be captured from instance initializer");
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaLambdaVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaLambdaVisitorTest {
@Test
void visitLambdaBodiesRecursively() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> classDeclarationVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
classDeclarationVisitor.visit(cu, ctx);
});
// Verify that the main test class is in the graph
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.lambda.LambdaTestClass"),
"LambdaTestClass should be in the graph");
// Verify that HelperClass is captured as a dependency
// This is from field declaration AND from lambda body: helper.process(item)
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.lambda.HelperClass"),
"HelperClass should be captured from lambda body method invocation");
// Verify edge from LambdaTestClass to HelperClass exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.LambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.HelperClass"),
"Should have edge from LambdaTestClass to HelperClass");
// Verify that DataProcessor is captured from lambda body: new DataProcessor()
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.lambda.DataProcessor"),
"DataProcessor should be captured from new class instantiation in lambda body");
// Verify edge from LambdaTestClass to DataProcessor exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.LambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.DataProcessor"),
"Should have edge from LambdaTestClass to DataProcessor from lambda body");
// Verify that StringBuilder is captured from lambda body: new StringBuilder(s)
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.lang.StringBuilder"),
"StringBuilder should be captured from new class instantiation in lambda body");
// Verify edge from LambdaTestClass to StringBuilder exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.LambdaTestClass", "java.lang.StringBuilder"),
"Should have edge from LambdaTestClass to StringBuilder from lambda body");
// Verify that String is captured (from method invocations like s.toUpperCase())
Assertions.assertTrue(
classReferencesGraph.containsVertex("java.lang.String"),
"String should be captured from method invocations in lambda body");
// Verify edge weight - multiple lambda usages should increase edge weight
DefaultWeightedEdge edge = classReferencesGraph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.LambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.DataProcessor");
// DataProcessor is used twice: once in processWithLambda() and once in lambdaWithLocalVariable()
Assertions.assertTrue(
classReferencesGraph.getEdgeWeight(edge) >= 2.0,
"Edge weight should reflect multiple uses of DataProcessor in lambda bodies");
}
@Test
void visitNestedLambdaBodiesRecursively() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> classDeclarationVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
classDeclarationVisitor.visit(cu, ctx);
});
// Verify that the nested lambda test class is in the graph
Assertions.assertTrue(
classReferencesGraph.containsVertex(
"org.hjug.graphbuilder.visitor.testclasses.lambda.NestedLambdaTestClass"),
"NestedLambdaTestClass should be in the graph");
// Verify DataProcessor is captured from INNER lambda: new DataProcessor() inside nested lambda
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.lambda.DataProcessor"),
"DataProcessor should be captured from inner nested lambda body");
// Verify edge from NestedLambdaTestClass to DataProcessor exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.NestedLambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.DataProcessor"),
"Should have edge from NestedLambdaTestClass to DataProcessor from nested lambda");
// Verify HelperClass is captured from nested lambda method invocation
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.lambda.HelperClass"),
"HelperClass should be captured from nested lambda method invocation");
// Verify edge from NestedLambdaTestClass to HelperClass exists
Assertions.assertTrue(
classReferencesGraph.containsEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.NestedLambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.HelperClass"),
"Should have edge from NestedLambdaTestClass to HelperClass from nested lambda");
// Verify edge weight reflects multiple nested lambda usages
DefaultWeightedEdge dataProcessorEdge = classReferencesGraph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.NestedLambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.DataProcessor");
// DataProcessor is used in multiple nested lambdas: processNestedLambdas() and deeplyNestedLambdaWithNewClass()
Assertions.assertTrue(
classReferencesGraph.getEdgeWeight(dataProcessorEdge) >= 2.0,
"Edge weight should reflect multiple uses of DataProcessor in nested lambda bodies");
// Verify that deeply nested instantiations are captured
DefaultWeightedEdge helperEdge = classReferencesGraph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.lambda.NestedLambdaTestClass",
"org.hjug.graphbuilder.visitor.testclasses.lambda.HelperClass");
// HelperClass is used in field declaration and in nested lambdas
Assertions.assertTrue(
classReferencesGraph.getEdgeWeight(helperEdge) >= 2.0,
"Edge weight should reflect HelperClass usage in nested lambda blocks");
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaMethodDeclarationVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaMethodDeclarationVisitorTest {
@Test
void visitMethodDeclarations() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses");
org.openrewrite.java.JavaParser javaParser =
JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaMethodDeclarationVisitor<ExecutionContext> methodDeclarationVisitor =
new JavaMethodDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
methodDeclarationVisitor.visit(cu, ctx);
});
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.A"));
// TODO: Assert stuff
/* Assertions.assertTrue(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.A"));
Assertions.assertTrue(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.B"));
Assertions.assertTrue(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.C"));
Assertions.assertFalse(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.D"));
Assertions.assertTrue(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.MyAnnotation"));
Assertions.assertFalse(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.E"));
Assertions.assertTrue(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.F"));
Assertions.assertTrue(methodDeclarationVisitor.getClassReferencesGraph().containsVertex("org.hjug.javaVariableVisitorTestClasses.G"));*/
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaMethodInvocationVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaMethodInvocationVisitorTest {
@Test
void visitMethodInvocations() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> classDeclarationVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
JavaVariableTypeVisitor<ExecutionContext> variableTypeVisitor =
new JavaVariableTypeVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
classDeclarationVisitor.visit(cu, ctx);
variableTypeVisitor.visit(cu, ctx);
});
Graph<String, DefaultWeightedEdge> graph = classReferencesGraph;
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.methodInvocation.A"));
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.methodInvocation.B"));
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.methodInvocation.C"));
Assertions.assertEquals(
3,
graph.getEdgeWeight(graph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.methodInvocation.A",
"org.hjug.graphbuilder.visitor.testclasses.methodInvocation.B")));
Assertions.assertEquals(
3,
graph.getEdgeWeight(graph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.methodInvocation.A",
"org.hjug.graphbuilder.visitor.testclasses.methodInvocation.C")));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaNewClassVisitorFullTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
public class JavaNewClassVisitorFullTest {
@Test
void visitNewClass() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
final JavaVisitor<ExecutionContext> javaVisitor = new JavaVisitor<>(dependencyCollector);
final JavaVariableTypeVisitor<ExecutionContext> javaVariableTypeVisitor =
new JavaVariableTypeVisitor<>(dependencyCollector);
final JavaMethodDeclarationVisitor<ExecutionContext> javaMethodDeclarationVisitor =
new JavaMethodDeclarationVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
javaVisitor.visit(cu, ctx);
javaVariableTypeVisitor.visit(cu, ctx);
javaMethodDeclarationVisitor.visit(cu, ctx);
});
Graph<String, DefaultWeightedEdge> graph = classReferencesGraph;
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.newClass.A"));
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.newClass.B"));
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.newClass.C"));
// capturing counts of all types
Assertions.assertEquals(
6,
graph.getEdgeWeight(graph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.newClass.A",
"org.hjug.graphbuilder.visitor.testclasses.newClass.B")));
Assertions.assertEquals(
3,
graph.getEdgeWeight(graph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.newClass.A",
"org.hjug.graphbuilder.visitor.testclasses.newClass.C")));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaNewClassVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
public class JavaNewClassVisitorTest {
@Test
void visitNewClass() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass");
JavaParser javaParser = JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaClassDeclarationVisitor<ExecutionContext> classDeclarationVisitor =
new JavaClassDeclarationVisitor<>(dependencyCollector);
JavaVariableTypeVisitor<ExecutionContext> variableTypeVisitor =
new JavaVariableTypeVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
classDeclarationVisitor.visit(cu, ctx);
variableTypeVisitor.visit(cu, ctx);
});
Graph<String, DefaultWeightedEdge> graph = classReferencesGraph;
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.newClass.A"));
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.newClass.B"));
Assertions.assertTrue(graph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.newClass.C"));
// only looking for what was visited by classDeclarationVisitor and variableTypeVisitor
Assertions.assertEquals(
5,
graph.getEdgeWeight(graph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.newClass.A",
"org.hjug.graphbuilder.visitor.testclasses.newClass.B")));
Assertions.assertEquals(
3,
graph.getEdgeWeight(graph.getEdge(
"org.hjug.graphbuilder.visitor.testclasses.newClass.A",
"org.hjug.graphbuilder.visitor.testclasses.newClass.C")));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaVariableTypeVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaVariableTypeVisitorTest {
@Test
void visitClasses() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses");
org.openrewrite.java.JavaParser javaParser =
JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
Graph<String, DefaultWeightedEdge> classReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
JavaVariableTypeVisitor<ExecutionContext> javaVariableCapturingVisitor =
new JavaVariableTypeVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
javaVariableCapturingVisitor.visit(cu, ctx);
});
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.A"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.B"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.C"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.D"));
Assertions.assertTrue(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.E"));
Assertions.assertTrue(
classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.MyAnnotation"));
Assertions.assertFalse(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.F"));
Assertions.assertFalse(classReferencesGraph.containsVertex("org.hjug.graphbuilder.visitor.testclasses.G"));
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaVisitorTest.java
================================================
package org.hjug.graphbuilder.visitor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.hjug.graphbuilder.GraphDependencyCollector;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.junit.jupiter.api.Test;
import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
class JavaVisitorTest {
@Test
void visitClasses() throws IOException {
File srcDirectory = new File("src/test/java/org/hjug/graphbuilder/visitor/testclasses");
org.openrewrite.java.JavaParser javaParser =
JavaParser.fromJavaVersion().build();
ExecutionContext ctx = new InMemoryExecutionContext(Throwable::printStackTrace);
final Graph<String, DefaultWeightedEdge> classReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
final Graph<String, DefaultWeightedEdge> packageReferencesGraph =
new SimpleDirectedWeightedGraph<>(DefaultWeightedEdge.class);
final GraphDependencyCollector dependencyCollector =
new GraphDependencyCollector(classReferencesGraph, packageReferencesGraph);
final JavaVisitor<ExecutionContext> javaVisitor = new JavaVisitor<>(dependencyCollector);
List<Path> list = Files.walk(Paths.get(srcDirectory.getAbsolutePath())).collect(Collectors.toList());
javaParser.parse(list, Paths.get(srcDirectory.getAbsolutePath()), ctx).forEach(cu -> {
System.out.println(cu.getSourcePath());
javaVisitor.visit(cu, ctx);
});
assertEquals(5, dependencyCollector.getPackagesInCodebase().size());
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/A.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
import java.util.List;
import java.util.Map;
@MyAnnotation
public class A<T> {
// public A(B cB, C cC){}
B<? extends C> crazyType;
@MyAnnotation
@MyOtherAnnotation
int intVar, intVar2;
@MyAnnotation
@MyOtherAnnotation
C rawC;
B<B> b, b3;
C<B.InnerB, B> c;
D[] ds;
D d;
@MyAnnotation
B<C>[] arrayOfGenericBsWithCTypeParam;
@MyAnnotation
B<C[]> bWithArrayOfCs;
List<A<B>> listWithNestedGenric;
Map<A, B> map;
List<? extends List<? extends Number>> listOfListsOfNumbers;
@MyAnnotation
<T extends A, U extends B> F doSomething(B<C> paramB, C<B.InnerB, B> genericParam) {
List<B<E>> list3;
A<E> a2;
B<C> b2;
C<A, B> c2;
H h = new H();
B.<H>invocationTest(h);
return new G();
}
class InnerClass {
class InnerInner {
class MegaInner {
D d;
}
}
}
static class StaticInnerClass {}
}
class NonPublic {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/B.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public class B<T> {
static <T extends B> D invocationTest(T type) {
return new D();
}
static class InnerB extends A {}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/C.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public class C<T extends A, U extends B> {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/D.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public class D {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/E.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public interface E {
void foo(A a);
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/F.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public class F {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/G.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public class G extends F {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/H.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
public class H<T> extends B<T> {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/MyAnnotation.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE_USE)
@interface MyAnnotation {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/MyOtherAnnotation.java
================================================
package org.hjug.graphbuilder.visitor.testclasses;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE_USE)
@interface MyOtherAnnotation {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers/ComplexInitializerClass.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.initializers;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class ComplexInitializerClass {
private static ConcurrentHashMap<String, String> staticCache;
private static AtomicInteger instanceCounter;
private DataProcessor processor;
private HelperService helper;
// Static initializer with new class instantiations
static {
staticCache = new ConcurrentHashMap<>();
instanceCounter = new AtomicInteger(0);
staticCache.put("initialized", "true");
}
// Instance initializer with dependencies
{
processor = new DataProcessor();
helper = new HelperService();
instanceCounter.incrementAndGet();
}
// Another static initializer
static {
staticCache.put("version", "1.0");
}
public void process() {
processor.execute();
}
static class DataProcessor {
public void execute() {}
}
static class HelperService {}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers/InitializerBlockTestClass.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.initializers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InitializerBlockTestClass {
private List<String> items;
private Map<String, Integer> counters;
private StringBuilder builder;
// Instance initializer block
{
items = new ArrayList<>();
counters = new HashMap<>();
builder = new StringBuilder("Initialized");
}
// Static initializer block
static {
System.out.println("Static initializer");
}
// Another instance initializer block with method invocations
{
items.add("default");
counters.put("default", 0);
builder.append(" with defaults");
}
public InitializerBlockTestClass() {
// Constructor
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/DataProcessor.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.lambda;
public class DataProcessor {
public String transform(String data) {
return data;
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/HelperClass.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.lambda;
public class HelperClass {
public String process(String input) {
return input.toUpperCase();
}
public static String staticProcess(String input) {
return input.toLowerCase();
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/LambdaTestClass.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaTestClass {
private List<String> items = new ArrayList<>();
private HelperClass helper = new HelperClass();
public void processWithLambda() {
// Lambda with method invocation on helper class
items.forEach(item -> helper.process(item));
// Lambda with multiple method invocations
items.stream().map(s -> s.toUpperCase()).filter(s -> s.length() > 5).collect(Collectors.toList());
// Lambda with new class instantiation - creates dependency on DataProcessor
items.stream().map(s -> new DataProcessor().transform(s)).collect(Collectors.toList());
// Lambda with new StringBuilder instantiation
items.stream().map(s -> new StringBuilder(s)).collect(Collectors.toList());
// Nested lambda
items.stream()
.map(s -> s.chars().mapToObj(c -> String.valueOf((char) c)).collect(Collectors.joining()))
.collect(Collectors.toList());
// Lambda with static method reference
items.stream().map(HelperClass::staticProcess).forEach(System.out::println);
// Lambda with type cast
items.stream().map(s -> (CharSequence) s).collect(Collectors.toList());
}
public void lambdaWithLocalVariable() {
items.forEach(item -> {
DataProcessor processor = new DataProcessor();
String processed = processor.transform(item);
System.out.println(processed);
});
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/NestedLambdaTestClass.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.lambda;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class NestedLambdaTestClass {
private List<List<String>> nestedItems = new ArrayList<>();
private HelperClass helper = new HelperClass();
public void processNestedLambdas() {
// Nested lambda with DataProcessor instantiation in inner lambda
nestedItems.stream()
.map(innerList -> innerList.stream()
.map(s -> new DataProcessor().transform(s))
.collect(Collectors.toList()))
.collect(Collectors.toList());
// Nested lambda with HelperClass method invocation in inner lambda
nestedItems.stream()
.flatMap(innerList -> innerList.stream().map(s -> helper.process(s)))
.collect(Collectors.toList());
// Triple nested lambda with multiple dependencies
nestedItems.stream()
.map(outerList -> outerList.stream()
.map(middleItem -> middleItem
.chars()
.mapToObj(c -> new DataProcessor().transform(String.valueOf((char) c)))
.collect(Collectors.joining()))
.collect(Collectors.toList()))
.collect(Collectors.toList());
}
public void deeplyNestedLambdaWithNewClass() {
// Deeply nested lambda creating new instances at each level
nestedItems.stream()
.map(level1 -> {
DataProcessor processor1 = new DataProcessor();
return level1.stream()
.map(level2 -> {
HelperClass helper2 = new HelperClass();
return helper2.process(processor1.transform(level2));
})
.collect(Collectors.toList());
})
.collect(Collectors.toList());
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/A.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;
public class A {
A doSomething() {
B.<C>invocationTest(new D());
A a = B.<C>invocationTest(new D());
// TODO: add visitor for J.ReturnType
return B.<C>invocationTest(new D());
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/B.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;
public class B<T> {
static <T extends B> A invocationTest(T type) {
return new A();
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/C.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;
public class C<T> extends B<T> {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/D.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;
public class D<T> extends C<T> {}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/A.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.newClass;
import java.util.ArrayList;
import java.util.List;
public class A {
B newClassMethod() {
new C();
C c = new C();
// var treated like "B", counts as 2
var b = new B(null);
// <> treated like <B>, counts as 2
List<B> listB = new ArrayList<>();
// TODO: add visitor for J.ReturnType
return new B(c);
}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/B.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.newClass;
public class B {
public B(C c) {}
}
================================================
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/C.java
================================================
package org.hjug.graphbuilder.visitor.testclasses.newClass;
public class C {}
================================================
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/A.java
================================================
package com.ideacrest.parser.testclasses;
public class A {
B b;
}
================================================
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/B.java
================================================
package com.ideacrest.parser.testclasses;
public class B {
C c;
}
================================================
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/C.java
================================================
package com.ideacrest.parser.testclasses;
public class C {
A a;
E e;
}
================================================
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/D.java
================================================
package com.ideacrest.parser.testclasses;
public class D {
A a;
C c;
}
================================================
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/E.java
================================================
package com.ideacrest.parser.testclasses;
public class E {
D d;
D d2;
}
================================================
FILE: cost-benefit-calculator/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hjug.refactorfirst</groupId>
<artifactId>refactor-first</artifactId>
<version>0.8.1-SNAPSHOT</version>
</parent>
<groupId>org.hjug.refactorfirst.costbenefitcalculator</groupId>
<artifactId>cost-benefit-calculator</artifactId>
<name>RefactorFirst Cost Benefit Calculator</name>
<dependencies>
<!-- Needed for PMD -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.codebasegraphbuilder</groupId>
<artifactId>codebase-graph-builder</artifactId>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.changepronenessranker</groupId>
<artifactId>change-proneness-ranker</artifactId>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.effortranker</groupId>
<artifactId>effort-ranker</artifactId>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.dsm</groupId>
<artifactId>graph-algorithms</artifactId>
</dependency>
<dependency>
<groupId>org.hjug.refactorfirst.testresources</groupId>
<artifactId>test-resources</artifactId>
</dependency>
</dependencies>
</project>
================================================
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/CostBenefitCalculator.java
================================================
package org.hjug.cbc;
import static net.sourceforge.pmd.RuleViolation.CLASS_NAME;
import static net.sourceforge.pmd.RuleViolation.PACKAGE_NAME;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pmd.*;
import net.sourceforge.pmd.lang.LanguageRegistry;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.hjug.git.ChangePronenessRanker;
import org.hjug.git.GitLogReader;
import org.hjug.git.ScmLogInfo;
import org.hjug.metrics.*;
import org.hjug.metrics.rules.CBORule;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
@Slf4j
public class CostBenefitCalculator implements AutoCloseable {
private Report report;
private final String repositoryPath;
private GitLogReader gitLogReader;
private final ChangePronenessRanker changePronenessRanker;
private final Map<String, String> classToSourceFilePathMapping;
public CostBenefitCalculator(String repositoryPath, Map<String, String> classToSourceFilePathMapping) {
this.repositoryPath = repositoryPath;
log.info("Initiating Cost Benefit calculation");
try {
gitLogReader = new GitLogReader(new File(repositoryPath));
} catch (IOException e) {
log.error("Failure to access Git repository", e);
}
changePronenessRanker = new ChangePronenessRanker(gitLogReader);
this.classToSourceFilePathMapping = classToSourceFilePathMapping;
}
@Override
public void close() throws Exception {
gitLogReader.close();
}
// copied from PMD's PmdTaskImpl.java and modified
public void runPmdAnalysis() throws IOException {
PMDConfiguration configuration = new PMDConfiguration();
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
loadRules(pmd);
try (Stream<Path> files = Files.walk(Paths.get(repositoryPath))) {
files.filter(Files::isRegularFile).forEach(file -> pmd.files().addFile(file));
}
report = pmd.performAnalysisAndCollectReport();
}
}
public void runPmdAnalysis(boolean excludeTests, String testSourceDirectory) throws IOException {
PMDConfiguration configuration = new PMDConfiguration();
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
loadRules(pmd);
try (Stream<Path> files = Files.walk(Paths.get(repositoryPath))) {
Stream<Path> pathStream;
if (excludeTests) {
pathStream = files.filter(Files::isRegularFile)
.filter(file -> !file.toString().contains(testSourceDirectory));
} else {
pathStream = files.filter(Files::isRegularFile);
}
pathStream.forEach(file -> pmd.files().addFile(file));
}
report = pmd.performAnalysisAndCollectReport();
}
}
private void loadRules(PmdAnalysis pmd) {
RuleSetLoader rulesetLoader = pmd.newRuleSetLoader();
pmd.addRuleSets(rulesetLoader.loadRuleSetsWithoutException(List.of("category/java/design.xml")));
Rule cboClassRule = new CBORule();
cboClassRule.setLanguage(LanguageRegistry.PMD.getLanguageByFullName("Java"));
pmd.addRuleSet(RuleSet.forSingleRule(cboClassRule));
log.info("files to be scanned: " + Paths.get(repositoryPath));
}
public List<RankedDisharmony> calculateGodClassCostBenefitValues() {
List<GodClass> godClasses = getGodClasses();
List<ScmLogInfo> scmLogInfos = getRankedChangeProneness(godClasses);
Map<String, ScmLogInfo> rankedLogInfosByPath = getRankedLogInfosByPath(scmLogInfos);
List<RankedDisharmony> rankedDisharmonies = godClasses.stream()
.filter(godClass -> rankedLogInfosByPath.containsKey(godClass.getFileName()))
.map(godClass -> new RankedDisharmony(godClass, rankedLogInfosByPath.get(godClass.getFileName())))
.sorted(Comparator.comparing(RankedDisharmony::getRawPriority).reversed())
.collect(Collectors.toList());
int godClassPriority = 1;
for (RankedDisharmony rankedGodClassDisharmony : rankedDisharmonies) {
rankedGodClassDisharmony.setPriority(godClassPriority++);
}
return rankedDisharmonies;
}
private static Map<String, ScmLogInfo> getRankedLogInfosByPath(List<ScmLogInfo> scmLogInfos) {
return scmLogInfos.stream().collect(Collectors.toMap(ScmLogInfo::getPath, logInfo -> logInfo, (a, b) -> b));
}
private static Map<String, ScmLogInfo> getRankedLogInfosByClass(List<ScmLogInfo> scmLogInfos) {
return scmLogInfos.stream()
.collect(Collectors.toMap(ScmLogInfo::getClassName, logInfo -> logInfo, (a, b) -> b));
}
private List<GodClass> getGodClasses() {
List<GodClass> godClasses = new ArrayList<>();
for (RuleViolation violation : report.getViolations()) {
if (violation.getRule().getName().contains("GodClass")) {
GodClass godClass = new GodClass(
violation.getAdditionalInfo().get(CLASS_NAME),
getFileName(violation),
violation.getAdditionalInfo().get(PACKAGE_NAME),
violation.getDescription());
log.info("God Class identified: {}", godClass.getFileName());
godClasses.add(godClass);
}
}
GodClassRanker godClassRanker = new GodClassRanker();
godClassRanker.rankGodClasses(godClasses);
return godClasses;
}
public <T extends Disharmony> List<ScmLogInfo> getRankedChangeProneness(List<T> disharmonies) {
log.info("Calculating Change Proneness");
Map<String, String> innerClassPaths = new ConcurrentHashMap<>();
Map<String, ScmLogInfo> scmLogInfosByPath = new ConcurrentHashMap<>();
List<Optional<ScmLogInfo>> scmLogInfos = disharmonies.parallelStream()
.map(disharmony -> {
String className = disharmony.getClassName();
String path = null;
ScmLogInfo scmLogInfo = null;
try {
if (className.contains("$")
&& classToSourceFilePathMapping.containsKey(
className.substring(0, className.indexOf("$")))) {
path = classToSourceFilePathMapping.get(className.substring(0, className.indexOf("$")));
log.debug("Found source file {} for nested class: {}", path, className);
innerClassPaths.put(className, path);
} else {
path = disharmony.getFileName();
try {
log.debug("Reading scmLogInfo for {}", path);
scmLogInfo = gitLogReader.fileLog(path);
scmLogInfo.setClassName(className);
log.debug("Successfully fetched scmLogInfo for {}", scmLogInfo.getPath());
scmLogInfosByPath.put(path, scmLogInfo);
} catch (GitAPIException | IOException e) {
log.error("Error reading Git repository contents.", e);
}
}
} catch (NullPointerException e) {
// Should not be reached
log.error(
"Error looking up class SCM info. If this error is encountered, "
+ "please log a bug on the RefactorFirst project and describe if the class is a nested class, lambda, etc. \nClass: {}, Path: {}",
className,
path,
e);
}
Optional<ScmLogInfo> scmLogInfoOptional = Optional.ofNullable(scmLogInfo);
if (scmLogInfoOptional.isEmpty()) {
log.warn("No scmLogInfo found for class: {} at path: {}", className, path);
}
return scmLogInfoOptional;
})
.collect(Collectors.toList());
List<Optional<ScmLogInfo>> innerClassScmLogInfos = innerClassPaths.entrySet().parallelStream()
.map(innerClassPathEntry -> {
ScmLogInfo scmLogInfo = scmLogInfosByPath.get(innerClassPathEntry.getValue());
ScmLogInfo innerClassScmLogInfo = null;
if (scmLogInfo == null) {
String className = innerClassPathEntry.getKey();
String path = classToSourceFilePathMapping.get(className.substring(0, className.indexOf("$")));
log.debug("Reading scmLogInfo for inner class {}", canonicaliseURIStringForRepoLookup(path));
try {
innerClassScmLogInfo = gitLogReader.fileLog(canonicaliseURIStringForRepoLookup(path));
innerClassScmLogInfo.setClassName(className);
log.debug(
"Successfully fetched scmLogInfo for inner class {} at {}",
innerClassScmLogInfo.getClassName(),
innerClassScmLogInfo.getPath());
scmLogInfosByPath.put(path, innerClassScmLogInfo);
} catch (GitAPIException | IOException e) {
log.error(
"Error reading Git repository contents for class {} with file path {}",
className,
path,
e);
}
} else {
innerClassScmLogInfo = new ScmLogInfo(
innerClassPathEntry.getValue(),
innerClassPathEntry.getKey(),
scmLogInfo.getEarliestCommit(),
scmLogInfo.getMostRecentCommit(),
scmLogInfo.getCommitCount());
String className = innerClassPathEntry.getKey();
innerClassScmLogInfo.setClassName(className);
String path = classToSourceFilePathMapping.get(className.substring(0, className.indexOf("$")));
scmLogInfosByPath.put(path, innerClassScmLogInfo);
}
return Optional.ofNullable(innerClassScmLogInfo);
})
.collect(Collectors.toList());
scmLogInfos.addAll(innerClassScmLogInfos);
List<ScmLogInfo> sortedScmInfos = new ArrayList<>(scmLogInfos.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList()));
changePronenessRanker.rankChangeProneness(sortedScmInfos);
return sortedScmInfos;
}
public List<RankedDisharmony> calculateCBOCostBenefitValues() {
List<CBOClass> cboClasses = getCBOClasses();
List<ScmLogInfo> scmLogInfos = getRankedChangeProneness(cboClasses);
Map<String, ScmLogInfo> rankedLogInfosByPath = getRankedLogInfosByPath(scmLogInfos);
for (Map.Entry<String, ScmLogInfo> stringScmLogInfoEntry : rankedLogInfosByPath.entrySet()) {
log.debug(
"ScmLogInfo entry: {} path: {}",
stringScmLogInfoEntry.getKey(),
stringScmLogInfoEntry.getValue().getPath());
}
List<RankedDisharmony> rankedDisharmonies = new ArrayList<>();
for (CBOClass cboClass : cboClasses) {
log.debug("CBO Class identified: {}", cboClass.getFileName());
log.debug(
"ScmLogInfo: {}",
rankedLogInfosByPath.get(cboClass.getFileName()).getPath());
rankedDisharmonies.add(new RankedDisharmony(cboClass, rankedLogInfosByPath.get(cboClass.getFileName())));
}
rankedDisharmonies.sort(
Comparator.comparing(RankedDisharmony::getRawPriority).reversed());
int cboPriority = 1;
for (RankedDisharmony rankedCBODisharmony : rankedDisharmonies) {
rankedCBODisharmony.setPriority(cboPriority++);
}
return rankedDisharmonies;
}
private List<CBOClass> getCBOClasses() {
List<CBOClass> cboClasses = new ArrayList<>();
for (RuleViolation violation : report.getViolations()) {
if (violation.getRule().getName().contains("CBORule")) {
log.info(violation.getDescription());
CBOClass godClass = new CBOClass(
violation.getAdditionalInfo().get(CLASS_NAME),
getFileName(violation),
violation.getAdditionalInfo().get(PACKAGE_NAME),
violation.getDescription());
log.debug("Highly Coupled class identified: {}", godClass.getFileName());
cboClasses.add(godClass);
}
}
return cboClasses;
}
public List<RankedDisharmony> calculateSourceNodeCostBenefitValues(
Graph<String, DefaultWeightedEdge> classGraph,
Map<DefaultWeightedEdge, CycleNode> edgeSourceNodeInfos,
Map<DefaultWeightedEdge, CycleNode> edgeTargetNodeInfos,
Map<DefaultWeightedEdge, Integer> edgeToRemoveCycleCounts,
Set<String> vertexesToRemove) {
List<ScmLogInfo> sourceLogInfos = getRankedChangeProneness(new ArrayList<>(edgeSourceNodeInfos.values()));
List<ScmLogInfo> targetLogInfos = getRankedChangeProneness(new ArrayList<>(edgeTargetNodeInfos.values()));
List<ScmLogInfo> scmLogInfos = new ArrayList<>(sourceLogInfos.size() + targetLogInfos.size());
scmLogInfos.addAll(sourceLogInfos);
scmLogInfos.addAll(targetLogInfos);
Map<String, ScmLogInfo> sourceRankedLogInfosByPath = getRankedLogInfosByPath(scmLogInfos);
List<RankedDisharmony> edgesThatNeedToBeRemoved = new ArrayList<>();
for (Map.Entry<DefaultWeightedEdge, CycleNode> entry : edgeSourceNodeInfos.entrySet()) {
String edgeSource = classGraph.getEdgeSource(entry.getKey());
String edgeSourcePath;
if (edgeSource.contains("$")) {
edgeSourcePath = classToSourceFilePathMapping.get(edgeSource.substring(0, edgeSource.indexOf("$")));
} else {
edgeSourcePath = classToSourceFilePathMapping.get(edgeSource);
}
String edgeTarget = classGraph.getEdgeTarget(entry.getKey());
String edgeTargetPath;
if (edgeTarget.contains("$")) {
edgeTargetPath = classToSourceFilePathMapping.get(edgeTarget.substring(0, edgeTarget.indexOf("$")));
} else {
edgeTargetPath = classToSourceFilePathMapping.get(edgeTarget);
}
String sourceNodeFileName = canonicaliseURIStringForRepoLookup(edgeSourcePath);
String targetNodeFileName = canonicaliseURIStringForRepoLookup(edgeTargetPath);
boolean sourceNodeShouldBeRemoved = vertexesToRemove.contains(edgeSource);
boolean targetNodeShouldBeRemoved = vertexesToRemove.contains(edgeTarget);
ScmLogInfo sourceScmLogInfo = null;
if (sourceRankedLogInfosByPath.containsKey(sourceNodeFileName)) {
sourceScmLogInfo = sourceRankedLogInfosByPath.get(sourceNodeFileName);
}
ScmLogInfo targetScmLogInfo = null;
if (sourceRankedLogInfosByPath.containsKey(sourceNodeFileName)) {
targetScmLogInfo = sourceRankedLogInfosByPath.get(targetNodeFileName);
}
RankedDisharmony edgeThatNeedsToBeRemoved = new RankedDisharmony(
edgeSource,
entry.getKey(),
edgeToRemoveCycleCounts.get(entry.getKey()),
(int) classGraph.getEdgeWeight(entry.getKey()),
sourceNodeShouldBeRemoved,
targetNodeShouldBeRemoved,
sourceScmLogInfo,
targetScmLogInfo);
edgesThatNeedToBeRemoved.add(edgeThatNeedsToBeRemoved);
}
sortEdgesThatNeedToBeRemoved(edgesThatNeedToBeRemoved);
// Then subtract edge weight
int rawPriority = 1;
for (RankedDisharmony rankedDisharmony : edgesThatNeedToBeRemoved) {
rankedDisharmony.setRawPriority(rawPriority++);
}
// Push edges with higher weights down in the priority list
edgesThatNeedToBeRemoved.sort(Comparator.comparing(RankedDisharmony::getRawPriority));
// Then set priority
int sourceNodePriority = 1;
for (RankedDisharmony rankedSourceNodeDisharmony : edgesThatNeedToBeRemoved) {
rankedSourceNodeDisharmony.setPriority(sourceNodePriority++);
}
return edgesThatNeedToBeRemoved;
}
static void sortEdgesThatNeedToBeRemoved(List<RankedDisharmony> rankedDisharmonies) {
// Sort by impact value
// Order by cycle count reversed (highest count bubbles to the top)
rankedDisharmonies.sort(Comparator.comparingInt(RankedDisharmony::getCycleCount)
.reversed()
// then by weight, with lowest weight edges bubbling to the top
.thenComparingInt(RankedDisharmony::getEffortRank)
// then by change proneness
.thenComparingInt(rankedDisharmony -> -1 * rankedDisharmony.getChangePronenessRank())
.thenComparingInt(rankedDisharmony -> -1 * rankedDisharmony.getEdgeTargetChangePronenessRank())
// then if the source node is in the list of nodes to be removed
// multiplying by -1 reverses the sort order (reverse doesn't work in chained comparators)
.thenComparingInt(rankedDisharmony -> -1 * rankedDisharmony.getSourceNodeShouldBeRemoved())
// then if the target node is in the list of nodes to be removed
.thenComparingInt(rankedDisharmony -> -1 * rankedDisharmony.getTargetNodeShouldBeRemoved()));
}
private String getFileName(RuleViolation violation) {
String uriString = violation.getFileId().getUriString();
return canonicaliseURIStringForRepoLookup(uriString);
}
String canonicaliseURIStringForRepoLookup(String uriString) {
if (repositoryPath.startsWith("/") || repositoryPath.startsWith("\\")) {
return uriString.replace("file://" + repositoryPath.replace("\\", "/") + "/", "");
}
return uriString.replace("file:///" + repositoryPath.replace("\\", "/") + "/", "");
}
}
================================================
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/CycleNode.java
================================================
package org.hjug.cbc;
import java.time.Instant;
import lombok.Data;
import org.hjug.git.ScmLogInfo;
import org.hjug.metrics.Disharmony;
@Data
public class CycleNode implements Disharmony {
private final String className;
private String fileName;
private Integer changePronenessRank;
private Instant firstCommitTime;
private Instant mostRecentCommitTime;
private Integer commitCount;
public CycleNode(String className, String fileName) {
this.className = className;
this.fileName = fileName;
}
public String getPackageName() {
return className.substring(0, className.lastIndexOf('.'));
}
public void setScmLogInfo(ScmLogInfo scmLogInfo) {
firstCommitTime = Instant.ofEpochSecond(scmLogInfo.getEarliestCommit());
mostRecentCommitTime = Instant.ofEpochSecond(scmLogInfo.getMostRecentCommit());
commitCount = scmLogInfo.getCommitCount();
}
}
================================================
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/CycleRanker.java
================================================
package org.hjug.cbc;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hjug.dsm.CircularReferenceChecker;
import org.hjug.graphbuilder.CodebaseGraphDTO;
import org.hjug.graphbuilder.JavaGraphBuilder;
import org.jgrapht.Graph;
import org.jgrapht.graph.AsSubgraph;
import org.jgrapht.graph.DefaultWeightedEdge;
@RequiredArgsConstructor
@Slf4j
public class CycleRanker {
private final String repositoryPath;
private final JavaGraphBuilder javaGraphBuilder = new JavaGraphBuilder();
@Getter
private Graph<String, DefaultWeightedEdge> classReferencesGraph;
@Getter
private CodebaseGraphDTO codebaseGraphDTO;
@Getter
private Map<String, String> classNamesAndPaths = new HashMap<>();
@Getter
private Map<String, String> fqnsAndPaths = new HashMap<>();
public void generateClassReferencesGraph(boolean excludeTests, String testSourceDirectory) {
try {
codebaseGraphDTO = javaGraphBuilder.getCodebaseGraphDTO(repositoryPath, excludeTests, testSourceDirectory);
classReferencesGraph = codebaseGraphDTO.getClassReferencesGraph();
loadClassNamesAndPaths();
/*for (Map.Entry<String, String> stringStringEntry : fqnsAndPaths.entrySet()) {
log.info(stringStringEntry.getKey() + " : " + stringStringEntry.getValue());
}*/
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public List<RankedCycle> performCycleAnalysis(boolean excludeTests, String testSourceDirectory) {
List<RankedCycle> rankedCycles = new ArrayList<>();
try {
boolean calculateCycleChurn = false;
generateClassReferencesGraph(excludeTests, testSourceDirectory);
identifyRankedCycles(rankedCycles);
sortRankedCycles(rankedCycles, calculateCycleChurn);
setPriorities(rankedCycles);
} catch (IOException e) {
throw new RuntimeException(e);
}
return rankedCycles;
}
private void identifyRankedCycles(List<RankedCycle> rankedCycles) throws IOException {
CircularReferenceChecker circularReferenceChecker = new CircularReferenceChecker();
Map<String, AsSubgraph<String, DefaultWeightedEdge>> cycles =
circularReferenceChecker.getCycles(classReferencesGraph);
cycles.forEach((vertex, subGraph) -> {
// TODO: Calculate min cuts for smaller graphs - has a runtime of O(V^4) for a graph
/*Set<DefaultWeightedEdge> minCutEdges;
GusfieldGomoryHuCutTree<String, DefaultWeightedEdge> gusfieldGomoryHuCutTree =
new GusfieldGomoryHuCutTree<>(new AsUndirectedGraph<>(subGraph));
double minCut = gusfieldGomoryHuCutTree.calculateMinCut();
minCutEdges = gusfieldGomoryHuCutTree.getCutEdges();*/
List<CycleNode> cycleNodes = subGraph.vertexSet().stream()
.map(classInCycle -> new CycleNode(classInCycle, classNamesAndPaths.get(classInCycle)))
// .peek(cycleNode -> log.info(cycleNode.toString()))
.collect(Collectors.toList());
rankedCycles.add(createRankedCycle(vertex, subGraph, cycleNodes, 0.0, new HashSet<>()));
});
}
public CycleNode classToCycleNode(String fqnClass) {
return new CycleNode(fqnClass, fqnsAndPaths.get(fqnClass));
}
private RankedCycle createRankedCycle(
String vertex,
AsSubgraph<String, DefaultWeightedEdge> subGraph,
List<CycleNode> cycleNodes,
double minCut,
Set<DefaultWeightedEdge> minCutEdges) {
return new RankedCycle(vertex, subGraph.vertexSet(), subGraph.edgeSet(), minCut, minCutEdges, cycleNodes);
}
private static void sortRankedCycles(List<RankedCycle> rankedCycles, boolean calculateChurnForCycles) {
if (calculateChurnForCycles) {
rankedCycles.sort(Comparator.comparing(RankedCycle::getAverageChangeProneness));
int cpr = 1;
for (RankedCycle rankedCycle : rankedCycles) {
rankedCycle.setChangePronenessRank(cpr++);
}
} else {
rankedCycles.sort(Comparator.comparing(RankedCycle::getRawPriority).reversed());
}
}
private static void setPriorities(List<RankedCycle> rankedCycles) {
int priority = 1;
for (RankedCycle rankedCycle : rankedCycles) {
rankedCycle.setPriority(priority++);
}
}
void loadClassNamesAndPaths() throws IOException {
try (Stream<Path> walk = Files.walk(Paths.get(repositoryPath))) {
walk.forEach(path -> {
String filename = path.getFileName().toString();
if (filename.endsWith(".java")) {
// extract package and class name
String packageName = getPackageName(path);
String uriString = path.toUri().toString();
String className = getClassName(filename);
String canonicalUri = canonicaliseURIStringForRepoLookup(uriString);
fqnsAndPaths.put(packageName + "." + className, canonicalUri);
classNamesAndPaths.put(className, canonicalUri);
}
});
}
}
private static String getPackageName(Path path) {
try {
return Files.readAllLines(path).stream()
.filter(line -> line.startsWith("package"))
.map(line -> line.replace("package", "").replace(";", "").trim())
.findFirst()
.orElse("");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private String canonicaliseURIStringForRepoLookup(String uriString) {
if (repositoryPath.startsWith("/") || repositoryPath.startsWith("\\")) {
return uriString.replace("file://" + repositoryPath.replace("\\", "/") + "/", "");
}
return uriString.replace("file:///" + repositoryPath.replace("\\", "/") + "/", "");
}
/**
* Extract class name from java file name
* Example : MyJavaClass.java becomes MyJavaClass
*
* @param javaFileName
* @return
*/
private String getClassName(String javaFileName) {
return javaFileName.substring(0, javaFileName.indexOf('.'));
}
}
====================================
gitextract_nn926aoz/
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── codesee-arch-diagram.yml
│ ├── maven-pr.yml
│ ├── maven.yml
│ └── release.yml
├── .gitignore
├── CITATIONS.md
├── LICENSE
├── README.md
├── change-proneness-ranker/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── git/
│ │ ├── ChangePronenessRanker.java
│ │ ├── GitLogReader.java
│ │ └── ScmLogInfo.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ └── git/
│ ├── ChangePronenessRankerTest.java
│ └── GitLogReaderTest.java
├── cli/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── hjug/
│ └── refactorfirst/
│ ├── Main.java
│ ├── ReportCommand.java
│ └── ReportType.java
├── codebase-graph-builder/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── graphbuilder/
│ │ ├── CodebaseGraphDTO.java
│ │ ├── DependencyCollector.java
│ │ ├── GraphBuilderConfig.java
│ │ ├── GraphDependencyCollector.java
│ │ ├── JavaGraphBuilder.java
│ │ └── visitor/
│ │ ├── BaseCodebaseVisitor.java
│ │ ├── BaseTypeProcessor.java
│ │ ├── FqnCapturingProcessor.java
│ │ ├── JavaClassDeclarationVisitor.java
│ │ ├── JavaFqnCapturingVisitor.java
│ │ ├── JavaMethodDeclarationVisitor.java
│ │ ├── JavaVariableTypeVisitor.java
│ │ ├── JavaVisitor.java
│ │ └── TypeDependencyExtractor.java
│ └── test/
│ ├── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── graphbuilder/
│ │ ├── JavaGraphBuilderTest.java
│ │ └── visitor/
│ │ ├── JavaClassDeclarationVisitorTest.java
│ │ ├── JavaFqnCapturingVisitorTest.java
│ │ ├── JavaInitializerBlockVisitorTest.java
│ │ ├── JavaLambdaVisitorTest.java
│ │ ├── JavaMethodDeclarationVisitorTest.java
│ │ ├── JavaMethodInvocationVisitorTest.java
│ │ ├── JavaNewClassVisitorFullTest.java
│ │ ├── JavaNewClassVisitorTest.java
│ │ ├── JavaVariableTypeVisitorTest.java
│ │ ├── JavaVisitorTest.java
│ │ └── testclasses/
│ │ ├── A.java
│ │ ├── B.java
│ │ ├── C.java
│ │ ├── D.java
│ │ ├── E.java
│ │ ├── F.java
│ │ ├── G.java
│ │ ├── H.java
│ │ ├── MyAnnotation.java
│ │ ├── MyOtherAnnotation.java
│ │ ├── initializers/
│ │ │ ├── ComplexInitializerClass.java
│ │ │ └── InitializerBlockTestClass.java
│ │ ├── lambda/
│ │ │ ├── DataProcessor.java
│ │ │ ├── HelperClass.java
│ │ │ ├── LambdaTestClass.java
│ │ │ └── NestedLambdaTestClass.java
│ │ ├── methodInvocation/
│ │ │ ├── A.java
│ │ │ ├── B.java
│ │ │ ├── C.java
│ │ │ └── D.java
│ │ └── newClass/
│ │ ├── A.java
│ │ ├── B.java
│ │ └── C.java
│ └── resources/
│ └── javaSrcDirectory/
│ └── com/
│ └── ideacrest/
│ └── parser/
│ └── testclasses/
│ ├── A.java
│ ├── B.java
│ ├── C.java
│ ├── D.java
│ └── E.java
├── cost-benefit-calculator/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── cbc/
│ │ ├── CostBenefitCalculator.java
│ │ ├── CycleNode.java
│ │ ├── CycleRanker.java
│ │ ├── RankedCycle.java
│ │ └── RankedDisharmony.java
│ └── test/
│ ├── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── cbc/
│ │ └── CostBenefitCalculatorTest.java
│ └── resources/
│ ├── hudson/
│ │ └── model/
│ │ └── User.java
│ └── org/
│ └── apache/
│ └── myfaces/
│ └── tobago/
│ └── facelets/
│ ├── AttributeHandler.java
│ ├── AttributeHandler2.java
│ └── AttributeHandlerAndSorter.java
├── coverage/
│ └── pom.xml
├── effort-ranker/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── metrics/
│ │ ├── CBOClass.java
│ │ ├── Disharmony.java
│ │ ├── GodClass.java
│ │ ├── GodClassRanker.java
│ │ └── rules/
│ │ └── CBORule.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ └── metrics/
│ ├── CBOClassParsingTest.java
│ ├── GodClassParsingTest.java
│ └── GodClassRankerTest.java
├── graph-algorithms/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ ├── dsm/
│ │ │ ├── CircularReferenceChecker.java
│ │ │ ├── DSM.java
│ │ │ ├── EdgeRemovalCalculator.java
│ │ │ ├── EdgeToRemoveInfo.java
│ │ │ ├── OptimalBackEdgeRemover.java
│ │ │ ├── SparseGraphCircularReferenceChecker.java
│ │ │ └── SparseIntDWGEdgeRemovalCalculator.java
│ │ └── feedback/
│ │ ├── SuperTypeToken.java
│ │ ├── arc/
│ │ │ ├── EdgeInfo.java
│ │ │ ├── EdgeInfoCalculator.java
│ │ │ ├── approximate/
│ │ │ │ ├── FeedbackArcSetResult.java
│ │ │ │ └── FeedbackArcSetSolver.java
│ │ │ ├── exact/
│ │ │ │ ├── FeedbackArcSetResult.java
│ │ │ │ └── MinimumFeedbackArcSetSolver.java
│ │ │ └── pageRank/
│ │ │ ├── DIAGRAM.md
│ │ │ ├── LineDigraph.java
│ │ │ └── PageRankFAS.java
│ │ └── vertex/
│ │ ├── approximate/
│ │ │ ├── FeedbackVertexSetResult.java
│ │ │ └── FeedbackVertexSetSolver.java
│ │ └── kernelized/
│ │ ├── DIAGRAM.md
│ │ ├── DirectedFeedbackVertexSetResult.java
│ │ ├── DirectedFeedbackVertexSetSolver.java
│ │ ├── EnhancedParameterComputer.java
│ │ ├── FeedbackVertexSetComputer.java
│ │ ├── ModulatorComputer.java
│ │ ├── ParameterComputer.java
│ │ └── TreewidthComputer.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ ├── dsm/
│ │ ├── CircularReferenceCheckerTests.java
│ │ ├── DSMTest.java
│ │ ├── EdgeRemovalCalculatorTest.java
│ │ └── OptimalBackEdgeRemoverTest.java
│ └── feedback/
│ ├── SuperTypeTokenTest.java
│ ├── arc/
│ │ ├── approximate/
│ │ │ ├── FeedbackArcSetBenchmarkTest.java
│ │ │ ├── FeedbackArcSetExample.java
│ │ │ └── FeedbackArcSetSolverTest.java
│ │ ├── exact/
│ │ │ ├── MinimumFeedbackArcSetBenchmarkTest.java
│ │ │ ├── MinimumFeedbackArcSetExample.java
│ │ │ └── MinimumFeedbackArcSetSolverTest.java
│ │ └── pageRank/
│ │ ├── PageRankFASExample.java
│ │ └── PageRankFASTest.java
│ └── vertex/
│ ├── approximate/
│ │ ├── FeedbackVertexSetBenchmarkTest.java
│ │ ├── FeedbackVertexSetExample.java
│ │ └── FeedbackVertexSetSolverTest.java
│ └── kernelized/
│ ├── DirectedFeedbackVertexSetBenchmarkTest.java
│ ├── DirectedFeedbackVertexSetExample.java
│ ├── DirectedFeedbackVertexSetSolverTest.java
│ ├── ModulatorComputerTest.java
│ ├── ParameterComputerExample.java
│ └── ParameterComputerTest.java
├── graph-data-generator/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── gdg/
│ │ └── GraphDataGenerator.java
│ └── test/
│ └── java/
│ └── org/
│ └── hjug/
│ └── gdg/
│ └── GraphDataGeneratorTest.java
├── jreleaser.yml
├── lombok.config
├── pom.xml
├── refactor-first-gradle-plugin/
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── pom.xml
│ ├── settings.gradle
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── hjug/
│ └── gradlereport/
│ └── RefactorFirstPlugin.java
├── refactor-first-maven-plugin/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── hjug/
│ └── mavenreport/
│ ├── RefactorFirstHtmlReport.java
│ ├── RefactorFirstMavenCsvReport.java
│ ├── RefactorFirstMavenJsonReport.java
│ ├── RefactorFirstMavenReport.java
│ └── RefactorFirstSimpleHtmlReport.java
├── report/
│ ├── .gitignore
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── refactorfirst/
│ │ └── report/
│ │ ├── CsvReport.java
│ │ ├── HtmlReport.java
│ │ ├── ReportWriter.java
│ │ ├── SimpleHtmlReport.java
│ │ └── json/
│ │ ├── JsonReport.java
│ │ ├── JsonReportDisharmonyEntry.java
│ │ └── JsonReportExecutor.java
│ └── test/
│ ├── java/
│ │ └── org/
│ │ └── hjug/
│ │ └── refactorfirst/
│ │ └── report/
│ │ ├── HtmlReportTest.java
│ │ └── SimpleHtmlReportTest.java
│ └── resources/
│ ├── highlight.html
│ ├── sigmaPlayground.html
│ └── spriteText.html
├── spring-petclinic-rest-report.html
└── test-resources/
├── pom.xml
└── src/
└── main/
└── resources/
├── AttributeHandler.java
├── AttributeHandler2.java
├── AttributeHandlerAndSorter.java
├── AttributeHandlerJavaEleven.java
├── Attributes.java
└── Console.java
SYMBOL INDEX (1246 symbols across 147 files)
FILE: change-proneness-ranker/src/main/java/org/hjug/git/ChangePronenessRanker.java
class ChangePronenessRanker (line 8) | @Slf4j
method ChangePronenessRanker (line 14) | public ChangePronenessRanker(GitLogReader repositoryLogReader) {
method rankChangeProneness (line 23) | public void rankChangeProneness(List<ScmLogInfo> scmLogInfos) {
FILE: change-proneness-ranker/src/main/java/org/hjug/git/GitLogReader.java
class GitLogReader (line 20) | @Slf4j
method GitLogReader (line 29) | public GitLogReader() {}
method GitLogReader (line 31) | public GitLogReader(File basedir) throws IOException {
method GitLogReader (line 44) | GitLogReader(Git git) {
method close (line 49) | @Override
method getGitDir (line 54) | public File getGitDir(File basedir) {
method fileLog (line 70) | public ScmLogInfo fileLog(String path) throws GitAPIException, IOExcep...
method captureChangeCountByCommitTimestamp (line 97) | public TreeMap<Integer, Integer> captureChangeCountByCommitTimestamp()...
method getDiffEntries (line 141) | private List<DiffEntry> getDiffEntries(RevCommit newCommit, RevCommit ...
method walkFirstCommit (line 153) | Map<Integer, Integer> walkFirstCommit(RevCommit firstCommit) throws IO...
FILE: change-proneness-ranker/src/main/java/org/hjug/git/ScmLogInfo.java
class ScmLogInfo (line 5) | @Data
method ScmLogInfo (line 16) | public ScmLogInfo(String path, String className, int earliestCommit, i...
FILE: change-proneness-ranker/src/test/java/org/hjug/git/ChangePronenessRankerTest.java
class ChangePronenessRankerTest (line 13) | class ChangePronenessRankerTest {
method setUp (line 18) | @BeforeEach
method testChangePronenessCalculation (line 24) | @Test
method testRankChangeProneness (line 44) | @Test
FILE: change-proneness-ranker/src/test/java/org/hjug/git/GitLogReaderTest.java
class GitLogReaderTest (line 17) | public class GitLogReaderTest {
method setUp (line 27) | @BeforeEach
method tearDown (line 33) | @AfterEach
method testFileLog (line 38) | @Test
method testWalkFirstCommit (line 69) | @Test
method testCaptureChangCountByCommitTimestamp (line 85) | @Test
method writeFile (line 116) | private void writeFile(String name, String content) throws IOException {
method convertInputStreamToString (line 123) | private String convertInputStreamToString(InputStream inputStream) thr...
FILE: cli/src/main/java/org/hjug/refactorfirst/Main.java
class Main (line 5) | public class Main {
method main (line 6) | public static void main(String[] args) {
FILE: cli/src/main/java/org/hjug/refactorfirst/ReportCommand.java
class ReportCommand (line 18) | @Command(mixinStandardHelpOptions = true, description = "Generate a repo...
method call (line 89) | @Override
method populateDefaultArguments (line 137) | private void populateDefaultArguments() {
method inferArgumentsFromMavenProject (line 146) | private void inferArgumentsFromMavenProject() {
FILE: cli/src/main/java/org/hjug/refactorfirst/ReportType.java
type ReportType (line 3) | public enum ReportType {
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/CodebaseGraphDTO.java
class CodebaseGraphDTO (line 8) | @Data
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/DependencyCollector.java
type DependencyCollector (line 3) | public interface DependencyCollector {
method addClassDependency (line 11) | void addClassDependency(String fromClassFqn, String toClassFqn);
method addPackageDependency (line 19) | void addPackageDependency(String fromPackageName, String toPackageName);
method recordClassLocation (line 27) | void recordClassLocation(String classFqn, String sourceFilePath);
method registerPackage (line 34) | void registerPackage(String packageName);
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphBuilderConfig.java
class GraphBuilderConfig (line 6) | @Value
method defaultConfig (line 16) | public static GraphBuilderConfig defaultConfig() {
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphDependencyCollector.java
class GraphDependencyCollector (line 9) | public class GraphDependencyCollector implements DependencyCollector {
method GraphDependencyCollector (line 20) | public GraphDependencyCollector(
method addClassDependency (line 27) | @Override
method addPackageDependency (line 44) | @Override
method recordClassLocation (line 61) | @Override
method registerPackage (line 66) | @Override
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/JavaGraphBuilder.java
class JavaGraphBuilder (line 22) | @Slf4j
method getCodebaseGraphDTO (line 34) | public CodebaseGraphDTO getCodebaseGraphDTO(String srcDirectory, boole...
method getCodebaseGraphDTO (line 51) | public CodebaseGraphDTO getCodebaseGraphDTO(String srcDirectory, Graph...
method processWithOpenRewrite (line 58) | private CodebaseGraphDTO processWithOpenRewrite(String srcDir, GraphBu...
method removeClassesNotInCodebase (line 104) | void removeClassesNotInCodebase(
method getPackage (line 118) | String getPackage(String fqn) {
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/BaseCodebaseVisitor.java
class BaseCodebaseVisitor (line 7) | @Getter
method BaseCodebaseVisitor (line 12) | protected BaseCodebaseVisitor(DependencyCollector dependencyCollector) {
method getCurrentOwnerFqn (line 16) | protected abstract String getCurrentOwnerFqn();
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/BaseTypeProcessor.java
class BaseTypeProcessor (line 12) | @Slf4j
method getDependencyCollector (line 17) | protected abstract DependencyCollector getDependencyCollector();
method processType (line 19) | protected void processType(String ownerFqn, JavaType javaType) {
method processAnnotation (line 29) | protected void processAnnotation(String ownerFqn, J.Annotation annotat...
method processTypeParameter (line 48) | protected void processTypeParameter(String ownerFqn, J.TypeParameter t...
method processAnnotations (line 62) | protected void processAnnotations(String ownerFqn, Cursor cursor) {
method getPackageFromFqn (line 69) | protected String getPackageFromFqn(String fqn) {
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/FqnCapturingProcessor.java
type FqnCapturingProcessor (line 9) | public interface FqnCapturingProcessor {
method captureClassDeclarations (line 11) | default J.ClassDeclaration captureClassDeclarations(
method getPackage (line 35) | default String getPackage(String fqn) {
method getClassName (line 50) | default String getClassName(String fqn) {
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaClassDeclarationVisitor.java
class JavaClassDeclarationVisitor (line 8) | @Slf4j
method JavaClassDeclarationVisitor (line 14) | public JavaClassDeclarationVisitor(DependencyCollector dependencyColle...
method visitClassDeclaration (line 24) | @Override
method visitMethodInvocation (line 67) | @Override
method visitNewClass (line 89) | @Override
method visitLambda (line 98) | @Override
method visitIf (line 109) | @Override
method visitForLoop (line 114) | @Override
method visitForEachLoop (line 119) | @Override
method visitWhileLoop (line 124) | @Override
method visitDoWhileLoop (line 129) | @Override
method visitSwitch (line 134) | @Override
method visitTry (line 139) | @Override
method visitInstanceOf (line 157) | @Override
method visitTypeCast (line 166) | @Override
method visitMemberReference (line 176) | @Override
method visitNewArray (line 185) | @Override
method getCurrentOwnerFqn (line 194) | @Override
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaFqnCapturingVisitor.java
class JavaFqnCapturingVisitor (line 14) | @Getter
method visitClassDeclaration (line 22) | @Override
method captureClassDeclarations (line 28) | J.ClassDeclaration captureClassDeclarations(J.ClassDeclaration classDe...
method getPackage (line 34) | String getPackage(String fqn) {
method getClassName (line 49) | String getClassName(String fqn) {
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaMethodDeclarationVisitor.java
class JavaMethodDeclarationVisitor (line 11) | @Slf4j
method JavaMethodDeclarationVisitor (line 16) | public JavaMethodDeclarationVisitor(DependencyCollector dependencyColl...
method visitMethodDeclaration (line 26) | @Override
method getCurrentOwnerFqn (line 72) | @Override
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaVariableTypeVisitor.java
class JavaVariableTypeVisitor (line 8) | @Slf4j
method JavaVariableTypeVisitor (line 13) | public JavaVariableTypeVisitor(DependencyCollector dependencyCollector) {
method visitVariableDeclarations (line 23) | @Override
method getCurrentOwnerFqn (line 73) | @Override
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaVisitor.java
class JavaVisitor (line 9) | @Slf4j
method JavaVisitor (line 17) | public JavaVisitor(DependencyCollector dependencyCollector) {
method visitClassDeclaration (line 22) | @Override
method visitCompilationUnit (line 28) | @Override
method getCurrentOwnerFqn (line 49) | @Override
FILE: codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/TypeDependencyExtractor.java
class TypeDependencyExtractor (line 8) | @Slf4j
method extractDependencies (line 17) | public Set<String> extractDependencies(JavaType javaType) {
method extractDependenciesRecursive (line 27) | private void extractDependenciesRecursive(JavaType javaType, Set<Strin...
method extractFromClass (line 39) | private void extractFromClass(JavaType.Class classType, Set<String> de...
method extractFromParameterized (line 45) | private void extractFromParameterized(JavaType.Parameterized parameter...
method extractFromArray (line 56) | private void extractFromArray(JavaType.Array arrayType, Set<String> de...
method extractFromGenericTypeVariable (line 61) | private void extractFromGenericTypeVariable(JavaType.GenericTypeVariab...
method extractAnnotations (line 75) | private void extractAnnotations(JavaType.FullyQualified fullyQualified...
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/JavaGraphBuilderTest.java
class JavaGraphBuilderTest (line 15) | class JavaGraphBuilderTest {
method parseSourceDirectoryEmptyTest (line 19) | @DisplayName("When source directory input param is empty or null throw...
method parseSourceDirectoryTest (line 28) | @DisplayName("Given a valid source directory input parameter return a ...
method getEdgeWeight (line 72) | private static double getEdgeWeight(
method removeClassesNotInCodebase (line 77) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaClassDeclarationVisitorTest.java
class JavaClassDeclarationVisitorTest (line 20) | class JavaClassDeclarationVisitorTest {
method visitClasses (line 22) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaFqnCapturingVisitorTest.java
class JavaFqnCapturingVisitorTest (line 18) | @Disabled
method visitClasses (line 21) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaInitializerBlockVisitorTest.java
class JavaInitializerBlockVisitorTest (line 20) | class JavaInitializerBlockVisitorTest {
method visitInstanceInitializerBlocks (line 22) | @Test
method visitStaticInitializerBlocks (line 89) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaLambdaVisitorTest.java
class JavaLambdaVisitorTest (line 20) | class JavaLambdaVisitorTest {
method visitLambdaBodiesRecursively (line 22) | @Test
method visitNestedLambdaBodiesRecursively (line 103) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaMethodDeclarationVisitorTest.java
class JavaMethodDeclarationVisitorTest (line 20) | class JavaMethodDeclarationVisitorTest {
method visitMethodDeclarations (line 22) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaMethodInvocationVisitorTest.java
class JavaMethodInvocationVisitorTest (line 20) | class JavaMethodInvocationVisitorTest {
method visitMethodInvocations (line 22) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaNewClassVisitorFullTest.java
class JavaNewClassVisitorFullTest (line 20) | public class JavaNewClassVisitorFullTest {
method visitNewClass (line 22) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaNewClassVisitorTest.java
class JavaNewClassVisitorTest (line 20) | public class JavaNewClassVisitorTest {
method visitNewClass (line 22) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaVariableTypeVisitorTest.java
class JavaVariableTypeVisitorTest (line 20) | class JavaVariableTypeVisitorTest {
method visitClasses (line 22) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaVisitorTest.java
class JavaVisitorTest (line 21) | class JavaVisitorTest {
method visitClasses (line 23) | @Test
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/A.java
class A (line 6) | @MyAnnotation
method doSomething (line 36) | @MyAnnotation
class InnerClass (line 50) | class InnerClass {
class InnerInner (line 51) | class InnerInner {
class MegaInner (line 52) | class MegaInner {
class StaticInnerClass (line 58) | static class StaticInnerClass {}
class NonPublic (line 61) | class NonPublic {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/B.java
class B (line 3) | public class B<T> {
method invocationTest (line 5) | static <T extends B> D invocationTest(T type) {
class InnerB (line 9) | static class InnerB extends A {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/C.java
class C (line 3) | public class C<T extends A, U extends B> {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/D.java
class D (line 3) | public class D {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/E.java
type E (line 3) | public interface E {
method foo (line 4) | void foo(A a);
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/F.java
class F (line 3) | public class F {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/G.java
class G (line 3) | public class G extends F {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/H.java
class H (line 3) | public class H<T> extends B<T> {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers/ComplexInitializerClass.java
class ComplexInitializerClass (line 6) | public class ComplexInitializerClass {
method process (line 33) | public void process() {
class DataProcessor (line 37) | static class DataProcessor {
method execute (line 38) | public void execute() {}
class HelperService (line 41) | static class HelperService {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers/InitializerBlockTestClass.java
class InitializerBlockTestClass (line 8) | public class InitializerBlockTestClass {
method InitializerBlockTestClass (line 33) | public InitializerBlockTestClass() {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/DataProcessor.java
class DataProcessor (line 3) | public class DataProcessor {
method transform (line 5) | public String transform(String data) {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/HelperClass.java
class HelperClass (line 3) | public class HelperClass {
method process (line 5) | public String process(String input) {
method staticProcess (line 9) | public static String staticProcess(String input) {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/LambdaTestClass.java
class LambdaTestClass (line 7) | public class LambdaTestClass {
method processWithLambda (line 12) | public void processWithLambda() {
method lambdaWithLocalVariable (line 37) | public void lambdaWithLocalVariable() {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/NestedLambdaTestClass.java
class NestedLambdaTestClass (line 7) | public class NestedLambdaTestClass {
method processNestedLambdas (line 12) | public void processNestedLambdas() {
method deeplyNestedLambdaWithNewClass (line 36) | public void deeplyNestedLambdaWithNewClass() {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/A.java
class A (line 3) | public class A {
method doSomething (line 5) | A doSomething() {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/B.java
class B (line 3) | public class B<T> {
method invocationTest (line 5) | static <T extends B> A invocationTest(T type) {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/C.java
class C (line 3) | public class C<T> extends B<T> {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/D.java
class D (line 3) | public class D<T> extends C<T> {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/A.java
class A (line 6) | public class A {
method newClassMethod (line 8) | B newClassMethod() {
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/B.java
class B (line 3) | public class B {
method B (line 5) | public B(C c) {}
FILE: codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/C.java
class C (line 3) | public class C {}
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/A.java
class A (line 3) | public class A {
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/B.java
class B (line 3) | public class B {
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/C.java
class C (line 3) | public class C {
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/D.java
class D (line 3) | public class D {
FILE: codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/E.java
class E (line 3) | public class E {
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/CostBenefitCalculator.java
class CostBenefitCalculator (line 27) | @Slf4j
method CostBenefitCalculator (line 37) | public CostBenefitCalculator(String repositoryPath, Map<String, String...
method close (line 51) | @Override
method runPmdAnalysis (line 57) | public void runPmdAnalysis() throws IOException {
method runPmdAnalysis (line 71) | public void runPmdAnalysis(boolean excludeTests, String testSourceDire...
method loadRules (line 93) | private void loadRules(PmdAnalysis pmd) {
method calculateGodClassCostBenefitValues (line 104) | public List<RankedDisharmony> calculateGodClassCostBenefitValues() {
method getRankedLogInfosByPath (line 125) | private static Map<String, ScmLogInfo> getRankedLogInfosByPath(List<Sc...
method getRankedLogInfosByClass (line 129) | private static Map<String, ScmLogInfo> getRankedLogInfosByClass(List<S...
method getGodClasses (line 134) | private List<GodClass> getGodClasses() {
method getRankedChangeProneness (line 154) | public <T extends Disharmony> List<ScmLogInfo> getRankedChangePronenes...
method calculateCBOCostBenefitValues (line 254) | public List<RankedDisharmony> calculateCBOCostBenefitValues() {
method getCBOClasses (line 287) | private List<CBOClass> getCBOClasses() {
method calculateSourceNodeCostBenefitValues (line 304) | public List<RankedDisharmony> calculateSourceNodeCostBenefitValues(
method sortEdgesThatNeedToBeRemoved (line 385) | static void sortEdgesThatNeedToBeRemoved(List<RankedDisharmony> ranked...
method getFileName (line 402) | private String getFileName(RuleViolation violation) {
method canonicaliseURIStringForRepoLookup (line 407) | String canonicaliseURIStringForRepoLookup(String uriString) {
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/CycleNode.java
class CycleNode (line 8) | @Data
method CycleNode (line 19) | public CycleNode(String className, String fileName) {
method getPackageName (line 24) | public String getPackageName() {
method setScmLogInfo (line 28) | public void setScmLogInfo(ScmLogInfo scmLogInfo) {
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/CycleRanker.java
class CycleRanker (line 20) | @RequiredArgsConstructor
method generateClassReferencesGraph (line 39) | public void generateClassReferencesGraph(boolean excludeTests, String ...
method performCycleAnalysis (line 56) | public List<RankedCycle> performCycleAnalysis(boolean excludeTests, St...
method identifyRankedCycles (line 71) | private void identifyRankedCycles(List<RankedCycle> rankedCycles) thro...
method classToCycleNode (line 92) | public CycleNode classToCycleNode(String fqnClass) {
method createRankedCycle (line 96) | private RankedCycle createRankedCycle(
method sortRankedCycles (line 106) | private static void sortRankedCycles(List<RankedCycle> rankedCycles, b...
method setPriorities (line 119) | private static void setPriorities(List<RankedCycle> rankedCycles) {
method loadClassNamesAndPaths (line 126) | void loadClassNamesAndPaths() throws IOException {
method getPackageName (line 143) | private static String getPackageName(Path path) {
method canonicaliseURIStringForRepoLookup (line 155) | private String canonicaliseURIStringForRepoLookup(String uriString) {
method getClassName (line 169) | private String getClassName(String javaFileName) {
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/RankedCycle.java
class RankedCycle (line 10) | @Data
method RankedCycle (line 29) | public RankedCycle(
method RankedCycle (line 57) | public RankedCycle(
FILE: cost-benefit-calculator/src/main/java/org/hjug/cbc/RankedDisharmony.java
class RankedDisharmony (line 11) | @Data
method RankedDisharmony (line 40) | public RankedDisharmony(GodClass godClass, ScmLogInfo scmLogInfo) {
method RankedDisharmony (line 61) | public RankedDisharmony(CBOClass cboClass, ScmLogInfo scmLogInfo) {
method RankedDisharmony (line 75) | public RankedDisharmony(
FILE: cost-benefit-calculator/src/test/java/org/hjug/cbc/CostBenefitCalculatorTest.java
class CostBenefitCalculatorTest (line 19) | class CostBenefitCalculatorTest {
method setUp (line 29) | @BeforeEach
method tearDown (line 37) | @AfterEach
method testCBOViolation (line 42) | @Test
method testCostBenefitCalculation (line 60) | @Test
method calculateSourceNodeCostBenefitValues_filtersMissingLogInfoAndAssignsPriority (line 97) | @Test
method calculateSourceNodeCostBenefitValues_prefersHigherChangePronenessRank (line 170) | @Test
method sortEdgesThatNeedToBeRemoved_sortsByMultipleCriteria (line 226) | @Test
method writeFile (line 328) | private void writeFile(String name, String content) throws IOException {
method convertInputStreamToString (line 337) | private String convertInputStreamToString(InputStream inputStream) thr...
class TestableCostBenefitCalculator (line 347) | private static class TestableCostBenefitCalculator extends CostBenefit...
method TestableCostBenefitCalculator (line 351) | TestableCostBenefitCalculator(String repositoryPath, List<ScmLogInfo...
method getClassToSourceFilePathMapping (line 356) | private static @NotNull Map<String, String> getClassToSourceFilePath...
method getRankedChangeProneness (line 368) | @Override
FILE: cost-benefit-calculator/src/test/resources/hudson/model/User.java
class User (line 122) | @ExportedBean
method User (line 188) | private User(String id, String fullName) {
method load (line 194) | private void load(String userId) {
method setUserToProperties (line 202) | private void setUserToProperties() {
method allocateDefaultPropertyInstancesAsNeeded (line 208) | private void allocateDefaultPropertyInstancesAsNeeded() {
method removeNullsThatFailedToLoad (line 218) | private void removeNullsThatFailedToLoad() {
method loadFromUserConfigFile (line 222) | private void loadFromUserConfigFile(String userId) {
method clearExistingProperties (line 234) | private void clearExistingProperties() {
method getConfigFile (line 238) | private XmlFile getConfigFile() {
method idStrategy (line 250) | @NonNull
method compareTo (line 260) | @Override
method getId (line 265) | @Exported
method getUrl (line 270) | public @NonNull String getUrl() {
method getSearchUrl (line 274) | @Override
method getAbsoluteUrl (line 282) | @Exported(visibility = 999)
method getFullName (line 291) | @Exported(visibility = 999)
method setFullName (line 300) | public void setFullName(String name) {
method getDescription (line 305) | @Exported
method setDescription (line 315) | public void setDescription(String description) {
method getProperties (line 322) | public Map<Descriptor<UserProperty>, UserProperty> getProperties() {
method addProperty (line 329) | public synchronized void addProperty(@NonNull UserProperty p) throws I...
method getAllProperties (line 343) | @Exported(name = "property", inline = true)
method getProperty (line 355) | public <T extends UserProperty> T getProperty(Class<T> clazz) {
method impersonate2 (line 374) | public @NonNull Authentication impersonate2() throws UsernameNotFoundE...
method impersonate (line 382) | @Deprecated
method getUserDetailsForImpersonation2 (line 401) | public @NonNull UserDetails getUserDetailsForImpersonation2() throws U...
method getUserDetailsForImpersonation (line 427) | @Deprecated
class LegitimateButUnknownUserDetails (line 439) | private static class LegitimateButUnknownUserDetails extends org.sprin...
method LegitimateButUnknownUserDetails (line 440) | private LegitimateButUnknownUserDetails(String username) throws Ille...
method impersonate (line 455) | @Restricted(NoExternalUse.class)
method doSubmitDescription (line 463) | @RequirePOST
method getUnknown (line 478) | public static @NonNull User getUnknown() {
method get (line 493) | @Deprecated
method get (line 514) | public static @Nullable User get(String idOrFullName, boolean create, ...
method getOrCreateById (line 534) | private static @Nullable User getOrCreateById(@NonNull String id, @Non...
method get (line 566) | @Deprecated
method getOrCreateByIdOrFullName (line 586) | public static @NonNull User getOrCreateByIdOrFullName(@NonNull String ...
method current (line 597) | public static @CheckForNull User current() {
method get2 (line 609) | public static @CheckForNull User get2(@CheckForNull Authentication a) {
method get (line 621) | @Deprecated
method getById (line 637) | public static @Nullable User getById(String id, boolean create) {
method getAll (line 644) | public static @NonNull Collection<User> getAll() {
method reload (line 654) | @Restricted(NoExternalUse.class)
method rekey (line 665) | public static void rekey() {
method getDisplayName (line 682) | @Override
method relatedTo (line 690) | private boolean relatedTo(@NonNull Run<?, ?> b) {
method getBuilds (line 708) | @SuppressWarnings("unchecked")
method getProjects (line 720) | public @NonNull Set<AbstractProject<?, ?>> getProjects() {
method toString (line 727) | @Override
method clear (line 737) | @Deprecated
method getConfigFileFor (line 746) | private static File getConfigFileFor(String id) {
method getUserFolderFor (line 750) | private static File getUserFolderFor(String id) {
method getUserFolder (line 763) | public @CheckForNull File getUserFolder() {
method getExistingUserFolder (line 767) | private @CheckForNull File getExistingUserFolder() {
method getRootDir (line 774) | static File getRootDir() {
method isIdOrFullnameAllowed (line 791) | public static boolean isIdOrFullnameAllowed(@CheckForNull String id) {
method save (line 806) | @Override
method constructUserConfigFile (line 822) | private File constructUserConfigFile() throws IOException {
method putUserFolderIfAbsent (line 826) | private File putUserFolderIfAbsent() throws IOException {
method delete (line 835) | public void delete() throws IOException {
method deleteExistingUserFolder (line 844) | private void deleteExistingUserFolder(File existingUserFolder) throws ...
method getApi (line 853) | public Api getApi() {
method doConfigSubmit (line 860) | @POST
method doDoDelete (line 901) | @RequirePOST
method doRssAll (line 914) | public void doRssAll(StaplerRequest req, StaplerResponse rsp) throws I...
method doRssFailed (line 918) | public void doRssFailed(StaplerRequest req, StaplerResponse rsp) throw...
method doRssLatest (line 922) | public void doRssLatest(StaplerRequest req, StaplerResponse rsp) throw...
method getACL (line 938) | @Override
method canDelete (line 950) | public boolean canDelete() {
method getAuthorities (line 964) | public @NonNull List<String> getAuthorities() {
method getDynamic (line 989) | public Object getDynamic(String token) {
method getPropertyActions (line 1006) | public List<Action> getPropertyActions() {
method getTransientActions (line 1021) | public List<Action> getTransientActions() {
method doContextMenu (line 1029) | @Override
method getTarget (line 1034) | @Override
method getIllegalPersistedUsernames (line 1051) | @Restricted(NoExternalUse.class)
method writeReplace (line 1056) | private Object writeReplace() {
class Replacer (line 1060) | private static class Replacer {
method Replacer (line 1063) | Replacer(User u) {
method readResolve (line 1067) | private Object readResolve() {
class AllUsers (line 1075) | @Extension
method scanAll (line 1081) | @Initializer(after = InitMilestone.JOB_CONFIG_ADAPTED)
method getInstance (line 1095) | private static AllUsers getInstance() {
method reload (line 1099) | private static void reload() {
method clear (line 1105) | private static void clear() {
method remove (line 1109) | private static void remove(String id) {
method get (line 1113) | private static User get(String id) {
method put (line 1117) | private static void put(String id, User user) {
method values (line 1121) | private static Collection<User> values() {
class CanonicalIdResolver (line 1136) | public abstract static class CanonicalIdResolver extends AbstractDescr...
method compareTo (line 1145) | @Override
method resolveCanonicalId (line 1155) | public abstract @CheckForNull String resolveCanonicalId(String idOrF...
method getPriority (line 1166) | public int getPriority() {
method all (line 1178) | public static List<CanonicalIdResolver> all() {
method resolve (line 1192) | @CheckForNull
class FullNameIdResolver (line 1212) | @Extension
method resolveCanonicalId (line 1216) | @Override
method getPriority (line 1224) | @Override
class UserIDCanonicalIdResolver (line 1235) | @Extension
method resolveCanonicalId (line 1244) | @Override
method getPriority (line 1268) | @Override
FILE: cost-benefit-calculator/src/test/resources/org/apache/myfaces/tobago/facelets/AttributeHandler.java
class AttributeHandler (line 58) | public final class AttributeHandler extends TagHandler {
method AttributeHandler (line 68) | public AttributeHandler(final TagConfig config) {
method apply (line 75) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 287) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 291) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 295) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 299) | private String removeElParenthesis(final String string) {
method getExpression (line 303) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 308) | private MethodExpression getMethodExpression(
method getValue (line 327) | private Object getValue(
method setConverter (line 343) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 357) | private void setConverter(
FILE: cost-benefit-calculator/src/test/resources/org/apache/myfaces/tobago/facelets/AttributeHandler2.java
class AttributeHandler (line 58) | public final class AttributeHandler extends TagHandler {
method AttributeHandler (line 68) | public AttributeHandler(final TagConfig config) {
method apply (line 75) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 287) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 291) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 295) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 299) | private String removeElParenthesis(final String string) {
method getExpression (line 303) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 308) | private MethodExpression getMethodExpression(
method getValue (line 327) | private Object getValue(
method setConverter (line 343) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 357) | private void setConverter(
method letsAddASimpleMethod (line 369) | public static void letsAddASimpleMethod() {
FILE: cost-benefit-calculator/src/test/resources/org/apache/myfaces/tobago/facelets/AttributeHandlerAndSorter.java
class AttributeHandlerAndSorter (line 83) | public final class AttributeHandlerAndSorter extends TagHandler {
method AttributeHandler (line 93) | public AttributeHandler(final TagConfig config) {
method apply (line 100) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 312) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 316) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 320) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 324) | private String removeElParenthesis(final String string) {
method getExpression (line 328) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 333) | private MethodExpression getMethodExpression(
method getValue (line 352) | private Object getValue(
method setConverter (line 368) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 382) | private void setConverter(
class Sorter (line 396) | class Sorter {
method perform (line 405) | @Deprecated
method perform (line 411) | public void perform(final AbstractUISheet data) {
method isSimpleProperty (line 552) | boolean isSimpleProperty(final String expressionString) {
method unsetSortableAttribute (line 566) | private void unsetSortableAttribute(final UIColumn uiColumn) {
method getFirstSortableChild (line 571) | private UIComponent getFirstSortableChild(final List<UIComponent> chil...
method getComparator (line 598) | public Comparator getComparator() {
method setComparator (line 602) | public void setComparator(final Comparator comparator) {
FILE: effort-ranker/src/main/java/org/hjug/metrics/CBOClass.java
class CBOClass (line 9) | @Data
method CBOClass (line 18) | public CBOClass(String className, String fileName, String packageName,...
FILE: effort-ranker/src/main/java/org/hjug/metrics/Disharmony.java
type Disharmony (line 3) | public interface Disharmony {
method getFileName (line 5) | String getFileName();
method getClassName (line 7) | String getClassName();
method getPackageName (line 9) | String getPackageName();
FILE: effort-ranker/src/main/java/org/hjug/metrics/GodClass.java
class GodClass (line 10) | @Data
method GodClass (line 26) | public GodClass(String className, String fileName, String packageName,...
method extractValue (line 45) | private String extractValue(String value) {
FILE: effort-ranker/src/main/java/org/hjug/metrics/GodClassRanker.java
class GodClassRanker (line 12) | @Slf4j
method rankGodClasses (line 15) | public void rankGodClasses(List<GodClass> godClasses) {
method computeOverallRank (line 22) | void computeOverallRank(List<GodClass> godClasses) {
method rankWmc (line 35) | void rankWmc(List<GodClass> godClasses) {
method rankAtfd (line 45) | void rankAtfd(List<GodClass> godClasses) {
method rankTcc (line 55) | void rankTcc(List<GodClass> godClasses) {
method setRank (line 65) | <T extends Number & Comparable<? super T>> void setRank(
FILE: effort-ranker/src/main/java/org/hjug/metrics/rules/CBORule.java
class CBORule (line 24) | public class CBORule extends AbstractJavaRule {
method CBORule (line 38) | public CBORule() {
method getMessage (line 42) | @Override
method visit (line 47) | @Override
method visit (line 61) | public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
method visit (line 69) | public Object visit(ASTMethodDeclaration node, Object data) {
method visit (line 75) | public Object visit(ASTLocalVariableDeclaration node, Object data) {
method visit (line 81) | public Object visit(ASTFormalParameter node, Object data) {
method visit (line 87) | public Object visit(ASTFieldDeclaration node, Object data) {
method checkVariableType (line 93) | private void checkVariableType(ASTType typeNode) {
method ignoreType (line 102) | private boolean ignoreType(ASTType typeNode, JTypeMirror t) {
FILE: effort-ranker/src/test/java/org/hjug/metrics/CBOClassParsingTest.java
class CBOClassParsingTest (line 10) | public class CBOClassParsingTest {
method before (line 14) | @BeforeEach
method after (line 20) | @AfterEach
method test (line 25) | @Test
FILE: effort-ranker/src/test/java/org/hjug/metrics/GodClassParsingTest.java
class GodClassParsingTest (line 10) | public class GodClassParsingTest {
method before (line 14) | @BeforeEach
method after (line 20) | @AfterEach
method test (line 25) | @Test
FILE: effort-ranker/src/test/java/org/hjug/metrics/GodClassRankerTest.java
class GodClassRankerTest (line 12) | public class GodClassRankerTest {
method setUp (line 43) | @BeforeEach
method testRankGodClasses (line 50) | @Test
method testWmcRanker (line 68) | @Test
method testWmcRankerWithDupeValue (line 82) | @Test
method testAtfdRanker (line 93) | @Test
method testAtfdRankerWithDupeValue (line 107) | @Test
method testTccRanker (line 118) | @Test
method testTccRankerWithDuplicateValue (line 132) | @Test
FILE: graph-algorithms/src/main/java/org/hjug/dsm/CircularReferenceChecker.java
class CircularReferenceChecker (line 10) | @Slf4j
method getCycles (line 22) | public Map<V, AsSubgraph<V, E>> getCycles(Graph<V, E> graph) {
method isDuplicateSubGraph (line 44) | private boolean isDuplicateSubGraph(AsSubgraph<V, E> subGraph, V verte...
method detectCycles (line 59) | private Map<V, AsSubgraph<V, E>> detectCycles(Graph<V, E> graph) {
FILE: graph-algorithms/src/main/java/org/hjug/dsm/DSM.java
class DSM (line 33) | public class DSM<V, E> {
method DSM (line 50) | public DSM(Graph<V, E> graph) {
method addActivity (line 55) | public void addActivity(V activity) {
method addDependency (line 59) | public void addDependency(V from, V to, int weight) {
method orderVertices (line 66) | private void orderVertices() {
method getSparseIntDirectedWeightedGraph (line 78) | private SparseIntDirectedWeightedGraph getSparseIntDirectedWeightedGra...
method convertIntToStringVertices (line 97) | List<V> convertIntToStringVertices(List<Integer> intVertices) {
method findStronglyConnectedSparseGraphComponents (line 108) | private List<Set<Integer>> findStronglyConnectedSparseGraphComponents(...
method topologicalSortSparseGraph (line 114) | private List<Integer> topologicalSortSparseGraph(List<Set<Integer>> sc...
method topologicalSortUtilSparseGraph (line 130) | private void topologicalSortUtilSparseGraph(
method getEdgesAboveDiagonal (line 143) | public List<E> getEdgesAboveDiagonal() {
method getSparseEdgesAboveDiagonal (line 168) | private List<Integer> getSparseEdgesAboveDiagonal() {
method getFirstLowestWeightEdgeAboveDiagonalToRemove (line 190) | public E getFirstLowestWeightEdgeAboveDiagonalToRemove() {
method getMinimumWeightEdgesAboveDiagonal (line 213) | public List<E> getMinimumWeightEdgesAboveDiagonal() {
method printDSM (line 236) | public void printDSM() {
method printDSM (line 244) | void printDSM(Graph<V, E> graph, List<V> sortedActivities) {
FILE: graph-algorithms/src/main/java/org/hjug/dsm/EdgeRemovalCalculator.java
class EdgeRemovalCalculator (line 10) | public class EdgeRemovalCalculator {
method EdgeRemovalCalculator (line 17) | public EdgeRemovalCalculator(Graph<String, DefaultWeightedEdge> graph,...
method EdgeRemovalCalculator (line 23) | public EdgeRemovalCalculator(Graph<String, DefaultWeightedEdge> graph,...
method getImpactOfEdgesAboveDiagonalIfRemoved (line 32) | public List<EdgeToRemoveInfo> getImpactOfEdgesAboveDiagonalIfRemoved(i...
method getImpactOfEdges (line 57) | public List<EdgeToRemoveInfo> getImpactOfEdges() {
method calculateEdgeToRemoveInfo (line 69) | public EdgeToRemoveInfo calculateEdgeToRemoveInfo(DefaultWeightedEdge ...
FILE: graph-algorithms/src/main/java/org/hjug/dsm/EdgeToRemoveInfo.java
class EdgeToRemoveInfo (line 6) | @Data
FILE: graph-algorithms/src/main/java/org/hjug/dsm/OptimalBackEdgeRemover.java
class OptimalBackEdgeRemover (line 9) | public class OptimalBackEdgeRemover<V, E> {
method OptimalBackEdgeRemover (line 16) | public OptimalBackEdgeRemover(Graph<V, E> graph) {
method findOptimalBackEdgesToRemove (line 24) | public Set<E> findOptimalBackEdgesToRemove() {
FILE: graph-algorithms/src/main/java/org/hjug/dsm/SparseGraphCircularReferenceChecker.java
class SparseGraphCircularReferenceChecker (line 10) | @Slf4j
method getCycles (line 22) | public Map<Integer, AsSubgraph<Integer, Integer>> getCycles(SparseIntD...
method isDuplicateSubGraph (line 44) | private boolean isDuplicateSubGraph(AsSubgraph<Integer, Integer> subGr...
method detectCycles (line 59) | private Map<Integer, AsSubgraph<Integer, Integer>> detectCycles(Sparse...
FILE: graph-algorithms/src/main/java/org/hjug/dsm/SparseIntDWGEdgeRemovalCalculator.java
class SparseIntDWGEdgeRemovalCalculator (line 17) | class SparseIntDWGEdgeRemovalCalculator {
method SparseIntDWGEdgeRemovalCalculator (line 27) | SparseIntDWGEdgeRemovalCalculator(
method getImpactOfSparseEdgesAboveDiagonalIfRemoved (line 46) | public List<EdgeToRemoveInfo> getImpactOfSparseEdgesAboveDiagonalIfRem...
method calculateSparseEdgeToRemoveInfo (line 54) | private EdgeToRemoveInfo calculateSparseEdgeToRemoveInfo(Integer edgeT...
method orderVertices (line 80) | private List<Integer> orderVertices(SparseIntDirectedWeightedGraph spa...
method findStronglyConnectedSparseGraphComponents (line 99) | private List<Set<Integer>> findStronglyConnectedSparseGraphComponents(...
method topologicalSortSparseGraph (line 105) | private List<Integer> topologicalSortSparseGraph(List<Set<Integer>> sc...
method topologicalSortUtilSparseGraph (line 118) | private void topologicalSortUtilSparseGraph(
method getSparseEdgesAboveDiagonal (line 131) | private List<Integer> getSparseEdgesAboveDiagonal(
method topologicalParallelSortSparseGraph (line 148) | private List<Integer> topologicalParallelSortSparseGraph(List<Set<Inte...
method topologicalSortUtilSparseGraph (line 162) | private void topologicalSortUtilSparseGraph(
FILE: graph-algorithms/src/main/java/org/hjug/feedback/SuperTypeToken.java
class SuperTypeToken (line 5) | public abstract class SuperTypeToken<T> {
method SuperTypeToken (line 8) | protected SuperTypeToken() {
method getType (line 17) | public Type getType() {
method getClassFromTypeToken (line 21) | public Class<T> getClassFromTypeToken() {
method getClassFromTypeToken (line 26) | static Class<?> getClassFromTypeToken(Type type) {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/EdgeInfo.java
class EdgeInfo (line 6) | @Data
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/EdgeInfoCalculator.java
class EdgeInfoCalculator (line 10) | @RequiredArgsConstructor
method calculateEdgeInformation (line 18) | public Collection<EdgeInfo> calculateEdgeInformation() {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/approximate/FeedbackArcSetResult.java
class FeedbackArcSetResult (line 9) | public class FeedbackArcSetResult<V, E> {
method FeedbackArcSetResult (line 13) | public FeedbackArcSetResult(List<V> vertexSequence, Set<E> feedbackArc...
method getVertexSequence (line 18) | public List<V> getVertexSequence() {
method getFeedbackArcs (line 22) | public Set<E> getFeedbackArcs() {
method getFeedbackArcCount (line 26) | public int getFeedbackArcCount() {
method toString (line 30) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/approximate/FeedbackArcSetSolver.java
class FeedbackArcSetSolver (line 17) | public class FeedbackArcSetSolver<V, E> {
method FeedbackArcSetSolver (line 24) | public FeedbackArcSetSolver(Graph<V, E> graph) {
method initializeDegrees (line 35) | private void initializeDegrees() {
method solve (line 53) | public FeedbackArcSetResult<V, E> solve() {
method findSinks (line 102) | private List<V> findSinks(Set<V> vertices) {
method findSources (line 111) | private List<V> findSources(Set<V> vertices) {
method findMaxDeltaVertex (line 120) | private Optional<V> findMaxDeltaVertex(Set<V> vertices) {
method removeVertex (line 129) | private void removeVertex(V vertex, Set<V> remainingVertices, Set<E> f...
method calculateFeedbackArcs (line 151) | private Set<E> calculateFeedbackArcs(List<V> sequence) {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/exact/FeedbackArcSetResult.java
class FeedbackArcSetResult (line 8) | public class FeedbackArcSetResult<V, E> {
method FeedbackArcSetResult (line 12) | public FeedbackArcSetResult(Set<E> feedbackArcSet, double objectiveVal...
method getFeedbackArcSet (line 17) | public Set<E> getFeedbackArcSet() {
method getObjectiveValue (line 21) | public double getObjectiveValue() {
method size (line 25) | public int size() {
method toString (line 29) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetSolver.java
class MinimumFeedbackArcSetSolver (line 21) | public class MinimumFeedbackArcSetSolver<V, E> {
method MinimumFeedbackArcSetSolver (line 28) | public MinimumFeedbackArcSetSolver(Graph<V, E> graph, Map<E, Double> e...
method createUniformWeights (line 39) | private Map<E, Double> createUniformWeights() {
method solve (line 48) | public FeedbackArcSetResult<V, E> solve() {
method computeInitialHeuristicSolution (line 98) | private Set<E> computeInitialHeuristicSolution() {
method solveRelaxedProblem (line 129) | private Set<E> solveRelaxedProblem() {
method findCyclesInSolution (line 162) | private Set<List<E>> findCyclesInSolution(Set<E> solution) {
method findShortestPath (line 186) | private List<E> findShortestPath(Graph<V, E> graph, V start, V target) {
method isAcyclic (line 231) | private boolean isAcyclic(Graph<V, E> graph) {
method hasCycles (line 239) | private boolean hasCycles(Graph<V, E> graph) {
method createGraphWithoutEdges (line 247) | private Graph<V, E> createGraphWithoutEdges(Set<E> excludedEdges) {
method createGraphCopy (line 266) | private Graph<V, E> createGraphCopy() {
method getEdgesInSCC (line 283) | private Set<E> getEdgesInSCC(Graph<V, E> graph, Set<V> scc) {
method isAllCyclesCovered (line 296) | private boolean isAllCyclesCovered(Set<E> solution) {
method calculateObjectiveValue (line 304) | private double calculateObjectiveValue(Set<E> solution) {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/pageRank/LineDigraph.java
class LineDigraph (line 12) | class LineDigraph<V, E> {
method LineDigraph (line 22) | public LineDigraph() {
method addVertex (line 33) | public boolean addVertex(LineVertex<V, E> vertex) {
method removeVertex (line 47) | public boolean removeVertex(LineVertex<V, E> vertex) {
method addEdge (line 72) | public boolean addEdge(LineVertex<V, E> source, LineVertex<V, E> targe...
method removeEdge (line 91) | public boolean removeEdge(LineVertex<V, E> source, LineVertex<V, E> ta...
method containsVertex (line 106) | public boolean containsVertex(LineVertex<V, E> vertex) {
method containsEdge (line 116) | public boolean containsEdge(LineVertex<V, E> source, LineVertex<V, E> ...
method vertexSet (line 124) | public Set<LineVertex<V, E>> vertexSet() {
method vertexCount (line 132) | public int vertexCount() {
method edgeCount (line 140) | public int edgeCount() {
method getOutgoingNeighbors (line 149) | public Set<LineVertex<V, E>> getOutgoingNeighbors(LineVertex<V, E> ver...
method getIncomingNeighbors (line 159) | public Set<LineVertex<V, E>> getIncomingNeighbors(LineVertex<V, E> ver...
method getAllNeighbors (line 168) | public Set<LineVertex<V, E>> getAllNeighbors(LineVertex<V, E> vertex) {
method getOutDegree (line 180) | public int getOutDegree(LineVertex<V, E> vertex) {
method getInDegree (line 189) | public int getInDegree(LineVertex<V, E> vertex) {
method getTotalDegree (line 198) | public int getTotalDegree(LineVertex<V, E> vertex) {
method isEmpty (line 206) | public boolean isEmpty() {
method clear (line 213) | public void clear() {
method getSources (line 223) | public Set<LineVertex<V, E>> getSources() {
method getSinks (line 231) | public Set<LineVertex<V, E>> getSinks() {
method getReachableVertices (line 240) | public Set<LineVertex<V, E>> getReachableVertices(LineVertex<V, E> sta...
method hasPath (line 267) | public boolean hasPath(LineVertex<V, E> source, LineVertex<V, E> targe...
method topologicalSort (line 283) | public List<LineVertex<V, E>> topologicalSort() {
method copy (line 319) | public LineDigraph<V, E> copy() {
method getStatistics (line 339) | public Map<String, Object> getStatistics() {
method toString (line 366) | @Override
method toDetailedString (line 380) | public String toDetailedString() {
method validateConsistency (line 404) | public boolean validateConsistency() {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/arc/pageRank/PageRankFAS.java
class PageRankFAS (line 21) | @Slf4j
method PageRankFAS (line 37) | public PageRankFAS(Graph<V, E> graph, SuperTypeToken<E> edgeTypeToken) {
method PageRankFAS (line 48) | public PageRankFAS(Graph<V, E> graph, int pageRankIterations, SuperTyp...
method computeFeedbackArcSet (line 58) | public Set<E> computeFeedbackArcSet() {
method processStronglyConnectedComponent (line 91) | private E processStronglyConnectedComponent(Graph<V, E> graph, Set<V> ...
method createLineDigraph (line 113) | private LineDigraph<V, E> createLineDigraph(Graph<V, E> graph) {
method createLineDigraphEdges (line 137) | private void createLineDigraphEdges(
method createLineDigraphEdgesDFS (line 152) | private void createLineDigraphEdgesDFS(
method computePageRank (line 197) | private Map<LineVertex<V, E>, Double> computePageRank(LineDigraph<V, E...
method applyOneIteration (line 232) | private void applyOneIteration(
method findStronglyConnectedComponents (line 258) | private List<Set<V>> findStronglyConnectedComponents(Graph<V, E> graph) {
method hasCycles (line 266) | private boolean hasCycles(Graph<V, E> graph) {
method createGraphCopy (line 274) | private Graph<V, E> createGraphCopy(Graph<V, E> original) {
method createSubgraph (line 293) | private Graph<V, E> createSubgraph(Graph<V, E> graph, Set<V> vertices) {
method getExecutionStatistics (line 321) | public Map<String, Object> getExecutionStatistics(Graph<V, E> graph) {
class LineVertex (line 349) | class LineVertex<V, E> {
method LineVertex (line 354) | public LineVertex(V source, V target, E originalEdge) {
method getSource (line 360) | public V getSource() {
method getTarget (line 364) | public V getTarget() {
method getOriginalEdge (line 368) | public E getOriginalEdge() {
method equals (line 372) | @Override
method hashCode (line 380) | @Override
method toString (line 385) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetResult.java
class FeedbackVertexSetResult (line 8) | public class FeedbackVertexSetResult<V> {
method FeedbackVertexSetResult (line 11) | public FeedbackVertexSetResult(Set<V> feedbackVertices) {
method getFeedbackVertices (line 15) | public Set<V> getFeedbackVertices() {
method size (line 19) | public int size() {
method toString (line 23) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetSolver.java
class FeedbackVertexSetSolver (line 23) | public class FeedbackVertexSetSolver<V, E> {
method FeedbackVertexSetSolver (line 32) | public FeedbackVertexSetSolver(
method createUniformWeights (line 45) | private Map<V, Double> createUniformWeights() {
method computeFractionalSolution (line 54) | private Map<V, Double> computeFractionalSolution() {
method computeCycleCounts (line 87) | private Map<V, Long> computeCycleCounts() {
method isInterestingComponent (line 104) | private boolean isInterestingComponent(Set<V> scc) {
method hasInterestingCycle (line 116) | private boolean hasInterestingCycle() {
method solve (line 125) | public FeedbackVertexSetResult<V> solve() {
method solveRecursive (line 132) | private FeedbackVertexSetResult<V> solveRecursive(Graph<V, E> currentG...
method computeDistances (line 217) | private Map<V, Double> computeDistances(Graph<V, E> graph, V source) {
method evaluateCut (line 245) | private CutCandidate<V> evaluateCut(Graph<V, E> graph, Map<V, Double> ...
method createLeftPartition (line 268) | private Set<V> createLeftPartition(Graph<V, E> graph, Map<V, Double> d...
method createRightPartition (line 277) | private Set<V> createRightPartition(Graph<V, E> graph, Map<V, Double> ...
method hasInterestingCycleInSubgraph (line 286) | private boolean hasInterestingCycleInSubgraph(Graph<V, E> subgraph, Se...
method intersection (line 304) | private Set<V> intersection(Set<V> set1, Set<V> set2) {
class CutCandidate (line 311) | private static class CutCandidate<V> {
method CutCandidate (line 316) | CutCandidate(Set<V> cut, double ratio, double distance) {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetResult.java
class DirectedFeedbackVertexSetResult (line 8) | public class DirectedFeedbackVertexSetResult<V> {
method DirectedFeedbackVertexSetResult (line 11) | public DirectedFeedbackVertexSetResult(Set<V> feedbackVertices) {
method getFeedbackVertices (line 15) | public Set<V> getFeedbackVertices() {
method size (line 19) | public int size() {
method toString (line 23) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetSolver.java
class DirectedFeedbackVertexSetSolver (line 24) | public class DirectedFeedbackVertexSetSolver<V, E> {
method DirectedFeedbackVertexSetSolver (line 39) | public DirectedFeedbackVertexSetSolver(
method createUniformWeights (line 58) | private Map<V, Double> createUniformWeights() {
method solve (line 68) | public DirectedFeedbackVertexSetResult<V> solve() {
method solve (line 76) | public DirectedFeedbackVertexSetResult<V> solve(int k) {
method computeZoneDecomposition (line 92) | private void computeZoneDecomposition(int k) {
method computeFlowBlocker (line 120) | private Set<V> computeFlowBlocker(Set<V> solutionS, int k) {
method computeMinimumVertexCut (line 141) | private Set<V> computeMinimumVertexCut(V source, V target, Set<V> excl...
method computeRemainder (line 186) | private Set<V> computeRemainder(Set<V> solutionS, Set<V> flowBlockerF,...
method partitionIntoZones (line 207) | private void partitionIntoZones() {
method computeConnectedComponent (line 228) | private Set<V> computeConnectedComponent(V startVertex, Set<V> candida...
method computeKDfvsRepresentatives (line 255) | private void computeKDfvsRepresentatives(int k) {
method computeKDfvsRepresentativeForZone (line 266) | private Set<V> computeKDfvsRepresentativeForZone(Set<V> zone, int k) {
method hasSelfLoop (line 300) | private boolean hasSelfLoop(V vertex) {
method solveWithReductionRules (line 307) | private DirectedFeedbackVertexSetResult<V> solveWithReductionRules(int...
method applyReductionRules (line 323) | private void applyReductionRules() {
method applyReductionRulesForZone (line 339) | private void applyReductionRulesForZone(Set<V> nonRepresentative, Set<...
method addBypassEdges (line 361) | private void addBypassEdges(V source, V target, Set<V> representatives) {
method findBypassChain (line 455) | private List<V> findBypassChain(V source, V target, Set<V> representat...
method createMinimalBypass (line 512) | private void createMinimalBypass(V source, V target, Set<V> representa...
method hasPath (line 578) | private boolean hasPath(V source, V target) {
method hasPathDFS (line 596) | private boolean hasPathDFS(V source, V target, Set<V> visited, int max...
method clearPathCache (line 631) | private void clearPathCache() {
method validateBypassEdges (line 638) | private boolean validateBypassEdges(V source, V target, Set<V> represe...
method addBypassEdgesKernelized (line 656) | private void addBypassEdgesKernelized(V source, V target, Set<V> repre...
method hasPathThroughZone (line 690) | private boolean hasPathThroughZone(V source, V target) {
method solveKernelizedInstance (line 728) | private Set<V> solveKernelizedInstance(int k) {
method computeMinimalFeedbackVertexSet (line 748) | private Set<V> computeMinimalFeedbackVertexSet(Graph<V, E> subgraph, i...
method computeMaxPathLength (line 798) | private int computeMaxPathLength() {
method computeDensityBasedLimit (line 842) | private int computeDensityBasedLimit(int n) {
method computeParameterBasedLimit (line 865) | private int computeParameterBasedLimit(int k, int n) {
method computeSCCBasedLimit (line 885) | private int computeSCCBasedLimit(int n) {
method computeTreewidthBasedLimit (line 910) | private int computeTreewidthBasedLimit(int n, int k) {
method estimateStronglyConnectedComponents (line 932) | private Set<Set<V>> estimateStronglyConnectedComponents() {
method exploreComponent (line 962) | private void exploreComponent(V vertex, Set<V> component, Set<V> visit...
method getDefaultMaxPathLength (line 986) | public static int getDefaultMaxPathLength() {
method getAdaptiveMaxPathLength (line 993) | private int getAdaptiveMaxPathLength() {
method getContextAwareMaxPathLength (line 1015) | private int getContextAwareMaxPathLength(PathContext context) {
type PathContext (line 1043) | private enum PathContext {
class PathComputationStats (line 1053) | private static class PathComputationStats {
method recordTime (line 1057) | public void recordTime(long time) {
method getAverageTime (line 1062) | public double getAverageTime() {
method getMaxPathLength (line 1073) | private int getMaxPathLength() {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/EnhancedParameterComputer.java
class EnhancedParameterComputer (line 14) | public class EnhancedParameterComputer<V, E> {
method EnhancedParameterComputer (line 21) | public EnhancedParameterComputer(SuperTypeToken<E> edgeTypeToken) {
method EnhancedParameterComputer (line 28) | public EnhancedParameterComputer(SuperTypeToken<E> edgeTypeToken, int ...
method computeOptimalParameters (line 38) | public EnhancedParameters<V> computeOptimalParameters(Graph<V, E> grap...
method computeOptimalParameters (line 45) | public EnhancedParameters<V> computeOptimalParameters(
method computeParameters (line 74) | public EnhancedParameters<V> computeParameters(Graph<V, E> graph, Set<...
method computeMultipleParameterOptions (line 85) | public List<EnhancedParameters<V>> computeMultipleParameterOptions(
method validateModulator (line 115) | public boolean validateModulator(Graph<V, E> graph, Set<V> modulator, ...
method computeParameterQuality (line 123) | private double computeParameterQuality(int k, int modulatorSize, int e...
method shutdown (line 128) | public void shutdown() {
class EnhancedParameters (line 140) | public static class EnhancedParameters<V> {
method EnhancedParameters (line 146) | public EnhancedParameters(int k, Set<V> modulator, int eta, double q...
method getK (line 153) | public int getK() {
method getModulator (line 157) | public Set<V> getModulator() {
method getModulatorSize (line 161) | public int getModulatorSize() {
method getEta (line 165) | public int getEta() {
method getQualityScore (line 169) | public double getQualityScore() {
method getTotalParameter (line 176) | public int getTotalParameter() {
method getKernelSizeBound (line 183) | public double getKernelSizeBound() {
method equals (line 188) | @Override
method hashCode (line 196) | @Override
method toString (line 201) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/FeedbackVertexSetComputer.java
class FeedbackVertexSetComputer (line 17) | public class FeedbackVertexSetComputer<V, E> {
method FeedbackVertexSetComputer (line 23) | public FeedbackVertexSetComputer(SuperTypeToken<E> edgeTypeToken) {
method FeedbackVertexSetComputer (line 29) | public FeedbackVertexSetComputer(SuperTypeToken<E> edgeTypeToken, int ...
method computeK (line 38) | public int computeK(Graph<V, E> graph) {
method greedyFeedbackVertexSet (line 70) | Set<V> greedyFeedbackVertexSet(Graph<V, E> graph) {
method stronglyConnectedComponentsBasedFVS (line 92) | private Set<V> stronglyConnectedComponentsBasedFVS(Graph<V, E> graph) {
method degreeBasedFeedbackVertexSet (line 123) | private Set<V> degreeBasedFeedbackVertexSet(Graph<V, E> graph) {
method localSearchFeedbackVertexSet (line 152) | private Set<V> localSearchFeedbackVertexSet(Graph<V, E> graph) {
method findVertexInCyclesWithMaxDegree (line 199) | private V findVertexInCyclesWithMaxDegree(Graph<V, E> graph) {
method calculateDegreeScore (line 213) | private double calculateDegreeScore(Graph<V, E> graph, V vertex) {
method hasSelfLoop (line 233) | private boolean hasSelfLoop(Graph<V, E> graph, V vertex) {
method hasCycles (line 240) | private boolean hasCycles(Graph<V, E> graph) {
method isValidFeedbackVertexSet (line 248) | private boolean isValidFeedbackVertexSet(Graph<V, E> graph, Set<V> fee...
method copyGraph (line 259) | @SuppressWarnings("unchecked")
method computeFallbackK (line 281) | private int computeFallbackK(Graph<V, E> graph) {
method getFutureValue (line 296) | private Set<V> getFutureValue(Future<Set<V>> future) {
method shutdown (line 304) | public void shutdown() {
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/ModulatorComputer.java
class ModulatorComputer (line 21) | public class ModulatorComputer<V, E> {
method ModulatorComputer (line 28) | public ModulatorComputer(SuperTypeToken<E> edgeTypeToken) {
method ModulatorComputer (line 35) | public ModulatorComputer(SuperTypeToken<E> edgeTypeToken, int parallel...
method computeModulator (line 45) | public ModulatorResult<V> computeModulator(Graph<V, E> graph, int targ...
method computeGreedyDegreeModulator (line 82) | private Set<V> computeGreedyDegreeModulator(Graph<V, E> graph, int tar...
method computeFeedbackVertexSetModulator (line 108) | private Set<V> computeFeedbackVertexSetModulator(Graph<V, E> graph, in...
method computeTreewidthDecompositionModulator (line 151) | private Set<V> computeTreewidthDecompositionModulator(Graph<V, E> grap...
method computeHighDegreeVertexModulator (line 187) | private Set<V> computeHighDegreeVertexModulator(Graph<V, E> graph, int...
method computeBottleneckVertexModulator (line 211) | private Set<V> computeBottleneckVertexModulator(Graph<V, E> graph, int...
method computeVertexRemovalScore (line 254) | public ConcurrentHashMap<V, Double> computeVertexRemovalScore(Graph<V,...
method computeBasicMetricsParallel (line 304) | private void computeBasicMetricsParallel(
method computeStructuralImportanceParallel (line 317) | private void computeStructuralImportanceParallel(
method computeComprehensiveScoresParallel (line 343) | private void computeComprehensiveScoresParallel(
method computeDegreeBasedScore (line 389) | private double computeDegreeBasedScore(int degree, int targetTreewidth...
method computeLocalClusteringImpact (line 417) | private double computeLocalClusteringImpact(Graph<V, DefaultEdge> grap...
method computeConnectivityImportance (line 448) | private double computeConnectivityImportance(Graph<V, DefaultEdge> gra...
method estimateBridgePotential (line 470) | private double estimateBridgePotential(
method estimateArticulationPotential (line 503) | private double estimateArticulationPotential(
method computeNeighborhoodDensityImpact (line 520) | private double computeNeighborhoodDensityImpact(Graph<V, DefaultEdge> ...
method computeNeighborhoodSparsity (line 553) | private double computeNeighborhoodSparsity(Graph<V, DefaultEdge> graph...
method computeNormalizedImportanceScore (line 580) | private double computeNormalizedImportanceScore(double importance, Dou...
method computeTargetProximityScore (line 594) | private double computeTargetProximityScore(Graph<V, DefaultEdge> graph...
method computeTreewidthReductionPotential (line 612) | private double computeTreewidthReductionPotential(Graph<V, DefaultEdge...
method computeCliqueFormationPotential (line 640) | private double computeCliqueFormationPotential(
method computeSubstructurePotential (line 675) | private double computeSubstructurePotential(
method computeConnectivityPreservationPenalty (line 689) | private double computeConnectivityPreservationPenalty(Graph<V, Default...
method applyTargetTreewidthAdjustmentsParallel (line 714) | private void applyTargetTreewidthAdjustmentsParallel(
method getNeighbors (line 748) | private Set<V> getNeighbors(V vertex, Graph<V, DefaultEdge> graph) {
method isBridgeVertex (line 769) | private boolean isBridgeVertex(Graph<V, DefaultEdge> graph, V vertex, ...
method isLikelyArticulationPoint (line 790) | private boolean isLikelyArticulationPoint(Graph<V, DefaultEdge> graph,...
method computeComponentConnectionPenalty (line 797) | private double computeComponentConnectionPenalty(
method shutdownThreadPool (line 820) | private void shutdownThreadPool(ForkJoinPool threadPool) {
method computeAdaptiveVertexRemovalScore (line 836) | public ConcurrentHashMap<V, Double> computeAdaptiveVertexRemovalScore(
method computeStructuralImportance (line 858) | private double computeStructuralImportance(Graph<V, DefaultEdge> graph...
method originalComputeBetweennessCentrality (line 876) | private Map<V, Double> originalComputeBetweennessCentrality(Graph<V, D...
method computeBetweennessCentrality (line 955) | public Map<V, Double> computeBetweennessCentrality(Graph<V, DefaultEdg...
method sampleSourceVertices (line 1023) | private Set<V> sampleSourceVertices(
method shouldUseDegreeWeightedSampling (line 1043) | private boolean shouldUseDegreeWeightedSampling(Graph<V, DefaultEdge> ...
method degreeWeightedSampling (line 1052) | private Set<V> degreeWeightedSampling(
method uniformRandomSampling (line 1096) | private Set<V> uniformRandomSampling(List<V> vertexList, int sampleSiz...
method computeSingleSourceBetweennessContributions (line 1120) | private Map<V, Double> computeSingleSourceBetweennessContributions(Gra...
method computeExactBetweennessCentrality (line 1188) | private Map<V, Double> computeExactBetweennessCentrality(Graph<V, Defa...
method computeBetweennessCentralityAdaptive (line 1212) | public Map<V, Double> computeBetweennessCentralityAdaptive(Graph<V, De...
method hasConverged (line 1259) | private boolean hasConverged(Map<V, Double> current, Map<V, Double> pr...
method findArticulationPoints (line 1279) | private Set<V> findArticulationPoints(Graph<V, DefaultEdge> graph) {
method computeBetweennessCentralityParallel (line 1320) | private Map<V, Double> computeBetweennessCentralityParallel(Graph<V, D...
method sampleSourceVerticesParallel (line 1414) | private Set<V> sampleSourceVerticesParallel(
method degreeWeightedSamplingParallel (line 1427) | private Set<V> degreeWeightedSamplingParallel(
method uniformRandomSamplingParallel (line 1482) | private Set<V> uniformRandomSamplingParallel(List<V> vertexList, int s...
method computeSingleSourceBetweennessContributionsParallel (line 1502) | private ConcurrentHashMap<V, Double> computeSingleSourceBetweennessCon...
method computeExactBetweennessCentralityParallel (line 1587) | private ConcurrentHashMap<V, Double> computeExactBetweennessCentrality...
method computeBetweennessCentralityAdaptiveParallel (line 1611) | public ConcurrentHashMap<V, Double> computeBetweennessCentralityAdapti...
method hasConvergedParallel (line 1682) | private boolean hasConvergedParallel(
method getSamplingMetrics (line 1702) | public ConcurrentHashMap<String, Double> getSamplingMetrics(int sample...
method computeModulatorQuality (line 1717) | private double computeModulatorQuality(Graph<V, E> graph, Set<V> modul...
method convertToUndirected (line 1731) | private Graph<V, DefaultEdge> convertToUndirected(Graph<V, E> directed) {
method computeFallbackModulator (line 1750) | private ModulatorResult<V> computeFallbackModulator(Graph<V, E> graph,...
method getFutureValue (line 1763) | private Set<V> getFutureValue(Future<Set<V>> future) {
method shutdown (line 1771) | public void shutdown() {
class ModulatorResult (line 1782) | public static class ModulatorResult<V> {
method ModulatorResult (line 1787) | public ModulatorResult(Set<V> modulator, int resultingTreewidth, dou...
method getModulator (line 1793) | public Set<V> getModulator() {
method getResultingTreewidth (line 1797) | public int getResultingTreewidth() {
method getQualityScore (line 1801) | public double getQualityScore() {
method getSize (line 1805) | public int getSize() {
method toString (line 1809) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/ParameterComputer.java
class ParameterComputer (line 12) | public class ParameterComputer<V, E> {
method ParameterComputer (line 17) | public ParameterComputer(SuperTypeToken<E> edgeTypeToken) {
method ParameterComputer (line 22) | public ParameterComputer(SuperTypeToken<E> edgeTypeToken, int parallel...
method computeParameters (line 30) | public Parameters computeParameters(Graph<V, E> graph) {
method computeParameters (line 37) | public Parameters computeParameters(Graph<V, E> graph, Set<V> modulato...
method computeParametersWithOptimalModulator (line 47) | public Parameters computeParametersWithOptimalModulator(Graph<V, E> gr...
method findGoodModulator (line 55) | private Set<V> findGoodModulator(Graph<V, E> graph, int maxSize) {
method findDegreeBasedModulator (line 69) | private Set<V> findDegreeBasedModulator(Graph<V, E> graph, int maxSize) {
method findFeedbackVertexSetBasedModulator (line 77) | private Set<V> findFeedbackVertexSetBasedModulator(Graph<V, E> graph, ...
method shutdown (line 86) | public void shutdown() {
class Parameters (line 94) | public static class Parameters {
method Parameters (line 99) | public Parameters(int k, int modulatorSize, int eta) {
method getK (line 105) | public int getK() {
method getModulatorSize (line 109) | public int getModulatorSize() {
method getEta (line 113) | public int getEta() {
method toString (line 117) | @Override
FILE: graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/TreewidthComputer.java
class TreewidthComputer (line 21) | public class TreewidthComputer<V, E> {
method TreewidthComputer (line 25) | public TreewidthComputer() {
method TreewidthComputer (line 29) | public TreewidthComputer(int parallelismLevel) {
method computeEta (line 37) | public int computeEta(Graph<V, E> graph, Set<V> modulator) {
method hasCycles (line 76) | private boolean hasCycles(Graph<V, E> graph) {
method convertToUndirectedWithoutModulator (line 84) | private Graph<V, DefaultEdge> convertToUndirectedWithoutModulator(Grap...
method minDegreeEliminationTreewidth (line 114) | private int minDegreeEliminationTreewidth(Graph<V, DefaultEdge> graph) {
method fillInHeuristicTreewidth (line 167) | public int fillInHeuristicTreewidth(Graph<V, DefaultEdge> graph) {
method fillInHeuristicTreewidthAsync (line 241) | public CompletableFuture<Integer> fillInHeuristicTreewidthAsync(Graph<...
method eliminateVertexParallel (line 300) | private void eliminateVertexParallel(
method getNeighborhoodParallel (line 329) | private Set<V> getNeighborhoodParallel(
method fillInNeighborhoodParallel (line 350) | private void fillInNeighborhoodParallel(Set<V> vertices, ConcurrentHas...
method calculateFillInParallel (line 376) | private int calculateFillInParallel(
method hasEdgeParallel (line 407) | private boolean hasEdgeParallel(V v1, V v2, ConcurrentHashMap<V, Set<V...
method maxCliqueTreewidth (line 417) | private int maxCliqueTreewidth(Graph<V, DefaultEdge> graph) {
method greedyTriangulationTreewidth (line 428) | private int greedyTriangulationTreewidth(Graph<V, DefaultEdge> graph) {
method triangulateNeighborhood (line 454) | private void triangulateNeighborhood(Set<V> neighbors, Map<V, Set<V>> ...
method calculateFillIn (line 467) | private int calculateFillIn(Set<V> neighbors, Map<V, Set<V>> adjacency...
method findMaxCliqueBronKerbosch (line 479) | private int findMaxCliqueBronKerbosch(Graph<V, DefaultEdge> graph) {
method bronKerbosch (line 489) | private void bronKerbosch(Graph<V, DefaultEdge> graph, Set<V> R, Set<V...
method findMaxCliqueGreedy (line 514) | private int findMaxCliqueGreedy(Graph<V, DefaultEdge> graph) {
method computeFallbackTreewidth (line 521) | private int computeFallbackTreewidth(Graph<V, DefaultEdge> graph) {
method getFutureValue (line 529) | private Integer getFutureValue(Future<Integer> future) {
method shutdown (line 537) | public void shutdown() {
FILE: graph-algorithms/src/test/java/org/hjug/dsm/CircularReferenceCheckerTests.java
class CircularReferenceCheckerTests (line 13) | class CircularReferenceCheckerTests {
method detectCyclesTest (line 17) | @DisplayName("Detect 3 cycles from given graph.")
FILE: graph-algorithms/src/test/java/org/hjug/dsm/DSMTest.java
class DSMTest (line 11) | class DSMTest {
method setUp (line 15) | @BeforeEach
method optimalBackwardEdgeToRemove (line 52) | @Test
method optimalBackwardEdgeToRemoveWithWeightOfOne (line 59) | @Test
method minWeightBackwardEdges (line 76) | @Test
method edgesAboveDiagonal (line 85) | @Test
FILE: graph-algorithms/src/test/java/org/hjug/dsm/EdgeRemovalCalculatorTest.java
class EdgeRemovalCalculatorTest (line 10) | public class EdgeRemovalCalculatorTest {
method getImpactOfEdgesAboveDiagonalIfRemoved (line 14) | @Test
FILE: graph-algorithms/src/test/java/org/hjug/dsm/OptimalBackEdgeRemoverTest.java
class OptimalBackEdgeRemoverTest (line 12) | class OptimalBackEdgeRemoverTest {
method noOptimalEdge (line 14) | @Test
method oneBackEdge (line 30) | @Test
method twoBackEdges (line 48) | @Test
method multi (line 68) | @Test
FILE: graph-algorithms/src/test/java/org/hjug/feedback/SuperTypeTokenTest.java
class SuperTypeTokenTest (line 10) | class SuperTypeTokenTest {
method setUp (line 14) | @BeforeEach
method getType (line 19) | @Test
method getGenericType (line 25) | @Test
method getClassFromType (line 32) | @Test
method typeWithGenericParameter (line 37) | @Test
class GenericTestClass (line 43) | class GenericTestClass<T> {
method GenericTestClass (line 46) | public GenericTestClass(SuperTypeToken<T> token) {
method getTypeTokenClass (line 50) | public Class<T> getTypeTokenClass() {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/approximate/FeedbackArcSetBenchmarkTest.java
class FeedbackArcSetBenchmarkTest (line 15) | class FeedbackArcSetBenchmarkTest {
method benchmarkDenseGraphs (line 17) | @Test
method benchmarkSparseGraphs (line 43) | @Test
method createDenseGraph (line 69) | private Graph<String, DefaultEdge> createDenseGraph(int size) {
method createSparseGraph (line 92) | private Graph<String, DefaultEdge> createSparseGraph(int size) {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/approximate/FeedbackArcSetExample.java
class FeedbackArcSetExample (line 7) | public class FeedbackArcSetExample {
method main (line 8) | public static void main(String[] args) {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/approximate/FeedbackArcSetSolverTest.java
class FeedbackArcSetSolverTest (line 21) | class FeedbackArcSetSolverTest {
method setUp (line 26) | @BeforeEach
class BasicAlgorithmTests (line 31) | @Nested
method testEmptyGraph (line 35) | @Test
method testSingleVertex (line 46) | @Test
method testAcyclicGraph (line 58) | @Test
method testSimpleCycle (line 75) | @Test
class ComplexGraphTests (line 95) | @Nested
method testMultipleCycles (line 99) | @Test
method testTournamentGraph (line 123) | @Test
class PerformanceTests (line 153) | @Nested
method testLargeRandomGraphs (line 157) | @ParameterizedTest
method testParallelPerformanceImprovement (line 174) | @Test
class EdgeCaseTests (line 194) | @Nested
method testSelfLoops (line 198) | @Test
method testDisconnectedComponents (line 215) | @Test
class CorrectnessTests (line 241) | @Nested
method testVertexOrderingValidity (line 245) | @Test
method testPerformanceBound (line 262) | @Test
method createRandomGraph (line 282) | private void createRandomGraph(int vertexCount, int edgeCount) {
method assertGraphIsAcyclicAfterRemoval (line 305) | private void assertGraphIsAcyclicAfterRemoval(FeedbackArcSetResult<Str...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetBenchmarkTest.java
class MinimumFeedbackArcSetBenchmarkTest (line 16) | class MinimumFeedbackArcSetBenchmarkTest {
method benchmarkGraphSizes (line 18) | @Test
method createRandomGraph (line 51) | private Graph<String, DefaultEdge> createRandomGraph(int size, double ...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetExample.java
class MinimumFeedbackArcSetExample (line 9) | public class MinimumFeedbackArcSetExample {
method main (line 10) | public static void main(String[] args) {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetSolverTest.java
class MinimumFeedbackArcSetSolverTest (line 22) | @Execution(ExecutionMode.CONCURRENT)
method setUp (line 28) | @BeforeEach
class BasicAlgorithmTests (line 33) | @Nested
method testEmptyGraph (line 37) | @Test
method testSingleVertex (line 47) | @Test
method testAcyclicGraph (line 57) | @Test
method testSimpleCycle (line 73) | @Test
method testSelfLoop (line 92) | @Test
class ComplexGraphTests (line 107) | @Nested
method testMultipleCycles (line 111) | @Test
method testDisconnectedComponents (line 135) | @Test
method testWeightedEdges (line 159) | @Test
class PerformanceTests (line 181) | @Nested
method testRandomGraphPerformance (line 185) | @ParameterizedTest
method testParallelProcessing (line 204) | @Test
class CorrectnessTests (line 221) | @Nested
method testOptimalityProperties (line 225) | @Test
method testEdgeCases (line 240) | @Test
method createRandomGraph (line 261) | private void createRandomGraph(int vertexCount, int edgeCount) {
method hasCycles (line 281) | private boolean hasCycles() {
method assertGraphIsAcyclicAfterRemoval (line 286) | private void assertGraphIsAcyclicAfterRemoval(FeedbackArcSetResult<Str...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/pageRank/PageRankFASExample.java
class PageRankFASExample (line 13) | public class PageRankFASExample {
method main (line 15) | public static void main(String[] args) {
method demonstrateSimpleCycle (line 43) | private static void demonstrateSimpleCycle() {
method demonstrateMultipleCycles (line 73) | private static void demonstrateMultipleCycles() {
method demonstrateComplexGraph (line 118) | private static void demonstrateComplexGraph() {
method demonstratePerformanceComparison (line 144) | private static void demonstratePerformanceComparison() {
method demonstrateCustomIterations (line 170) | private static void demonstrateCustomIterations() {
method createComplexTestGraph (line 195) | private static Graph<String, DefaultEdge> createComplexTestGraph() {
method createRandomGraph (line 241) | private static Graph<String, DefaultEdge> createRandomGraph(int numVer...
method copyGraph (line 272) | private static Graph<String, DefaultEdge> copyGraph(Graph<String, Defa...
method verifyAcyclicity (line 291) | private static void verifyAcyclicity(Graph<String, DefaultEdge> origin...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/arc/pageRank/PageRankFASTest.java
class PageRankFASTest (line 17) | class PageRankFASTest {
class LineDigraphTests (line 21) | @Nested
method testLineDigraphBasicOperations (line 25) | @Test
method testLineDigraphDegrees (line 59) | @Test
method testLineDigraphSourcesAndSinks (line 91) | @Test
method testLineDigraphPathFinding (line 116) | @Test
method testLineDigraphTopologicalSort (line 147) | @Test
method testLineDigraphConsistency (line 180) | @Test
class UpdatedAlgorithmTests (line 206) | @Nested
method testUpdatedAlgorithmSimpleCycle (line 210) | @Test
method testExecutionStatistics (line 226) | @Test
method testMultipleSCCs (line 247) | @Test
method testPerformanceWithDifferentIterations (line 265) | @Test
method createSimpleCycle (line 304) | private Graph<String, DefaultEdge> createSimpleCycle() {
method createComplexGraph (line 317) | private Graph<String, DefaultEdge> createComplexGraph() {
method createMultipleSCCGraph (line 343) | private Graph<String, DefaultEdge> createMultipleSCCGraph() {
method copyGraph (line 375) | private Graph<String, DefaultEdge> copyGraph(Graph<String, DefaultEdge...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetBenchmarkTest.java
class FeedbackVertexSetBenchmarkTest (line 15) | class FeedbackVertexSetBenchmarkTest {
method benchmarkGraphSizes (line 17) | @Test
method createRandomGraph (line 43) | private Graph<String, DefaultEdge> createRandomGraph(int size, double ...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetExample.java
class FeedbackVertexSetExample (line 9) | public class FeedbackVertexSetExample {
method main (line 10) | public static void main(String[] args) {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetSolverTest.java
class FeedbackVertexSetSolverTest (line 21) | @Execution(ExecutionMode.CONCURRENT)
method setUp (line 27) | @BeforeEach
class BasicAlgorithmTests (line 32) | @Nested
method testEmptyGraph (line 36) | @Test
method testSingleVertex (line 46) | @Test
method testAcyclicGraph (line 56) | @Test
method testSimpleCycle (line 72) | @Test
method testSelfLoop (line 91) | @Test
class ComplexGraphTests (line 106) | @Nested
method testMultipleCycles (line 110) | @Test
method testDisconnectedComponents (line 134) | @Test
class PerformanceTests (line 159) | @Nested
method testRandomGraphPerformance (line 163) | @ParameterizedTest
method testWeightedVertices (line 183) | @Test
class CorrectnessTests (line 207) | @Nested
method testApproximationBounds (line 211) | @Test
method testSpecialVertexConstraints (line 229) | @Test
method createRandomGraph (line 253) | private void createRandomGraph(int vertexCount, int edgeCount) {
method hasCycles (line 273) | private boolean hasCycles(Graph<String, DefaultEdge> graph) {
method isGraphIsAcyclicAfterRemoval (line 278) | private boolean isGraphIsAcyclicAfterRemoval(FeedbackVertexSetResult<S...
method createGraphWithoutFeedbackVertices (line 288) | private Graph<String, DefaultEdge> createGraphWithoutFeedbackVertices(...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetBenchmarkTest.java
class DirectedFeedbackVertexSetBenchmarkTest (line 16) | class DirectedFeedbackVertexSetBenchmarkTest {
method benchmarkGraphSizes (line 18) | @Test
method createRandomGraph (line 53) | private Graph<String, DefaultEdge> createRandomGraph(int size, double ...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetExample.java
class DirectedFeedbackVertexSetExample (line 10) | public class DirectedFeedbackVertexSetExample {
method main (line 11) | public static void main(String[] args) {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetSolverTest.java
class DirectedFeedbackVertexSetSolverTest (line 22) | @Execution(ExecutionMode.CONCURRENT)
method setUp (line 28) | @BeforeEach
class BasicAlgorithmTests (line 33) | @Nested
method testEmptyGraph (line 37) | @Test
method testSingleVertex (line 47) | @Test
method testAcyclicGraph (line 57) | @Test
method testSimpleCycle (line 73) | @Test
method testSelfLoop (line 92) | @Test
class ComplexGraphTests (line 106) | @Nested
method testMultipleCycles (line 110) | @Test
method testTreewidthModulator (line 134) | @Test
method testWeightedVertices (line 156) | @Test
class PerformanceTests (line 180) | @Nested
method testRandomGraphPerformance (line 185) | @ParameterizedTest
method testParallelProcessing (line 204) | @Test
class KernelizationTests (line 221) | @Nested
method testKernelizationProperties (line 225) | @Test
method testZoneDecomposition (line 243) | @Test
method createRandomGraph (line 268) | private void createRandomGraph(int vertexCount, int edgeCount) {
method hasCycles (line 289) | private boolean hasCycles() {
method assertGraphIsAcyclicAfterRemoval (line 294) | private void assertGraphIsAcyclicAfterRemoval(DirectedFeedbackVertexSe...
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/ModulatorComputerTest.java
class ModulatorComputerTest (line 18) | @Execution(ExecutionMode.CONCURRENT)
method setUp (line 25) | @BeforeEach
method tearDown (line 32) | @AfterEach
class ModulatorComputationTests (line 38) | @Nested
method testTreeGraphModulator (line 42) | @Test
method testCycleGraphModulator (line 52) | @Test
method testCompleteGraphModulator (line 66) | @Test
method testModulatorSizeLimit (line 76) | @Test
method testRandomGraphModulator (line 87) | @ParameterizedTest
method testModulatorQualityImprovement (line 102) | @Test
class EnhancedParameterComputerTests (line 115) | @Nested
method testSimpleGraphParameters (line 119) | @Test
method testMultipleParameterOptions (line 133) | @Test
method testModulatorValidation (line 151) | @Test
method testKernelSizeBounds (line 162) | @Test
method testEdgeCases (line 175) | @Test
class IntegrationPerformanceTests (line 197) | @Nested
method testComplexGraphParameters (line 201) | @Test
method testConcurrentParameterComputation (line 219) | @Test
method testConsistentResults (line 244) | @RepeatedTest(3)
method createTreeGraph (line 264) | private Graph<String, DefaultEdge> createTreeGraph(int size) {
method createCycleGraph (line 278) | private Graph<String, DefaultEdge> createCycleGraph(int size) {
method createCompleteGraph (line 292) | private Graph<String, DefaultEdge> createCompleteGraph(int size) {
method createPathGraph (line 310) | private Graph<String, DefaultEdge> createPathGraph(int size) {
method createGridGraph (line 326) | private Graph<String, DefaultEdge> createGridGraph(int rows, int cols) {
method createRandomGraph (line 356) | private Graph<String, DefaultEdge> createRandomGraph(int vertexCount, ...
method createComplexGraph (line 377) | private Graph<String, DefaultEdge> createComplexGraph() {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/ParameterComputerExample.java
class ParameterComputerExample (line 9) | public class ParameterComputerExample {
method main (line 11) | public static void main(String[] args) {
FILE: graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/ParameterComputerTest.java
class ParameterComputerTest (line 19) | @Execution(ExecutionMode.CONCURRENT)
method setUp (line 27) | @BeforeEach
method tearDown (line 35) | @AfterEach
class TreewidthComputationTests (line 42) | @Nested
method testEmptyGraph (line 46) | @Test
method testSingleVertex (line 54) | @Test
method testPathGraph (line 62) | @Test
method testCycleGraph (line 70) | @Test
method testModulatorRemoval (line 78) | @Test
method testRandomGraphTreewidth (line 90) | @ParameterizedTest
class FeedbackVertexSetComputationTests (line 106) | @Nested
method testAcyclicGraph (line 110) | @Test
method testSimpleCycle (line 118) | @Test
method testSelfLoops (line 126) | @Test
method testMultipleCycles (line 137) | @Test
method testDisconnectedComponents (line 145) | @Test
method testLargeRandomGraphs (line 153) | @ParameterizedTest
class ParameterComputerIntegrationTests (line 169) | @Nested
method testSimpleGraphParameters (line 173) | @Test
method testParametersWithModulator (line 184) | @Test
method testOptimalModulatorFinding (line 197) | @Test
method testConsistentResults (line 208) | @RepeatedTest(5)
class MultithreadingPerformanceTests (line 222) | @Nested
method testConcurrentParameterComputation (line 226) | @Test
method testScalingWithParallelism (line 247) | @Test
method createSingleVertexGraph (line 270) | private Graph<String, DefaultEdge> createSingleVertexGraph() {
method createPathGraph (line 276) | private Graph<String, DefaultEdge> createPathGraph(int length) {
method createCycleGraph (line 290) | private Graph<String, DefaultEdge> createCycleGraph(int size) {
method createCompleteGraph (line 296) | private Graph<String, DefaultEdge> createCompleteGraph(int size) {
method createStarGraph (line 314) | private Graph<String, DefaultEdge> createStarGraph(int size) {
method createMultipleCyclesGraph (line 327) | private Graph<String, DefaultEdge> createMultipleCyclesGraph() {
method createDisconnectedCyclesGraph (line 348) | private Graph<String, DefaultEdge> createDisconnectedCyclesGraph() {
method createRandomGraph (line 370) | private Graph<String, DefaultEdge> createRandomGraph(int vertexCount, ...
FILE: graph-data-generator/src/main/java/org/hjug/gdg/GraphDataGenerator.java
class GraphDataGenerator (line 6) | public class GraphDataGenerator {
method getGodClassScriptStart (line 8) | public String getGodClassScriptStart() {
method getGodClassScriptEnd (line 17) | public String getGodClassScriptEnd() {
method getCBOScriptStart (line 35) | public String getCBOScriptStart() {
method getCBOScriptEnd (line 44) | public String getCBOScriptEnd() {
method generateGodClassBubbleChartData (line 62) | public String generateGodClassBubbleChartData(List<RankedDisharmony> r...
method generateCBOBubbleChartData (line 88) | public String generateCBOBubbleChartData(List<RankedDisharmony> ranked...
FILE: graph-data-generator/src/test/java/org/hjug/gdg/GraphDataGeneratorTest.java
class GraphDataGeneratorTest (line 14) | class GraphDataGeneratorTest {
method setUp (line 18) | @BeforeEach
method getScriptStart (line 23) | @Test
method getScriptEnd (line 34) | @Test
method generateBubbleChartDataOneDataPoint (line 55) | @Test
method generateBubbleChartDataTwoDataPoints (line 78) | @Test
FILE: refactor-first-gradle-plugin/src/main/java/org/hjug/gradlereport/RefactorFirstPlugin.java
class RefactorFirstPlugin (line 6) | public class RefactorFirstPlugin implements Plugin<Project> {
method apply (line 7) | public void apply(Project project) {
FILE: refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstHtmlReport.java
class RefactorFirstHtmlReport (line 13) | @Slf4j
method execute (line 56) | @Override
FILE: refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenCsvReport.java
class RefactorFirstMavenCsvReport (line 12) | @Mojo(
method execute (line 36) | @Override
FILE: refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenJsonReport.java
class RefactorFirstMavenJsonReport (line 13) | @Mojo(
method execute (line 28) | @Override
FILE: refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java
class RefactorFirstMavenReport (line 16) | @Slf4j
method getOutputName (line 50) | public String getOutputName() {
method getName (line 55) | public String getName(Locale locale) {
method getDescription (line 60) | public String getDescription(Locale locale) {
method executeReport (line 66) | @Override
method printHead (line 87) | private void printHead(Sink mainSink) {
method renderJsDeclaration (line 115) | private void renderJsDeclaration(Sink mainSink, String scriptUrl) {
method renderStyle (line 123) | private void renderStyle(Sink mainSink) {
FILE: refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstSimpleHtmlReport.java
class RefactorFirstSimpleHtmlReport (line 13) | @Slf4j
method execute (line 56) | @Override
FILE: report/src/main/java/org/hjug/refactorfirst/report/CsvReport.java
class CsvReport (line 16) | @Slf4j
method execute (line 19) | public void execute(
method createFileDateTimeFormatter (line 130) | private DateTimeFormatter createFileDateTimeFormatter() {
method createCsvDateTimeFormatter (line 136) | private DateTimeFormatter createCsvDateTimeFormatter() {
method getDataList (line 142) | private String[] getDataList(RankedDisharmony rankedDisharmony, boolea...
method getHeaderList (line 173) | private String[] getHeaderList(boolean showDetails) {
method addsRow (line 207) | private void addsRow(StringBuilder contentBuilder, String[] rankedDish...
method getOutputNamePrefix (line 213) | public String getOutputNamePrefix() {
method getName (line 218) | public String getName(Locale locale) {
method getDescription (line 223) | public String getDescription(Locale locale) {
FILE: report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java
class HtmlReport (line 14) | @Slf4j
method printHead (line 385) | @Override
method printScripts (line 412) | String printScripts() {
method printOpenBodyTag (line 416) | @Override
method printOverlay (line 421) | private String printOverlay() {
method printTitle (line 425) | @Override
method renderGithubButtons (line 430) | @Override
method writeGodClassGchartJs (line 442) | @Override
method writeGCBOGchartJs (line 452) | @Override
method getName (line 462) | public String getName(Locale locale) {
method getDescription (line 467) | public String getDescription(Locale locale) {
method renderGodClassChart (line 473) | @Override
method renderCBOChart (line 486) | @Override
method renderClassGraphVisuals (line 498) | @Override
method generateGraphButtons (line 523) | private StringBuilder generateGraphButtons(String graphName, String do...
method generateDotImage (line 540) | private static String generateDotImage(String graphName) {
method buildClassGraphDot (line 565) | String buildClassGraphDot(Graph<String, DefaultWeightedEdge> classGrap...
method renderEdge (line 606) | private void renderEdge(
method renderCycleVisuals (line 656) | @Override
method buildCycleDot (line 678) | String buildCycleDot(Graph<String, DefaultWeightedEdge> classGraph, Ra...
method generate2DPopup (line 702) | String generate2DPopup(String cycleName) {
method generateForce3DPopup (line 709) | String generateForce3DPopup(String cycleName) {
method generateHidePopup (line 716) | String generateHidePopup(String cycleName) {
FILE: report/src/main/java/org/hjug/refactorfirst/report/ReportWriter.java
class ReportWriter (line 10) | @Slf4j
method writeReportToDisk (line 13) | public static void writeReportToDisk(
FILE: report/src/main/java/org/hjug/refactorfirst/report/SimpleHtmlReport.java
class SimpleHtmlReport (line 31) | @Slf4j
method execute (line 89) | public void execute(
method generateReport (line 134) | public StringBuilder generateReport(
method renderCycles (line 341) | private String renderCycles(List<RankedCycle> rankedCycles) {
method renderEdgeDisharmonies (line 350) | private String renderEdgeDisharmonies(List<RankedDisharmony> edgeDisha...
method getEdgeDisharmonyTableHeadings (line 392) | private String[] getEdgeDisharmonyTableHeadings() {
method getEdgeDisharmony (line 403) | private String[] getEdgeDisharmony(RankedDisharmony edgeInfo) {
method renderClassCycleSummary (line 414) | private String renderClassCycleSummary(List<RankedCycle> rankedCycles) {
method renderEdge (line 463) | private String renderEdge(DefaultWeightedEdge edge) {
method getCycleSummaryTableHeadings (line 489) | private String[] getCycleSummaryTableHeadings() {
method getRankedCycleSummaryData (line 493) | private String[] getRankedCycleSummaryData(RankedCycle rankedCycle, St...
method renderSingleCycle (line 503) | private String renderSingleCycle(RankedCycle cycle) {
method renderClassGraphVisuals (line 576) | public String renderClassGraphVisuals() {
method renderCycleVisuals (line 580) | public String renderCycleVisuals(RankedCycle cycle) {
method renderGodClassInfo (line 584) | private String renderGodClassInfo(
method renderHighlyCoupledClassInfo (line 654) | private String renderHighlyCoupledClassInfo(List<RankedDisharmony> ran...
method drawTableCell (line 701) | String drawTableCell(String rowData) {
method isNumber (line 717) | boolean isNumber(String rowData) {
method isDateTime (line 721) | boolean isDateTime(String rowData) {
method printTitle (line 725) | public String printTitle(String projectName, String projectVersion) {
method printHead (line 729) | public String printHead() {
method printScripts (line 733) | String printScripts() {
method printOpenBodyTag (line 737) | public String printOpenBodyTag() {
method printBreadcrumbs (line 741) | public String printBreadcrumbs() {
method printProjectHeader (line 748) | public String printProjectHeader(String projectName, String projectVer...
method printProjectFooter (line 761) | public String printProjectFooter() {
method renderGithubButtons (line 769) | String renderGithubButtons() {
method getOutputName (line 773) | String getOutputName() {
method renderGodClassChart (line 778) | String renderGodClassChart(List<RankedDisharmony> rankedGodClassDishar...
method writeGodClassGchartJs (line 782) | String writeGodClassGchartJs(List<RankedDisharmony> rankedDisharmonies...
method writeGCBOGchartJs (line 787) | String writeGCBOGchartJs(List<RankedDisharmony> rankedDisharmonies, in...
method renderCBOChart (line 792) | String renderCBOChart(List<RankedDisharmony> rankedCBODisharmonies, in...
method getClassName (line 796) | String getClassName(String fqn) {
method extractVertexes (line 806) | static String[] extractVertexes(DefaultWeightedEdge edge) {
FILE: report/src/main/java/org/hjug/refactorfirst/report/json/JsonReport.java
class JsonReport (line 7) | @Data
FILE: report/src/main/java/org/hjug/refactorfirst/report/json/JsonReportDisharmonyEntry.java
class JsonReportDisharmonyEntry (line 11) | @Data
method fromRankedDisharmony (line 36) | public static JsonReportDisharmonyEntry fromRankedDisharmony(RankedDis...
FILE: report/src/main/java/org/hjug/refactorfirst/report/json/JsonReportExecutor.java
class JsonReportExecutor (line 19) | @Slf4j
method execute (line 26) | public void execute(File baseDir, String outputDirectory) {
method writeErrorReport (line 67) | private void writeErrorReport(final JsonReport errorReport, String out...
FILE: report/src/test/java/org/hjug/refactorfirst/report/HtmlReportTest.java
class HtmlReportTest (line 13) | class HtmlReportTest {
method testGetOutputName (line 17) | @Test
method getName (line 23) | @Test
method getDescription (line 29) | @Test
method buildCycleDot (line 38) | @Test
FILE: report/src/test/java/org/hjug/refactorfirst/report/SimpleHtmlReportTest.java
class SimpleHtmlReportTest (line 6) | class SimpleHtmlReportTest {
method isDateTime (line 8) | @Test
FILE: test-resources/src/main/resources/AttributeHandler.java
class AttributeHandler (line 58) | public final class AttributeHandler extends TagHandler {
method AttributeHandler (line 68) | public AttributeHandler(final TagConfig config) {
method apply (line 75) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 287) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 291) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 295) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 299) | private String removeElParenthesis(final String string) {
method getExpression (line 303) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 308) | private MethodExpression getMethodExpression(
method getValue (line 327) | private Object getValue(
method setConverter (line 343) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 357) | private void setConverter(
FILE: test-resources/src/main/resources/AttributeHandler2.java
class AttributeHandler (line 58) | public final class AttributeHandler extends TagHandler {
method AttributeHandler (line 68) | public AttributeHandler(final TagConfig config) {
method apply (line 75) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 287) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 291) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 295) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 299) | private String removeElParenthesis(final String string) {
method getExpression (line 303) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 308) | private MethodExpression getMethodExpression(
method getValue (line 327) | private Object getValue(
method setConverter (line 343) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 357) | private void setConverter(
method letsAddASimpleMethod (line 369) | public static void letsAddASimpleMethod() {
FILE: test-resources/src/main/resources/AttributeHandlerAndSorter.java
class AttributeHandler (line 84) | public final class AttributeHandler extends TagHandler {
method AttributeHandler (line 94) | public AttributeHandler(final TagConfig config) {
method apply (line 101) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 313) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 317) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 321) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 325) | private String removeElParenthesis(final String string) {
method getExpression (line 329) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 334) | private MethodExpression getMethodExpression(
method getValue (line 353) | private Object getValue(
method setConverter (line 369) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 383) | private void setConverter(
class Sorter (line 397) | class Sorter {
method perform (line 406) | @Deprecated
method perform (line 412) | public void perform(final AbstractUISheet data) {
method isSimpleProperty (line 553) | boolean isSimpleProperty(final String expressionString) {
method unsetSortableAttribute (line 567) | private void unsetSortableAttribute(final UIColumn uiColumn) {
method getFirstSortableChild (line 572) | private UIComponent getFirstSortableChild(final List<UIComponent> chil...
method getComparator (line 599) | public Comparator getComparator() {
method setComparator (line 603) | public void setComparator(final Comparator comparator) {
FILE: test-resources/src/main/resources/AttributeHandlerJavaEleven.java
class AttributeHandlerJavaEleven (line 58) | public final class AttributeHandlerJavaEleven extends TagHandler {
method AttributeHandler (line 68) | public AttributeHandler(final TagConfig config) {
method apply (line 75) | public void apply(final FaceletContext faceletContext, final UICompone...
method isMethodOrValueExpression (line 287) | private boolean isMethodOrValueExpression(final String string) {
method containsMethodOrValueExpression (line 291) | private boolean containsMethodOrValueExpression(final String string) {
method isSimpleExpression (line 295) | private boolean isSimpleExpression(final String string) {
method removeElParenthesis (line 299) | private String removeElParenthesis(final String string) {
method getExpression (line 303) | private ValueExpression getExpression(final FaceletContext faceletCont...
method getMethodExpression (line 308) | private MethodExpression getMethodExpression(
method getValue (line 327) | private Object getValue(
method setConverter (line 343) | private void setConverter(final FaceletContext faceletContext, final U...
method setConverter (line 357) | private void setConverter(
FILE: test-resources/src/main/resources/Attributes.java
class Attributes (line 26) | public final class Attributes {
FILE: test-resources/src/main/resources/Console.java
class Console (line 138) | public class Console implements Closeable {
method tablePrinter (line 200) | private static <T extends KsqlEntity> Handler1<KsqlEntity, Console> ta...
type RowCaptor (line 223) | public interface RowCaptor {
method addRow (line 225) | void addRow(DataRow row);
method addRows (line 227) | void addRows(List<List<String>> fields);
method build (line 230) | public static Console build(final OutputFormat outputFormat) {
method Console (line 252) | public Console(
method writer (line 264) | public PrintWriter writer() {
method flush (line 268) | public void flush() {
method setSpool (line 272) | public void setSpool(final File file) {
method unsetSpool (line 283) | public void unsetSpool() {
method getWidth (line 289) | public int getWidth() {
method clearScreen (line 293) | public void clearScreen() {
method setStatusMessage (line 297) | public StatusClosable setStatusMessage(final String message) {
method handle (line 301) | public void handle(final Signal signal, final SignalHandler signalHand...
method setCliProperty (line 305) | public void setCliProperty(final String name, final Object value) {
method close (line 313) | @Override
method addResult (line 318) | public void addResult(final List<List<String>> rowValues) {
method getCliSpecificCommands (line 322) | public Map<String, CliSpecificCommand> getCliSpecificCommands() {
method nextNonCliCommand (line 326) | public String nextNonCliCommand() {
method getHistory (line 337) | public List<HistoryEntry> getHistory() {
method printErrorMessage (line 341) | public void printErrorMessage(final KsqlErrorMessage errorMessage) {
method printError (line 348) | public void printError(final String shortMsg, final String fullMsg) {
method printStreamedRow (line 353) | public void printStreamedRow(final StreamedRow row) {
method printKsqlEntityList (line 377) | public void printKsqlEntityList(final List<KsqlEntity> entityList) {
method printRowHeader (line 400) | private void printRowHeader(final Header header) {
method registerCliSpecificCommand (line 423) | public void registerCliSpecificCommand(final CliSpecificCommand cliSpe...
method setOutputFormat (line 427) | public void setOutputFormat(final String newFormat) {
method getOutputFormat (line 440) | public OutputFormat getOutputFormat() {
method getCliCommand (line 444) | private Optional<CliCmdExecutor> getCliCommand(final String line) {
method printAsTable (line 458) | private void printAsTable(final DataRow row) {
method printAsTable (line 479) | private void printAsTable(final KsqlEntity entity) {
method printWarnings (line 493) | private void printWarnings(final KsqlEntity entity) {
method formatFieldType (line 499) | private static String formatFieldType(
method printSchema (line 525) | private void printSchema(
method printTopicInfo (line 541) | private void printTopicInfo(final SourceDescription source) {
method printSourceConstraints (line 569) | private void printSourceConstraints(final List<String> sourceConstrain...
method printQueries (line 581) | private void printQueries(
method printExecutionPlan (line 601) | private void printExecutionPlan(final QueryDescription queryDescriptio...
method printTopology (line 612) | private void printTopology(final QueryDescription queryDescription) {
method printOverriddenProperties (line 623) | private void printOverriddenProperties(final QueryDescription queryDes...
method printQueryError (line 645) | private void printQueryError(final QueryDescription query) {
method printStatistics (line 660) | private void printStatistics(final SourceDescription source) {
method printSourceDescription (line 698) | private void printSourceDescription(final SourceDescription source) {
method printSourceDescriptionList (line 766) | private void printSourceDescriptionList(final SourceDescriptionList so...
method printQuerySources (line 774) | private void printQuerySources(final QueryDescription query) {
method printQuerySinks (line 788) | private void printQuerySinks(final QueryDescription query) {
method printQueryDescription (line 802) | private void printQueryDescription(final QueryDescription query) {
method printConnectorDescription (line 823) | private void printConnectorDescription(final ConnectorDescription desc...
method printQueryDescriptionList (line 870) | private void printQueryDescriptionList(final QueryDescriptionList quer...
method printFunctionDescription (line 878) | private void printFunctionDescription(final FunctionDescriptionList de...
method printAssertTopic (line 911) | private void printAssertTopic(final AssertTopicEntity assertTopic) {
method printAssertSchema (line 916) | private void printAssertSchema(final AssertSchemaEntity assertSchema) {
method argToString (line 931) | private static String argToString(final ArgumentInfo arg) {
method printDescription (line 936) | private void printDescription(final String format, final String name, ...
method splitLongLine (line 958) | private static String splitLongLine(final String input, final int maxL...
method printAsJson (line 981) | private void printAsJson(final Object o) {
class NoOpRowCaptor (line 991) | static class NoOpRowCaptor implements RowCaptor {
method addRow (line 993) | @Override
method addRows (line 997) | @Override
method maybeHandleCliSpecificCommands (line 1002) | public boolean maybeHandleCliSpecificCommands(final String line) {
class CliCmdExecutor (line 1016) | private static final class CliCmdExecutor {
method of (line 1022) | private static CliCmdExecutor of(final CliSpecificCommand cmd, final...
method CliCmdExecutor (line 1031) | private CliCmdExecutor(final CliSpecificCommand cmd, final List<Stri...
method execute (line 1036) | public void execute(final PrintWriter terminal) {
Condensed preview — 187 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,188K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 130,
"preview": "github: jimbethancourt\n#open_collective: RefactorFirst\n#ko_fi: jimbethancourt\n#liberapay: jimbethancourt\n#patreon: jimbe"
},
{
"path": ".github/workflows/codesee-arch-diagram.yml",
"chars": 501,
"preview": "# This workflow was added by CodeSee. Learn more at https://codesee.io/\n# This is v2.0 of this workflow file\non:\n push:"
},
{
"path": ".github/workflows/maven-pr.yml",
"chars": 1130,
"preview": "# This workflow will build a Java project with Maven\n# For more information see: https://help.github.com/actions/languag"
},
{
"path": ".github/workflows/maven.yml",
"chars": 1222,
"preview": "# This workflow will build a Java project with Maven\n# For more information see: https://help.github.com/actions/languag"
},
{
"path": ".github/workflows/release.yml",
"chars": 3006,
"preview": "# Based on https://github.com/jagodevreede/semver-check/blob/c9353fa86eb9ae8f6b309057748672a6c1e0f435/.github/workflows/"
},
{
"path": ".gitignore",
"chars": 4211,
"preview": "\n# Created by https://www.toptal.com/developers/gitignore/api/java,maven,intellij,eclipse\n# Edit at https://www.toptal.c"
},
{
"path": "CITATIONS.md",
"chars": 1250,
"preview": "# Research Citations\n\n\n\n## Directed Feedback Arc Set\n**Title:** Computing a Feedback Arc Set Using PageRank \n**Authors:"
},
{
"path": "LICENSE",
"chars": 11356,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 10958,
"preview": "# RefactorFirst\n\nThis tool for Java codebases will help you identify what you should refactor first:\n- God Classes\n- Hig"
},
{
"path": "change-proneness-ranker/pom.xml",
"chars": 1199,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "change-proneness-ranker/src/main/java/org/hjug/git/ChangePronenessRanker.java",
"chars": 1827,
"preview": "package org.hjug.git;\n\nimport java.io.IOException;\nimport java.util.*;\nimport lombok.extern.slf4j.Slf4j;\nimport org.ecli"
},
{
"path": "change-proneness-ranker/src/main/java/org/hjug/git/GitLogReader.java",
"chars": 6666,
"preview": "package org.hjug.git;\n\nimport java.io.*;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java."
},
{
"path": "change-proneness-ranker/src/main/java/org/hjug/git/ScmLogInfo.java",
"chars": 620,
"preview": "package org.hjug.git;\n\nimport lombok.Data;\n\n@Data\npublic class ScmLogInfo {\n\n private String path;\n private String"
},
{
"path": "change-proneness-ranker/src/test/java/org/hjug/git/ChangePronenessRankerTest.java",
"chars": 3259,
"preview": "package org.hjug.git;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.I"
},
{
"path": "change-proneness-ranker/src/test/java/org/hjug/git/GitLogReaderTest.java",
"chars": 5456,
"preview": "package org.hjug.git;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\nimport java.io.*;\nimport java.util.*;\nimp"
},
{
"path": "cli/.gitignore",
"chars": 490,
"preview": "target/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### IntelliJ IDEA ###\n.idea/mod"
},
{
"path": "cli/pom.xml",
"chars": 3824,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "cli/src/main/java/org/hjug/refactorfirst/Main.java",
"chars": 317,
"preview": "package org.hjug.refactorfirst;\n\nimport picocli.CommandLine;\n\npublic class Main {\n public static void main(String[] a"
},
{
"path": "cli/src/main/java/org/hjug/refactorfirst/ReportCommand.java",
"chars": 6148,
"preview": "package org.hjug.refactorfirst;\n\nimport static picocli.CommandLine.Option;\n\nimport java.io.File;\nimport java.io.FileRead"
},
{
"path": "cli/src/main/java/org/hjug/refactorfirst/ReportType.java",
"chars": 106,
"preview": "package org.hjug.refactorfirst;\n\npublic enum ReportType {\n SIMPLE_HTML,\n HTML,\n JSON,\n CSV;\n}\n"
},
{
"path": "codebase-graph-builder/pom.xml",
"chars": 2282,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/CodebaseGraphDTO.java",
"chars": 462,
"preview": "package org.hjug.graphbuilder;\n\nimport java.util.Map;\nimport lombok.Data;\nimport org.jgrapht.Graph;\nimport org.jgrapht.g"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/DependencyCollector.java",
"chars": 1142,
"preview": "package org.hjug.graphbuilder;\n\npublic interface DependencyCollector {\n\n /**\n * Records a dependency from one cla"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphBuilderConfig.java",
"chars": 366,
"preview": "package org.hjug.graphbuilder;\n\nimport lombok.Builder;\nimport lombok.Value;\n\n@Value\n@Builder\npublic class GraphBuilderCo"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/GraphDependencyCollector.java",
"chars": 2457,
"preview": "package org.hjug.graphbuilder;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport lombok.Getter;\nimport org.jgrapht"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/JavaGraphBuilder.java",
"chars": 5235,
"preview": "package org.hjug.graphbuilder;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/BaseCodebaseVisitor.java",
"chars": 495,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport lombok.Getter;\nimport org.hjug.graphbuilder.DependencyCollector;\nimport o"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/BaseTypeProcessor.java",
"chars": 2751,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.hjug.graphbuilder.DependencyCollect"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/FqnCapturingProcessor.java",
"chars": 1834,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaClassDeclarationVisitor.java",
"chars": 7164,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.List;\nimport lombok.extern.slf4j.Slf4j;\nimport org.hjug.graphbu"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaFqnCapturingVisitor.java",
"chars": 1669,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.*;\nimport lombok.Getter;\nimport org.openrewrite.java.JavaIsoVis"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaMethodDeclarationVisitor.java",
"chars": 2724,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.List;\nimport lombok.extern.slf4j.Slf4j;\nimport org.hjug.graphbu"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaVariableTypeVisitor.java",
"chars": 2686,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.List;\nimport lombok.extern.slf4j.Slf4j;\nimport org.hjug.graphbu"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/JavaVisitor.java",
"chars": 1818,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.*;\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf4j;\nimpo"
},
{
"path": "codebase-graph-builder/src/main/java/org/hjug/graphbuilder/visitor/TypeDependencyExtractor.java",
"chars": 3630,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport lombok.extern.slf4j.Slf4j"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/JavaGraphBuilderTest.java",
"chars": 5376,
"preview": "package org.hjug.graphbuilder;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.io.File;\nimport java.io.I"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaClassDeclarationVisitorTest.java",
"chars": 2842,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaFqnCapturingVisitorTest.java",
"chars": 3487,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaInitializerBlockVisitorTest.java",
"chars": 7967,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaLambdaVisitorTest.java",
"chars": 9528,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaMethodDeclarationVisitorTest.java",
"chars": 3209,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaMethodInvocationVisitorTest.java",
"chars": 3048,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaNewClassVisitorFullTest.java",
"chars": 3191,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaNewClassVisitorTest.java",
"chars": 3071,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaVariableTypeVisitorTest.java",
"chars": 2831,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimp"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/JavaVisitorTest.java",
"chars": 1967,
"preview": "package org.hjug.graphbuilder.visitor;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.io.Fil"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/A.java",
"chars": 1073,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\nimport java.util.List;\nimport java.util.Map;\n\n@MyAnnotation\npublic c"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/B.java",
"chars": 195,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic class B<T> {\n\n static <T extends B> D invocationTest(T typ"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/C.java",
"chars": 96,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic class C<T extends A, U extends B> {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/D.java",
"chars": 70,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic class D {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/E.java",
"chars": 94,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic interface E {\n void foo(A a);\n}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/F.java",
"chars": 70,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic class F {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/G.java",
"chars": 80,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic class G extends F {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/H.java",
"chars": 86,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\npublic class H<T> extends B<T> {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/MyAnnotation.java",
"chars": 187,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/MyOtherAnnotation.java",
"chars": 192,
"preview": "package org.hjug.graphbuilder.visitor.testclasses;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers/ComplexInitializerClass.java",
"chars": 1064,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.initializers;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport j"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/initializers/InitializerBlockTestClass.java",
"chars": 849,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.initializers;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\ni"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/DataProcessor.java",
"chars": 161,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.lambda;\n\npublic class DataProcessor {\n\n public String transform(Str"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/HelperClass.java",
"chars": 271,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.lambda;\n\npublic class HelperClass {\n\n public String process(String "
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/LambdaTestClass.java",
"chars": 1626,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.lambda;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport jav"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/lambda/NestedLambdaTestClass.java",
"chars": 2083,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.lambda;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport jav"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/A.java",
"chars": 290,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;\n\npublic class A {\n\n A doSomething() {\n B.<"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/B.java",
"chars": 174,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;\n\npublic class B<T> {\n\n static <T extends B> A inv"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/C.java",
"chars": 103,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;\n\npublic class C<T> extends B<T> {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/methodInvocation/D.java",
"chars": 103,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.methodInvocation;\n\npublic class D<T> extends C<T> {}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/A.java",
"chars": 438,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.newClass;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic "
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/B.java",
"chars": 102,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.newClass;\n\npublic class B {\n\n public B(C c) {}\n}\n"
},
{
"path": "codebase-graph-builder/src/test/java/org/hjug/graphbuilder/visitor/testclasses/newClass/C.java",
"chars": 79,
"preview": "package org.hjug.graphbuilder.visitor.testclasses.newClass;\n\npublic class C {}\n"
},
{
"path": "codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/A.java",
"chars": 68,
"preview": "package com.ideacrest.parser.testclasses;\n\npublic class A {\n\tB b;\n}\n"
},
{
"path": "codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/B.java",
"chars": 68,
"preview": "package com.ideacrest.parser.testclasses;\n\npublic class B {\n\tC c;\n}\n"
},
{
"path": "codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/C.java",
"chars": 74,
"preview": "package com.ideacrest.parser.testclasses;\n\npublic class C {\n\tA a;\n\tE e;\n}\n"
},
{
"path": "codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/D.java",
"chars": 74,
"preview": "package com.ideacrest.parser.testclasses;\n\npublic class D {\n\tA a;\n\tC c;\n}\n"
},
{
"path": "codebase-graph-builder/src/test/resources/javaSrcDirectory/com/ideacrest/parser/testclasses/E.java",
"chars": 75,
"preview": "package com.ideacrest.parser.testclasses;\n\npublic class E {\n\tD d;\n\tD d2;\n}\n"
},
{
"path": "cost-benefit-calculator/pom.xml",
"chars": 1686,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "cost-benefit-calculator/src/main/java/org/hjug/cbc/CostBenefitCalculator.java",
"chars": 19438,
"preview": "package org.hjug.cbc;\n\nimport static net.sourceforge.pmd.RuleViolation.CLASS_NAME;\nimport static net.sourceforge.pmd.Rul"
},
{
"path": "cost-benefit-calculator/src/main/java/org/hjug/cbc/CycleNode.java",
"chars": 941,
"preview": "package org.hjug.cbc;\n\nimport java.time.Instant;\nimport lombok.Data;\nimport org.hjug.git.ScmLogInfo;\nimport org.hjug.met"
},
{
"path": "cost-benefit-calculator/src/main/java/org/hjug/cbc/CycleRanker.java",
"chars": 6715,
"preview": "package org.hjug.cbc;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.ni"
},
{
"path": "cost-benefit-calculator/src/main/java/org/hjug/cbc/RankedCycle.java",
"chars": 2611,
"preview": "package org.hjug.cbc;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport lombok.Data;\nimport"
},
{
"path": "cost-benefit-calculator/src/main/java/org/hjug/cbc/RankedDisharmony.java",
"chars": 4061,
"preview": "package org.hjug.cbc;\n\nimport java.nio.file.Paths;\nimport java.time.Instant;\nimport lombok.Data;\nimport org.hjug.git.Scm"
},
{
"path": "cost-benefit-calculator/src/test/java/org/hjug/cbc/CostBenefitCalculatorTest.java",
"chars": 18620,
"preview": "package org.hjug.cbc;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\nimport java.io.*;\nimport java.util.*;\nimp"
},
{
"path": "cost-benefit-calculator/src/test/resources/hudson/model/User.java",
"chars": 46992,
"preview": "/*\n * The MIT License\n *\n * Copyright (c) 2004-2018, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt,\n * Tom Huy"
},
{
"path": "cost-benefit-calculator/src/test/resources/org/apache/myfaces/tobago/facelets/AttributeHandler.java",
"chars": 19724,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "cost-benefit-calculator/src/test/resources/org/apache/myfaces/tobago/facelets/AttributeHandler2.java",
"chars": 19817,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "cost-benefit-calculator/src/test/resources/org/apache/myfaces/tobago/facelets/AttributeHandlerAndSorter.java",
"chars": 29476,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "coverage/pom.xml",
"chars": 2579,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "effort-ranker/pom.xml",
"chars": 1093,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "effort-ranker/src/main/java/org/hjug/metrics/CBOClass.java",
"chars": 642,
"preview": "package org.hjug.metrics;\n\nimport java.util.Scanner;\nimport lombok.Data;\n\n/**\n * Created by Jim on 11/16/2016.\n */\n@Data"
},
{
"path": "effort-ranker/src/main/java/org/hjug/metrics/Disharmony.java",
"chars": 144,
"preview": "package org.hjug.metrics;\n\npublic interface Disharmony {\n\n String getFileName();\n\n String getClassName();\n\n Str"
},
{
"path": "effort-ranker/src/main/java/org/hjug/metrics/GodClass.java",
"chars": 1381,
"preview": "package org.hjug.metrics;\n\nimport java.text.NumberFormat;\nimport java.text.ParseException;\nimport lombok.Data;\n\n/**\n * C"
},
{
"path": "effort-ranker/src/main/java/org/hjug/metrics/GodClassRanker.java",
"chars": 2732,
"preview": "package org.hjug.metrics;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.function.Function;\nimpor"
},
{
"path": "effort-ranker/src/main/java/org/hjug/metrics/rules/CBORule.java",
"chars": 4344,
"preview": "package org.hjug.metrics.rules;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport net.sourceforge.pmd.lang.java.as"
},
{
"path": "effort-ranker/src/test/java/org/hjug/metrics/CBOClassParsingTest.java",
"chars": 855,
"preview": "package org.hjug.metrics;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.Locale;\nimport"
},
{
"path": "effort-ranker/src/test/java/org/hjug/metrics/GodClassParsingTest.java",
"chars": 942,
"preview": "package org.hjug.metrics;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.Locale;\nimport"
},
{
"path": "effort-ranker/src/test/java/org/hjug/metrics/GodClassRankerTest.java",
"chars": 6052,
"preview": "package org.hjug.metrics;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.junit.jupiter.api.Assertions;\ni"
},
{
"path": "graph-algorithms/pom.xml",
"chars": 1383,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/CircularReferenceChecker.java",
"chars": 2396,
"preview": "package org.hjug.dsm;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport lombok.extern.slf4j.Slf4j;\nimport org.jgra"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/DSM.java",
"chars": 9896,
"preview": "package org.hjug.dsm;\n\nimport java.util.*;\nimport java.util.stream.Collectors;\nimport lombok.Getter;\nimport org.jgrapht."
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/EdgeRemovalCalculator.java",
"chars": 3965,
"preview": "package org.hjug.dsm;\n\nimport java.util.*;\nimport java.util.stream.Collectors;\nimport org.jgrapht.Graph;\nimport org.jgra"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/EdgeToRemoveInfo.java",
"chars": 304,
"preview": "package org.hjug.dsm;\n\nimport lombok.Data;\nimport org.jgrapht.graph.DefaultWeightedEdge;\n\n@Data\npublic class EdgeToRemov"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/OptimalBackEdgeRemover.java",
"chars": 4024,
"preview": "package org.hjug.dsm;\n\nimport java.util.*;\nimport org.jgrapht.Graph;\nimport org.jgrapht.alg.cycle.CycleDetector;\nimport "
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/SparseGraphCircularReferenceChecker.java",
"chars": 2645,
"preview": "package org.hjug.dsm;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport lombok.extern.slf4j.Slf4j;\nimport org.jgra"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/dsm/SparseIntDWGEdgeRemovalCalculator.java",
"chars": 8074,
"preview": "package org.hjug.dsm;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Co"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/SuperTypeToken.java",
"chars": 1724,
"preview": "package org.hjug.feedback;\n\nimport java.lang.reflect.*;\n\npublic abstract class SuperTypeToken<T> {\n private final Typ"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/EdgeInfo.java",
"chars": 329,
"preview": "package org.hjug.feedback.arc;\n\nimport lombok.Data;\nimport org.jgrapht.graph.DefaultWeightedEdge;\n\n@Data\npublic class Ed"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/EdgeInfoCalculator.java",
"chars": 1686,
"preview": "package org.hjug.feedback.arc;\n\nimport java.util.*;\nimport java.util.stream.Collectors;\nimport lombok.RequiredArgsConstr"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/approximate/FeedbackArcSetResult.java",
"chars": 887,
"preview": "package org.hjug.feedback.arc.approximate;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Result container for th"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/approximate/FeedbackArcSetSolver.java",
"chars": 6207,
"preview": "package org.hjug.feedback.arc.approximate;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport ja"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/exact/FeedbackArcSetResult.java",
"chars": 896,
"preview": "package org.hjug.feedback.arc.exact;\n\nimport java.util.Set;\n\n/**\n * Result container for the minimum feedback arc set al"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetSolver.java",
"chars": 11477,
"preview": "package org.hjug.feedback.arc.exact;\n\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.ato"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/pageRank/DIAGRAM.md",
"chars": 5161,
"preview": "# PageRank Feedback Arc Set (PageRankFAS) Algorithm\n\nBased on the paper *\"Computing a Feedback Arc Set Using PageRank\"* "
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/pageRank/LineDigraph.java",
"chars": 13830,
"preview": "package org.hjug.feedback.arc.pageRank;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java."
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/arc/pageRank/PageRankFAS.java",
"chars": 14307,
"preview": "package org.hjug.feedback.arc.pageRank;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java."
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetResult.java",
"chars": 686,
"preview": "package org.hjug.feedback.vertex.approximate;\n\nimport java.util.Set;\n\n/**\n * Result container for the Feedback Vertex Se"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetSolver.java",
"chars": 13143,
"preview": "package org.hjug.feedback.vertex.approximate;\n\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concu"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/DIAGRAM.md",
"chars": 8030,
"preview": "# Kernelized Directed Feedback Vertex Set (DFVS) Algorithm\n\nBased on: *\"Wannabe Bounded Treewidth Graphs Admit a Polynom"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetResult.java",
"chars": 721,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.Set;\n\n/**\n * Result container for the Directed Feedback V"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetSolver.java",
"chars": 39298,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concur"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/EnhancedParameterComputer.java",
"chars": 7857,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.*;\nimport java.util.concurrent.CompletableFuture;\nimport "
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/FeedbackVertexSetComputer.java",
"chars": 10946,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.stream"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/ModulatorComputer.java",
"chars": 74442,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport com.google.common.util.concurrent.AtomicDouble;\nimport java.util.*;"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/ParameterComputer.java",
"chars": 4171,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport org.hjug.feedback.S"
},
{
"path": "graph-algorithms/src/main/java/org/hjug/feedback/vertex/kernelized/TreewidthComputer.java",
"chars": 21442,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concur"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/dsm/CircularReferenceCheckerTests.java",
"chars": 1642,
"preview": "package org.hjug.dsm;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.Map;\nimport org.jg"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/dsm/DSMTest.java",
"chars": 3258,
"preview": "package org.hjug.dsm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.List;\nimport org.jgrapht.grap"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/dsm/EdgeRemovalCalculatorTest.java",
"chars": 1810,
"preview": "package org.hjug.dsm;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.List;\nimport org.j"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/dsm/OptimalBackEdgeRemoverTest.java",
"chars": 4265,
"preview": "package org.hjug.dsm;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.ArrayList;\nimport java.util.S"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/SuperTypeTokenTest.java",
"chars": 1367,
"preview": "package org.hjug.feedback;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.List;\nimport org.jgrapht"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/approximate/FeedbackArcSetBenchmarkTest.java",
"chars": 4171,
"preview": "package org.hjug.feedback.arc.approximate;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurre"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/approximate/FeedbackArcSetExample.java",
"chars": 1229,
"preview": "package org.hjug.feedback.arc.approximate;\n\nimport org.jgrapht.Graph;\nimport org.jgrapht.graph.DefaultDirectedGraph;\nimp"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/approximate/FeedbackArcSetSolverTest.java",
"chars": 11654,
"preview": "package org.hjug.feedback.arc.approximate;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nimpor"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetBenchmarkTest.java",
"chars": 2797,
"preview": "package org.hjug.feedback.arc.exact;\n\nimport java.util.*;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.uti"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetExample.java",
"chars": 1597,
"preview": "package org.hjug.feedback.arc.exact;\n\nimport java.util.Map;\nimport org.hjug.feedback.SuperTypeToken;\nimport org.jgrapht."
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/exact/MinimumFeedbackArcSetSolverTest.java",
"chars": 11339,
"preview": "package org.hjug.feedback.arc.exact;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nimport java"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/pageRank/PageRankFASExample.java",
"chars": 11173,
"preview": "package org.hjug.feedback.arc.pageRank;\n\nimport java.util.Set;\nimport org.hjug.feedback.SuperTypeToken;\nimport org.jgrap"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/arc/pageRank/PageRankFASTest.java",
"chars": 15220,
"preview": "package org.hjug.feedback.arc.pageRank;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nimport o"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetBenchmarkTest.java",
"chars": 2488,
"preview": "package org.hjug.feedback.vertex.approximate;\n\nimport java.util.*;\nimport java.util.concurrent.ThreadLocalRandom;\nimport"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetExample.java",
"chars": 1504,
"preview": "package org.hjug.feedback.vertex.approximate;\n\nimport java.util.Map;\nimport java.util.Set;\nimport org.jgrapht.Graph;\nimp"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/approximate/FeedbackVertexSetSolverTest.java",
"chars": 11123,
"preview": "package org.hjug.feedback.vertex.approximate;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nim"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetBenchmarkTest.java",
"chars": 2958,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.*;\nimport java.util.concurrent.ThreadLocalRandom;\nimport "
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetExample.java",
"chars": 1587,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.Map;\nimport java.util.Set;\nimport org.hjug.feedback.Super"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/DirectedFeedbackVertexSetSolverTest.java",
"chars": 11871,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nimp"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/ModulatorComputerTest.java",
"chars": 15358,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nimp"
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/ParameterComputerExample.java",
"chars": 1873,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport java.util.Set;\nimport org.hjug.feedback.SuperTypeToken;\nimport org."
},
{
"path": "graph-algorithms/src/test/java/org/hjug/feedback/vertex/kernelized/ParameterComputerTest.java",
"chars": 13894,
"preview": "package org.hjug.feedback.vertex.kernelized;\n\nimport static org.junit.jupiter.api.Assertions.*;\n\nimport java.util.*;\nimp"
},
{
"path": "graph-data-generator/pom.xml",
"chars": 851,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "graph-data-generator/src/main/java/org/hjug/gdg/GraphDataGenerator.java",
"chars": 5021,
"preview": "package org.hjug.gdg;\n\nimport java.util.List;\nimport org.hjug.cbc.RankedDisharmony;\n\npublic class GraphDataGenerator {\n\n"
},
{
"path": "graph-data-generator/src/test/java/org/hjug/gdg/GraphDataGeneratorTest.java",
"chars": 4433,
"preview": "package org.hjug.gdg;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.ArrayList;\nimport "
},
{
"path": "jreleaser.yml",
"chars": 984,
"preview": "# Generated with JReleaser 1.22.0 at 2026-01-24T15:46:34.8940566-06:00\nproject:\n name: RefactorFirst\n description: Ide"
},
{
"path": "lombok.config",
"chars": 42,
"preview": "lombok.addLombokGeneratedAnnotation = true"
},
{
"path": "pom.xml",
"chars": 20650,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "refactor-first-gradle-plugin/build.gradle",
"chars": 909,
"preview": "plugins {\n id 'java-gradle-plugin'\n id 'maven-publish'\n id 'com.gradle.plugin-publish' version '0.12.0'\n}\n\nrepo"
},
{
"path": "refactor-first-gradle-plugin/gradle/wrapper/gradle-wrapper.properties",
"chars": 200,
"preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
},
{
"path": "refactor-first-gradle-plugin/gradlew",
"chars": 5766,
"preview": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0"
},
{
"path": "refactor-first-gradle-plugin/gradlew.bat",
"chars": 2674,
"preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
},
{
"path": "refactor-first-gradle-plugin/pom.xml",
"chars": 3920,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "refactor-first-gradle-plugin/settings.gradle",
"chars": 49,
"preview": "rootProject.name = 'refactor-first-gradle-plugin'"
},
{
"path": "refactor-first-gradle-plugin/src/main/java/org/hjug/gradlereport/RefactorFirstPlugin.java",
"chars": 220,
"preview": "package org.hjug.gradlereport;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\n\npublic class RefactorFirst"
},
{
"path": "refactor-first-maven-plugin/pom.xml",
"chars": 3970,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstHtmlReport.java",
"chars": 2383,
"preview": "package org.hjug.mavenreport;\n\nimport java.io.File;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.maven.plugin.Abs"
},
{
"path": "refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenCsvReport.java",
"chars": 1610,
"preview": "package org.hjug.mavenreport;\n\nimport java.io.File;\nimport org.apache.maven.plugin.AbstractMojo;\nimport org.apache.maven"
},
{
"path": "refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenJsonReport.java",
"chars": 1421,
"preview": "package org.hjug.mavenreport;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport java.io.File;\nimport org.apach"
},
{
"path": "refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstMavenReport.java",
"chars": 5215,
"preview": "package org.hjug.mavenreport;\n\nimport java.util.*;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.maven.doxia.marku"
},
{
"path": "refactor-first-maven-plugin/src/main/java/org/hjug/mavenreport/RefactorFirstSimpleHtmlReport.java",
"chars": 2411,
"preview": "package org.hjug.mavenreport;\n\nimport java.io.File;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.maven.plugin.Abs"
},
{
"path": "report/.gitignore",
"chars": 490,
"preview": "target/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### IntelliJ IDEA ###\n.idea/mod"
},
{
"path": "report/pom.xml",
"chars": 1105,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/CsvReport.java",
"chars": 8776,
"preview": "package org.hjug.refactorfirst.report;\n\nimport static org.hjug.refactorfirst.report.ReportWriter.writeReportToDisk;\n\nimp"
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/HtmlReport.java",
"chars": 37079,
"preview": "package org.hjug.refactorfirst.report;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport"
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/ReportWriter.java",
"chars": 1179,
"preview": "package org.hjug.refactorfirst.report;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.IOException;\n"
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/SimpleHtmlReport.java",
"chars": 32370,
"preview": "package org.hjug.refactorfirst.report;\n\nimport static org.hjug.refactorfirst.report.ReportWriter.writeReportToDisk;\n\nimp"
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/json/JsonReport.java",
"chars": 246,
"preview": "package org.hjug.refactorfirst.report.json;\n\nimport java.util.List;\nimport lombok.Builder;\nimport lombok.Data;\n\n@Data\n@B"
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/json/JsonReportDisharmonyEntry.java",
"chars": 1568,
"preview": "package org.hjug.refactorfirst.report.json;\n\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\nimport "
},
{
"path": "report/src/main/java/org/hjug/refactorfirst/report/json/JsonReportExecutor.java",
"chars": 2919,
"preview": "package org.hjug.refactorfirst.report.json;\n\nimport static org.hjug.refactorfirst.report.ReportWriter.writeReportToDisk;"
},
{
"path": "report/src/test/java/org/hjug/refactorfirst/report/HtmlReportTest.java",
"chars": 2437,
"preview": "package org.hjug.refactorfirst.report;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nimport java.util.*"
},
{
"path": "report/src/test/java/org/hjug/refactorfirst/report/SimpleHtmlReportTest.java",
"chars": 361,
"preview": "package org.hjug.refactorfirst.report;\n\nimport org.junit.jupiter.api.Assertions;\nimport org.junit.jupiter.api.Test;\n\ncla"
},
{
"path": "report/src/test/resources/highlight.html",
"chars": 3464,
"preview": "<head>\n <style> body { margin: 0; } </style>\n\n <script src=\"https://unpkg.com/3d-force-graph\"></script>\n <scrip"
},
{
"path": "report/src/test/resources/sigmaPlayground.html",
"chars": 32518,
"preview": "<!-- This is a playground for experimentation -->\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n "
},
{
"path": "report/src/test/resources/spriteText.html",
"chars": 1795,
"preview": "<head>\n <style> body { margin: 0; } </style>\n\n <script src=\"https://unpkg.com/3d-force-graph\"></script>\n <scrip"
},
{
"path": "spring-petclinic-rest-report.html",
"chars": 43218,
"preview": "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n\n<head><title>Refactor First Report for spring-petcl"
},
{
"path": "test-resources/pom.xml",
"chars": 614,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "test-resources/src/main/resources/AttributeHandler.java",
"chars": 19724,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "test-resources/src/main/resources/AttributeHandler2.java",
"chars": 19817,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "test-resources/src/main/resources/AttributeHandlerAndSorter.java",
"chars": 29635,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "test-resources/src/main/resources/AttributeHandlerJavaEleven.java",
"chars": 19729,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "test-resources/src/main/resources/Attributes.java",
"chars": 11920,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "test-resources/src/main/resources/Console.java",
"chars": 44000,
"preview": "/*\n * Copyright 2018 Confluent Inc.\n *\n * Licensed under the Confluent Community License (the \"License\"); you may not us"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the refactorfirst/RefactorFirst GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 187 files (1.1 MB), approximately 245.7k tokens, and a symbol index with 1246 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.