Skip to content

Commit 6756cba

Browse files
Add gradle task to verify bytecode version of compiled classes (#2954)
1 parent b8b005b commit 6756cba

2 files changed

Lines changed: 83 additions & 1 deletion

File tree

build.gradle.kts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
1818
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
1919
import de.undercouch.gradle.tasks.download.Download
20+
import net.dv8tion.jda.tasks.VerifyBytecodeVersion
2021
import net.dv8tion.jda.tasks.Version
2122
import net.dv8tion.jda.tasks.applyAudioExclusions
2223
import net.dv8tion.jda.tasks.applyOpusExclusions
@@ -327,7 +328,7 @@ tasks.withType<JavaCompile> {
327328
options.compilerArgs.addAll(args)
328329
}
329330

330-
tasks.named<JavaCompile>("compileJava").configure {
331+
val compileJava by tasks.getting(JavaCompile::class) {
331332
dependsOn(generateJavaSources)
332333
source = generateJavaSources.get().source
333334
}
@@ -393,6 +394,17 @@ tasks.test {
393394
}
394395
}
395396

397+
val verifyBytecodeVersion by tasks.registering(VerifyBytecodeVersion::class) {
398+
group = "verification"
399+
400+
expectedMajorVersion = 52
401+
classes.from(compileJava.outputs.files.asFileTree.matching {
402+
include("**/*.class")
403+
})
404+
}
405+
406+
compileJava.finalizedBy(verifyBytecodeVersion)
407+
396408

397409
////////////////////////////////////
398410
// //
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
3+
*
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
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+
17+
package net.dv8tion.jda.tasks
18+
19+
import org.gradle.api.DefaultTask
20+
import org.gradle.api.GradleException
21+
import org.gradle.api.file.ConfigurableFileCollection
22+
import org.gradle.api.provider.Property
23+
import org.gradle.api.tasks.CacheableTask
24+
import org.gradle.api.tasks.Input
25+
import org.gradle.api.tasks.InputFiles
26+
import org.gradle.api.tasks.PathSensitive
27+
import org.gradle.api.tasks.PathSensitivity
28+
import org.gradle.api.tasks.TaskAction
29+
import java.io.File
30+
31+
@CacheableTask
32+
abstract class VerifyBytecodeVersion : DefaultTask() {
33+
@get:InputFiles
34+
@get:PathSensitive(PathSensitivity.RELATIVE)
35+
abstract val classes: ConfigurableFileCollection
36+
37+
@get:Input
38+
abstract val expectedMajorVersion: Property<Int>
39+
40+
@TaskAction
41+
fun verify() {
42+
val badFiles = classes.filter { it.readBytecodeVersion() != expectedMajorVersion.get() }.toList()
43+
44+
if (badFiles.isNotEmpty()) {
45+
println("Found ${badFiles.size} files that did not have the bytecode version ${expectedMajorVersion.get()}")
46+
println("The following classes have the wrong bytecode version:")
47+
for (file in badFiles) {
48+
println("\t- ${file.path} has version ${file.readBytecodeVersion()}")
49+
}
50+
51+
throw GradleException("Some compiled classes have the wrong bytecode version.")
52+
}
53+
}
54+
}
55+
56+
private val validClassHeaderBytes = listOf(0xCA.toByte(), 0xFE.toByte(), 0xBA.toByte(), 0xBE.toByte())
57+
58+
private fun File.readBytecodeVersion(): Int? = inputStream().buffered().use { stream ->
59+
val header = stream.readNBytes(8)
60+
if (header.size < 8) {
61+
return null
62+
}
63+
64+
if (header.take(4) != validClassHeaderBytes) {
65+
return null
66+
}
67+
68+
// Big-endian major version: bytes[6..7]
69+
return ((header[6].toInt() and 0xFF) shl 8) or (header[7].toInt() and 0xFF)
70+
}

0 commit comments

Comments
 (0)