1
1
package org.gradle.android.workarounds
2
2
3
+ import com.google.common.annotations.VisibleForTesting
4
+ import com.google.common.collect.Lists
3
5
import org.gradle.android.AndroidIssue
4
6
import org.gradle.api.Project
5
7
import org.gradle.api.artifacts.transform.CacheableTransform
@@ -24,6 +26,8 @@ import javax.inject.Inject
24
26
import java.lang.module.ModuleDescriptor
25
27
import java.nio.ByteBuffer
26
28
import java.nio.file.Files
29
+ import java.util.stream.Collectors
30
+ import java.util.stream.Stream
27
31
28
32
/**
29
33
* Works around cache misses due to the custom Java runtime used when source compatibility is set higher
@@ -40,13 +44,18 @@ class JdkImageWorkaround implements Workaround {
40
44
41
45
@Override
42
46
void apply (Project project ) {
47
+ // We would prefer not to configure this if a jdkImage is not in use, but the attributes
48
+ // being ignored are unlikely to ever have a runtime impact. Doing this outside of task
49
+ // configuration prevents issues with things that use the tooling api to finalize the
50
+ // runtime configuration before querying (and instantiating) task configurations.
51
+ applyRuntimeClasspathNormalization(project)
52
+
43
53
applyToAllAndroidVariants(project) { variant ->
44
54
variant. javaCompileProvider. configure { JavaCompile task ->
45
55
def jdkImageInput = getJdkImageInput(task)
46
56
if (jdkImageInput != null ) {
47
57
setupExtractedJdkImageInputTransform(project, getJvmHome(task))
48
58
replaceCommandLineProvider(task, jdkImageInput)
49
- applyRuntimeClasspathNormalization(task. project)
50
59
}
51
60
}
52
61
}
@@ -178,28 +187,76 @@ class JdkImageWorkaround implements Workaround {
178
187
179
188
// Capture the module descriptor ignoring the version, which is not enforced anyways
180
189
File moduleInfoFile = new File (targetDir, ' java.base/module-info.class' )
181
- ModuleDescriptor strippedDescriptor = captureModuleDescriptorWithoutVersion(moduleInfoFile)
190
+ ModuleDescriptor descriptor = captureModuleDescriptorWithoutVersion(moduleInfoFile)
182
191
File descriptorData = new File (targetDir, " module-descriptor.txt" )
183
- descriptorData. text = strippedDescriptor . toString( )
192
+ descriptorData. text = serializeDescriptor(descriptor )
184
193
185
194
fileOperations. delete {
186
195
delete(moduleInfoFile)
187
196
}
188
197
}
189
198
190
199
private static ModuleDescriptor captureModuleDescriptorWithoutVersion (File moduleFile ) {
191
- ModuleDescriptor descriptor = ModuleDescriptor . read(ByteBuffer . wrap(Files . readAllBytes(moduleFile. toPath())))
192
- ModuleDescriptor.Builder strippedDescriptor = ModuleDescriptor . newModule(descriptor. name())
193
- strippedDescriptor. packages(descriptor. packages())
194
- if (descriptor. mainClass(). present) {
195
- strippedDescriptor. mainClass(descriptor. mainClass(). get())
200
+ return ModuleDescriptor . read(ByteBuffer . wrap(Files . readAllBytes(moduleFile. toPath())))
201
+ }
202
+
203
+ @VisibleForTesting
204
+ static String serializeDescriptor (ModuleDescriptor descriptor ) {
205
+ StringBuilder sb = new StringBuilder ()
206
+
207
+ if (descriptor. isOpen())
208
+ sb. append(" open " )
209
+ sb. append(" module { name: " ). append(descriptor. name())
210
+ if (! descriptor. requires(). isEmpty())
211
+ sb. append(" , " ). append(descriptor. requires(). sort(). collect { serializeRequires(it) })
212
+ if (! descriptor. uses(). isEmpty())
213
+ sb. append(" , uses: " ). append(descriptor. uses(). sort())
214
+ if (! descriptor. exports(). isEmpty())
215
+ sb. append(" , exports: " ). append(descriptor. exports(). sort(). collect { serializeExports(it) })
216
+ if (! descriptor. opens(). isEmpty())
217
+ sb. append(" , opens: " ). append(descriptor. opens(). sort(). collect { serializeOpens(it) })
218
+ if (! descriptor. provides(). isEmpty()) {
219
+ sb. append(" , provides: " ). append(descriptor. provides(). sort(). collect { serializeProvides(it) })
196
220
}
197
- descriptor. exports(). each { strippedDescriptor. exports(it) }
198
- descriptor. opens(). each {strippedDescriptor. opens(it) }
199
- descriptor. provides(). each { strippedDescriptor. provides(it) }
200
- descriptor. requires(). each { strippedDescriptor. requires(it) }
201
- descriptor. uses()each { strippedDescriptor. uses(it) }
202
- return strippedDescriptor. build()
221
+ sb. append(" }" )
222
+ return sb. toString()
223
+ }
224
+
225
+ private static String serializeRequires (ModuleDescriptor.Requires requires ) {
226
+ String requireString
227
+ if (! requires. compiledVersion(). empty) {
228
+ requireString = requires. name() + " (@" + requires. compiledVersion() + " )"
229
+ } else {
230
+ requireString = requires. name()
231
+ }
232
+ return withSerializedMods(requires. modifiers(), requireString)
233
+ }
234
+
235
+ private static String serializeExports (ModuleDescriptor.Exports exports ) {
236
+ String s = withSerializedMods(exports. modifiers(), exports. source())
237
+ if (exports. targets(). isEmpty())
238
+ return s;
239
+ else
240
+ return s + " to " + exports. targets(). sort()
241
+ }
242
+
243
+ private static String serializeOpens (ModuleDescriptor.Opens opens ) {
244
+ String s = withSerializedMods(opens. modifiers(), opens. source())
245
+ if (opens. targets(). isEmpty())
246
+ return s;
247
+ else
248
+ return s + " to " + opens. targets(). sort()
249
+ }
250
+
251
+ private static String serializeProvides (ModuleDescriptor.Provides provides ) {
252
+ return provides. service() + " with " + Lists . newArrayList(provides. providers()). sort()
253
+ }
254
+
255
+ static <M> String withSerializedMods (Set<M> mods , String what ) {
256
+ return (Stream . concat(mods. stream(). map(e -> e. toString()
257
+ .toLowerCase(Locale . ROOT )). sorted(),
258
+ Stream . of(what)))
259
+ .collect(Collectors . joining(" " ))
203
260
}
204
261
}
205
262
}
0 commit comments