From 47beee017a9b7c25717b3445177c728a6959e414 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 10:48:51 -0500 Subject: [PATCH 1/7] remove checkstyle --- checkstyle.xml | 108 ------------------------------------------------- pom.xml | 37 ----------------- 2 files changed, 145 deletions(-) delete mode 100644 checkstyle.xml diff --git a/checkstyle.xml b/checkstyle.xml deleted file mode 100644 index fd7b4e3c..00000000 --- a/checkstyle.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pom.xml b/pom.xml index 928c19a7..cd1c15a2 100644 --- a/pom.xml +++ b/pom.xml @@ -136,43 +136,6 @@ - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.1.1 - - checkstyle.xml - true - true - true - true - 0 - - - ${project.build.sourceDirectory} - - - - - checkstyle - process-classes - - check - - - true - true - - - - - - com.puppycrawl.tools - checkstyle - 8.20 - - - org.codehaus.mojo findbugs-maven-plugin From 56780a7988fa211cf9d407842fd381d62e67bbcc Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 13:13:41 -0500 Subject: [PATCH 2/7] add foss-root as parent which makes the 'release' profile redundant, and the copyright-header.txt file address a conflict found by maven-enforcer-plugin's requireUpperBoundDeps rule regarding org.codehaus.plexus:plexus-component-annotations --- RELEASE | 6 +-- copyright-header.txt | 15 ------- pom.xml | 96 ++++++++------------------------------------ 3 files changed, 20 insertions(+), 97 deletions(-) delete mode 100644 copyright-header.txt diff --git a/RELEASE b/RELEASE index 2c449709..948a9ec2 100644 --- a/RELEASE +++ b/RELEASE @@ -28,8 +28,8 @@ Optional: -Activate the 'release' profile when releasing: +then to release: -$ mvn -Prelease release:clean release:prepare -$ mvn -Prelease release:perform +$ mvn release:clean release:prepare +$ mvn release:perform diff --git a/copyright-header.txt b/copyright-header.txt deleted file mode 100644 index bd093f12..00000000 --- a/copyright-header.txt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2015 Spotify AB - * - * 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. - */ diff --git a/pom.xml b/pom.xml index cd1c15a2..42bee8cb 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,12 @@ 4.0.0 - com.spotify + + com.spotify + foss-root + 15 + + missinglink-parent 0.2.3-SNAPSHOT pom @@ -95,6 +100,17 @@ + + + + + org.codehaus.plexus + plexus-component-annotations + 1.6 + + + + @@ -171,82 +187,4 @@ - - - - release - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - v@{project.version} - true - - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.9.4 - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.8 - true - - ossrh - https://oss.sonatype.org/ - true - - - - - - - From ce7ab3fe62ef3ff50f7445c5387838ef3034af59 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 13:14:30 -0500 Subject: [PATCH 3/7] add missing license headers --- .../PrimitiveTypeDescriptorBenchmark.java | 20 +++++++++++++++++++ .../spotify/missinglink/ArtifactLoader.java | 20 +++++++++++++++++++ .../com/spotify/missinglink/CheckerState.java | 20 +++++++++++++++++++ .../com/spotify/missinglink/ClassLoader.java | 20 +++++++++++++++++++ .../com/spotify/missinglink/Conflict.java | 20 +++++++++++++++++++ .../spotify/missinglink/ConflictChecker.java | 20 +++++++++++++++++++ .../missinglink/Java9ModuleLoader.java | 20 +++++++++++++++++++ .../missinglink/MissingLinkException.java | 20 +++++++++++++++++++ .../spotify/missinglink/PrettyPrinter.java | 20 +++++++++++++++++++ .../missinglink/datamodel/AccessedField.java | 20 +++++++++++++++++++ .../datamodel/ArrayTypeDescriptor.java | 20 +++++++++++++++++++ .../missinglink/datamodel/Artifact.java | 20 +++++++++++++++++++ .../missinglink/datamodel/ArtifactName.java | 20 +++++++++++++++++++ .../missinglink/datamodel/CalledMethod.java | 20 +++++++++++++++++++ .../datamodel/ClassTypeDescriptor.java | 20 +++++++++++++++++++ .../missinglink/datamodel/DeclaredClass.java | 20 +++++++++++++++++++ .../missinglink/datamodel/DeclaredField.java | 20 +++++++++++++++++++ .../missinglink/datamodel/DeclaredMethod.java | 20 +++++++++++++++++++ .../missinglink/datamodel/Dependency.java | 20 +++++++++++++++++++ .../datamodel/FieldDependency.java | 20 +++++++++++++++++++ .../datamodel/MethodDependency.java | 20 +++++++++++++++++++ .../datamodel/MethodDescriptor.java | 20 +++++++++++++++++++ .../datamodel/MethodDescriptors.java | 20 +++++++++++++++++++ .../datamodel/PrimitiveTypeDescriptor.java | 20 +++++++++++++++++++ .../missinglink/datamodel/TypeDescriptor.java | 20 +++++++++++++++++++ .../datamodel/TypeDescriptors.java | 20 +++++++++++++++++++ .../datamodel/VoidTypeDescriptor.java | 20 +++++++++++++++++++ .../missinglink/ArtifactLoaderTest.java | 20 +++++++++++++++++++ .../spotify/missinglink/ClassLoaderTest.java | 20 +++++++++++++++++++ .../spotify/missinglink/ClassLoadingUtil.java | 20 +++++++++++++++++++ .../missinglink/ConflictCheckerTest.java | 20 +++++++++++++++++++ .../com/spotify/missinglink/FeatureTest.java | 20 +++++++++++++++++++ .../spotify/missinglink/FilePathHelper.java | 20 +++++++++++++++++++ .../missinglink/PrettyPrinterTest.java | 20 +++++++++++++++++++ .../spotify/missinglink/ReachableTest.java | 20 +++++++++++++++++++ .../java/com/spotify/missinglink/Simple.java | 20 +++++++++++++++++++ .../missinglink/TypeDescriptorTest.java | 20 +++++++++++++++++++ .../datamodel/MethodDescriptorsTest.java | 20 +++++++++++++++++++ .../nested/ClassWithNestedClass.java | 20 +++++++++++++++++++ .../spotify/missinglink/maven/CheckMojo.java | 20 +++++++++++++++++++ .../missinglink/maven/IgnoredPackage.java | 20 +++++++++++++++++++ .../missinglink/maven/MavenArtifactName.java | 20 +++++++++++++++++++ .../com/spotify/missinglink/maven/Scope.java | 20 +++++++++++++++++++ .../missinglink/maven/CheckMojoTest.java | 20 +++++++++++++++++++ .../maven/MavenArtifactNameTest.java | 20 +++++++++++++++++++ 45 files changed, 900 insertions(+) diff --git a/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java b/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java index 4b773eb4..ecbb3205 100644 --- a/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java +++ b/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-benchmarks + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java b/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java index 8b0d82f0..aec2d813 100644 --- a/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java +++ b/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/CheckerState.java b/core/src/main/java/com/spotify/missinglink/CheckerState.java index c6488912..fc204810 100644 --- a/core/src/main/java/com/spotify/missinglink/CheckerState.java +++ b/core/src/main/java/com/spotify/missinglink/CheckerState.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/ClassLoader.java b/core/src/main/java/com/spotify/missinglink/ClassLoader.java index b76401df..d0ffd66f 100644 --- a/core/src/main/java/com/spotify/missinglink/ClassLoader.java +++ b/core/src/main/java/com/spotify/missinglink/ClassLoader.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/Conflict.java b/core/src/main/java/com/spotify/missinglink/Conflict.java index a10436e9..b6ff99cb 100644 --- a/core/src/main/java/com/spotify/missinglink/Conflict.java +++ b/core/src/main/java/com/spotify/missinglink/Conflict.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/ConflictChecker.java b/core/src/main/java/com/spotify/missinglink/ConflictChecker.java index 9574788c..3faca358 100644 --- a/core/src/main/java/com/spotify/missinglink/ConflictChecker.java +++ b/core/src/main/java/com/spotify/missinglink/ConflictChecker.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java b/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java index 2e0f977a..5055bc11 100644 --- a/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java +++ b/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2019 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/MissingLinkException.java b/core/src/main/java/com/spotify/missinglink/MissingLinkException.java index 3ad56181..59e5c28d 100644 --- a/core/src/main/java/com/spotify/missinglink/MissingLinkException.java +++ b/core/src/main/java/com/spotify/missinglink/MissingLinkException.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/PrettyPrinter.java b/core/src/main/java/com/spotify/missinglink/PrettyPrinter.java index 3f014312..e77727dc 100644 --- a/core/src/main/java/com/spotify/missinglink/PrettyPrinter.java +++ b/core/src/main/java/com/spotify/missinglink/PrettyPrinter.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/AccessedField.java b/core/src/main/java/com/spotify/missinglink/datamodel/AccessedField.java index 907cb817..d0a71fb5 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/AccessedField.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/AccessedField.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java index e30efc0c..a9cf976c 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java b/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java index 5dbbaa45..5870b7b1 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java b/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java index d15560cd..a99ef874 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java b/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java index 3473d2eb..212b8c2e 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/ClassTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/ClassTypeDescriptor.java index 5b23f03f..0986593b 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/ClassTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/ClassTypeDescriptor.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java index af0ce5af..9bcb0711 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java index 3e6a6b7e..bd49e489 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredMethod.java b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredMethod.java index d9ecd399..f39808ff 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredMethod.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredMethod.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java b/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java index a4196cbc..04312c28 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java b/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java index da962c80..573e3cc4 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java index ad38c9f7..2217f102 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java index 48c17d9e..3578c075 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java index f5a71e6f..b2301fce 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java index e569e272..691046d9 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java index 0e75bc72..b659b116 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java index 7b4118b4..250a0d0b 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java index 0c6d44f8..cae2b984 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java b/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java index 45a47497..44ab3b21 100644 --- a/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java +++ b/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java b/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java index f40ea775..b058a094 100644 --- a/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java +++ b/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java b/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java index c9d3d3fc..fd550b33 100644 --- a/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java +++ b/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java b/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java index 1b4fb4c7..0fa0f4d4 100644 --- a/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java +++ b/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/FeatureTest.java b/core/src/test/java/com/spotify/missinglink/FeatureTest.java index 95be0f31..e40ea578 100644 --- a/core/src/test/java/com/spotify/missinglink/FeatureTest.java +++ b/core/src/test/java/com/spotify/missinglink/FeatureTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/FilePathHelper.java b/core/src/test/java/com/spotify/missinglink/FilePathHelper.java index d6a1074e..687947a1 100644 --- a/core/src/test/java/com/spotify/missinglink/FilePathHelper.java +++ b/core/src/test/java/com/spotify/missinglink/FilePathHelper.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java b/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java index 39df8918..cf84391a 100644 --- a/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java +++ b/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/ReachableTest.java b/core/src/test/java/com/spotify/missinglink/ReachableTest.java index 1d3131fc..dc24c1bf 100644 --- a/core/src/test/java/com/spotify/missinglink/ReachableTest.java +++ b/core/src/test/java/com/spotify/missinglink/ReachableTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/Simple.java b/core/src/test/java/com/spotify/missinglink/Simple.java index 0d6158a8..74d171f5 100644 --- a/core/src/test/java/com/spotify/missinglink/Simple.java +++ b/core/src/test/java/com/spotify/missinglink/Simple.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java b/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java index 164cf2ef..6726ddad 100644 --- a/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java +++ b/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java b/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java index 5067c611..553e716b 100644 --- a/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java +++ b/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/core/src/test/java/com/spotify/missinglink/nested/ClassWithNestedClass.java b/core/src/test/java/com/spotify/missinglink/nested/ClassWithNestedClass.java index 7140683a..ea64daa7 100644 --- a/core/src/test/java/com/spotify/missinglink/nested/ClassWithNestedClass.java +++ b/core/src/test/java/com/spotify/missinglink/nested/ClassWithNestedClass.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-core + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java index b9ce43ec..e9a759cb 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-maven-plugin + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java index e7f84215..5845eaee 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-maven-plugin + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java index b4780a3e..e9e08e30 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-maven-plugin + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/Scope.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/Scope.java index 68e66503..44997f07 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/Scope.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/Scope.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-maven-plugin + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java b/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java index b2e92a92..bb419ca4 100644 --- a/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java +++ b/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-maven-plugin + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * diff --git a/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java b/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java index 6f31bbf5..6bc073e4 100644 --- a/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java +++ b/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java @@ -1,3 +1,23 @@ +/*- + * -\-\- + * missinglink-maven-plugin + * -- + * Copyright (C) 2016 - 2021 Spotify AB + * -- + * 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. + * -/-/- + */ + /* * Copyright (c) 2015 Spotify AB * From ef5a7ed1aaf92ca8efb14674d99a75d2f2b30663 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 10:53:34 -0500 Subject: [PATCH 4/7] add fmt-maven-plugin for automatic formatting --- .github/workflows/ci.yaml | 2 +- pom.xml | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e3854fb0..7676f7c5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,6 +33,6 @@ jobs: restore-keys: ${{ runner.os }}-java-${{ matrix.java_version }}-m2 - name: Build with Maven # TODO: use 'verify' to run ITs (https://github.com/spotify/missinglink/issues/130) - run: mvn --batch-mode --update-snapshots package + run: mvn --batch-mode --update-snapshots fmt:check package - name: Codecov uses: codecov/codecov-action@v1 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 42bee8cb..1f5a027e 100644 --- a/pom.xml +++ b/pom.xml @@ -165,6 +165,19 @@ + + + com.coveo + fmt-maven-plugin + 2.10 + + + + format + + + + org.jacoco jacoco-maven-plugin From bc80616c22204a8ec79019be51a8fab55d2d2389 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 10:54:31 -0500 Subject: [PATCH 5/7] reformat code with fmt:format --- .../PrimitiveTypeDescriptorBenchmark.java | 17 +- .../spotify/missinglink/ArtifactLoader.java | 67 ++- .../com/spotify/missinglink/CheckerState.java | 4 +- .../com/spotify/missinglink/ClassLoader.java | 102 +++-- .../com/spotify/missinglink/Conflict.java | 1 - .../spotify/missinglink/ConflictChecker.java | 275 ++++++------ .../missinglink/Java9ModuleLoader.java | 30 +- .../spotify/missinglink/PrettyPrinter.java | 30 +- .../missinglink/datamodel/AccessedField.java | 2 +- .../datamodel/ArrayTypeDescriptor.java | 1 - .../missinglink/datamodel/Artifact.java | 4 +- .../missinglink/datamodel/ArtifactName.java | 1 - .../missinglink/datamodel/CalledMethod.java | 2 +- .../missinglink/datamodel/DeclaredClass.java | 1 - .../missinglink/datamodel/DeclaredField.java | 1 + .../missinglink/datamodel/Dependency.java | 2 + .../datamodel/FieldDependency.java | 4 + .../datamodel/MethodDependency.java | 3 + .../datamodel/MethodDescriptor.java | 4 +- .../datamodel/MethodDescriptors.java | 16 +- .../datamodel/PrimitiveTypeDescriptor.java | 12 +- .../missinglink/datamodel/TypeDescriptor.java | 3 +- .../datamodel/TypeDescriptors.java | 5 +- .../datamodel/VoidTypeDescriptor.java | 3 +- .../missinglink/ArtifactLoaderTest.java | 200 +++++---- .../spotify/missinglink/ClassLoaderTest.java | 25 +- .../spotify/missinglink/ClassLoadingUtil.java | 46 +- .../missinglink/ConflictCheckerTest.java | 129 +++--- .../com/spotify/missinglink/FeatureTest.java | 355 ++++++++-------- .../missinglink/PrettyPrinterTest.java | 4 +- .../spotify/missinglink/ReachableTest.java | 84 ++-- .../java/com/spotify/missinglink/Simple.java | 50 +-- .../missinglink/TypeDescriptorTest.java | 39 +- .../datamodel/MethodDescriptorsTest.java | 22 +- .../spotify/missinglink/maven/CheckMojo.java | 401 ++++++++++-------- .../missinglink/maven/IgnoredPackage.java | 19 +- .../missinglink/maven/MavenArtifactName.java | 18 +- .../missinglink/maven/CheckMojoTest.java | 274 ++++++------ .../maven/MavenArtifactNameTest.java | 5 +- 39 files changed, 1179 insertions(+), 1082 deletions(-) diff --git a/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java b/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java index ecbb3205..f806109f 100644 --- a/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java +++ b/benchmarks/src/main/java/com/spotify/missinglink/benchmarks/PrimitiveTypeDescriptorBenchmark.java @@ -37,26 +37,23 @@ package com.spotify.missinglink.benchmarks; import com.spotify.missinglink.datamodel.PrimitiveTypeDescriptor; - +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; - - @State(Scope.Benchmark) public class PrimitiveTypeDescriptorBenchmark { /** - * This class holds the raw String value to use to pass to - * {@link PrimitiveTypeDescriptor#fromRaw(String)}. The annotations used set up JMH to use the - * one holder per test thread, and set up a new value for each iteration of the benchmark (not - * each invocation). + * This class holds the raw String value to use to pass to {@link + * PrimitiveTypeDescriptor#fromRaw(String)}. The annotations used set up JMH to use the one holder + * per test thread, and set up a new value for each iteration of the benchmark (not each + * invocation). */ @State(Scope.Thread) public static class RawStringHolder { diff --git a/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java b/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java index aec2d813..f0c1a61b 100644 --- a/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java +++ b/core/src/main/java/com/spotify/missinglink/ArtifactLoader.java @@ -35,12 +35,13 @@ */ package com.spotify.missinglink; +import static java.util.stream.Collectors.toList; + import com.spotify.missinglink.datamodel.Artifact; import com.spotify.missinglink.datamodel.ArtifactBuilder; import com.spotify.missinglink.datamodel.ArtifactName; import com.spotify.missinglink.datamodel.ClassTypeDescriptor; import com.spotify.missinglink.datamodel.DeclaredClass; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -58,8 +59,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static java.util.stream.Collectors.toList; - public class ArtifactLoader { /** Load artifact at path, using path name as artifactId */ @@ -81,7 +80,8 @@ public Artifact load(ArtifactName artifactName, File path) throws IOException { return loadFromDirectory(artifactName, path); } - // This is designed to handle Multi-Release JAR files, where there are class files for multiple versions of JVM in one jar. + // This is designed to handle Multi-Release JAR files, where there are class files for multiple + // versions of JVM in one jar. // You don't want to end up trying to parse a new class file when running on an old JVM. // https://openjdk.java.net/jeps/238 private Collection getClassesForCurrentJavaVersion(Iterable entries) { @@ -90,7 +90,7 @@ private Collection getClassesForCurrentJavaVersion(Iterable SortedMap> classFilesPerJavaVersion = new TreeMap<>(); String patternString = "META-INF/versions/(\\d+)/"; Pattern pattern = Pattern.compile(patternString); - for (JarEntry entry: entries) { + for (JarEntry entry : entries) { String fileFullName = entry.getName(); if (fileFullName.endsWith(".class")) { Matcher m = pattern.matcher(fileFullName); @@ -105,7 +105,7 @@ private Collection getClassesForCurrentJavaVersion(Iterable } else { Integer withoutVersion = 0; if (!classFilesPerJavaVersion.containsKey(withoutVersion)) { - classFilesPerJavaVersion.put(withoutVersion, new HashMap<>()); + classFilesPerJavaVersion.put(withoutVersion, new HashMap<>()); } classFilesPerJavaVersion.get(withoutVersion).put(fileFullName, entry); } @@ -121,15 +121,16 @@ private Collection getClassesForCurrentJavaVersion(Iterable currentJavaVersion = Integer.parseInt(javaVersionElements[0]); } - // Start layering the class files from old JVM version to new and thus effectively override the old files by the new ones. + // Start layering the class files from old JVM version to new and thus effectively override the + // old files by the new ones. Map selectedClassFiles = new HashMap<>(); for (Map.Entry> entry : classFilesPerJavaVersion.entrySet()) { - Integer targetJavaVersion = entry.getKey(); - if (targetJavaVersion > currentJavaVersion) { - break; - } - Map pathToClassfile = entry.getValue(); - selectedClassFiles.putAll(pathToClassfile); + Integer targetJavaVersion = entry.getKey(); + if (targetJavaVersion > currentJavaVersion) { + break; + } + Map pathToClassfile = entry.getValue(); + selectedClassFiles.putAll(pathToClassfile); } return selectedClassFiles.values(); @@ -139,18 +140,17 @@ private Artifact loadFromJar(ArtifactName artifactName, File path) { try (JarFile jarFile = new JarFile(path)) { Map classes = new HashMap<>(); Iterable classFiles = - getClassesForCurrentJavaVersion(Collections.list(jarFile.entries())); - for (JarEntry entry: classFiles) { - try { - DeclaredClass cl = ClassLoader.load(jarFile.getInputStream(entry)); - classes.put(cl.className(), cl); - } catch (MissingLinkException e) { - throw e; - } catch (Exception e) { - throw new MissingLinkException("Could not load " + entry.getName() + " from " + path, - e); - } + getClassesForCurrentJavaVersion(Collections.list(jarFile.entries())); + for (JarEntry entry : classFiles) { + try { + DeclaredClass cl = ClassLoader.load(jarFile.getInputStream(entry)); + classes.put(cl.className(), cl); + } catch (MissingLinkException e) { + throw e; + } catch (Exception e) { + throw new MissingLinkException("Could not load " + entry.getName() + " from " + path, e); } + } return artifact(artifactName, classes); } catch (IOException e) { throw new RuntimeException("Could not load " + path, e); @@ -160,10 +160,11 @@ private Artifact loadFromJar(ArtifactName artifactName, File path) { private Artifact loadFromDirectory(ArtifactName artifactName, File dir) throws IOException { Map classes = new HashMap<>(); - List classFilesInDir = Files.walk(dir.toPath()) - .map(Path::toFile) - .filter(file -> file.isFile() && file.getName().endsWith(".class")) - .collect(toList()); + List classFilesInDir = + Files.walk(dir.toPath()) + .map(Path::toFile) + .filter(file -> file.isFile() && file.getName().endsWith(".class")) + .collect(toList()); for (File file : classFilesInDir) { try (FileInputStream fis = new FileInputStream(file)) { @@ -174,17 +175,13 @@ private Artifact loadFromDirectory(ArtifactName artifactName, File dir) throws I return artifact(artifactName, classes); } - private static Artifact artifact(ArtifactName name, - Map classes) { - return new ArtifactBuilder() - .name(name) - .classes(classes) - .build(); + private static Artifact artifact( + ArtifactName name, Map classes) { + return new ArtifactBuilder().name(name).classes(classes).build(); } public static void main(String[] args) throws Exception { ArtifactLoader l = new ArtifactLoader(); System.out.println(l.load(new File("core/src/test/resources/ArtifactLoaderTest.jar"))); } - } diff --git a/core/src/main/java/com/spotify/missinglink/CheckerState.java b/core/src/main/java/com/spotify/missinglink/CheckerState.java index fc204810..4f4abce2 100644 --- a/core/src/main/java/com/spotify/missinglink/CheckerState.java +++ b/core/src/main/java/com/spotify/missinglink/CheckerState.java @@ -38,10 +38,8 @@ import com.spotify.missinglink.datamodel.ArtifactName; import com.spotify.missinglink.datamodel.ClassTypeDescriptor; import com.spotify.missinglink.datamodel.DeclaredClass; - -import java.util.Map; - import io.norberg.automatter.AutoMatter; +import java.util.Map; @AutoMatter interface CheckerState { diff --git a/core/src/main/java/com/spotify/missinglink/ClassLoader.java b/core/src/main/java/com/spotify/missinglink/ClassLoader.java index d0ffd66f..67c53cc0 100644 --- a/core/src/main/java/com/spotify/missinglink/ClassLoader.java +++ b/core/src/main/java/com/spotify/missinglink/ClassLoader.java @@ -73,17 +73,14 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TryCatchBlockNode; -/** - * Loads a single class from an input stream. - */ +/** Loads a single class from an input stream. */ public final class ClassLoader { // This is a set of classes that is using @HotSpotIntrinsicCandidate // and thus define native methods that don't actually exist in the class file // This could be removed if we stop loading the full JDK - private static final Set BLACKLIST = new HashSet<>(Arrays.asList( - "java/lang/invoke/MethodHandle" - )); + private static final Set BLACKLIST = + new HashSet<>(Arrays.asList("java/lang/invoke/MethodHandle")); private ClassLoader() { // prevent instantiation @@ -120,8 +117,7 @@ private static ClassNode readClassNode(InputStream in) throws IOException { private static Set readParents(ClassNode classNode) { final Set parents = - classNode.interfaces - .stream() + classNode.interfaces.stream() .map(TypeDescriptors::fromClassName) .collect(Collectors.toSet()); // java/lang/Object has no superclass @@ -136,18 +132,20 @@ private static Set readDeclaredFields(ClassNode classNode) { final Iterable classFields = classNode.fields; for (FieldNode field : classFields) { - fields.add(new DeclaredFieldBuilder() - .name(field.name) - .descriptor(TypeDescriptors.fromRaw(field.desc)) - .build()); + fields.add( + new DeclaredFieldBuilder() + .name(field.name) + .descriptor(TypeDescriptors.fromRaw(field.desc)) + .build()); } return fields; } - private static void analyseMethod(String className, - MethodNode method, - Map declaredMethods, - Set loadedClasses) { + private static void analyseMethod( + String className, + MethodNode method, + Map declaredMethods, + Set loadedClasses) { final Set thisCalls = new HashSet<>(); final Set thisFields = new HashSet<>(); @@ -160,29 +158,36 @@ private static void analyseMethod(String className, lineNumber = ((LineNumberNode) insn).line; } if (insn instanceof MethodInsnNode) { - handleMethodCall(thisCalls, lineNumber, (MethodInsnNode) insn, + handleMethodCall( + thisCalls, + lineNumber, + (MethodInsnNode) insn, getTryCatchBlocksProtecting(instructions, insn, method)); } if (insn instanceof FieldInsnNode) { - handleFieldAccess(thisFields, lineNumber, (FieldInsnNode) insn, + handleFieldAccess( + thisFields, + lineNumber, + (FieldInsnNode) insn, getTryCatchBlocksProtecting(instructions, insn, method)); } if (insn instanceof LdcInsnNode) { handleLdc(loadedClasses, (LdcInsnNode) insn); } } catch (Exception e) { - throw new MissingLinkException("Error analysing " + className + "." + method.name + - ", line: " + lineNumber, e); + throw new MissingLinkException( + "Error analysing " + className + "." + method.name + ", line: " + lineNumber, e); } } - final DeclaredMethod declaredMethod = new DeclaredMethodBuilder() - .descriptor(MethodDescriptors.fromDesc(method.desc, method.name)) - .lineNumber(lineNumber) - .methodCalls(thisCalls) - .fieldAccesses(thisFields) - .isStatic((method.access & Opcodes.ACC_STATIC) != 0) - .build(); + final DeclaredMethod declaredMethod = + new DeclaredMethodBuilder() + .descriptor(MethodDescriptors.fromDesc(method.desc, method.name)) + .lineNumber(lineNumber) + .methodCalls(thisCalls) + .fieldAccesses(thisFields) + .isStatic((method.access & Opcodes.ACC_STATIC) != 0) + .build(); if (declaredMethods.put(declaredMethod.descriptor(), declaredMethod) != null) { throw new RuntimeException( @@ -218,10 +223,11 @@ private static List getTryCatchBlocksProtecting( return protectedByTryCatches; } - private static void handleMethodCall(final Set thisCalls, - final int lineNumber, - final MethodInsnNode insn, - final List tryCatchBlocksProtecting) { + private static void handleMethodCall( + final Set thisCalls, + final int lineNumber, + final MethodInsnNode insn, + final List tryCatchBlocksProtecting) { boolean isStatic; switch (insn.getOpcode()) { case Opcodes.INVOKEVIRTUAL: @@ -238,20 +244,25 @@ private static void handleMethodCall(final Set thisCalls, throw new RuntimeException("Unexpected method call opcode: " + insn.getOpcode()); } if (isArray(insn.owner) && !BLACKLIST.contains(insn.owner)) { - thisCalls.add(new CalledMethodBuilder() - .owner(TypeDescriptors.fromClassName(insn.owner)) - .descriptor(MethodDescriptors.fromDesc(insn.desc, insn.name)) - .isStatic(isStatic) - .lineNumber(lineNumber) - .caughtExceptions(tryCatchBlocksProtecting.stream() - .map(node -> TypeDescriptors.fromClassName(node.type)).collect(Collectors.toList())) - .build()); + thisCalls.add( + new CalledMethodBuilder() + .owner(TypeDescriptors.fromClassName(insn.owner)) + .descriptor(MethodDescriptors.fromDesc(insn.desc, insn.name)) + .isStatic(isStatic) + .lineNumber(lineNumber) + .caughtExceptions( + tryCatchBlocksProtecting.stream() + .map(node -> TypeDescriptors.fromClassName(node.type)) + .collect(Collectors.toList())) + .build()); } } - private static void handleFieldAccess(Set thisFields, int lineNumber, - FieldInsnNode insn, - final List tryCatchBlocksProtecting) { + private static void handleFieldAccess( + Set thisFields, + int lineNumber, + FieldInsnNode insn, + final List tryCatchBlocksProtecting) { if (isArray(insn.owner)) { thisFields.add( new AccessedFieldBuilder() @@ -259,9 +270,10 @@ private static void handleFieldAccess(Set thisFields, int lineNum .descriptor(TypeDescriptors.fromRaw(insn.desc)) .owner(TypeDescriptors.fromClassName(insn.owner)) .lineNumber(lineNumber) - .caughtExceptions(tryCatchBlocksProtecting.stream() - .map(node -> TypeDescriptors.fromClassName(node.type)) - .collect(Collectors.toList())) + .caughtExceptions( + tryCatchBlocksProtecting.stream() + .map(node -> TypeDescriptors.fromClassName(node.type)) + .collect(Collectors.toList())) .build()); } } diff --git a/core/src/main/java/com/spotify/missinglink/Conflict.java b/core/src/main/java/com/spotify/missinglink/Conflict.java index b6ff99cb..6bfe34e5 100644 --- a/core/src/main/java/com/spotify/missinglink/Conflict.java +++ b/core/src/main/java/com/spotify/missinglink/Conflict.java @@ -37,7 +37,6 @@ import com.spotify.missinglink.datamodel.ArtifactName; import com.spotify.missinglink.datamodel.Dependency; - import io.norberg.automatter.AutoMatter; @AutoMatter diff --git a/core/src/main/java/com/spotify/missinglink/ConflictChecker.java b/core/src/main/java/com/spotify/missinglink/ConflictChecker.java index 3faca358..38f2e903 100644 --- a/core/src/main/java/com/spotify/missinglink/ConflictChecker.java +++ b/core/src/main/java/com/spotify/missinglink/ConflictChecker.java @@ -63,68 +63,61 @@ /** * Inputs: - *

- * 1) The full set of artifact dependencies (D). This can be extracted from the dependency graph. + * + *

1) The full set of artifact dependencies (D). This can be extracted from the dependency graph. * The exact structure of the graph is not interesting, only knowing which dependencies are a part * of it. Note that this means that the same library can appear multiple times (with different - * versions) - * 2) The classpath of artifacts that is actually used (C). Ordering is important here. If a class - * appears - * more than once, the first occurrence will be used. - *

- * Assumptions: - *

- * 1) Each artifact could be compiled successfully using their own dependencies. - * 2) Each artifact was compiled against the same JDK, or at the very least only using parts of the - * JDK - * that didn't change compatibility. This is not a fully safe assumption, but to catch the - * kind of problems that could occur due to this would need a more broad analysis. - *

- * Strategy: - * 1) Identify which classes are a part of D but does not exist in C. This is the missing set (M) - * 2) Identify which classes are a part of D but are replaced in D (or is not the first occurrence) - * This is the suspicious set (S) - * 3) Walk through the class hierarchy graph. - * If something depends on something in M, also add that class to M. - * If something depends on something in S, also add that class to S - * 4) Walk through the method call graph, starting from the main entry point (the primary artifact) - * Whenever a method call is reached, check if the class and method exists. - * If it doesn't exist, also look in parent classes - * (implementations could exist both in superclasses and interfaces). - *

- * Note that we only need to try to verify the method if it's made to a class that is in M or S. - * If it is in M: fail. - * If it is in S: check it. - *

- * If we don't have access to one of the parents, we could simply assume that the call is safe - * This would however lead to all methods being marked as safe, since everything ultimately - * inherits from Object (or some other jdk class). - *

- * The alternative is to mark such calls as failures, which may lead to false positives. - * This might be ok for the MVP. - *

- * So we need to have the JDK classes (or some other provided dependencies) as input - * in order to lookup inheritance. - *

+ * versions) 2) The classpath of artifacts that is actually used (C). Ordering is important here. If + * a class appears more than once, the first occurrence will be used. + * + *

Assumptions: + * + *

1) Each artifact could be compiled successfully using their own dependencies. 2) Each artifact + * was compiled against the same JDK, or at the very least only using parts of the JDK that didn't + * change compatibility. This is not a fully safe assumption, but to catch the kind of problems that + * could occur due to this would need a more broad analysis. + * + *

Strategy: 1) Identify which classes are a part of D but does not exist in C. This is the + * missing set (M) 2) Identify which classes are a part of D but are replaced in D (or is not the + * first occurrence) This is the suspicious set (S) 3) Walk through the class hierarchy graph. If + * something depends on something in M, also add that class to M. If something depends on something + * in S, also add that class to S 4) Walk through the method call graph, starting from the main + * entry point (the primary artifact) Whenever a method call is reached, check if the class and + * method exists. If it doesn't exist, also look in parent classes (implementations could exist both + * in superclasses and interfaces). + * + *

Note that we only need to try to verify the method if it's made to a class that is in M or S. + * If it is in M: fail. If it is in S: check it. + * + *

If we don't have access to one of the parents, we could simply assume that the call is safe + * This would however lead to all methods being marked as safe, since everything ultimately inherits + * from Object (or some other jdk class). + * + *

The alternative is to mark such calls as failures, which may lead to false positives. This + * might be ok for the MVP. + * + *

So we need to have the JDK classes (or some other provided dependencies) as input in order to + * lookup inheritance. + * *

+ * *

- * For now, this is not really in place - we simply just look at all the things in the classpath + * + *

For now, this is not really in place - we simply just look at all the things in the classpath */ public class ConflictChecker { public static final ArtifactName UNKNOWN_ARTIFACT_NAME = new ArtifactName(""); /** - * @param projectArtifact the main artifact of the project we're verifying - * (this is considered the entry point for reachability) + * @param projectArtifact the main artifact of the project we're verifying (this is considered the + * entry point for reachability) * @param artifactsToCheck all artifacts that are on the runtime classpath - * @param allArtifacts all artifacts, including implicit artifacts (runtime provided - * artifacts) + * @param allArtifacts all artifacts, including implicit artifacts (runtime provided artifacts) * @return a list of conflicts */ - public List check(Artifact projectArtifact, - List artifactsToCheck, - List allArtifacts) { + public List check( + Artifact projectArtifact, List artifactsToCheck, List allArtifacts) { final CheckerStateBuilder stateBuilder = new CheckerStateBuilder(); @@ -137,7 +130,8 @@ public List check(Artifact projectArtifact, final List conflicts = new ArrayList<>(); - // Then go through everything in the classpath to make sure all the method calls / field references + // Then go through everything in the classpath to make sure all the method calls / field + // references // are satisfied. for (Artifact artifact : artifactsToCheck) { for (DeclaredClass clazz : artifact.classes().values()) { @@ -160,8 +154,8 @@ public List check(Artifact projectArtifact, * @param stateBuilder conflict checker state we're populating * @param allArtifacts maven artifacts to populate checker state with */ - private void createCanonicalClassMapping(CheckerStateBuilder stateBuilder, - List allArtifacts) { + private void createCanonicalClassMapping( + CheckerStateBuilder stateBuilder, List allArtifacts) { for (Artifact artifact : allArtifacts) { for (DeclaredClass clazz : artifact.classes().values()) { if (stateBuilder.knownClasses().putIfAbsent(clazz.className(), clazz) == null) { @@ -171,10 +165,8 @@ private void createCanonicalClassMapping(CheckerStateBuilder stateBuilder, } } - private List checkForBrokenMethodCalls(CheckerState state, - Artifact artifact, - DeclaredClass clazz, - DeclaredMethod method) { + private List checkForBrokenMethodCalls( + CheckerState state, Artifact artifact, DeclaredClass clazz, DeclaredMethod method) { List conflicts = new ArrayList<>(); for (CalledMethod calledMethod : method.methodCalls()) { @@ -182,30 +174,30 @@ private List checkForBrokenMethodCalls(CheckerState state, final DeclaredClass calledClass = state.knownClasses().get(owningClass); if (calledClass == null) { - final boolean catchesNoClassDef = calledMethod - .caughtExceptions() - .stream() - .anyMatch(c -> c.getClassName().equals("java.lang.NoClassDefFoundError")); + final boolean catchesNoClassDef = + calledMethod.caughtExceptions().stream() + .anyMatch(c -> c.getClassName().equals("java.lang.NoClassDefFoundError")); if (!catchesNoClassDef) { - conflicts.add(conflict(ConflictCategory.CLASS_NOT_FOUND, - "Class not found: " + owningClass, - dependency(clazz, method, calledMethod), - artifact.name(), - state.sourceMappings().get(owningClass) - )); + conflicts.add( + conflict( + ConflictCategory.CLASS_NOT_FOUND, + "Class not found: " + owningClass, + dependency(clazz, method, calledMethod), + artifact.name(), + state.sourceMappings().get(owningClass))); } } else if (missingMethod(calledMethod, calledClass, state.knownClasses())) { - final boolean catchesNoSuchMethod = calledMethod - .caughtExceptions() - .stream() - .anyMatch(c -> c.getClassName().equals("java.lang.NoSuchMethodError")); + final boolean catchesNoSuchMethod = + calledMethod.caughtExceptions().stream() + .anyMatch(c -> c.getClassName().equals("java.lang.NoSuchMethodError")); if (!catchesNoSuchMethod) { - conflicts.add(conflict(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND, - "Method not found: " + calledMethod.pretty(), - dependency(clazz, method, calledMethod), - artifact.name(), - state.sourceMappings().get(owningClass) - )); + conflicts.add( + conflict( + ConflictCategory.METHOD_SIGNATURE_NOT_FOUND, + "Method not found: " + calledMethod.pretty(), + dependency(clazz, method, calledMethod), + artifact.name(), + state.sourceMappings().get(owningClass))); } } } @@ -213,9 +205,8 @@ private List checkForBrokenMethodCalls(CheckerState state, return conflicts; } - private List checkForBrokenFieldAccess(CheckerState state, Artifact artifact, - DeclaredClass clazz, - DeclaredMethod method) { + private List checkForBrokenFieldAccess( + CheckerState state, Artifact artifact, DeclaredClass clazz, DeclaredMethod method) { List conflicts = new ArrayList<>(); @@ -223,25 +214,25 @@ private List checkForBrokenFieldAccess(CheckerState state, Artifact ar final ClassTypeDescriptor owningClass = field.owner(); final DeclaredClass calledClass = state.knownClasses().get(owningClass); - DeclaredField declaredField = new DeclaredFieldBuilder() - .descriptor(field.descriptor()) - .name(field.name()) - .build(); + DeclaredField declaredField = + new DeclaredFieldBuilder().descriptor(field.descriptor()).name(field.name()).build(); if (calledClass == null) { - conflicts.add(conflict(ConflictCategory.CLASS_NOT_FOUND, - "Class not found: " + owningClass, - dependency(clazz, method, field), - artifact.name(), - state.sourceMappings().get(owningClass) - )); + conflicts.add( + conflict( + ConflictCategory.CLASS_NOT_FOUND, + "Class not found: " + owningClass, + dependency(clazz, method, field), + artifact.name(), + state.sourceMappings().get(owningClass))); } else if (missingField(declaredField, calledClass, state.knownClasses())) { - conflicts.add(conflict(ConflictCategory.FIELD_NOT_FOUND, - "Field not found: " + field.name(), - dependency(clazz, method, field), - artifact.name(), - state.sourceMappings().get(owningClass) - )); + conflicts.add( + conflict( + ConflictCategory.FIELD_NOT_FOUND, + "Field not found: " + field.name(), + dependency(clazz, method, field), + artifact.name(), + state.sourceMappings().get(owningClass))); } else { // Everything is ok! @@ -252,8 +243,7 @@ private List checkForBrokenFieldAccess(CheckerState state, Artifact ar } static Set reachableFrom( - Collection values, - Map knownClasses) { + Collection values, Map knownClasses) { Queue toCheck = new LinkedList<>(values); @@ -266,42 +256,46 @@ static Set reachableFrom( continue; } - toCheck.addAll(current.parents().stream() - .map(knownClasses::get) - .filter(declaredClass -> declaredClass != null) - .collect(toList())); - - toCheck.addAll(current.loadedClasses().stream() - .map(knownClasses::get) - .filter(declaredClass -> declaredClass != null) - .collect(toList())); - - toCheck.addAll(current.methods().values() - .stream() - .flatMap(declaredMethod -> declaredMethod.methodCalls().stream()) - .map(CalledMethod::owner) - .filter(typeDescriptor -> !reachable.contains(typeDescriptor)) - .map(knownClasses::get) - .filter(declaredClass -> declaredClass != null) - .collect(toList())); - - toCheck.addAll(current.methods().values() - .stream() - .flatMap(declaredMethod -> declaredMethod.fieldAccesses().stream()) - .map(AccessedField::owner) - .filter(typeDescriptor -> !reachable.contains(typeDescriptor)) - .map(knownClasses::get) - .filter(declaredClass -> declaredClass != null) - .collect(toList())); + toCheck.addAll( + current.parents().stream() + .map(knownClasses::get) + .filter(declaredClass -> declaredClass != null) + .collect(toList())); + + toCheck.addAll( + current.loadedClasses().stream() + .map(knownClasses::get) + .filter(declaredClass -> declaredClass != null) + .collect(toList())); + + toCheck.addAll( + current.methods().values().stream() + .flatMap(declaredMethod -> declaredMethod.methodCalls().stream()) + .map(CalledMethod::owner) + .filter(typeDescriptor -> !reachable.contains(typeDescriptor)) + .map(knownClasses::get) + .filter(declaredClass -> declaredClass != null) + .collect(toList())); + + toCheck.addAll( + current.methods().values().stream() + .flatMap(declaredMethod -> declaredMethod.fieldAccesses().stream()) + .map(AccessedField::owner) + .filter(typeDescriptor -> !reachable.contains(typeDescriptor)) + .map(knownClasses::get) + .filter(declaredClass -> declaredClass != null) + .collect(toList())); } return reachable; } - private Conflict conflict(ConflictCategory category, String reason, - Dependency dependency, - ArtifactName usedBy, - ArtifactName existsIn) { + private Conflict conflict( + ConflictCategory category, + String reason, + Dependency dependency, + ArtifactName usedBy, + ArtifactName existsIn) { if (existsIn == null) { existsIn = UNKNOWN_ARTIFACT_NAME; } @@ -314,8 +308,8 @@ private Conflict conflict(ConflictCategory category, String reason, .build(); } - private Dependency dependency(DeclaredClass clazz, DeclaredMethod method, - CalledMethod calledMethod) { + private Dependency dependency( + DeclaredClass clazz, DeclaredMethod method, CalledMethod calledMethod) { return new MethodDependencyBuilder() .fromClass(clazz.className()) .fromMethod(method.descriptor()) @@ -325,8 +319,7 @@ private Dependency dependency(DeclaredClass clazz, DeclaredMethod method, .build(); } - private Dependency dependency(DeclaredClass clazz, DeclaredMethod method, - AccessedField field) { + private Dependency dependency(DeclaredClass clazz, DeclaredMethod method, AccessedField field) { return new FieldDependencyBuilder() .fromClass(clazz.className()) .fromMethod(method.descriptor()) @@ -337,8 +330,10 @@ private Dependency dependency(DeclaredClass clazz, DeclaredMethod method, .build(); } - private boolean missingMethod(CalledMethod calledMethod, DeclaredClass calledClass, - Map classMap) { + private boolean missingMethod( + CalledMethod calledMethod, + DeclaredClass calledClass, + Map classMap) { final MethodDescriptor descriptor = calledMethod.descriptor(); final DeclaredMethod method = calledClass.methods().get(descriptor); @@ -366,8 +361,10 @@ private boolean missingMethod(CalledMethod calledMethod, DeclaredClass calledCla return true; } - private boolean missingField(DeclaredField field, DeclaredClass calledClass, - Map classMap) { + private boolean missingField( + DeclaredField field, + DeclaredClass calledClass, + Map classMap) { if (calledClass.fields().contains(field)) { // TODO: also validate return type @@ -379,9 +376,8 @@ private boolean missingField(DeclaredField field, DeclaredClass calledClass, final DeclaredClass declaredClass = classMap.get(parentClass); // TODO 6/2/15 mbrown -- treat properly, by flagging as a different type of Conflict if (declaredClass == null) { - System.out.printf("Warning: Cannot find parent %s of class %s%n", - parentClass, - calledClass.className()); + System.out.printf( + "Warning: Cannot find parent %s of class %s%n", parentClass, calledClass.className()); } else if (!missingField(field, declaredClass, classMap)) { return false; } @@ -389,5 +385,4 @@ private boolean missingField(DeclaredField field, DeclaredClass calledClass, return true; } - } diff --git a/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java b/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java index 5055bc11..64d16744 100644 --- a/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java +++ b/core/src/main/java/com/spotify/missinglink/Java9ModuleLoader.java @@ -61,19 +61,15 @@ public static List getJava9ModuleArtifacts(BiConsumer getJava9ModuleArtifacts(BiConsumer opened = - (Optional) moduleReaderClass.getMethod("open", String.class) - .invoke(reader, className); + (Optional) + moduleReaderClass.getMethod("open", String.class).invoke(reader, className); if (!opened.isPresent()) { continue; } @@ -101,14 +97,18 @@ public static List getJava9ModuleArtifacts(BiConsumer caughtExceptions(); default String pretty() { diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java index a9cf976c..a00d773f 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/ArrayTypeDescriptor.java @@ -35,7 +35,6 @@ */ package com.spotify.missinglink.datamodel; - import java.util.Objects; public class ArrayTypeDescriptor implements TypeDescriptor { diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java b/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java index 5870b7b1..b34ff05f 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/Artifact.java @@ -44,8 +44,6 @@ public interface Artifact { /** "Name" of artifact, for example a directory path or jar file or something else symbolic. */ ArtifactName name(); - /** - * Map of classname to class object. Names are com/foo/bar/Baz. Returned map is immutable. - */ + /** Map of classname to class object. Names are com/foo/bar/Baz. Returned map is immutable. */ Map classes(); } diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java b/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java index a99ef874..2bb6bb08 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/ArtifactName.java @@ -63,7 +63,6 @@ public boolean equals(Object o) { ArtifactName that = (ArtifactName) o; return name.equals(that.name); - } @Override diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java b/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java index 212b8c2e..3719813c 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/CalledMethod.java @@ -51,7 +51,7 @@ public interface CalledMethod { int lineNumber(); - /** List of exception classes that protect this method call **/ + /** List of exception classes that protect this method call * */ List caughtExceptions(); default String pretty() { diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java index 9bcb0711..a9af2832 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredClass.java @@ -54,5 +54,4 @@ public interface DeclaredClass { Map methods(); Set fields(); - } diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java index bd49e489..c27260f5 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/DeclaredField.java @@ -41,5 +41,6 @@ /** Represents field in a class */ public interface DeclaredField { String name(); + TypeDescriptor descriptor(); } diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java b/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java index 04312c28..a89ed540 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/Dependency.java @@ -42,7 +42,9 @@ public interface Dependency { ClassTypeDescriptor fromClass(); + MethodDescriptor fromMethod(); + int fromLineNumber(); ClassTypeDescriptor targetClass(); diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java b/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java index 573e3cc4..884b7f12 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/FieldDependency.java @@ -45,11 +45,15 @@ public interface FieldDependency extends Dependency { ClassTypeDescriptor fromClass(); + MethodDescriptor fromMethod(); + int fromLineNumber(); ClassTypeDescriptor targetClass(); + TypeDescriptor fieldType(); + String fieldName(); @Override diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java index 2217f102..1afbaa69 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDependency.java @@ -45,10 +45,13 @@ public interface MethodDependency extends Dependency { ClassTypeDescriptor fromClass(); + MethodDescriptor fromMethod(); + int fromLineNumber(); ClassTypeDescriptor targetClass(); + MethodDescriptor targetMethod(); @Override diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java index 3578c075..8ed25779 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptor.java @@ -61,9 +61,7 @@ default String prettyWithoutReturnType() { default String prettyParameters() { StringJoiner joiner = new StringJoiner(", ", "(", ")"); - parameterTypes().stream() - .map(TypeDescriptor::toString) - .forEach(joiner::add); + parameterTypes().stream().map(TypeDescriptor::toString).forEach(joiner::add); return joiner.toString(); } diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java index b2301fce..0570a849 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/MethodDescriptors.java @@ -42,13 +42,11 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; - import org.objectweb.asm.Type; public final class MethodDescriptors { - private MethodDescriptors() { - } + private MethodDescriptors() {} public static MethodDescriptor fromDesc(String desc, String name) { final MethodKey key = new MethodKey(name, desc); @@ -58,10 +56,11 @@ public static MethodDescriptor fromDesc(String desc, String name) { private static MethodDescriptor newDescriptor(MethodKey key) { Type type = Type.getMethodType(key.desc); - List params = Arrays.stream(type.getArgumentTypes()) - .map(Type::getDescriptor) - .map(TypeDescriptors::fromRaw) - .collect(toList()); + List params = + Arrays.stream(type.getArgumentTypes()) + .map(Type::getDescriptor) + .map(TypeDescriptors::fromRaw) + .collect(toList()); return new MethodDescriptorBuilder() .returnType(TypeDescriptors.fromRaw(type.getReturnType().getDescriptor())) @@ -71,7 +70,7 @@ private static MethodDescriptor newDescriptor(MethodKey key) { } private static final Map methodDescriptorCache = - new ConcurrentHashMap<>(); + new ConcurrentHashMap<>(); private static class MethodKey { private final String name; @@ -97,7 +96,6 @@ public boolean equals(Object o) { return false; } return desc.equals(key.desc); - } @Override diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java index 691046d9..a877a92f 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/PrimitiveTypeDescriptor.java @@ -40,9 +40,14 @@ import java.util.Map; public enum PrimitiveTypeDescriptor implements TypeDescriptor { - - BYTE('B', "byte"), SHORT('S', "short"), INT('I', "int"), LONG('J', "long"), - FLOAT('F', "float"), DOUBLE('D', "double"), BOOLEAN('Z', "boolean"), CHAR('C', "char"); + BYTE('B', "byte"), + SHORT('S', "short"), + INT('I', "int"), + LONG('J', "long"), + FLOAT('F', "float"), + DOUBLE('D', "double"), + BOOLEAN('Z', "boolean"), + CHAR('C', "char"); private final char raw; private final String pretty; @@ -78,5 +83,4 @@ public static PrimitiveTypeDescriptor fromRaw(String typeDescriptor) { } return descriptor; } - } diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java index b659b116..b7f0deb4 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptor.java @@ -35,5 +35,4 @@ */ package com.spotify.missinglink.datamodel; -public interface TypeDescriptor { -} +public interface TypeDescriptor {} diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java index 250a0d0b..a6a195b3 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/TypeDescriptors.java @@ -41,8 +41,7 @@ public class TypeDescriptors { - private TypeDescriptors() { - } + private TypeDescriptors() {} // Keep a cache of all the created ClassTypeDescriptor instances to prevent unnecessary // duplication of instances. ClassTypeDescriptor is immutable once constructed. @@ -50,7 +49,7 @@ private TypeDescriptors() { // want to turn a String into a ClassTypeDescriptor, we can optimize how many strings are // created/replaced with this map. private static Map classTypeDescriptorCache = - new ConcurrentHashMap<>(); + new ConcurrentHashMap<>(); public static ClassTypeDescriptor fromClassName(String className) { return classTypeDescriptorCache.computeIfAbsent(className, ClassTypeDescriptor::new); diff --git a/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java b/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java index cae2b984..ac9d2373 100644 --- a/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java +++ b/core/src/main/java/com/spotify/missinglink/datamodel/VoidTypeDescriptor.java @@ -39,8 +39,7 @@ public class VoidTypeDescriptor implements TypeDescriptor { public static final VoidTypeDescriptor voidTypeDescriptor = new VoidTypeDescriptor(); - private VoidTypeDescriptor() { - } + private VoidTypeDescriptor() {} @Override public String toString() { diff --git a/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java b/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java index 44ab3b21..56a9e7be 100644 --- a/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java +++ b/core/src/test/java/com/spotify/missinglink/ArtifactLoaderTest.java @@ -35,6 +35,11 @@ */ package com.spotify.missinglink; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import com.spotify.missinglink.datamodel.AccessedField; import com.spotify.missinglink.datamodel.Artifact; import com.spotify.missinglink.datamodel.CalledMethod; @@ -48,24 +53,17 @@ import com.spotify.missinglink.datamodel.MethodDescriptorBuilder; import com.spotify.missinglink.datamodel.TypeDescriptor; import com.spotify.missinglink.datamodel.TypeDescriptors; - -import java.util.Collections; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Set; import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; public class ArtifactLoaderTest { @@ -81,40 +79,47 @@ public class ArtifactLoaderTest { public void setUp() throws IOException { artifact = loader.load(FilePathHelper.getPath("src/test/resources/ArtifactLoaderTest.jar")); - methodOneDescriptor = new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("V")) - .name("methodOne") - .parameterTypes(Collections.singletonList(TypeDescriptors.fromRaw("Ljava/lang/String;"))) - .build(); - - internalStaticFieldAccessDescriptor = new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("V")) - .name("internalStaticFieldAccess") - .build(); - - internalFieldAccessDescriptor = new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("V")) - .name("internalFieldAccess") - .build(); - - printlnDescriptor = new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("V")) - .name("println") - .parameterTypes(Collections.singletonList(TypeDescriptors.fromRaw("Ljava/lang/String;"))) - .build(); + methodOneDescriptor = + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("V")) + .name("methodOne") + .parameterTypes( + Collections.singletonList(TypeDescriptors.fromRaw("Ljava/lang/String;"))) + .build(); + + internalStaticFieldAccessDescriptor = + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("V")) + .name("internalStaticFieldAccess") + .build(); + + internalFieldAccessDescriptor = + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("V")) + .name("internalFieldAccess") + .build(); + + printlnDescriptor = + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("V")) + .name("println") + .parameterTypes( + Collections.singletonList(TypeDescriptors.fromRaw("Ljava/lang/String;"))) + .build(); } /** - * verify that the DeclaredClass.parents() set is actually populated with - * ClassTypeDescriptor instances - other types might leak through due to asm's use of raw lists. + * verify that the DeclaredClass.parents() set is actually populated with ClassTypeDescriptor + * instances - other types might leak through due to asm's use of raw lists. */ @Test @SuppressWarnings("rawtypes") public void testTypeOfClassParentsWhenInterfaces() throws IOException { final Artifact artifact = loadTestClassesAsArtifact(); - final DeclaredClass classThatImplementsInterfaces = getDeclaredClass(artifact, - "com/spotify/missinglink/ArtifactLoaderTest$ExampleClassWithInterfaces"); + final DeclaredClass classThatImplementsInterfaces = + getDeclaredClass( + artifact, "com/spotify/missinglink/ArtifactLoaderTest$ExampleClassWithInterfaces"); Set parents = classThatImplementsInterfaces.parents(); for (Object key : parents) { @@ -129,70 +134,97 @@ private static class ExampleClassWithInterfaces implements Serializable, Cloneab @Test public void testLoadClass() throws Exception { - assertNotNull("Artifact must contain class 'A'", + assertNotNull( + "Artifact must contain class 'A'", artifact.classes().get(TypeDescriptors.fromClassName("A"))); } @Test public void testLoadMethod() throws Exception { - assertTrue("Class must contain method with hairy signature", artifact.classes().get( - TypeDescriptors.fromClassName("A")).methods().containsKey(methodOneDescriptor)); + assertTrue( + "Class must contain method with hairy signature", + artifact + .classes() + .get(TypeDescriptors.fromClassName("A")) + .methods() + .containsKey(methodOneDescriptor)); } @Test public void testLoadCall() throws Exception { final DeclaredClass declaredClass = artifact.classes().get(TypeDescriptors.fromClassName("A")); DeclaredMethod method = declaredClass.methods().get(methodOneDescriptor); - CalledMethod call = new CalledMethodBuilder() - .owner(TypeDescriptors.fromClassName("java/io/PrintStream")) - .lineNumber(15) - .isStatic(false) - .descriptor(printlnDescriptor).build(); - assertTrue("Method must contain call to other method with hairy signature", + CalledMethod call = + new CalledMethodBuilder() + .owner(TypeDescriptors.fromClassName("java/io/PrintStream")) + .lineNumber(15) + .isStatic(false) + .descriptor(printlnDescriptor) + .build(); + assertTrue( + "Method must contain call to other method with hairy signature", method.methodCalls().contains(call)); } @Test public void testLoadField() throws Exception { DeclaredClass loadedClass = artifact.classes().get(TypeDescriptors.fromClassName("A")); - DeclaredField myField = new DeclaredFieldBuilder().name("publicFieldOne") - .descriptor(TypeDescriptors.fromRaw("Ljava/lang/Object;")).build(); - assertTrue("Class must contain field with hairy signature", - loadedClass.fields().contains(myField)); + DeclaredField myField = + new DeclaredFieldBuilder() + .name("publicFieldOne") + .descriptor(TypeDescriptors.fromRaw("Ljava/lang/Object;")) + .build(); + assertTrue( + "Class must contain field with hairy signature", loadedClass.fields().contains(myField)); } @Test public void testLoadStaticFieldAccess() throws Exception { - DeclaredMethod method = artifact.classes().get(TypeDescriptors.fromClassName("A")).methods() - .get(internalStaticFieldAccessDescriptor); + DeclaredMethod method = + artifact + .classes() + .get(TypeDescriptors.fromClassName("A")) + .methods() + .get(internalStaticFieldAccessDescriptor); AccessedField access = Simple.newAccess("Ljava/lang/Object;", "staticFieldOne", "A", 11); - assertTrue("Method must contain access to staticFieldOne: " + method.fieldAccesses() - + " does not contain " + access, method.fieldAccesses().contains(access)); + assertTrue( + "Method must contain access to staticFieldOne: " + + method.fieldAccesses() + + " does not contain " + + access, + method.fieldAccesses().contains(access)); } @Test public void testLoadFieldAccess() throws Exception { - DeclaredMethod method = artifact.classes().get(TypeDescriptors.fromClassName("A")).methods() - .get(internalFieldAccessDescriptor); + DeclaredMethod method = + artifact + .classes() + .get(TypeDescriptors.fromClassName("A")) + .methods() + .get(internalFieldAccessDescriptor); AccessedField access = Simple.newAccess("Ljava/lang/Object;", "publicFieldOne", "A", 12); - assertTrue("Method must contain access to staticFieldOne: " + method.fieldAccesses() - + " does not contain " + access, method.fieldAccesses().contains(access)); + assertTrue( + "Method must contain access to staticFieldOne: " + + method.fieldAccesses() + + " does not contain " + + access, + method.fieldAccesses().contains(access)); } @Test public void testLoadParent() throws Exception { - assertEquals(artifact.classes().get(TypeDescriptors.fromClassName("A")).parents(), + assertEquals( + artifact.classes().get(TypeDescriptors.fromClassName("A")).parents(), Collections.singleton(TypeDescriptors.fromClassName("java/lang/Object"))); } /** * Verify that the asm jar can be loaded without exceptions by ArtifactLoader. - *

- * This test caught bugs where ArtifactLoader treated MethodSignature as the thing that was - * unique - * within a classfile, whereas the actually unique thing is the MethodDescriptor (combining the - * ReturnDescriptor and ParameterDescriptor list). - *

+ * + *

This test caught bugs where ArtifactLoader treated MethodSignature as the thing that was + * unique within a classfile, whereas the actually unique thing is the MethodDescriptor (combining + * the ReturnDescriptor and ParameterDescriptor list). */ @Test public void testLoadAsmJar() throws Exception { @@ -205,7 +237,7 @@ public void testLoadAsmJar() throws Exception { @Test public void testLoadBouncyCastleJar() throws Exception { final Artifact artifact = - loader.load(FilePathHelper.getPath("src/test/resources/bcprov-jdk15on-1.68.jar")); + loader.load(FilePathHelper.getPath("src/test/resources/bcprov-jdk15on-1.68.jar")); String currentJavaVersion = System.getProperty("java.version"); if (currentJavaVersion.startsWith("1.8.")) { @@ -222,8 +254,7 @@ private Artifact loadAsmJar() throws IOException { } /** - * Attempt to find rt.jar from the Java installation on the classpath, and verify it can be - * loaded + * Attempt to find rt.jar from the Java installation on the classpath, and verify it can be loaded * by ArtifactLoader without exception */ @Test @@ -233,8 +264,8 @@ public void testLoadRtJar() throws Exception { final Collection files = Arrays.stream(classPath.split(System.getProperty("path.separator"))) .map(File::new) - // TODO 6/2/15 mbrown -- is every Java installation required to have a rt.jar? - // maybe just parse all jars on the classpath instead? + // TODO 6/2/15 mbrown -- is every Java installation required to have a rt.jar? + // maybe just parse all jars on the classpath instead? .filter(file -> file.isFile() && file.getName().equals("rt.jar")) .collect(Collectors.toList()); @@ -254,7 +285,7 @@ public void testLoadFromDirectory() throws Exception { assertThat(artifact.classes()) .overridingErrorMessage("Loading classes from a directory should be supported") .isNotEmpty() - // test that a class known to be in this directory exists in the map + // test that a class known to be in this directory exists in the map .containsKey(TypeDescriptors.fromClassName(MethodDescriptor.class.getName())); } @@ -262,24 +293,26 @@ public void testLoadFromDirectory() throws Exception { public void testNestedClassesNamedConsistenly() throws Exception { final Artifact artifact = loadTestClassesAsArtifact(); - final DeclaredClass theClass = getDeclaredClass(artifact, - "com/spotify/missinglink/nested/ClassWithNestedClass"); + final DeclaredClass theClass = + getDeclaredClass(artifact, "com/spotify/missinglink/nested/ClassWithNestedClass"); - final MethodDescriptor fooMethodDescriptor = theClass.methods().keySet().stream() - .filter(descriptor -> descriptor.name().equals("foo")) - .findFirst() - .orElseThrow(() -> new RuntimeException("foo method missing?")); + final MethodDescriptor fooMethodDescriptor = + theClass.methods().keySet().stream() + .filter(descriptor -> descriptor.name().equals("foo")) + .findFirst() + .orElseThrow(() -> new RuntimeException("foo method missing?")); final DeclaredMethod fooMethod = theClass.methods().get(fooMethodDescriptor); - String nestedClassName = fooMethod.methodCalls().stream() - .map(CalledMethod::owner) - .map(TypeDescriptor::toString) - .filter(name -> name.contains("NestedClass")) - .findFirst() - .orElseThrow(() -> new RuntimeException("call to NestedClass.bar missing?")); + String nestedClassName = + fooMethod.methodCalls().stream() + .map(CalledMethod::owner) + .map(TypeDescriptor::toString) + .filter(name -> name.contains("NestedClass")) + .findFirst() + .orElseThrow(() -> new RuntimeException("call to NestedClass.bar missing?")); - //make sure that the classMap contains an entry for the nestedClassName + // make sure that the classMap contains an entry for the nestedClassName assertThat(artifact.classes()).containsKey(TypeDescriptors.fromClassName(nestedClassName)); } @@ -293,5 +326,4 @@ private DeclaredClass getDeclaredClass(Artifact artifact, String className) { private Artifact loadTestClassesAsArtifact() throws IOException { return loader.load(FilePathHelper.getPath("target/test-classes")); } - } diff --git a/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java b/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java index b058a094..b7b9ffa8 100644 --- a/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java +++ b/core/src/test/java/com/spotify/missinglink/ClassLoaderTest.java @@ -35,20 +35,18 @@ */ package com.spotify.missinglink; +import static com.spotify.missinglink.ClassLoadingUtil.findClass; +import static org.assertj.core.api.Assertions.assertThat; + import com.spotify.missinglink.datamodel.DeclaredClass; import com.spotify.missinglink.datamodel.TypeDescriptors; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import java.io.File; import java.io.FileInputStream; import java.nio.file.Files; import java.nio.file.Path; - -import static com.spotify.missinglink.ClassLoadingUtil.findClass; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; public class ClassLoaderTest { @@ -57,11 +55,12 @@ public class ClassLoaderTest { @Before public void setUp() throws Exception { final File outputDir = FilePathHelper.getPath("target/classes"); - File someClass = Files.walk(outputDir.toPath()) - .map(Path::toFile) - .filter(file -> file.isFile() && file.getName().endsWith(".class")) - .findFirst() - .orElseThrow(() -> new IllegalStateException("no classfiles in " + outputDir + " ?")); + File someClass = + Files.walk(outputDir.toPath()) + .map(Path::toFile) + .filter(file -> file.isFile() && file.getName().endsWith(".class")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("no classfiles in " + outputDir + " ?")); inputStream = new FileInputStream(someClass); } diff --git a/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java b/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java index fd550b33..e2604e25 100644 --- a/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java +++ b/core/src/test/java/com/spotify/missinglink/ClassLoadingUtil.java @@ -50,23 +50,23 @@ public class ClassLoadingUtil { private static final ArtifactLoader artifactLoader = new ArtifactLoader(); - private static final AtomicReference> bootstrapArtifacts = - new AtomicReference<>(); + private static final AtomicReference> bootstrapArtifacts = new AtomicReference<>(); public static FileInputStream findClass(Class aClass) throws Exception { final String name = aClass.getName().replace('.', '/') + ".class"; final File outputDir = FilePathHelper.getPath("target/test-classes"); - List files = Files.walk(outputDir.toPath()) + List files = + Files.walk(outputDir.toPath()) .map(Path::toFile) .filter(file -> file.isFile() && file.getAbsolutePath().endsWith(name)) .collect(Collectors.toList()); if (files.isEmpty()) { - throw new IllegalStateException("no file matching " + aClass + " found in " - + outputDir + " ?"); + throw new IllegalStateException( + "no file matching " + aClass + " found in " + outputDir + " ?"); } if (files.size() >= 2) { - throw new IllegalStateException("too many files matching " + aClass + " found in " - + outputDir + ": " + files); + throw new IllegalStateException( + "too many files matching " + aClass + " found in " + outputDir + ": " + files); } return new FileInputStream(files.get(0)); } @@ -77,15 +77,16 @@ public static List bootstrapArtifacts() { String bootstrapClasspath = System.getProperty("sun.boot.class.path"); if (bootstrapClasspath != null) { - List artifacts = constructArtifacts(Arrays.asList( - bootstrapClasspath.split(System.getProperty("path.separator")))) - .stream() - .filter(c -> !c.name().name().equals("test-classes")) - .collect(Collectors.toList()); + List artifacts = + constructArtifacts( + Arrays.asList(bootstrapClasspath.split(System.getProperty("path.separator")))) + .stream() + .filter(c -> !c.name().name().equals("test-classes")) + .collect(Collectors.toList()); bootstrapArtifacts.set(artifacts); } else { - List artifacts = Java9ModuleLoader - .getJava9ModuleArtifacts((s, ex) -> ex.printStackTrace()); + List artifacts = + Java9ModuleLoader.getJava9ModuleArtifacts((s, ex) -> ex.printStackTrace()); bootstrapArtifacts.set(artifacts); } } @@ -93,14 +94,15 @@ public static List bootstrapArtifacts() { } private static List constructArtifacts(Iterable entries) { - final List list = StreamSupport.stream(entries.spliterator(), false) - // don't inspect paths that don't exist. - // some bootclasspath entries, like sunrsasign.jar, are reported even if they - // don't exist on disk - ¯\_(ツ)_/¯ - .distinct() - .filter(ClassLoadingUtil::filterValidClasspathEntries) - .map(ClassLoadingUtil::filepathToArtifact) - .collect(Collectors.toList()); + final List list = + StreamSupport.stream(entries.spliterator(), false) + // don't inspect paths that don't exist. + // some bootclasspath entries, like sunrsasign.jar, are reported even if they + // don't exist on disk - ¯\_(ツ)_/¯ + .distinct() + .filter(ClassLoadingUtil::filterValidClasspathEntries) + .map(ClassLoadingUtil::filepathToArtifact) + .collect(Collectors.toList()); return list; } diff --git a/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java b/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java index 0fa0f4d4..e26e16f1 100644 --- a/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java +++ b/core/src/test/java/com/spotify/missinglink/ConflictCheckerTest.java @@ -61,73 +61,96 @@ public class ConflictCheckerTest { @Before public void setUp() throws Exception { - final MethodDescriptor cloneDescriptor = new MethodDescriptorBuilder() - .name("clone") - .returnType(TypeDescriptors.fromClassName("java/lang/Object")) - .build(); + final MethodDescriptor cloneDescriptor = + new MethodDescriptorBuilder() + .name("clone") + .returnType(TypeDescriptors.fromClassName("java/lang/Object")) + .build(); - rt = new ArtifactBuilder() - .name(new ArtifactName("rt")) - .classes(Collections.singletonMap( - TypeDescriptors.fromClassName("java/lang/Object"), new DeclaredClassBuilder() - .className(TypeDescriptors.fromClassName("java/lang/Object")) - .methods(Collections.singletonMap( - cloneDescriptor, - new DeclaredMethodBuilder() - .descriptor(cloneDescriptor) + rt = + new ArtifactBuilder() + .name(new ArtifactName("rt")) + .classes( + Collections.singletonMap( + TypeDescriptors.fromClassName("java/lang/Object"), + new DeclaredClassBuilder() + .className(TypeDescriptors.fromClassName("java/lang/Object")) + .methods( + Collections.singletonMap( + cloneDescriptor, + new DeclaredMethodBuilder().descriptor(cloneDescriptor).build())) + // TODO: maybe add more methods here .build())) - // TODO: maybe add more methods here - .build())) - .build(); + .build(); - projectArtifact = new ArtifactBuilder() - .name(new ArtifactName("foo")) - .classes(Collections.singletonMap( - TypeDescriptors.fromClassName("com/spotify/ClassName"), - Simple.newClass("com/spotify/ClassName") - .parents(Collections.singleton(TypeDescriptors.fromClassName("java/lang/Object"))) - .methods(Simple.methodMap( - Simple.newMethod(false, Simple.OBJECT, "something") - .methodCalls(Collections.singleton(new CalledMethodBuilder() - .owner(TypeDescriptors.fromClassName( - "java/lang/Object")) - .descriptor(cloneDescriptor) - .build())) + projectArtifact = + new ArtifactBuilder() + .name(new ArtifactName("foo")) + .classes( + Collections.singletonMap( + TypeDescriptors.fromClassName("com/spotify/ClassName"), + Simple.newClass("com/spotify/ClassName") + .parents( + Collections.singleton( + TypeDescriptors.fromClassName("java/lang/Object"))) + .methods( + Simple.methodMap( + Simple.newMethod(false, Simple.OBJECT, "something") + .methodCalls( + Collections.singleton( + new CalledMethodBuilder() + .owner( + TypeDescriptors.fromClassName( + "java/lang/Object")) + .descriptor(cloneDescriptor) + .build())) + .build())) .build())) - .build())) - .build(); + .build(); ClassTypeDescriptor libClass1 = TypeDescriptors.fromClassName("org/library/ClassName"); - MethodDescriptor brokenMethodDescriptor = new MethodDescriptorBuilder() - .name("broken") - .returnType(TypeDescriptors.fromClassName("java/lang/Object")) - .build(); + MethodDescriptor brokenMethodDescriptor = + new MethodDescriptorBuilder() + .name("broken") + .returnType(TypeDescriptors.fromClassName("java/lang/Object")) + .build(); - libraryArtifact = new ArtifactBuilder() - .name(new ArtifactName("lib")) - .classes(Collections.singletonMap( - libClass1, new DeclaredClassBuilder() - .className(libClass1) - .parents(Collections.singleton(TypeDescriptors.fromClassName("java/lang/Object"))) - .methods(Simple.methodMap( - Simple.newMethod(false, Simple.OBJECT, "broken") - .methodCalls(Collections.singleton(new CalledMethodBuilder() - .owner(TypeDescriptors.fromClassName("java/lang/Object")) - .descriptor(brokenMethodDescriptor) - .build())) + libraryArtifact = + new ArtifactBuilder() + .name(new ArtifactName("lib")) + .classes( + Collections.singletonMap( + libClass1, + new DeclaredClassBuilder() + .className(libClass1) + .parents( + Collections.singleton( + TypeDescriptors.fromClassName("java/lang/Object"))) + .methods( + Simple.methodMap( + Simple.newMethod(false, Simple.OBJECT, "broken") + .methodCalls( + Collections.singleton( + new CalledMethodBuilder() + .owner( + TypeDescriptors.fromClassName( + "java/lang/Object")) + .descriptor(brokenMethodDescriptor) + .build())) + .build())) .build())) - .build())) - .build(); + .build(); } @Test public void shouldSupportInvocationsOnArrayTypes() throws Exception { ConflictChecker checker = new ConflictChecker(); - final List conflicts = checker.check(projectArtifact, - Arrays.asList(projectArtifact, rt), - Arrays.asList(projectArtifact, rt) - ); + final List conflicts = + checker.check( + projectArtifact, + Arrays.asList(projectArtifact, rt), + Arrays.asList(projectArtifact, rt)); assertThat(conflicts).isEmpty(); } diff --git a/core/src/test/java/com/spotify/missinglink/FeatureTest.java b/core/src/test/java/com/spotify/missinglink/FeatureTest.java index e40ea578..d6fddccc 100644 --- a/core/src/test/java/com/spotify/missinglink/FeatureTest.java +++ b/core/src/test/java/com/spotify/missinglink/FeatureTest.java @@ -63,7 +63,6 @@ import com.spotify.missinglink.datamodel.FieldDependencyBuilder; import com.spotify.missinglink.datamodel.MethodDependencyBuilder; import com.spotify.missinglink.datamodel.TypeDescriptors; - import java.lang.invoke.MethodHandle; import java.util.ArrayList; import java.util.Arrays; @@ -84,27 +83,25 @@ public void testSimpleConflict() throws Exception { final Artifact d2 = newArtifact("empty"); final CalledMethod methodCall = newCall(fooClass, methodOnlyInD1, false, true); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main") - .methodCalls(Collections.singleton(methodCall)).build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main").methodCalls(Collections.singleton(methodCall)).build(); - final DeclaredClass rootClass = newClass("com/Root") - .methods(methodMap(mainMethod)) - .build(); + final DeclaredClass rootClass = newClass("com/Root").methods(methodMap(mainMethod)).build(); final Artifact root = newArtifact("root", rootClass); final List classpath = Arrays.asList(root, d2); - final Conflict expectedConflict = new ConflictBuilder() - .dependency(dependency(rootClass.className(), mainMethod, methodCall)) - .reason("Class not found: com.d.Foo") - .category(ConflictCategory.CLASS_NOT_FOUND) - .usedBy(root.name()) - .existsIn(ConflictChecker.UNKNOWN_ARTIFACT_NAME) - .build(); + final Conflict expectedConflict = + new ConflictBuilder() + .dependency(dependency(rootClass.className(), mainMethod, methodCall)) + .reason("Class not found: com.d.Foo") + .category(ConflictCategory.CLASS_NOT_FOUND) + .usedBy(root.name()) + .existsIn(ConflictChecker.UNKNOWN_ARTIFACT_NAME) + .build(); - assertThat(conflictChecker - .check(root, classpath, classpath)) + assertThat(conflictChecker.check(root, classpath, classpath)) .isEqualTo(Collections.singletonList(expectedConflict)); } @@ -112,36 +109,33 @@ public void testSimpleConflict() throws Exception { public void testSimpleConflict2() throws Exception { final DeclaredMethod methodOnlyInD1 = newMethod(false, INT, "foo").build(); - final DeclaredClass fooClass = newClass("com/d/Foo") - .methods(methodMap(methodOnlyInD1)) - .build(); + final DeclaredClass fooClass = newClass("com/d/Foo").methods(methodMap(methodOnlyInD1)).build(); final DeclaredClass d2Class = newClass("com/d/Foo").build(); final Artifact d2 = newArtifact("D2", d2Class); final CalledMethod methodCall = newCall(fooClass, methodOnlyInD1, false, true); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); - final DeclaredClass rootClass = newClass("com/Root") - .methods(methodMap(mainMethod)) - .build(); + final DeclaredClass rootClass = newClass("com/Root").methods(methodMap(mainMethod)).build(); final Artifact root = newArtifact("root", rootClass); final List classpath = Arrays.asList(root, d2); - final Conflict expectedConflict = new ConflictBuilder() - .dependency(dependency(rootClass.className(), mainMethod, methodCall)) - .reason("Method not found: com.d.Foo.foo()") - .category(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND) - .usedBy(root.name()) - .existsIn(d2.name()) - .build(); + final Conflict expectedConflict = + new ConflictBuilder() + .dependency(dependency(rootClass.className(), mainMethod, methodCall)) + .reason("Method not found: com.d.Foo.foo()") + .category(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND) + .usedBy(root.name()) + .existsIn(d2.name()) + .build(); - assertThat(conflictChecker - .check(root, classpath, classpath)) + assertThat(conflictChecker.check(root, classpath, classpath)) .isEqualTo(Collections.singletonList(expectedConflict)); } @@ -151,15 +145,12 @@ public void testMissingField() throws Exception { final DeclaredClass d2Class = newClass("com/d/Foo").build(); final Artifact d2 = newArtifact("D2", d2Class); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .fieldAccesses(Collections.singleton( - newAccess("I", "foo", "com/d/Foo", 12) - )) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .fieldAccesses(Collections.singleton(newAccess("I", "foo", "com/d/Foo", 12))) + .build(); - final DeclaredClass rootClass = newClass("com/Root") - .methods(methodMap(mainMethod)) - .build(); + final DeclaredClass rootClass = newClass("com/Root").methods(methodMap(mainMethod)).build(); final Artifact root = newArtifact("root", rootClass); @@ -167,16 +158,16 @@ public void testMissingField() throws Exception { final AccessedField accessed = newAccess(INT, "foo", "com/d/Foo", 12); - final Conflict expectedConflict = new ConflictBuilder() - .dependency(dependency(rootClass.className(), mainMethod, accessed)) - .reason("Field not found: foo") - .category(ConflictCategory.FIELD_NOT_FOUND) - .usedBy(root.name()) - .existsIn(d2.name()) - .build(); + final Conflict expectedConflict = + new ConflictBuilder() + .dependency(dependency(rootClass.className(), mainMethod, accessed)) + .reason("Field not found: foo") + .category(ConflictCategory.FIELD_NOT_FOUND) + .usedBy(root.name()) + .existsIn(d2.name()) + .build(); - assertThat(conflictChecker - .check(root, classpath, classpath)) + assertThat(conflictChecker.check(root, classpath, classpath)) .isEqualTo(Collections.singletonList(expectedConflict)); } @@ -185,23 +176,23 @@ public void testNoConflictWithInheritedMethodCall() throws Exception { final DeclaredMethod methodOnlyInSuper = newMethod(false, INT, "foo").build(); final DeclaredClass superClass = newClass("com/super").methods(methodMap(methodOnlyInSuper)).build(); - final DeclaredClass subClass = newClass("com/Sub") - .parents(Collections.singleton(superClass.className())) - .build(); + final DeclaredClass subClass = + newClass("com/Sub").parents(Collections.singleton(superClass.className())).build(); final CalledMethod methodCall = newCall(subClass, methodOnlyInSuper, false, true); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); final DeclaredClass mainClass = newClass("com/Main").methods(methodMap(mainMethod)).build(); final Artifact artifact = newArtifact("art", superClass, subClass, mainClass); - assertThat(conflictChecker.check(artifact, - Collections.singletonList(artifact), - Collections.singletonList(artifact) - )).isEmpty(); + assertThat( + conflictChecker.check( + artifact, Collections.singletonList(artifact), Collections.singletonList(artifact))) + .isEmpty(); } @Test @@ -210,24 +201,26 @@ public void testNoConflictWithCovariantReturnType() throws Exception { final DeclaredClass superClass = newClass("com/Super").methods(methodMap(superMethod)).build(); final DeclaredMethod subMethod = newMethod(false, "Ljava/lang/String;", "foo").build(); - final DeclaredClass subClass = newClass("com/Sub").methods(methodMap(subMethod)) - .parents(Collections.singleton(superClass.className())) - .build(); + final DeclaredClass subClass = + newClass("com/Sub") + .methods(methodMap(subMethod)) + .parents(Collections.singleton(superClass.className())) + .build(); final CalledMethod methodCall = newCall(subClass, superMethod, false, true); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); final DeclaredClass mainClass = newClass("com/Main").methods(methodMap(mainMethod)).build(); final Artifact artifact = newArtifact("art", superClass, subClass, mainClass); - assertThat(conflictChecker - .check(artifact, - Collections.singletonList(artifact), - Collections.singletonList(artifact) - )).isEmpty(); + assertThat( + conflictChecker.check( + artifact, Collections.singletonList(artifact), Collections.singletonList(artifact))) + .isEmpty(); } @Test @@ -237,18 +230,19 @@ public void testNoConflictWithStaticCall() throws Exception { newClass("com/super").methods(methodMap(methodOnlyInSuper)).build(); final CalledMethod methodCall = newCall(superClass, methodOnlyInSuper, true, false); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); final DeclaredClass mainClass = newClass("com/Main").methods(methodMap(mainMethod)).build(); final Artifact artifact = newArtifact("art", superClass, mainClass); - assertThat(conflictChecker.check(artifact, - Collections.singletonList(artifact), - Collections.singletonList(artifact) - )).isEmpty(); + assertThat( + conflictChecker.check( + artifact, Collections.singletonList(artifact), Collections.singletonList(artifact))) + .isEmpty(); } @Test @@ -258,27 +252,28 @@ public void testConflictWithStaticToVirtualCall() throws Exception { newClass("com/super").methods(methodMap(methodOnlyInSuper)).build(); final CalledMethod methodCall = newCall(superClass, methodOnlyInSuper, true, false); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); final DeclaredClass mainClass = newClass("com/Main").methods(methodMap(mainMethod)).build(); final Artifact artifact = newArtifact("art", superClass, mainClass); - final Conflict expectedConflict = new ConflictBuilder() - .dependency(dependency(mainClass.className(), mainMethod, methodCall)) - .reason("Method not found: com.super.foo()") - .category(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND) - .usedBy(artifact.name()) - .existsIn(artifact.name()) - .build(); - - assertEquals(Collections.singletonList(expectedConflict), - conflictChecker.check(artifact, - Collections.singletonList(artifact), - Collections.singletonList(artifact) - )); + final Conflict expectedConflict = + new ConflictBuilder() + .dependency(dependency(mainClass.className(), mainMethod, methodCall)) + .reason("Method not found: com.super.foo()") + .category(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND) + .usedBy(artifact.name()) + .existsIn(artifact.name()) + .build(); + + assertEquals( + Collections.singletonList(expectedConflict), + conflictChecker.check( + artifact, Collections.singletonList(artifact), Collections.singletonList(artifact))); } @Test @@ -288,29 +283,32 @@ public void testConflictWithVirtualToStaticCall() throws Exception { newClass("com/super").methods(methodMap(methodOnlyInSuper)).build(); final CalledMethod methodCall = newCall(superClass, methodOnlyInSuper, false, true); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); - final DeclaredClass mainClass = newClass("com/Main") - .parents(Collections.singleton(superClass.className())) - .methods(methodMap(mainMethod)).build(); + final DeclaredClass mainClass = + newClass("com/Main") + .parents(Collections.singleton(superClass.className())) + .methods(methodMap(mainMethod)) + .build(); final Artifact artifact = newArtifact("art", superClass, mainClass); - final Conflict expectedConflict = new ConflictBuilder() - .dependency(dependency(mainClass.className(), mainMethod, methodCall)) - .reason("Method not found: com.super.foo()") - .category(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND) - .usedBy(artifact.name()) - .existsIn(artifact.name()) - .build(); - - assertEquals(Collections.singletonList(expectedConflict), - conflictChecker.check(artifact, - Collections.singletonList(artifact), - Collections.singletonList(artifact) - )); + final Conflict expectedConflict = + new ConflictBuilder() + .dependency(dependency(mainClass.className(), mainMethod, methodCall)) + .reason("Method not found: com.super.foo()") + .category(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND) + .usedBy(artifact.name()) + .existsIn(artifact.name()) + .build(); + + assertEquals( + Collections.singletonList(expectedConflict), + conflictChecker.check( + artifact, Collections.singletonList(artifact), Collections.singletonList(artifact))); } @Test @@ -321,21 +319,23 @@ public void testNoConflictWithStaticCallInSuper() throws Exception { ClassTypeDescriptor mainClassName = TypeDescriptors.fromClassName("com/Main"); final CalledMethod methodCall = newCall(mainClassName, methodOnlyInSuper, true); - final DeclaredMethod mainMethod = newMethod(true, VOID, "main", array(STRING)) - .methodCalls(Collections.singleton(methodCall)) - .build(); + final DeclaredMethod mainMethod = + newMethod(true, VOID, "main", array(STRING)) + .methodCalls(Collections.singleton(methodCall)) + .build(); - final DeclaredClass mainClass = newClass("com/Main") - .parents(Collections.singleton(superClass.className())) - .methods(methodMap(mainMethod)).build(); + final DeclaredClass mainClass = + newClass("com/Main") + .parents(Collections.singleton(superClass.className())) + .methods(methodMap(mainMethod)) + .build(); final Artifact artifact = newArtifact("art", superClass, mainClass); - assertEquals(Collections.emptyList(), - conflictChecker.check(artifact, - Collections.singletonList(artifact), - Collections.singletonList(artifact) - )); + assertEquals( + Collections.emptyList(), + conflictChecker.check( + artifact, Collections.singletonList(artifact), Collections.singletonList(artifact))); } @Test @@ -367,9 +367,8 @@ boolean foo(Object o) { List allArtifacts = new ArrayList<>(ClassLoadingUtil.bootstrapArtifacts()); allArtifacts.add(artifact); - assertThat(conflictChecker.check(artifact, - Collections.singletonList(artifact), - allArtifacts)).isEmpty(); + assertThat(conflictChecker.check(artifact, Collections.singletonList(artifact), allArtifacts)) + .isEmpty(); } @Test @@ -391,9 +390,7 @@ void main(HasVararg hasVararg) { List allArtifacts = new ArrayList<>(ClassLoadingUtil.bootstrapArtifacts()); allArtifacts.add(art); - assertThat(conflictChecker.check(art, - Collections.singletonList(art), - allArtifacts)).isEmpty(); + assertThat(conflictChecker.check(art, Collections.singletonList(art), allArtifacts)).isEmpty(); } @Test @@ -403,20 +400,14 @@ public void testNoConflictWithMethodHandlerInvoke() throws Exception { List allArtifacts = new ArrayList<>(ClassLoadingUtil.bootstrapArtifacts()); allArtifacts.add(art); - assertThat(conflictChecker.check(art, - Collections.singletonList(art), - allArtifacts)).isEmpty(); + assertThat(conflictChecker.check(art, Collections.singletonList(art), allArtifacts)).isEmpty(); } @Test public void shouldReportMissingParent() throws Exception { - class LostParent { - - } + class LostParent {} - class LacksParent extends LostParent { - - } + class LacksParent extends LostParent {} DeclaredClass parent = load(findClass(LostParent.class)); DeclaredClass mainClass = load(findClass(LacksParent.class)); @@ -426,34 +417,35 @@ class LacksParent extends LostParent { List allArtifacts = new ArrayList<>(ClassLoadingUtil.bootstrapArtifacts()); allArtifacts.add(artifact); - DeclaredMethod parentInit = parent.methods().values().stream() - .filter(declaredMethod -> declaredMethod.descriptor().name().equals("")) - .findFirst() - .get(); - DeclaredMethod init = mainClass.methods().values().stream() - .filter(declaredMethod -> declaredMethod.descriptor().name().equals("")) - .findFirst() - .get(); - - CalledMethod calledMethod = new CalledMethodBuilder() - .descriptor(parentInit.descriptor()) - .isStatic(parentInit.isStatic()) - .lineNumber(init.lineNumber()) - .owner(parent.className()) - .build(); - - Conflict expectedConflict = new ConflictBuilder() - .dependency(dependency(mainClass.className(), init, calledMethod)) - .reason("Class not found: com.spotify.missinglink.FeatureTest$1LostParent") - .category(ConflictCategory.CLASS_NOT_FOUND) - .usedBy(artifact.name()) - .existsIn(ConflictChecker.UNKNOWN_ARTIFACT_NAME) - .build(); - - assertThat(conflictChecker.check(artifact, - Collections.singletonList(artifact), - allArtifacts)) - + DeclaredMethod parentInit = + parent.methods().values().stream() + .filter(declaredMethod -> declaredMethod.descriptor().name().equals("")) + .findFirst() + .get(); + DeclaredMethod init = + mainClass.methods().values().stream() + .filter(declaredMethod -> declaredMethod.descriptor().name().equals("")) + .findFirst() + .get(); + + CalledMethod calledMethod = + new CalledMethodBuilder() + .descriptor(parentInit.descriptor()) + .isStatic(parentInit.isStatic()) + .lineNumber(init.lineNumber()) + .owner(parent.className()) + .build(); + + Conflict expectedConflict = + new ConflictBuilder() + .dependency(dependency(mainClass.className(), init, calledMethod)) + .reason("Class not found: com.spotify.missinglink.FeatureTest$1LostParent") + .category(ConflictCategory.CLASS_NOT_FOUND) + .usedBy(artifact.name()) + .existsIn(ConflictChecker.UNKNOWN_ARTIFACT_NAME) + .build(); + + assertThat(conflictChecker.check(artifact, Collections.singletonList(artifact), allArtifacts)) .containsExactly(expectedConflict); } @@ -461,9 +453,7 @@ class LacksParent extends LostParent { public void shouldNotReportConflictIfCatchingNoClassDefFoundError() throws Exception { class MissingClass { - public void foo() { - - } + public void foo() {} } class CatchesMissingClass { @@ -484,9 +474,7 @@ public void bar() { List allArtifacts = new ArrayList<>(ClassLoadingUtil.bootstrapArtifacts()); allArtifacts.add(artifact); - assertThat(conflictChecker.check(artifact, - Collections.singletonList(artifact), - allArtifacts)) + assertThat(conflictChecker.check(artifact, Collections.singletonList(artifact), allArtifacts)) .isEmpty(); } @@ -494,9 +482,7 @@ public void bar() { public void shouldNotReportConflictIfCatchingNoSuchMethodError() throws Exception { class MissingMethodClass { - public void foo() { - - } + public void foo() {} } class CatchesMissingMethod { @@ -510,9 +496,8 @@ public void bar() { } } - DeclaredClass missingMethod = DeclaredClassBuilder - .from(load(findClass(MissingMethodClass.class))) - .build(); + DeclaredClass missingMethod = + DeclaredClassBuilder.from(load(findClass(MissingMethodClass.class))).build(); DeclaredClass catcher = load(findClass(CatchesMissingMethod.class)); @@ -521,14 +506,12 @@ public void bar() { List allArtifacts = new ArrayList<>(ClassLoadingUtil.bootstrapArtifacts()); allArtifacts.add(artifact); - assertThat(conflictChecker.check(artifact, - Collections.singletonList(artifact), - allArtifacts)) + assertThat(conflictChecker.check(artifact, Collections.singletonList(artifact), allArtifacts)) .isEmpty(); } - private static Dependency dependency(ClassTypeDescriptor className, - DeclaredMethod declaredMethod, CalledMethod methodCall) { + private static Dependency dependency( + ClassTypeDescriptor className, DeclaredMethod declaredMethod, CalledMethod methodCall) { return new MethodDependencyBuilder() .fromClass(className) .fromMethod(declaredMethod.descriptor()) @@ -538,8 +521,8 @@ private static Dependency dependency(ClassTypeDescriptor className, .build(); } - private static Dependency dependency(ClassTypeDescriptor className, - DeclaredMethod declaredMethod, AccessedField field) { + private static Dependency dependency( + ClassTypeDescriptor className, DeclaredMethod declaredMethod, AccessedField field) { return new FieldDependencyBuilder() .fromClass(className) .fromMethod(declaredMethod.descriptor()) diff --git a/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java b/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java index cf84391a..6e587b81 100644 --- a/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java +++ b/core/src/test/java/com/spotify/missinglink/PrettyPrinterTest.java @@ -35,10 +35,10 @@ */ package com.spotify.missinglink; -import org.junit.Test; - import static org.junit.Assert.assertEquals; +import org.junit.Test; + public class PrettyPrinterTest { @Test diff --git a/core/src/test/java/com/spotify/missinglink/ReachableTest.java b/core/src/test/java/com/spotify/missinglink/ReachableTest.java index dc24c1bf..0c9d0563 100644 --- a/core/src/test/java/com/spotify/missinglink/ReachableTest.java +++ b/core/src/test/java/com/spotify/missinglink/ReachableTest.java @@ -35,7 +35,6 @@ */ package com.spotify.missinglink; - import static com.spotify.missinglink.Simple.INT; import static com.spotify.missinglink.Simple.VOID; import static com.spotify.missinglink.Simple.classMap; @@ -74,76 +73,73 @@ public void testUnreachable() { @Test public void testReachableViaCall() { DeclaredMethod remoteMethod = newMethod(false, VOID, "called").build(); - DeclaredClass remote = newClass("other/Unknown") - .methods(methodMap(remoteMethod)) - .build(); - DeclaredClass root = newClass("my/Root") - .methods(methodMap( - newMethod(false, VOID, "foo") - .methodCalls( - Collections.singleton(newCall(remote, remoteMethod, false, true))).build())) - .build(); + DeclaredClass remote = newClass("other/Unknown").methods(methodMap(remoteMethod)).build(); + DeclaredClass root = + newClass("my/Root") + .methods( + methodMap( + newMethod(false, VOID, "foo") + .methodCalls( + Collections.singleton(newCall(remote, remoteMethod, false, true))) + .build())) + .build(); Set myClasses = Collections.singleton(root); Map world = classMap(root, remote); Set reachable = ConflictChecker.reachableFrom(myClasses, world); - Set expected = new HashSet<>(Arrays.asList( - root.className(), remote.className() - )); + Set expected = + new HashSet<>(Arrays.asList(root.className(), remote.className())); assertEquals(expected, reachable); } @Test public void testReachableViaInheritance() { - DeclaredClass remote = newClass("other/Unknown") - .build(); - DeclaredClass root = newClass("my/Root") - .parents(Collections.singleton(TypeDescriptors.fromClassName("other/Unknown"))) - .build(); + DeclaredClass remote = newClass("other/Unknown").build(); + DeclaredClass root = + newClass("my/Root") + .parents(Collections.singleton(TypeDescriptors.fromClassName("other/Unknown"))) + .build(); Set myClasses = Collections.singleton(root); Map world = classMap(root, remote); Set reachable = ConflictChecker.reachableFrom(myClasses, world); - Set expected = new HashSet<>(Arrays.asList( - root.className(), remote.className() - )); + Set expected = + new HashSet<>(Arrays.asList(root.className(), remote.className())); assertEquals(expected, reachable); } @Test public void testReachableViaLdcLoad() { - DeclaredClass remote = newClass("other/Unknown") - .build(); - DeclaredClass root = newClass("my/Root") - .loadedClasses(Collections.singleton(TypeDescriptors.fromClassName("other/Unknown"))) - .build(); + DeclaredClass remote = newClass("other/Unknown").build(); + DeclaredClass root = + newClass("my/Root") + .loadedClasses(Collections.singleton(TypeDescriptors.fromClassName("other/Unknown"))) + .build(); Set myClasses = Collections.singleton(root); Map world = classMap(root, remote); Set reachable = ConflictChecker.reachableFrom(myClasses, world); - Set expected = new HashSet<>(Arrays.asList( - root.className(), remote.className() - )); + Set expected = + new HashSet<>(Arrays.asList(root.className(), remote.className())); assertEquals(expected, reachable); } @Test public void testReachableViaField() { - DeclaredClass remote = newClass("other/Unknown") - .fields(Collections.singleton(newField(INT, "remoteField"))) - .build(); - Map methods = methodMap( - newMethod(false, VOID, "foo") - .fieldAccesses( - Collections.singleton(Simple.newAccess(INT, "remoteField", "other/Unknown", 12))) - .build()); - DeclaredClass root = newClass("my/Root") - .methods(methods) - .build(); + DeclaredClass remote = + newClass("other/Unknown") + .fields(Collections.singleton(newField(INT, "remoteField"))) + .build(); + Map methods = + methodMap( + newMethod(false, VOID, "foo") + .fieldAccesses( + Collections.singleton( + Simple.newAccess(INT, "remoteField", "other/Unknown", 12))) + .build()); + DeclaredClass root = newClass("my/Root").methods(methods).build(); Set myClasses = Collections.singleton(root); Map world = classMap(root, remote); Set reachable = ConflictChecker.reachableFrom(myClasses, world); - Set expected = new HashSet<>(Arrays.asList( - root.className(), remote.className() - )); + Set expected = + new HashSet<>(Arrays.asList(root.className(), remote.className())); assertEquals(expected, reachable); } - } diff --git a/core/src/test/java/com/spotify/missinglink/Simple.java b/core/src/test/java/com/spotify/missinglink/Simple.java index 74d171f5..9d5fcdad 100644 --- a/core/src/test/java/com/spotify/missinglink/Simple.java +++ b/core/src/test/java/com/spotify/missinglink/Simple.java @@ -59,9 +59,7 @@ import java.util.Map; import java.util.stream.Collectors; -/** - * Created by axel on 04/06/15. - */ +/** Created by axel on 04/06/15. */ public class Simple { public static final String INT = "I"; @@ -73,41 +71,38 @@ public static String array(String of) { return "[" + of; } - /** * Empty new DeclaredClass, all collections filled in with empty values + * * @param className * @return */ public static DeclaredClassBuilder newClass(String className) { - return new DeclaredClassBuilder() - .className(TypeDescriptors.fromClassName(className)); + return new DeclaredClassBuilder().className(TypeDescriptors.fromClassName(className)); } - - public static DeclaredMethodBuilder newMethod(boolean isStatic, String returnDesc, String name, - String... parameterDesc) { - List param = Arrays.stream(parameterDesc) - .map(TypeDescriptors::fromRaw) - .collect(Collectors.toList()); + public static DeclaredMethodBuilder newMethod( + boolean isStatic, String returnDesc, String name, String... parameterDesc) { + List param = + Arrays.stream(parameterDesc).map(TypeDescriptors::fromRaw).collect(Collectors.toList()); return new DeclaredMethodBuilder() .isStatic(isStatic) - .descriptor(new MethodDescriptorBuilder() - .name(name) - .parameterTypes(param) - .returnType(TypeDescriptors.fromRaw(returnDesc)).build() - ); + .descriptor( + new MethodDescriptorBuilder() + .name(name) + .parameterTypes(param) + .returnType(TypeDescriptors.fromRaw(returnDesc)) + .build()); } public static CalledMethod newCall( - DeclaredClass owner, DeclaredMethod method, - boolean isStatic, boolean isVirtual) { + DeclaredClass owner, DeclaredMethod method, boolean isStatic, boolean isVirtual) { return newCall(owner.className(), method, isStatic); } - public static CalledMethod newCall(ClassTypeDescriptor owner, DeclaredMethod method, - boolean isStatic) { + public static CalledMethod newCall( + ClassTypeDescriptor owner, DeclaredMethod method, boolean isStatic) { return new CalledMethodBuilder() .owner(owner) .descriptor(method.descriptor()) @@ -125,17 +120,14 @@ public static Map classMap(DeclaredClass... public static Map methodMap(DeclaredMethod... methods) { Map map = new HashMap<>(); - for (DeclaredMethod method: methods) { + for (DeclaredMethod method : methods) { map.put(method.descriptor(), method); } return map; } public static DeclaredField newField(String desc, String name) { - return new DeclaredFieldBuilder() - .name(name) - .descriptor(TypeDescriptors.fromRaw(desc)) - .build(); + return new DeclaredFieldBuilder().name(name).descriptor(TypeDescriptors.fromRaw(desc)).build(); } public static AccessedField newAccess(String desc, String name, String owner, int lineNumber) { @@ -153,10 +145,6 @@ public static Artifact newArtifact(String name, DeclaredClass... classes) { map.put(clazz.className(), clazz); } - return new ArtifactBuilder() - .name(new ArtifactName(name)) - .classes(map) - .build(); + return new ArtifactBuilder().name(new ArtifactName(name)).classes(map).build(); } - } diff --git a/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java b/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java index 6726ddad..a024282a 100644 --- a/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java +++ b/core/src/test/java/com/spotify/missinglink/TypeDescriptorTest.java @@ -35,39 +35,49 @@ */ package com.spotify.missinglink; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + import com.spotify.missinglink.datamodel.ArrayTypeDescriptor; import com.spotify.missinglink.datamodel.ClassTypeDescriptor; import com.spotify.missinglink.datamodel.PrimitiveTypeDescriptor; import com.spotify.missinglink.datamodel.TypeDescriptor; import com.spotify.missinglink.datamodel.TypeDescriptors; import java.util.HashMap; -import org.junit.Test; - import java.util.InputMismatchException; import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import org.junit.Test; public class TypeDescriptorTest { @Test public void testEquality() { String[] signatures = { - "B", "S", "I", "J", "F", "D", "Z", "C", - "[D", "[[D", "[[[D", - "LFoo;", "LBar;", "[LFoo;", "Lfoo/bar/Baz;" + "B", + "S", + "I", + "J", + "F", + "D", + "Z", + "C", + "[D", + "[[D", + "[[[D", + "LFoo;", + "LBar;", + "[LFoo;", + "Lfoo/bar/Baz;" }; for (String signature1 : signatures) { for (String signature2 : signatures) { if (signature1.equals(signature2)) { - assertEquals(TypeDescriptors.fromRaw(signature1), - TypeDescriptors.fromRaw(signature2)); - assertEquals(TypeDescriptors.fromRaw(signature1).hashCode(), - TypeDescriptors.fromRaw(signature2).hashCode()); + assertEquals(TypeDescriptors.fromRaw(signature1), TypeDescriptors.fromRaw(signature2)); + assertEquals( + TypeDescriptors.fromRaw(signature1).hashCode(), + TypeDescriptors.fromRaw(signature2).hashCode()); } else { - assertNotEquals(TypeDescriptors.fromRaw(signature1), - TypeDescriptors.fromRaw(signature2)); + assertNotEquals(TypeDescriptors.fromRaw(signature1), TypeDescriptors.fromRaw(signature2)); } } } @@ -97,7 +107,6 @@ public void testDescriptions() { } } - @Test public void testTypes() { Map desc = new HashMap<>(); diff --git a/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java b/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java index 553e716b..d28cebb7 100644 --- a/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java +++ b/core/src/test/java/com/spotify/missinglink/datamodel/MethodDescriptorsTest.java @@ -35,24 +35,24 @@ */ package com.spotify.missinglink.datamodel; -import org.junit.Test; - import static org.junit.Assert.assertEquals; +import org.junit.Test; + public class MethodDescriptorsTest { @Test public void testMethodDescriptionParser() { MethodDescriptor desc1 = MethodDescriptors.fromDesc("([I[[Lfoo/Bar;Z)V", "baz"); - MethodDescriptor desc2 = new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("V")) - .parameterTypes( - TypeDescriptors.fromRaw("[I"), - TypeDescriptors.fromRaw("[[Lfoo/Bar;"), - TypeDescriptors.fromRaw("Z") - ) - .name("baz") - .build(); + MethodDescriptor desc2 = + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("V")) + .parameterTypes( + TypeDescriptors.fromRaw("[I"), + TypeDescriptors.fromRaw("[[Lfoo/Bar;"), + TypeDescriptors.fromRaw("Z")) + .name("baz") + .build(); assertEquals("Method descriptors should be identical", desc1, desc2); } diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java index e9a759cb..13b8c775 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/CheckMojo.java @@ -80,7 +80,9 @@ import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; -@Mojo(name = "check", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, +@Mojo( + name = "check", + requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, defaultPhase = LifecyclePhase.PROCESS_CLASSES) public class CheckMojo extends AbstractMojo { @@ -118,57 +120,53 @@ public class CheckMojo extends AbstractMojo { protected List includeScopes = new ArrayList<>(); /** - * Dependencies of the project to exclude from analysis. Defaults to an empty list. The - * dependency should be specified as an {@link Exclusion} containing a groupId and artifactId. - * Classes in these artifacts will not be checked for conflicts. + * Dependencies of the project to exclude from analysis. Defaults to an empty list. The dependency + * should be specified as an {@link Exclusion} containing a groupId and artifactId. Classes in + * these artifacts will not be checked for conflicts. */ - @Parameter - protected List excludeDependencies = new ArrayList<>(); + @Parameter protected List excludeDependencies = new ArrayList<>(); /** * Optional list of packages to ignore conflicts in where the source of the conflict is in one of * the specified packages. - *

- * This parameter does not exclude those packages from analysis, but the plugin will not - * output the conflicts that are found in those packages when the caller side of the conflict is - * in this package, and they will not count against the {@link #failOnConflicts} setting.

- *

- * For example, if the package "javax.foo" is in ignoreSourcePackages, then any conflict - * found originating in a javax.foo class is ignored. This is mostly the same behavior as {@link + * + *

This parameter does not exclude those packages from analysis, but the plugin will not output + * the conflicts that are found in those packages when the caller side of the conflict is in this + * package, and they will not count against the {@link #failOnConflicts} setting. + * + *

For example, if the package "javax.foo" is in ignoreSourcePackages, then any conflict found + * originating in a javax.foo class is ignored. This is mostly the same behavior as {@link * #excludeDependencies} but operates at a package name level instead of a groupId/artifactId - * level.

+ * level. */ - @Parameter - protected List ignoreSourcePackages = new ArrayList<>(); + @Parameter protected List ignoreSourcePackages = new ArrayList<>(); /** * Optional list of packages to ignore conflicts in where the destination/called-side of the * conflict is in one of the specified packages. - *

- * This parameter does not exclude those packages from analysis, but the plugin will not output + * + *

This parameter does not exclude those packages from analysis, but the plugin will not output * the conflicts that are found in those packages when the called side of the conflict is in this - * package, and they will not count against the {@link #failOnConflicts} setting.

- *

- * For example, if the package "javax.bar" is in ignoreDestinationPackages, then any conflict - * found having to do with calling a method in a class in javax.bar is ignored.

+ * package, and they will not count against the {@link #failOnConflicts} setting. + * + *

For example, if the package "javax.bar" is in ignoreDestinationPackages, then any conflict + * found having to do with calling a method in a class in javax.bar is ignored. */ - @Parameter - protected List ignoreDestinationPackages = new ArrayList<>(); + @Parameter protected List ignoreDestinationPackages = new ArrayList<>(); /** - * Optional: can be set to explicitly define the path to use for the bootclasspath - * containing the java.* / standard library classes. Note that this value is expected to look like - * a classpath - various file paths separated by the path separator. - *

- * When not set, the bootclasspath is determined by examining the "sun.boot.class.path" system - * on java 8 and below. On java 9 and above will use the modules. - * property.

+ * Optional: can be set to explicitly define the path to use for the bootclasspath containing the + * java.* / standard library classes. Note that this value is expected to look like a classpath - + * various file paths separated by the path separator. + * + *

When not set, the bootclasspath is determined by examining the "sun.boot.class.path" system + * on java 8 and below. On java 9 and above will use the modules. property. */ @Parameter(property = "misslink.bootClasspath") protected String bootClasspath; - - // TODO 6/1/15 mbrown -- how to hook into the Plexus container for proper DI lookups and the conventional maven plugin way of how to set up things like this + // TODO 6/1/15 mbrown -- how to hook into the Plexus container for proper DI lookups and the + // conventional maven plugin way of how to set up things like this protected ArtifactLoader artifactLoader = new ArtifactLoader(); protected ConflictChecker conflictChecker = new ConflictChecker(); @@ -181,20 +179,21 @@ public void execute() throws MojoExecutionException, MojoFailureException { // when verbose flag is set, log detailed messages to info log. otherwise log to debug. This is // so that verbose output from this plugin can be seen easily without having to specify mvn -X. - final Consumer log = verbose ? msg -> getLog().info(msg) - : msg -> getLog().debug(msg); + final Consumer log = verbose ? msg -> getLog().info(msg) : msg -> getLog().debug(msg); logDependencies(log); final Set categoriesToInclude; try { - categoriesToInclude = includeCategories.stream() - .map(ConflictCategory::valueOf) - .collect(Collectors.toSet()); + categoriesToInclude = + includeCategories.stream().map(ConflictCategory::valueOf).collect(Collectors.toSet()); } catch (IllegalArgumentException e) { getLog().error(e); throw new MojoExecutionException( - "Invalid value(s) for 'includeCategories': " + includeCategories + ". " - + "Valid choices are: " + Joiner.on(", ").join(ConflictCategory.values())); + "Invalid value(s) for 'includeCategories': " + + includeCategories + + ". " + + "Valid choices are: " + + Joiner.on(", ").join(ConflictCategory.values())); } Collection conflicts = loadArtifactsAndCheckConflicts(); @@ -214,9 +213,11 @@ public void execute() throws MojoExecutionException, MojoFailureException { outputConflicts(conflicts); if (failOnConflicts) { - final String message = conflicts.size() + " class/method conflicts found between source " - + "code in this project and the runtime dependencies from the Maven" - + " project. Look above for specific descriptions of each conflict"; + final String message = + conflicts.size() + + " class/method conflicts found between source " + + "code in this project and the runtime dependencies from the Maven" + + " project. Look above for specific descriptions of each conflict"; throw new MojoFailureException(message); } } @@ -225,53 +226,70 @@ public void execute() throws MojoExecutionException, MojoFailureException { private void logDependencies(Consumer log) { // project.getDependencies() only lists the declared dependencies, use .getArtifacts for // the transitive dependencies as well - final ArrayList - mavenDependencies = Lists.newArrayList(project.getArtifacts()); + final ArrayList mavenDependencies = + Lists.newArrayList(project.getArtifacts()); Collections.sort(mavenDependencies, Ordering.usingToString()); log.accept("Project has " + mavenDependencies.size() + " dependencies"); - mavenDependencies.stream() - .map(art -> "Dependency: " + art.toString()) - .forEach(log); + mavenDependencies.stream().map(art -> "Dependency: " + art.toString()).forEach(log); } - private Collection filterConflicts(Collection conflicts, - Set categoriesToInclude) { + private Collection filterConflicts( + Collection conflicts, Set categoriesToInclude) { if (!categoriesToInclude.isEmpty()) { - getLog().debug("Only including conflicts from categories: " - + Joiner.on(", ").join(categoriesToInclude)); - - conflicts = filterConflictsBy(conflicts, categoriesToInclude::contains, - num -> num + " conflicts removed based on includeCategories=" - + Joiner.on(", ").join(includeCategories) + ". " - + "Run plugin again without the 'includeCategories' parameter to see " - + "all conflicts that were found."); + getLog() + .debug( + "Only including conflicts from categories: " + + Joiner.on(", ").join(categoriesToInclude)); + + conflicts = + filterConflictsBy( + conflicts, + categoriesToInclude::contains, + num -> + num + + " conflicts removed based on includeCategories=" + + Joiner.on(", ").join(includeCategories) + + ". " + + "Run plugin again without the 'includeCategories' parameter to see " + + "all conflicts that were found."); } if (!ignoreSourcePackages.isEmpty()) { getLog().debug("Ignoring source packages: " + Joiner.on(", ").join(ignoreSourcePackages)); - final Predicate predicate = conflict -> !packageIsIgnored(ignoreSourcePackages, - conflict.dependency().fromClass()); - - conflicts = filterConflictsBy(conflicts, predicate, - num -> num + " conflicts found in ignored source packages. " - + "Run plugin again without the 'ignoreSourcePackages' parameter to see " - + "all conflicts that were found."); + final Predicate predicate = + conflict -> !packageIsIgnored(ignoreSourcePackages, conflict.dependency().fromClass()); + + conflicts = + filterConflictsBy( + conflicts, + predicate, + num -> + num + + " conflicts found in ignored source packages. " + + "Run plugin again without the 'ignoreSourcePackages' parameter to see " + + "all conflicts that were found."); } if (!ignoreDestinationPackages.isEmpty()) { - getLog().debug( - "Ignoring destination packages: " + Joiner.on(", ").join(ignoreDestinationPackages)); - - final Predicate predicate = conflict -> !packageIsIgnored(ignoreDestinationPackages, - conflict.dependency().targetClass()); - - conflicts = filterConflictsBy(conflicts, predicate, - num -> num + " conflicts found in ignored destination packages. " - + "Run plugin again without the 'ignoreDestinationPackages' parameter to see " - + "all conflicts that were found." - ); + getLog() + .debug( + "Ignoring destination packages: " + Joiner.on(", ").join(ignoreDestinationPackages)); + + final Predicate predicate = + conflict -> + !packageIsIgnored(ignoreDestinationPackages, conflict.dependency().targetClass()); + + conflicts = + filterConflictsBy( + conflicts, + predicate, + num -> + num + + " conflicts found in ignored destination packages. " + + "Run plugin again without the 'ignoreDestinationPackages' parameter to see " + + "all conflicts that were found."); } return conflicts; @@ -280,20 +298,20 @@ private Collection filterConflicts(Collection conflicts, /** * Repeated logic for filtering the collection of Conflicts based on a predicate. * - * @param conflicts conflicts to filter - * @param predicate predicate to filter by + * @param conflicts conflicts to filter + * @param predicate predicate to filter by * @param logMessage a function that when give the difference in size between the original - * collection and filtered collection, produces a message that will be logged - * as a warning to the user. + * collection and filtered collection, produces a message that will be logged as a warning to + * the user. * @return filtered conflicts */ - private Collection filterConflictsBy(Collection conflicts, - Predicate predicate, - Function logMessage) { + private Collection filterConflictsBy( + Collection conflicts, + Predicate predicate, + Function logMessage) { - final Set filteredConflicts = conflicts.stream() - .filter(predicate) - .collect(Collectors.toSet()); + final Set filteredConflicts = + conflicts.stream().filter(predicate).collect(Collectors.toSet()); if (filteredConflicts.size() != conflicts.size()) { final int diff = conflicts.size() - filteredConflicts.size(); @@ -305,24 +323,24 @@ private Collection filterConflictsBy(Collection conflicts, /** * Tests if the Conflict represented by this ClassTypeDescriptor (whether on the source-side or - * destination-side) is ignored based on the collection of IgnoredPackages. Reusable logic - * between + * destination-side) is ignored based on the collection of IgnoredPackages. Reusable logic between * ignoring source/destination packages. */ - private boolean packageIsIgnored(Collection ignoredPackages, - ClassTypeDescriptor classTypeDescriptor) { + private boolean packageIsIgnored( + Collection ignoredPackages, ClassTypeDescriptor classTypeDescriptor) { final String className = classTypeDescriptor.getClassName().replace('/', '.'); // this might be missing some corner-cases on naming rules: final String conflictPackageName = className.substring(0, className.lastIndexOf('.')); return ignoredPackages.stream() - .anyMatch(p -> { - final String ignoredPackageName = p.getPackage(); - return conflictPackageName.equals(ignoredPackageName) || - (p.isIgnoreSubpackages() && conflictPackageName - .startsWith(ignoredPackageName + ".")); - }); + .anyMatch( + p -> { + final String ignoredPackageName = p.getPackage(); + return conflictPackageName.equals(ignoredPackageName) + || (p.isIgnoreSubpackages() + && conflictPackageName.startsWith(ignoredPackageName + ".")); + }); } private Collection loadArtifactsAndCheckConflicts() { @@ -333,10 +351,10 @@ private Collection loadArtifactsAndCheckConflicts() { .filter(artifact -> includeScopes.contains(Scope.valueOf(artifact.getScope()))) .collect(Collectors.toList()); - getLog().debug("project dependencies: " + projectDeps.stream() - .map(this::mavenCoordinates) - .collect(Collectors.toList()) - ); + getLog() + .debug( + "project dependencies: " + + projectDeps.stream().map(this::mavenCoordinates).collect(Collectors.toList())); Stopwatch stopwatch = Stopwatch.createStarted(); // artifacts in runtime scope from the maven project (including transitives) @@ -354,22 +372,25 @@ private Collection loadArtifactsAndCheckConflicts() { stopwatch.stop(); getLog().debug("constructing bootstrap artifacts took: " + asMillis(stopwatch) + " ms"); - final ImmutableList allArtifacts = ImmutableList.builder() - .addAll(runtimeProjectArtifacts) - .addAll(bootstrapArtifacts) - .build(); + final ImmutableList allArtifacts = + ImmutableList.builder() + .addAll(runtimeProjectArtifacts) + .addAll(bootstrapArtifacts) + .build(); - final ImmutableList runtimeArtifactsAfterExclusions = ImmutableList.copyOf( - runtimeProjectArtifacts.stream() - .filter(artifact -> !isExcluded(artifact)) - .collect(Collectors.toSet()) - ); + final ImmutableList runtimeArtifactsAfterExclusions = + ImmutableList.copyOf( + runtimeProjectArtifacts.stream() + .filter(artifact -> !isExcluded(artifact)) + .collect(Collectors.toSet())); final Artifact projectArtifact = toArtifact(project.getBuild().getOutputDirectory()); if (projectArtifact.classes().isEmpty()) { - getLog().warn("No classes found in project build directory" - + " - did you run 'mvn compile' first?"); + getLog() + .warn( + "No classes found in project build directory" + + " - did you run 'mvn compile' first?"); } stopwatch.reset().start(); @@ -380,8 +401,8 @@ private Collection loadArtifactsAndCheckConflicts() { getLog().debug(" " + artifact.name().name()); } - final Collection conflicts = conflictChecker.check( - projectArtifact, runtimeArtifactsAfterExclusions, allArtifacts); + final Collection conflicts = + conflictChecker.check(projectArtifact, runtimeArtifactsAfterExclusions, allArtifacts); stopwatch.stop(); getLog().debug("conflict checking took: " + asMillis(stopwatch) + " ms"); @@ -390,17 +411,15 @@ private Collection loadArtifactsAndCheckConflicts() { return conflicts; } - private List loadBootstrapArtifacts(final String bootstrapClasspath) { if (bootstrapClasspath == null) { return Java9ModuleLoader.getJava9ModuleArtifacts((s, ex) -> getLog().warn(s, ex)); } else { - return constructArtifacts(Arrays.asList( - bootstrapClasspath.split(System.getProperty("path.separator")))); + return constructArtifacts( + Arrays.asList(bootstrapClasspath.split(System.getProperty("path.separator")))); } } - private String bootClassPathToUse() { if (this.bootClasspath != null) { getLog().debug("using configured boot classpath: " + this.bootClasspath); @@ -415,16 +434,21 @@ private String bootClassPathToUse() { // To be able to load the Java platform classes (i.e. java.util.*), we have to look at the // bootstrap class path - not sure about the standard way to find this. // (http://docs.oracle.com/javase/7/docs/technotes/tools/findingclasses.html) - // TODO 6/4/15 mbrown -- warn users that bootclasspath might be a different version (JAVA_HOME probably) than what they use for javac + // TODO 6/4/15 mbrown -- warn users that bootclasspath might be a different version (JAVA_HOME + // probably) than what they use for javac final String bootClasspath = System.getProperty("sun.boot.class.path"); getLog().debug("derived bootclasspath: " + bootClasspath); return bootClasspath; } private String mavenCoordinates(org.apache.maven.artifact.Artifact dep) { - return - dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion() + ":" + dep - .getScope(); + return dep.getGroupId() + + ":" + + dep.getArtifactId() + + ":" + + dep.getVersion() + + ":" + + dep.getScope(); } private boolean isExcluded(Artifact artifact) { @@ -432,8 +456,10 @@ private boolean isExcluded(Artifact artifact) { MavenArtifactName name = (MavenArtifactName) artifact.name(); // excluded if the exclusions lists contains a match return excludeDependencies.stream() - .anyMatch(excl -> excl.getGroupId().equals(name.groupId()) - && excl.getArtifactId().equals(name.artifactId())); + .anyMatch( + excl -> + excl.getGroupId().equals(name.groupId()) + && excl.getArtifactId().equals(name.artifactId())); } return false; } @@ -448,46 +474,55 @@ private void outputConflicts(Collection conflicts) { descriptions.put(ConflictCategory.METHOD_SIGNATURE_NOT_FOUND, "Method being called not found"); // group conflict by category - final Map> byCategory = conflicts.stream() - .collect(Collectors.groupingBy(Conflict::category)); - - byCategory.forEach((category, conflictsInCategory) -> { - final String desc = descriptions.getOrDefault(category, category.name().replace('_', ' ')); - getLog().warn(""); - getLog().warn("Category: " + desc); - - // next group by artifact containing the conflict - final Map> byArtifact = conflictsInCategory.stream() - .collect(Collectors.groupingBy(Conflict::usedBy)); - - byArtifact.forEach((artifactName, conflictsInArtifact) -> { - getLog().warn(" In artifact: " + artifactName.name()); - - // next group by class containing the conflict - final Map> byClassName = - conflictsInArtifact.stream() - .collect(Collectors.groupingBy(c -> c.dependency().fromClass())); - - byClassName.forEach((classDesc, conflictsInClass) -> { - getLog().warn(" In class: " + classDesc.toString()); - - conflictsInClass.stream() - .forEach(c -> { - final Dependency dep = c.dependency(); - getLog().warn(" In method: " + dep.fromMethod().prettyWithoutReturnType() - + optionalLineNumber(dep.fromLineNumber())); - getLog().warn(" " + dep.describe()); - getLog().warn(" Problem: " + c.reason()); - if (c.existsIn() != ConflictChecker.UNKNOWN_ARTIFACT_NAME) { - getLog().warn(" Found in: " + c.existsIn().name()); - } - // this could be smarter about separating each blob of warnings by method, but for - // now just output a bunch of dashes always - getLog().warn(" --------"); + final Map> byCategory = + conflicts.stream().collect(Collectors.groupingBy(Conflict::category)); + + byCategory.forEach( + (category, conflictsInCategory) -> { + final String desc = + descriptions.getOrDefault(category, category.name().replace('_', ' ')); + getLog().warn(""); + getLog().warn("Category: " + desc); + + // next group by artifact containing the conflict + final Map> byArtifact = + conflictsInCategory.stream().collect(Collectors.groupingBy(Conflict::usedBy)); + + byArtifact.forEach( + (artifactName, conflictsInArtifact) -> { + getLog().warn(" In artifact: " + artifactName.name()); + + // next group by class containing the conflict + final Map> byClassName = + conflictsInArtifact.stream() + .collect(Collectors.groupingBy(c -> c.dependency().fromClass())); + + byClassName.forEach( + (classDesc, conflictsInClass) -> { + getLog().warn(" In class: " + classDesc.toString()); + + conflictsInClass.stream() + .forEach( + c -> { + final Dependency dep = c.dependency(); + getLog() + .warn( + " In method: " + + dep.fromMethod().prettyWithoutReturnType() + + optionalLineNumber(dep.fromLineNumber())); + getLog().warn(" " + dep.describe()); + getLog().warn(" Problem: " + c.reason()); + if (c.existsIn() != ConflictChecker.UNKNOWN_ARTIFACT_NAME) { + getLog().warn(" Found in: " + c.existsIn().name()); + } + // this could be smarter about separating each blob of warnings by + // method, but for + // now just output a bunch of dashes always + getLog().warn(" --------"); + }); + }); }); }); - }); - }); } private String optionalLineNumber(int lineNumber) { @@ -497,10 +532,12 @@ private String optionalLineNumber(int lineNumber) { private Artifact toArtifact(String outputDirectory) { return new ArtifactBuilder() .name(new ArtifactName("project")) - .classes(Files.fileTreeTraverser().breadthFirstTraversal(new File(outputDirectory)) - .filter(f -> f.getName().endsWith(".class")) - .transform(this::loadClass) - .uniqueIndex(DeclaredClass::className)) + .classes( + Files.fileTreeTraverser() + .breadthFirstTraversal(new File(outputDirectory)) + .filter(f -> f.getName().endsWith(".class")) + .transform(this::loadClass) + .uniqueIndex(DeclaredClass::className)) .build(); } @@ -513,14 +550,15 @@ private DeclaredClass loadClass(File f) { } private ImmutableList constructArtifacts(Iterable entries) { - final List list = StreamSupport.stream(entries.spliterator(), false) - // don't inspect paths that don't exist. - // some bootclasspath entries, like sunrsasign.jar, are reported even if they - // don't exist on disk - ¯\_(ツ)_/¯ - .distinct() - .filter(this::filterValidClasspathEntries) - .map(this::filepathToArtifact) - .collect(Collectors.toList()); + final List list = + StreamSupport.stream(entries.spliterator(), false) + // don't inspect paths that don't exist. + // some bootclasspath entries, like sunrsasign.jar, are reported even if they + // don't exist on disk - ¯\_(ツ)_/¯ + .distinct() + .filter(this::filterValidClasspathEntries) + .map(this::filepathToArtifact) + .collect(Collectors.toList()); return ImmutableList.copyOf(list); } @@ -539,16 +577,16 @@ private boolean filterValid(File file) { private boolean filterValidClasspathEntries(org.apache.maven.artifact.Artifact artifact) { return filterValid(artifact.getFile()); - } private ImmutableList constructArtifacts( List mavenDeps) { - final List list = mavenDeps.stream() - .filter(this::filterValidClasspathEntries) - .map(this::mavenDepToArtifact) - .collect(Collectors.toList()); + final List list = + mavenDeps.stream() + .filter(this::filterValidClasspathEntries) + .map(this::mavenDepToArtifact) + .collect(Collectors.toList()); return ImmutableList.copyOf(list); } @@ -561,11 +599,8 @@ private Artifact mavenDepToArtifact(org.apache.maven.artifact.Artifact dep) { final File path = dep.getFile(); getLog().debug("loading artifact for path: " + path); - final MavenArtifactName name = new MavenArtifactName( - dep.getGroupId(), - dep.getArtifactId(), - dep.getVersion() - ); + final MavenArtifactName name = + new MavenArtifactName(dep.getGroupId(), dep.getArtifactId(), dep.getVersion()); return doArtifactLoad(() -> artifactLoader.load(name, path)); } diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java index 5845eaee..d69356f4 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/IgnoredPackage.java @@ -35,10 +35,10 @@ */ package com.spotify.missinglink.maven; -import com.google.common.base.Preconditions; - import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.Preconditions; + /** * Package names to be ignored when reporting conflicts. A package name is a String like * "javax.servlet" (not a regular expression). By default, subpackages of the specified package are @@ -52,8 +52,7 @@ public class IgnoredPackage { private String name; private boolean ignoreSubpackages = true; - public IgnoredPackage() { - } + public IgnoredPackage() {} public IgnoredPackage(String name, boolean ignoreSubpackages) { this.name = checkNotNull(name); @@ -93,7 +92,6 @@ public boolean equals(Object o) { return false; } return name.equals(that.name); - } @Override @@ -105,9 +103,12 @@ public int hashCode() { @Override public String toString() { - return "IgnoredPackage{" + - "name='" + name + '\'' + - ", ignoreSubpackages=" + ignoreSubpackages + - '}'; + return "IgnoredPackage{" + + "name='" + + name + + '\'' + + ", ignoreSubpackages=" + + ignoreSubpackages + + '}'; } } diff --git a/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java b/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java index e9e08e30..d6ce3f63 100644 --- a/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java +++ b/maven-plugin/src/main/java/com/spotify/missinglink/maven/MavenArtifactName.java @@ -35,10 +35,10 @@ */ package com.spotify.missinglink.maven; -import com.spotify.missinglink.datamodel.ArtifactName; - import static com.google.common.base.Preconditions.checkNotNull; +import com.spotify.missinglink.datamodel.ArtifactName; + public class MavenArtifactName extends ArtifactName { private final String groupId; @@ -85,7 +85,6 @@ public boolean equals(Object o) { return false; } return version.equals(that.version); - } @Override @@ -99,7 +98,16 @@ public int hashCode() { @Override public String toString() { - return "MavenArtifactName{" + "groupId='" + groupId + '\'' + ", artifactId='" + artifactId - + '\'' + ", version='" + version + '\'' + '}'; + return "MavenArtifactName{" + + "groupId='" + + groupId + + '\'' + + ", artifactId='" + + artifactId + + '\'' + + ", version='" + + version + + '\'' + + '}'; } } diff --git a/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java b/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java index bb419ca4..fd1bd38d 100644 --- a/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java +++ b/maven-plugin/src/test/java/com/spotify/missinglink/maven/CheckMojoTest.java @@ -35,10 +35,19 @@ */ package com.spotify.missinglink.maven; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; - import com.spotify.missinglink.ArtifactLoader; import com.spotify.missinglink.Conflict; import com.spotify.missinglink.Conflict.ConflictCategory; @@ -57,7 +66,8 @@ import com.spotify.missinglink.datamodel.MethodDependencyBuilder; import com.spotify.missinglink.datamodel.MethodDescriptorBuilder; import com.spotify.missinglink.datamodel.TypeDescriptors; - +import java.io.File; +import java.util.List; import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -74,98 +84,86 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyListOf; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - /** * A note on the maven plugin testing harness: - *

- * The MojoRule class (and AbstractMojoTestCase) use pom.xml files in the src/test/project folder + * + *

The MojoRule class (and AbstractMojoTestCase) use pom.xml files in the src/test/project folder * to test constructing and invoking an instance of a plugin from the Maven pom.xml format. - *

- * However these pom.xml files used for testing *the Mojo* do not load a real MavenProject - + * + *

However these pom.xml files used for testing *the Mojo* do not load a real MavenProject - * nothing in the pom.xml files used for testing is used to construct a real project, i.e. there is - * no - * dependency resolution, etc. - *

- * So inside the CheckDependencyConflictsMojo class, calls to things like project.getArtifacts() + * no dependency resolution, etc. + * + *

So inside the CheckDependencyConflictsMojo class, calls to things like project.getArtifacts() * to look at the resolved transitive dependencies will always return an empty list. - *

- * The only real value of testing the Mojo using this method is to test how the fields of the Mojo - * are set based on the POM XML file. - *

+ * + *

The only real value of testing the Mojo using this method is to test how the fields of the + * Mojo are set based on the POM XML file. */ public class CheckMojoTest { private static final Logger log = LoggerFactory.getLogger(CheckMojoTest.class); - @Rule - public MojoRule rule = new MojoRule(); + @Rule public MojoRule rule = new MojoRule(); - @Rule - public TestResources resources = new TestResources(); + @Rule public TestResources resources = new TestResources(); - @Rule - public ExpectedException exception = ExpectedException.none(); + @Rule public ExpectedException exception = ExpectedException.none(); private final ArtifactLoader artifactLoader = mock(ArtifactLoader.class); private final ConflictChecker conflictChecker = mock(ConflictChecker.class); @Before public void setUp() throws Exception { - //default behavior for mocks + // default behavior for mocks - final Artifact emptyArtifact = new ArtifactBuilder() - .name(new ArtifactName("empty")) - .classes(ImmutableMap.of()) - .build(); + final Artifact emptyArtifact = + new ArtifactBuilder() + .name(new ArtifactName("empty")) + .classes(ImmutableMap.of()) + .build(); when(artifactLoader.load(any(File.class))).thenReturn(emptyArtifact); - when(artifactLoader.load(any(ArtifactName.class), any(File.class))).thenAnswer(invocation -> - ArtifactBuilder.from(emptyArtifact) - .name((ArtifactName) invocation.getArguments()[0]) - .build()); + when(artifactLoader.load(any(ArtifactName.class), any(File.class))) + .thenAnswer( + invocation -> + ArtifactBuilder.from(emptyArtifact) + .name((ArtifactName) invocation.getArguments()[0]) + .build()); setMockConflictResults(ImmutableList.of()); } private void setMockConflictResults(ImmutableList results) { - when(conflictChecker.check(any(Artifact.class), - anyListOf(Artifact.class), - anyListOf(Artifact.class)) - ).thenReturn(results); + when(conflictChecker.check( + any(Artifact.class), anyListOf(Artifact.class), anyListOf(Artifact.class))) + .thenReturn(results); } private CheckMojo getMojo(String dirName) throws Exception { final File basedir = resources.getBasedir(dirName); log.debug("Constructing Mojo against test basedir {}", basedir); - final CheckMojo mojo = - (CheckMojo) rule.lookupConfiguredMojo(basedir, "check"); + final CheckMojo mojo = (CheckMojo) rule.lookupConfiguredMojo(basedir, "check"); mojo.artifactLoader = artifactLoader; mojo.conflictChecker = conflictChecker; return mojo; } - private static Conflict conflict(ConflictCategory category, ClassTypeDescriptor inClass, - DeclaredMethod caller, CalledMethod callee, String reason) { - - final Dependency dep = new MethodDependencyBuilder() - .fromClass(inClass) - .fromMethod(caller.descriptor()) - .fromLineNumber(callee.lineNumber()) - .targetClass(callee.owner()) - .targetMethod(callee.descriptor()) - .build(); + private static Conflict conflict( + ConflictCategory category, + ClassTypeDescriptor inClass, + DeclaredMethod caller, + CalledMethod callee, + String reason) { + + final Dependency dep = + new MethodDependencyBuilder() + .fromClass(inClass) + .fromMethod(caller.descriptor()) + .fromLineNumber(callee.lineNumber()) + .targetClass(callee.owner()) + .targetMethod(callee.descriptor()) + .build(); return new ConflictBuilder() .category(category) @@ -176,35 +174,39 @@ private static Conflict conflict(ConflictCategory category, ClassTypeDescriptor .build(); } - private ImmutableList mockConflicts(ConflictCategory category, - ConflictCategory... additionalCategories) { + private ImmutableList mockConflicts( + ConflictCategory category, ConflictCategory... additionalCategories) { final ClassTypeDescriptor ctd = TypeDescriptors.fromClassName("com/foo/Whatever"); return mockConflicts(ctd, category, additionalCategories); - } - private ImmutableList mockConflicts(ClassTypeDescriptor ctd, - ConflictCategory category, - ConflictCategory... additionalCategories) { - - final CalledMethod callee = new CalledMethodBuilder() - .owner(TypeDescriptors.fromClassName("com/foo/Bar")) - .descriptor(new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) - .name("bat") - .parameterTypes(ImmutableList.of()) - .build()) - .build(); - - final DeclaredMethod caller = new DeclaredMethodBuilder() - .methodCalls(ImmutableSet.of()) - .fieldAccesses(ImmutableSet.of()) - .descriptor(new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) - .name("bat") - .parameterTypes(ImmutableList.of(TypeDescriptors.fromRaw("I"))) - .build()) - .build(); + private ImmutableList mockConflicts( + ClassTypeDescriptor ctd, + ConflictCategory category, + ConflictCategory... additionalCategories) { + + final CalledMethod callee = + new CalledMethodBuilder() + .owner(TypeDescriptors.fromClassName("com/foo/Bar")) + .descriptor( + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) + .name("bat") + .parameterTypes(ImmutableList.of()) + .build()) + .build(); + + final DeclaredMethod caller = + new DeclaredMethodBuilder() + .methodCalls(ImmutableSet.of()) + .fieldAccesses(ImmutableSet.of()) + .descriptor( + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) + .name("bat") + .parameterTypes(ImmutableList.of(TypeDescriptors.fromRaw("I"))) + .build()) + .build(); ImmutableList.Builder builder = ImmutableList.builder(); builder.add(conflict(category, ctd, caller, callee, "reasons!")); @@ -231,13 +233,14 @@ public void doesNotFailOnConflictByDefault() throws Exception { } /** - * Tests that when {@link CheckMojo#failOnConflicts} is set to true, then the - * build is failed if ConflictChecker returns conflicts. + * Tests that when {@link CheckMojo#failOnConflicts} is set to true, then the build is failed if + * ConflictChecker returns conflicts. */ @Test public void failsOnConflictWhenOptionIsSet() throws Exception { - setMockConflictResults(mockConflicts( - ConflictCategory.CLASS_NOT_FOUND, ConflictCategory.METHOD_SIGNATURE_NOT_FOUND)); + setMockConflictResults( + mockConflicts( + ConflictCategory.CLASS_NOT_FOUND, ConflictCategory.METHOD_SIGNATURE_NOT_FOUND)); exception.expect(MojoFailureException.class); exception.expectMessage("conflicts found"); @@ -251,11 +254,12 @@ public void failsOnConflictWhenOptionIsSet() throws Exception { */ @Test public void testBadValuesForIncludeCategories() throws Exception { - when(conflictChecker.check(any(Artifact.class), - anyListOf(Artifact.class), - anyListOf(Artifact.class)) - ).thenThrow(new RuntimeException("Mojo should not get as far as checking conflicts if the " - + "configuration is bad!")); + when(conflictChecker.check( + any(Artifact.class), anyListOf(Artifact.class), anyListOf(Artifact.class))) + .thenThrow( + new RuntimeException( + "Mojo should not get as far as checking conflicts if the " + + "configuration is bad!")); exception.expect(MojoExecutionException.class); exception.expectMessage("Invalid value(s) for 'includeCategories'"); @@ -281,19 +285,16 @@ public void testExcludeArtifacts() throws Exception { final CheckMojo mojo = getMojo("exclude-dependencies"); // inject some dependencies to exclude later - mojo.project.setArtifacts(ImmutableSet.of( - new DefaultArtifact("com.foobar", "bizbat", "1.2.3", "compile", "jar", "", null) - )); + mojo.project.setArtifacts( + ImmutableSet.of( + new DefaultArtifact("com.foobar", "bizbat", "1.2.3", "compile", "jar", "", null))); mojo.execute(); ArgumentCaptor toCheck = ArgumentCaptor.forClass(ImmutableList.class); - verify(conflictChecker).check( - any(Artifact.class), - toCheck.capture(), - anyListOf(Artifact.class) - ); + verify(conflictChecker) + .check(any(Artifact.class), toCheck.capture(), anyListOf(Artifact.class)); assertThat(toCheck.getValue()).isEmpty(); } @@ -312,43 +313,50 @@ public void testIgnoreSourcePackages() throws Exception { .hasSize(2) .contains( new IgnoredPackage("groovy.lang", true), - new IgnoredPackage("org.codehaus.janino", false) - ); + new IgnoredPackage("org.codehaus.janino", false)); setMockConflictResults( - mockConflicts(TypeDescriptors.fromClassName("groovy.lang.foo.Bar"), - ConflictCategory.CLASS_NOT_FOUND) - ); + mockConflicts( + TypeDescriptors.fromClassName("groovy.lang.foo.Bar"), + ConflictCategory.CLASS_NOT_FOUND)); mojo.execute(); } @Test public void testIgnoreDestinationPackages() throws Exception { - final CalledMethod callee = new CalledMethodBuilder() - .owner(TypeDescriptors.fromClassName("com/foo/Bar")) - .descriptor(new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) - .name("bat") - .parameterTypes(ImmutableList.of()) - .build()) - .build(); - - final DeclaredMethod caller = new DeclaredMethodBuilder() - .methodCalls(ImmutableSet.of()) - .fieldAccesses(ImmutableSet.of()) - .descriptor(new MethodDescriptorBuilder() - .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) - .name("bat") - .parameterTypes(ImmutableList.of(TypeDescriptors.fromRaw("I"))) - .build()) - .build(); + final CalledMethod callee = + new CalledMethodBuilder() + .owner(TypeDescriptors.fromClassName("com/foo/Bar")) + .descriptor( + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) + .name("bat") + .parameterTypes(ImmutableList.of()) + .build()) + .build(); + + final DeclaredMethod caller = + new DeclaredMethodBuilder() + .methodCalls(ImmutableSet.of()) + .fieldAccesses(ImmutableSet.of()) + .descriptor( + new MethodDescriptorBuilder() + .returnType(TypeDescriptors.fromRaw("Ljava/lang/String;")) + .name("bat") + .parameterTypes(ImmutableList.of(TypeDescriptors.fromRaw("I"))) + .build()) + .build(); // a conflict from com/Whatever => com/foo/Bar.bat where the latter class cannot be found - setMockConflictResults(ImmutableList.of( - conflict(ConflictCategory.CLASS_NOT_FOUND, TypeDescriptors.fromClassName("com/Whatever"), - caller, callee, "class com/foo/Bar not found") - )); + setMockConflictResults( + ImmutableList.of( + conflict( + ConflictCategory.CLASS_NOT_FOUND, + TypeDescriptors.fromClassName("com/Whatever"), + caller, + callee, + "class com/foo/Bar not found"))); final CheckMojo mojo = getMojo("ignore-destination-packages"); @@ -406,16 +414,15 @@ public void shouldCheckProvidedIfConfigured() throws Exception { } private void setupProvidedArtifact(CheckMojo mojo) { - ImmutableSet artifacts = ImmutableSet.of( - new DefaultArtifact("com.foobar", "bizbat", "1.2.3", "compile", "jar", "", null), - new DefaultArtifact("com.foobar", "boobaz", "1.2.3", "provided", "jar", "", null) - ); + ImmutableSet artifacts = + ImmutableSet.of( + new DefaultArtifact("com.foobar", "bizbat", "1.2.3", "compile", "jar", "", null), + new DefaultArtifact("com.foobar", "boobaz", "1.2.3", "provided", "jar", "", null)); // use '.' as the file so as to pretend that the artifacts are class file dependencies artifacts.stream().forEach(artifact -> artifact.setFile(new File("."))); mojo.project.setArtifacts(artifacts); - } private Matcher hasId(String artifactId) { @@ -438,7 +445,8 @@ private Matcher> listWithProvidedArtifact() { protected boolean matchesSafely(List item) { return item.stream() .filter(artifact -> "boobaz".equals(artifact.name().name())) - .findFirst().isPresent(); + .findFirst() + .isPresent(); } @Override diff --git a/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java b/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java index 6bc073e4..4ebec4bc 100644 --- a/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java +++ b/maven-plugin/src/test/java/com/spotify/missinglink/maven/MavenArtifactNameTest.java @@ -35,10 +35,10 @@ */ package com.spotify.missinglink.maven; -import org.junit.Test; - import static org.junit.Assert.assertEquals; +import org.junit.Test; + public class MavenArtifactNameTest { @Test @@ -46,5 +46,4 @@ public void testNameAsCoordinates() { final MavenArtifactName name = new MavenArtifactName("com.spotify", "secret-project", "1.2.3"); assertEquals("com.spotify:secret-project:1.2.3", name.name()); } - } From a0f2f256be2a90dc6f1baeec253fea10e06f2c71 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 13:20:32 -0500 Subject: [PATCH 6/7] add note to CONTRIBUTING.md about fmt plugin --- CONTRIBUTING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c19cdcb5..139b4274 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,11 @@ weren't. With Java 8+ and Maven 3+, simply run `mvn install` in the project directory. For any patches, please make sure that they pass all tests (and that new tests -are added), and that no Checkstyle rules are violated. +are added). + +Code will be automatically formatted by +when you run `mvn compile`. The CI build will fail if any code is not formatted +according to the plugin's rules. New code should be accompanied by tests that increase the overall code coverage of the project. From 88363144af744ec8508df5471ef1916555af14e6 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Tue, 23 Feb 2021 13:26:29 -0500 Subject: [PATCH 7/7] downgrade fmt-maven-plugin to allow running on Java 8 --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1f5a027e..953b4c6a 100644 --- a/pom.xml +++ b/pom.xml @@ -169,7 +169,8 @@ com.coveo fmt-maven-plugin - 2.10 + + 2.9.1