Skip to content

Commit 55c33b4

Browse files
authored
Add the concept of an "attribute" to Dependency. (#5881)
Add the concept of an "attribute" to Dependency We use maven Dependency to model Gradle dependencies, but Gradle and Maven allocate information differently. Maven has a separate dependency management section, whereas in Gradle BOMs are intermixed with regular dependencies and differentiated via the "category" attribute. Being unable to reliably differentiate `platform()` and project dependencies from binary dependencies has limited how accurate our model updates can be. UpgradeDependencyVersion and UpgradeTransitiveDependencyVersion try their best but without some of this information inaccuracies add up over time. For example right now dependency vulnerability check will tell you a gradle project that uses `platform()` has a vulnerability if the BOM references a vulnerable dependency, even if that dependency isn't actually used in the project. Because to our model a BOM currently just looks like any other dependency.
1 parent 452e04b commit 55c33b4

File tree

15 files changed

+698
-5
lines changed

15 files changed

+698
-5
lines changed

rewrite-core/src/main/java/org/openrewrite/RecipeSerializer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.fasterxml.jackson.dataformat.smile.SmileGenerator;
2929
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
3030
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
31+
import lombok.Getter;
3132

3233
import java.io.IOException;
3334
import java.io.InputStream;
@@ -37,6 +38,7 @@
3738
import java.lang.reflect.InvocationTargetException;
3839
import java.lang.reflect.Method;
3940

41+
@Getter
4042
public class RecipeSerializer {
4143
private final ObjectMapper mapper;
4244

rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependency.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.openrewrite.java.search.UsesType;
3030
import org.openrewrite.java.tree.J;
3131
import org.openrewrite.java.tree.JavaSourceFile;
32+
import org.openrewrite.kotlin.tree.K;
3233
import org.openrewrite.maven.table.MavenMetadataFailures;
3334
import org.openrewrite.maven.tree.GroupArtifact;
3435
import org.openrewrite.semver.Semver;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.gradle.attributes;
17+
18+
19+
import org.jspecify.annotations.Nullable;
20+
import org.openrewrite.maven.attributes.Attribute;
21+
22+
/**
23+
* Attribute representing the <a href="https://docs.gradle.org/current/javadoc/org/gradle/api/attributes/Bundling.html">bundling</a> of a dependency variant.
24+
*/
25+
public enum Bundling implements Attribute {
26+
/**
27+
* Dependencies are provided externally at runtime (not bundled)
28+
*/
29+
EXTERNAL,
30+
31+
/**
32+
* Dependencies are embedded inside the artifact (fat jar)
33+
*/
34+
EMBEDDED,
35+
36+
/**
37+
* Dependencies are shadowed (relocated) inside the artifact
38+
*/
39+
SHADOWED;
40+
41+
public static String key() {
42+
return "org.gradle.dependency.bundling";
43+
}
44+
45+
public static @Nullable Bundling from(@Nullable String bundling) {
46+
if (bundling == null) {
47+
return null;
48+
}
49+
switch (bundling) {
50+
case "external":
51+
return Bundling.EXTERNAL;
52+
case "embedded":
53+
return Bundling.EMBEDDED;
54+
case "shadowed":
55+
return Bundling.SHADOWED;
56+
default:
57+
return null;
58+
}
59+
}
60+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.gradle.attributes;
17+
18+
import org.jspecify.annotations.Nullable;
19+
import org.openrewrite.maven.attributes.Attribute;
20+
21+
/**
22+
* See <a href="https://docs.gradle.org/current/javadoc/org/gradle/api/attributes/Category.html">category javadoc</a>
23+
*/
24+
public enum Category implements Attribute {
25+
/**
26+
* The documentation category
27+
*/
28+
DOCUMENTATION,
29+
30+
/**
31+
* The enforced platform, usually a synthetic variant derived from the platform
32+
*/
33+
ENFORCED_PLATFORM,
34+
35+
/**
36+
* The library category
37+
*/
38+
LIBRARY,
39+
40+
/**
41+
* Typically marks a dependency as <a href="https://docs.gradle.org/current/userguide/platforms.html">platform</a>.
42+
* "platform" has very similar semantics to a Maven bill of materials (BOM) added to the "import" scope via dependencyManagement.
43+
*/
44+
REGULAR_PLATFORM,
45+
46+
/**
47+
* The verification category, for variants which contain the results of running verification tasks (e.g. Test, Jacoco).
48+
*/
49+
VERIFICATION;
50+
51+
public static String key() {
52+
return "org.gradle.category";
53+
}
54+
55+
public static @Nullable Category from(@Nullable String category) {
56+
if (category == null) {
57+
return null;
58+
}
59+
switch (category) {
60+
case "documentation":
61+
return Category.DOCUMENTATION;
62+
case "enforced-platform":
63+
return Category.ENFORCED_PLATFORM;
64+
case "library":
65+
return Category.LIBRARY;
66+
case "platform":
67+
return Category.REGULAR_PLATFORM;
68+
case "verification":
69+
return Category.VERIFICATION;
70+
default:
71+
return null;
72+
}
73+
}
74+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.gradle.attributes;
17+
18+
import org.jspecify.annotations.Nullable;
19+
import org.openrewrite.maven.attributes.Attribute;
20+
21+
/**
22+
* See Gradle javadocs for <a href="https://docs.gradle.org/current/javadoc/org/gradle/api/attributes/DocsType.html">org.gradle.api.attributes.DocsType</a>
23+
*/
24+
public enum DocsType implements Attribute {
25+
/**
26+
* The typical documentation for Java APIs
27+
*/
28+
JAVADOC,
29+
30+
/**
31+
* The source files of the module
32+
*/
33+
SOURCES,
34+
/**
35+
* A user manual
36+
*/
37+
USER_MANUAL,
38+
/**
39+
* Samples illustrating how to use the software module
40+
*/
41+
SAMPLES,
42+
/**
43+
* The typical documentation for native APIs
44+
*/
45+
DOXYGEN;
46+
47+
public static String key() {
48+
return "org.gradle.docstype";
49+
}
50+
51+
public static @Nullable DocsType from(@Nullable String docsType) {
52+
if (docsType == null) {
53+
return null;
54+
}
55+
switch (docsType) {
56+
case "javadoc":
57+
return DocsType.JAVADOC;
58+
case "sources":
59+
return DocsType.SOURCES;
60+
case "user-manual":
61+
return DocsType.USER_MANUAL;
62+
case "samples":
63+
return DocsType.SAMPLES;
64+
case "doxygen":
65+
return DocsType.DOXYGEN;
66+
default:
67+
return null;
68+
}
69+
}
70+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.gradle.attributes;
17+
18+
import org.jspecify.annotations.Nullable;
19+
import org.openrewrite.maven.attributes.Attribute;
20+
21+
/**
22+
* Attribute representing the technical elements of a <a href="https://docs.gradle.org/current/javadoc/org/gradle/api/attributes/LibraryElements.html">library variant</a>.
23+
*/
24+
public enum LibraryElements implements Attribute {
25+
/**
26+
* The JVM classes format
27+
*/
28+
CLASSES,
29+
30+
/**
31+
* The JVM class files and resources
32+
*/
33+
CLASSES_AND_RESOURCES,
34+
35+
/**
36+
* Dynamic libraries for native modules
37+
*/
38+
DYNAMIC_LIB,
39+
40+
/**
41+
* Header files for C++
42+
*/
43+
HEADERS_CPLUSPLUS,
44+
45+
/**
46+
* The JVM archive format
47+
*/
48+
JAR,
49+
50+
/**
51+
* Link archives for native modules
52+
*/
53+
LINK_ARCHIVE,
54+
/**
55+
* Objects for native modules
56+
*/
57+
OBJECTS,
58+
59+
/**
60+
* JVM resources
61+
*/
62+
RESOURCES;
63+
64+
public static String key() {
65+
return "org.gradle.libraryelements";
66+
}
67+
68+
public static @Nullable LibraryElements from(@Nullable String libraryElements) {
69+
if (libraryElements == null) {
70+
return null;
71+
}
72+
switch (libraryElements) {
73+
case "classes":
74+
return LibraryElements.CLASSES;
75+
case "classes+resources":
76+
return LibraryElements.CLASSES_AND_RESOURCES;
77+
case "dynamic-lib":
78+
return LibraryElements.DYNAMIC_LIB;
79+
case "headers-cplusplus":
80+
return LibraryElements.HEADERS_CPLUSPLUS;
81+
case "jar":
82+
return LibraryElements.JAR;
83+
case "link-archive":
84+
return LibraryElements.LINK_ARCHIVE;
85+
case "objects":
86+
return LibraryElements.OBJECTS;
87+
case "resources":
88+
return LibraryElements.RESOURCES;
89+
default:
90+
return null;
91+
}
92+
}
93+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.gradle.attributes;
17+
18+
import lombok.Value;
19+
import org.openrewrite.maven.attributes.Attribute;
20+
21+
/**
22+
* Marks a dependency as representing another Gradle project within the same multi-project build
23+
*/
24+
@Value
25+
public class ProjectAttribute implements Attribute {
26+
/**
27+
* The path to the project within the gradle build.
28+
* Note that this is not a filesystem path. Delimiters are ":"
29+
* So the root project's path is ":"
30+
* A subproject may have a path like ":someDir:projectName"
31+
*/
32+
String path;
33+
34+
public static String key() {
35+
return "org.gradle.api.artifacts.ProjectDependency";
36+
}
37+
38+
public static ProjectAttribute from(String path) {
39+
return new ProjectAttribute(path);
40+
}
41+
}

0 commit comments

Comments
 (0)