mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[testFramework] IJPL-200805: Do not use Unsafe for checking if a class is initialized
`Unsafe` is removed in JDK 25 GitOrigin-RevId: d726e9b3b5a8e92971dcd6f47264543c1521a9d7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0e9ed14f70
commit
98a89917c8
@@ -13,8 +13,10 @@ import com.intellij.util.containers.HashingStrategy;
|
||||
import com.intellij.util.containers.RefValueHashMapUtil;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -39,17 +41,17 @@ public final class DebugReflectionUtil {
|
||||
}));
|
||||
|
||||
private static final Field[] EMPTY_FIELD_ARRAY = new Field[0];
|
||||
private static final Method Unsafe_shouldBeInitialized;
|
||||
private static final Method ClassLoader_findLoadedClass;
|
||||
|
||||
static {
|
||||
Method shouldBeInitialized;
|
||||
Method findLoadedClass;
|
||||
try {
|
||||
shouldBeInitialized = ReflectionUtil.getDeclaredMethod(Class.forName("sun.misc.Unsafe"), "shouldBeInitialized", Class.class);
|
||||
findLoadedClass = ReflectionUtil.getDeclaredMethod(Class.forName("java.lang.ClassLoader"), "findLoadedClass", String.class);
|
||||
}
|
||||
catch (ClassNotFoundException ignored) {
|
||||
shouldBeInitialized = null;
|
||||
findLoadedClass = null;
|
||||
}
|
||||
Unsafe_shouldBeInitialized = shouldBeInitialized;
|
||||
ClassLoader_findLoadedClass = findLoadedClass;
|
||||
}
|
||||
|
||||
private static Field @NotNull [] getAllFields(@NotNull Class<?> aClass) {
|
||||
@@ -98,11 +100,12 @@ public final class DebugReflectionUtil {
|
||||
return type.isPrimitive() || type == String.class || type == Class.class || type.isArray() && isTrivial(type.getComponentType());
|
||||
}
|
||||
|
||||
private static boolean isInitialized(@NotNull Class<?> root) {
|
||||
if (Unsafe_shouldBeInitialized == null) return false;
|
||||
@VisibleForTesting
|
||||
@ApiStatus.Internal
|
||||
public static boolean isInitialized(ClassLoader classLoader, @NotNull String rootName) {
|
||||
boolean isInitialized = false;
|
||||
try {
|
||||
isInitialized = !(Boolean)Unsafe_shouldBeInitialized.invoke(ReflectionUtil.getUnsafe(), root);
|
||||
isInitialized = ClassLoader_findLoadedClass.invoke(classLoader, rootName) != null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
@@ -199,7 +202,7 @@ public final class DebugReflectionUtil {
|
||||
}
|
||||
}
|
||||
// check for objects leaking via static fields. process initialized classes only
|
||||
if (root instanceof Class && isInitialized((Class<?>)root)) {
|
||||
if (root instanceof Class && isInitialized(((Class<?>)root).getClassLoader(), ((Class<?>)root).getName())) {
|
||||
for (Field field : getAllFields((Class<?>)root)) {
|
||||
if ((field.getModifiers() & Modifier.STATIC) == 0) continue;
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.util
|
||||
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.util.ref.DebugReflectionUtil
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
|
||||
@TestApplication
|
||||
class DebugReflectionUtilTest {
|
||||
|
||||
@Test
|
||||
fun `isInitialized returns false for not initialized class`() {
|
||||
assertFalse {
|
||||
DebugReflectionUtil.isInitialized(Thread.currentThread().contextClassLoader, "com.intellij.util.ThisClassWillFailOnInitialization")
|
||||
}
|
||||
assertThrows<ExceptionInInitializerError> {
|
||||
ThisClassWillFailOnInitialization()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `isInitialized returns false for not initialized class 2`() {
|
||||
assertFalse {
|
||||
DebugReflectionUtil.isInitialized(Thread.currentThread().contextClassLoader, "com.intellij.util.ThisClassWillNotFailOnInitialization")
|
||||
}
|
||||
ThisClassWillNotFailOnInitialization()
|
||||
assertTrue {
|
||||
DebugReflectionUtil.isInitialized(Thread.currentThread().contextClassLoader, "com.intellij.util.ThisClassWillNotFailOnInitialization")
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.util;
|
||||
|
||||
import kotlin.jvm.JvmStatic;
|
||||
|
||||
public class ThisClassWillFailOnInitialization {
|
||||
|
||||
static {
|
||||
willFail();
|
||||
}
|
||||
|
||||
private static void willFail() {
|
||||
throw new RuntimeException("This class will fail on initialization");
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.util;
|
||||
|
||||
public class ThisClassWillNotFailOnInitialization {
|
||||
}
|
||||
Reference in New Issue
Block a user