Skip to content

Commit f810d39

Browse files
authored
Merge pull request #83 from JohT/feature/java-reports
Add java specific queries and reports
2 parents ff0a102 + f3dc431 commit f810d39

File tree

8 files changed

+147
-16
lines changed

8 files changed

+147
-16
lines changed
Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
// Annotated language elements by number of annotations
1+
// Annotated code elements overall by element type with some examples
22

33
MATCH (annotatedElement:Annotation|Parameter|Field|Method|Type&!ExternalType&!JavaType)-[:ANNOTATED_BY]->()-[]->(annotation:Type)
4-
OPTIONAL MATCH (parameterOwner:Method)-[:HAS]->(annotatedElement:Parameter)
4+
OPTIONAL MATCH (parameterOwnerType:Type)-[:DECLARES]->(parameterOwnerMethod:Method)-[:HAS]->(annotatedElement:Parameter)
5+
OPTIONAL MATCH (memberDeclaringType:Type)-[:DECLARES]->(annotatedElement:Member)
56
WITH annotation
67
,annotatedElement
7-
,parameterOwner.signature AS parameterOwnerMethodSignature
8-
,coalesce(annotatedElement.fqn, annotatedElement.fileName, annotatedElement.signature, annotatedElement.name) AS nameOfAnnotatedElement
8+
,coalesce(annotatedElement.fqn
9+
,annotatedElement.fileName
10+
,memberDeclaringType.fqn + '.' + annotatedElement.name
11+
,parameterOwnerType.fqn + '.' + parameterOwnerMethod.name + '(' + annotatedElement.index + ')'
12+
,annotatedElement.name
13+
) AS nameOfAnnotatedElement
914
WITH annotation.fqn AS annotationName
1015
,CASE WHEN 'Annotation' IN labels(annotatedElement) THEN 'Annotation'
1116
WHEN 'Parameter' IN labels(annotatedElement) THEN 'Parameter'
@@ -18,15 +23,11 @@ OPTIONAL MATCH (parameterOwner:Method)-[:HAS]->(annotatedElement:Parameter)
1823
WHEN 'Enum' IN labels(annotatedElement) THEN 'Enum'
1924
WHEN 'Type' IN labels(annotatedElement) THEN 'Type'
2025
ELSE 'Unexpected'
21-
END AS languageElement
22-
,count(DISTINCT annotatedElement) AS numberOfAnnotatedElements
23-
,collect(DISTINCT nameOfAnnotatedElement) AS annotatedElements
24-
,collect(DISTINCT parameterOwnerMethodSignature) AS methodSignatures
26+
END AS languageElement
27+
,count(DISTINCT annotatedElement) AS numberOfAnnotatedElements
28+
,collect(DISTINCT nameOfAnnotatedElement) AS annotatedElements
2529
RETURN annotationName
2630
,languageElement
2731
,numberOfAnnotatedElements
28-
,CASE languageElement
29-
WHEN 'Parameter' THEN methodSignatures[0..9]
30-
ELSE annotatedElements[0..9]
31-
END AS examples
32+
,annotatedElements[0..9] AS examples
3233
ORDER BY numberOfAnnotatedElements DESCENDING
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Annotated code elements per artifact and element type with some examples
2+
3+
MATCH (annotatedElement:Annotation|Parameter|Field|Method|Type&!ExternalType&!JavaType)-[:ANNOTATED_BY]->()-[]->(annotation:Type)
4+
OPTIONAL MATCH (annotatedElementArtifact:Artifact)-[:CONTAINS]->(annotatedElement)
5+
OPTIONAL MATCH (memberArtifact:Artifact)-[:CONTAINS]->(memberDeclaringType:Type)-[:DECLARES]->(annotatedElement:Member)
6+
OPTIONAL MATCH (parameterArtifact:Artifact)-[:CONTAINS]->(parameterOwnerType:Type)-[:DECLARES]->(parameterOwnerMethod:Method)-[:HAS]->(annotatedElement:Parameter)
7+
WITH annotation
8+
,annotatedElement
9+
,coalesce(annotatedElement.fqn
10+
,annotatedElement.fileName
11+
,memberDeclaringType.fqn + '.' + annotatedElement.name
12+
,parameterOwnerType.fqn + '.' + parameterOwnerMethod.name + '(' + annotatedElement.index + ')'
13+
,annotatedElement.name
14+
) AS nameOfAnnotatedElement
15+
,replace(last(split(coalesce(parameterArtifact, memberArtifact, annotatedElementArtifact).fileName, '/')), '.jar', '') AS artifactName
16+
WITH annotation.fqn AS annotationName
17+
,CASE WHEN 'Annotation' IN labels(annotatedElement) THEN 'Annotation'
18+
WHEN 'Parameter' IN labels(annotatedElement) THEN 'Parameter'
19+
WHEN 'Field' IN labels(annotatedElement) THEN 'Field'
20+
WHEN 'Constructor' IN labels(annotatedElement) THEN 'Constructor'
21+
WHEN 'Method' IN labels(annotatedElement) THEN 'Method'
22+
WHEN 'Member' IN labels(annotatedElement) THEN 'Member'
23+
WHEN 'Class' IN labels(annotatedElement) THEN 'Class'
24+
WHEN 'Interface' IN labels(annotatedElement) THEN 'Interface'
25+
WHEN 'Enum' IN labels(annotatedElement) THEN 'Enum'
26+
WHEN 'Type' IN labels(annotatedElement) THEN 'Type'
27+
ELSE 'Unexpected'
28+
END AS languageElement
29+
,artifactName
30+
,count(DISTINCT annotatedElement) AS numberOfAnnotatedElements
31+
,collect(DISTINCT nameOfAnnotatedElement) AS annotatedElements
32+
RETURN artifactName
33+
,annotationName
34+
,languageElement
35+
,numberOfAnnotatedElements
36+
,annotatedElements[0..9] AS examples
37+
ORDER BY artifactName ASCENDING, numberOfAnnotatedElements DESCENDING
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Query Java Reflection usage combined with invokations of "Class.forName"
2+
3+
MATCH (dependentArtifact:Artifact)-[:CONTAINS]-(dependentType:Type)
4+
WITH replace(last(split(dependentArtifact.fileName, '/')), '.jar', '') AS dependentArtifactName
5+
,dependentType AS dependentType
6+
OPTIONAL MATCH (dependentType)-[:DEPENDS_ON]->(reflectionType:Type)
7+
WHERE reflectionType.fqn STARTS WITH 'java.lang.reflect.'
8+
OPTIONAL MATCH (dependentType)-[:DECLARES]->(dependentMethod:Method)-[:INVOKES]->(classForName:Method)
9+
WHERE classForName.signature STARTS WITH 'java.lang.Class forName'
10+
WITH dependentArtifactName
11+
,collect(DISTINCT coalesce(reflectionType.fqn, 'Class.forName')) AS reflectionTypes
12+
,collect(DISTINCT dependentType.fqn) AS reflectionCaller
13+
,count(DISTINCT dependentType.fqn) AS numberOfReflectionCaller
14+
RETURN dependentArtifactName
15+
,numberOfReflectionCaller
16+
,reflectionTypes[0..19] AS someReflectionTypes
17+
,reflectionCaller[0..19] AS someDependentTypes
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Query deprecated type and member usage by non deprecated elements
2+
3+
MATCH (annotated)-[:ANNOTATED_BY]->(:Annotation)-[:OF_TYPE]->(:Type{fqn:'java.lang.Deprecated'})
4+
OPTIONAL MATCH (artifactReadsDeprecated:Artifact)-[:CONTAINS]->(typeReadsDeprecated:Type)-[:DECLARES]->(readsDeprecated:Method)-[:READS]->(annotated:Field)
5+
OPTIONAL MATCH (artifactInvokesDeprecated:Artifact)-[:CONTAINS]->(typeInvokesDeprecated:Type)-[:DECLARES]->(invokesDeprecated:Method)-[:INVOKES]->(annotated:Method)
6+
OPTIONAL MATCH (artifactInvokesParameterDeprecated:Artifact)-[:CONTAINS]->(typeInvokesParameterDeprecated:Type)-[:DECLARES]->(invokesParameterDeprecated:Method)-[:INVOKES]->(parameterAnnotatedMethod:Method)-[:HAS]->(annotated:Parameter)
7+
OPTIONAL MATCH (artifactDependsOnDeprecated:Artifact)-[:CONTAINS]->(typeDependsOnDeprecated:Type)-[:DEPENDS_ON]->(annotated:Type)
8+
WITH coalesce(artifactReadsDeprecated, artifactInvokesDeprecated, artifactInvokesParameterDeprecated, artifactDependsOnDeprecated) AS artifact
9+
,coalesce(typeReadsDeprecated, typeInvokesDeprecated, typeInvokesParameterDeprecated, typeDependsOnDeprecated) AS type
10+
,coalesce(readsDeprecated, invokesDeprecated, invokesParameterDeprecated) AS method
11+
,CASE WHEN 'Annotation' IN labels(annotated) THEN 'Annotation'
12+
WHEN 'Parameter' IN labels(annotated) THEN 'Parameter'
13+
WHEN 'Field' IN labels(annotated) THEN 'Field'
14+
WHEN 'Constructor' IN labels(annotated) THEN 'Constructor'
15+
WHEN 'Method' IN labels(annotated) THEN 'Method'
16+
WHEN 'Member' IN labels(annotated) THEN 'Member'
17+
WHEN 'Class' IN labels(annotated) THEN 'Class'
18+
WHEN 'Interface' IN labels(annotated) THEN 'Interface'
19+
WHEN 'Enum' IN labels(annotated) THEN 'Enum'
20+
WHEN 'Type' IN labels(annotated) THEN 'Type'
21+
ELSE 'Unexpected'
22+
END AS deprecatedElement
23+
,coalesce(typeReadsDeprecated.fqn + '.' + readsDeprecated.name
24+
,typeInvokesDeprecated.fqn + '.' + invokesDeprecated.name
25+
,typeInvokesParameterDeprecated.fqn + '.' + invokesParameterDeprecated.name
26+
,typeDependsOnDeprecated.fqn
27+
) AS elementUsingDeprecatedElement
28+
WHERE artifact IS NOT NULL
29+
AND NOT (type)-[:ANNOTATED_BY]->(:Annotation)-[:OF_TYPE]->(:Type{fqn:'java.lang.Deprecated'})
30+
AND NOT (method)-[:ANNOTATED_BY]->(:Annotation)-[:OF_TYPE]->(:Type{fqn:'java.lang.Deprecated'})
31+
RETURN replace(last(split(artifact.fileName, '/')), '.jar', '') AS artifactName
32+
,deprecatedElement
33+
,count(DISTINCT elementUsingDeprecatedElement) AS numberOfElementsUsingDeprecatedElements
34+
,collect(DISTINCT elementUsingDeprecatedElement)[0..19] AS someElementsUsingDeprecatedElements
35+
ORDER BY artifactName ASCENDING

jupyter/InternalDependencies.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@
559559
"metadata": {},
560560
"outputs": [],
561561
"source": [
562-
"annotated_elements=query_cypher_to_data_frame(\"../cypher/Internal_Dependencies/Annotated_language_elements.cypher\", limit=30)\n",
562+
"annotated_elements=query_cypher_to_data_frame(\"../cypher/Java/Annotated_code_elements.cypher\", limit=30)\n",
563563
"annotated_elements"
564564
]
565565
}

reports/java-csv/ReflectionUsage.csv

Whitespace-only changes.

scripts/reports/InternalDependenciesCsv.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,4 @@ execute_cypher "${CYPHER_DIR}/Candidates_for_Interface_Segregation.cypher" > "${
4848

4949
execute_cypher "${INTERNAL_DEPENDENCIES_CYPHER_DIR}/List_types_that_are_used_by_many_different_packages.cypher" > "${FULL_REPORT_DIRECTORY}/WidelyUsedTypes.csv"
5050
execute_cypher "${INTERNAL_DEPENDENCIES_CYPHER_DIR}/How_many_packages_compared_to_all_existing_are_used_by_dependent_artifacts.cypher" > "${FULL_REPORT_DIRECTORY}/ArtifactPackageUsage.csv"
51-
execute_cypher "${INTERNAL_DEPENDENCIES_CYPHER_DIR}/How_many_classes_compared_to_all_existing_in_the_same_package_are_used_by_dependent_packages_across_different_artifacts.cypher" > "${FULL_REPORT_DIRECTORY}/ClassesPerPackageUsageAcrossArtifacts.csv"
52-
53-
execute_cypher "${INTERNAL_DEPENDENCIES_CYPHER_DIR}/Annotated_language_elements.cypher" > "${FULL_REPORT_DIRECTORY}/AnnotatedCodeElements.csv"
51+
execute_cypher "${INTERNAL_DEPENDENCIES_CYPHER_DIR}/How_many_classes_compared_to_all_existing_in_the_same_package_are_used_by_dependent_packages_across_different_artifacts.cypher" > "${FULL_REPORT_DIRECTORY}/ClassesPerPackageUsageAcrossArtifacts.csv"

scripts/reports/JavaCsv.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
3+
# Executes "Java" Cypher queries to get the "java-csv" CSV reports.
4+
# It contains lists of e.g. reflection usage, annotated language elements and usage of deprecated elements.
5+
6+
# Requires executeQueryFunctions.sh
7+
8+
# Fail on any error ("-e" = exit on first error, "-o pipefail" exist on errors within piped commands)
9+
set -o errexit -o pipefail
10+
11+
# Overrideable Constants (defaults also defined in sub scripts)
12+
REPORTS_DIRECTORY=${REPORTS_DIRECTORY:-"reports"}
13+
14+
## Get this "scripts/reports" directory if not already set
15+
# Even if $BASH_SOURCE is made for Bourne-like shells it is also supported by others and therefore here the preferred solution.
16+
# CDPATH reduces the scope of the cd command to potentially prevent unintended directory changes.
17+
# This way non-standard tools like readlink aren't needed.
18+
REPORTS_SCRIPT_DIR=${REPORTS_SCRIPT_DIR:-$( CDPATH=. cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P )}
19+
echo "JavaCsv: REPORTS_SCRIPT_DIR=${REPORTS_SCRIPT_DIR}"
20+
21+
# Get the "scripts" directory by taking the path of this script and going one directory up.
22+
SCRIPTS_DIR=${SCRIPTS_DIR:-"${REPORTS_SCRIPT_DIR}/.."} # Repository directory containing the shell scripts
23+
echo "JavaCsv SCRIPTS_DIR=${SCRIPTS_DIR}"
24+
25+
# Get the "cypher" directory by taking the path of this script and going two directory up and then to "cypher".
26+
CYPHER_DIR=${CYPHER_DIR:-"${REPORTS_SCRIPT_DIR}/../../cypher"}
27+
echo "JavaCsv CYPHER_DIR=${CYPHER_DIR}"
28+
29+
# Define functions to execute cypher queries from within a given file
30+
source "${SCRIPTS_DIR}/executeQueryFunctions.sh"
31+
32+
# Create report directory
33+
REPORT_NAME="java-csv"
34+
FULL_REPORT_DIRECTORY="${REPORTS_DIRECTORY}/${REPORT_NAME}"
35+
mkdir -p "${FULL_REPORT_DIRECTORY}"
36+
37+
# Local Constants
38+
JAVA_CYPHER_DIR="${CYPHER_DIR}/Java"
39+
40+
execute_cypher "${JAVA_CYPHER_DIR}/Java_Reflection_usage.cypher" > "${FULL_REPORT_DIRECTORY}/ReflectionUsage.csv"
41+
execute_cypher "${JAVA_CYPHER_DIR}/Java_deprecated_element_usage.cypher" > "${FULL_REPORT_DIRECTORY}/DeprecatedElementUsage.csv"
42+
execute_cypher "${JAVA_CYPHER_DIR}/Annotated_code_elements.cypher" > "${FULL_REPORT_DIRECTORY}/AnnotatedCodeElements.csv"
43+
execute_cypher "${JAVA_CYPHER_DIR}/Annotated_code_elements_per_artifact.cypher" > "${FULL_REPORT_DIRECTORY}/AnnotatedCodeElementsPerArtifact.csv"

0 commit comments

Comments
 (0)