|
| 1 | +/* |
| 2 | + * Copyright 2014-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. |
| 3 | + */ |
| 4 | + |
| 5 | +import sun.misc.Unsafe |
| 6 | +import java.lang.reflect.Field |
| 7 | + |
| 8 | +@Suppress("UNCHECKED_CAST") |
| 9 | +internal object ConfigurationCacheWorkarounds { |
| 10 | + private val ignoreBeanFieldsField = Class.forName("org.gradle.internal.serialize.beans.services.Workarounds") |
| 11 | + .getDeclaredField("ignoredBeanFields") |
| 12 | + .apply { isAccessible = true } |
| 13 | + |
| 14 | + private val unsafe = runCatching { |
| 15 | + Unsafe::class.java.getDeclaredField("theUnsafe") |
| 16 | + .apply { isAccessible = true } |
| 17 | + .get(null) as Unsafe |
| 18 | + }.getOrNull() |
| 19 | + |
| 20 | + private var ignoreBeanFields = ignoreBeanFieldsField.get(null) as Array<Pair<String, String>> |
| 21 | + set(value) { |
| 22 | + val isSet = runCatching { unsafe?.setFinalStatic(ignoreBeanFieldsField, value) }.getOrNull() != null |
| 23 | + if (isSet) { |
| 24 | + field = value |
| 25 | + } else { |
| 26 | + // If we can't set a new array to the field, fallback to replacing array's content with new values |
| 27 | + for (i in 0..minOf(field.lastIndex, value.lastIndex)) field[i] = value[i] |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + /** Registers fields that should be excluded from configuration cache. */ |
| 32 | + fun addIgnoredBeanFields(vararg fields: Pair<String, String>) { |
| 33 | + ignoreBeanFields = fields as Array<Pair<String, String>> + ignoreBeanFields |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +@Suppress("DEPRECATION") |
| 38 | +private fun Unsafe.setFinalStatic(field: Field, value: Any) { |
| 39 | + val fieldBase = staticFieldBase(field) |
| 40 | + val fieldOffset = staticFieldOffset(field) |
| 41 | + |
| 42 | + putObject(fieldBase, fieldOffset, value) |
| 43 | +} |
0 commit comments