d547a707bf
Reviewed-by: alanb, jpai, mchung, lancea
238 lines
10 KiB
Java
238 lines
10 KiB
Java
/*
|
|
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8227046
|
|
* @summary reflection test for sealed classes
|
|
* @compile SealedClassesReflectionTest.java
|
|
* @run testng/othervm SealedClassesReflectionTest
|
|
*/
|
|
|
|
import java.lang.annotation.*;
|
|
import java.lang.constant.ClassDesc;
|
|
import java.lang.reflect.*;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import org.testng.annotations.*;
|
|
import static org.testng.Assert.*;
|
|
|
|
@Test
|
|
public class SealedClassesReflectionTest {
|
|
|
|
sealed class SealedClass1 permits FinalSubclass1, NonSealedSubclass1 {}
|
|
final class FinalSubclass1 extends SealedClass1 {}
|
|
non-sealed class NonSealedSubclass1 extends SealedClass1 {}
|
|
|
|
sealed class SealedClass2 permits FinalSubclass2, FinalSubclass3 {}
|
|
final class FinalSubclass2 extends SealedClass2 {}
|
|
final class FinalSubclass3 extends SealedClass2 {}
|
|
|
|
sealed class SealedClass3 permits FinalSubclass4, SealedSubclass1 {}
|
|
final class FinalSubclass4 extends SealedClass3 {}
|
|
sealed class SealedSubclass1 extends SealedClass3 permits FinalSubclass5 {}
|
|
final class FinalSubclass5 extends SealedSubclass1 {}
|
|
|
|
sealed interface SealedInt1 permits FinalSubclass6, NonSealedSubInt1 {}
|
|
final class FinalSubclass6 implements SealedInt1 {}
|
|
non-sealed interface NonSealedSubInt1 extends SealedInt1 {}
|
|
|
|
sealed interface SealedInt2 permits FinalSubclass7, FinalSubclass8 {}
|
|
final class FinalSubclass7 implements SealedInt2 {}
|
|
final class FinalSubclass8 implements SealedInt2 {}
|
|
|
|
sealed interface SealedInt3 permits FinalSubclass9, SealedSubInt1, SealedSubclass2 {}
|
|
final class FinalSubclass9 implements SealedInt3 {}
|
|
sealed interface SealedSubInt1 extends SealedInt3 permits FinalSubclass10 {}
|
|
final class FinalSubclass10 implements SealedSubInt1 {}
|
|
sealed class SealedSubclass2 implements SealedInt3 permits NonSealedSubclass2 {}
|
|
non-sealed class NonSealedSubclass2 extends SealedSubclass2 {}
|
|
|
|
@DataProvider(name = "sealedClasses")
|
|
public Object[][] sealedClassesData() {
|
|
return List.of(
|
|
SealedClass1.class,
|
|
SealedClass2.class,
|
|
SealedClass3.class,
|
|
SealedSubclass1.class,
|
|
SealedInt1.class,
|
|
SealedInt2.class,
|
|
SealedInt3.class,
|
|
SealedSubInt1.class
|
|
).stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
|
|
}
|
|
|
|
@Test(dataProvider = "sealedClasses")
|
|
public void testSealedClasses(Class<?> cls) {
|
|
assertTrue(cls.isSealed());
|
|
assertTrue(!Modifier.isFinal(cls.getModifiers()));
|
|
assertTrue(cls.getPermittedSubclasses() != null);
|
|
assertTrue(cls.getPermittedSubclasses().length > 0);
|
|
}
|
|
|
|
@DataProvider(name = "notSealedClasses")
|
|
public Object[][] notSealedClassesData() {
|
|
return List.of(
|
|
Object.class,
|
|
void.class, Void.class, Void[].class,
|
|
byte.class, byte[].class, Byte.class, Byte[].class,
|
|
short.class, short[].class, Short.class, Short[].class,
|
|
char.class, char[].class, Character.class, Character[].class,
|
|
int.class, int[].class, Integer.class, Integer[].class,
|
|
long.class, long[].class, Long.class, Long[].class,
|
|
float.class, float[].class, Float.class, Float[].class,
|
|
double.class, double[].class, Double.class, Double[].class,
|
|
boolean.class, boolean[].class, Boolean.class, Boolean[].class,
|
|
String.class, String[].class
|
|
).stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
|
|
}
|
|
|
|
@Test(dataProvider = "notSealedClasses")
|
|
public void testNotSealedClasses(Class<?> cls) {
|
|
assertTrue(!cls.isSealed());
|
|
assertTrue(cls.getPermittedSubclasses() == null);
|
|
}
|
|
|
|
@DataProvider(name = "non_sealedClasses")
|
|
public Object[][] non_sealedClassesData() {
|
|
return List.of(
|
|
NonSealedSubclass1.class,
|
|
NonSealedSubInt1.class,
|
|
NonSealedSubclass2.class
|
|
).stream().map(c -> new Object[] {c}).toArray(Object[][]::new);
|
|
}
|
|
|
|
@Test(dataProvider = "non_sealedClasses")
|
|
public void testnon_sealedClasses(Class<?> cls) {
|
|
assertTrue(!cls.isSealed());
|
|
assertTrue(!Modifier.isFinal(cls.getModifiers()));
|
|
assertTrue((cls.getSuperclass() != null && cls.getSuperclass().isSealed()) || Arrays.stream(cls.getInterfaces()).anyMatch(Class::isSealed));
|
|
assertTrue(cls.getPermittedSubclasses() == null);
|
|
}
|
|
|
|
@DataProvider(name = "reflectionData")
|
|
public Object[][] reflectionData() {
|
|
return new Object[][] {
|
|
new Object[] {
|
|
SealedClass1.class,
|
|
2,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass1", "SealedClassesReflectionTest$NonSealedSubclass1"},
|
|
new Class<?>[] {FinalSubclass1.class, NonSealedSubclass1.class},
|
|
new SealedStatus[] {SealedStatus.FINAL, SealedStatus.NON_SEALED}},
|
|
|
|
new Object[] {
|
|
SealedClass2.class,
|
|
2,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass2", "SealedClassesReflectionTest$FinalSubclass3"},
|
|
new Class<?>[] {FinalSubclass2.class, FinalSubclass3.class},
|
|
new SealedStatus[] {SealedStatus.FINAL, SealedStatus.FINAL}},
|
|
|
|
new Object[] {
|
|
SealedClass3.class,
|
|
2,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass4", "SealedClassesReflectionTest$SealedSubclass1"},
|
|
new Class<?>[] {FinalSubclass4.class, SealedSubclass1.class},
|
|
new SealedStatus[] {SealedStatus.FINAL, SealedStatus.SEALED}},
|
|
|
|
new Object[] {
|
|
SealedSubclass1.class,
|
|
1,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass5"},
|
|
new Class<?>[] {FinalSubclass5.class},
|
|
new SealedStatus[] {SealedStatus.FINAL}},
|
|
|
|
new Object[] {
|
|
SealedInt1.class,
|
|
2,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass6", "SealedClassesReflectionTest$NonSealedSubInt1"},
|
|
new Class<?>[] {FinalSubclass6.class, NonSealedSubInt1.class},
|
|
new SealedStatus[] {SealedStatus.FINAL, SealedStatus.NON_SEALED}},
|
|
|
|
new Object[] {
|
|
SealedInt2.class,
|
|
2,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass7", "SealedClassesReflectionTest$FinalSubclass8"},
|
|
new Class<?>[] {FinalSubclass7.class, FinalSubclass8.class},
|
|
new SealedStatus[] {SealedStatus.FINAL, SealedStatus.FINAL}},
|
|
|
|
new Object[] {
|
|
SealedInt3.class,
|
|
3,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass9",
|
|
"SealedClassesReflectionTest$SealedSubInt1",
|
|
"SealedClassesReflectionTest$SealedSubclass2"},
|
|
new Class<?>[] {FinalSubclass9.class, SealedSubInt1.class, SealedSubclass2.class},
|
|
new SealedStatus[] {SealedStatus.FINAL, SealedStatus.SEALED, SealedStatus.SEALED}},
|
|
|
|
new Object[] {
|
|
SealedSubInt1.class,
|
|
1,
|
|
new String[] {"SealedClassesReflectionTest$FinalSubclass10"},
|
|
new Class<?>[] {FinalSubclass10.class},
|
|
new SealedStatus[] {SealedStatus.FINAL}},
|
|
|
|
new Object[] {
|
|
SealedSubclass2.class,
|
|
1,
|
|
new String[] {"SealedClassesReflectionTest$NonSealedSubclass2"},
|
|
new Class<?>[] {NonSealedSubclass2.class},
|
|
new SealedStatus[] {SealedStatus.NON_SEALED}},
|
|
};
|
|
}
|
|
|
|
enum SealedStatus {
|
|
SEALED, NON_SEALED, FINAL
|
|
}
|
|
|
|
@Test(dataProvider = "reflectionData")
|
|
public void testSealedReflection(Class<?> sealedClass,
|
|
int numberOfSubclasses,
|
|
String[] subclassDescriptors,
|
|
Class<?>[] subclasses,
|
|
SealedStatus[] subclassSealedStatus)
|
|
throws ReflectiveOperationException
|
|
{
|
|
assertTrue(sealedClass.isSealed());
|
|
assertTrue(sealedClass.getPermittedSubclasses().length == numberOfSubclasses);
|
|
int i = 0;
|
|
for (Class<?> cd : sealedClass.getPermittedSubclasses()) {
|
|
assertTrue(cd.getName().equals(subclassDescriptors[i]), "expected: " + subclassDescriptors[i] + " found: " + cd.getName());
|
|
i++;
|
|
}
|
|
i = 0;
|
|
for (Class<?> subclass : subclasses) {
|
|
switch (subclassSealedStatus[i++]) {
|
|
case SEALED:
|
|
assertTrue(subclass.isSealed());
|
|
break;
|
|
case FINAL:
|
|
assertTrue(Modifier.isFinal(subclass.getModifiers()));
|
|
break;
|
|
case NON_SEALED:
|
|
assertTrue(!subclass.isSealed() && !Modifier.isFinal(subclass.getModifiers()));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|