/
githubmirror
/
galahad
Обзор
Документация
Войти
/
githubmirror
/
galahad
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/jdk/java/lang/reflect/Generics/MalformedSignatureTest.java
224 строки
10 KB
Chen Liang
8350704: Create tests to ensure the failure behavior of core reflection APIs
04 апр 2025, 03:58
04 апр 2025, 03:58
a449aee
Код
Авторство
О чём код?
/* * Copyright (c) 2024, 2025, 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 6832374 7052898 8350704 * @summary Test behaviors with malformed signature strings in Signature attribute. * @library /test/lib * @run junit MalformedSignatureTest */ import java.lang.classfile.*; import java.lang.classfile.attribute.RecordAttribute; import java.lang.classfile.attribute.RecordComponentInfo; import java.lang.classfile.attribute.SignatureAttribute; import java.lang.constant.ClassDesc; import java.lang.reflect.GenericSignatureFormatError; import java.nio.file.Path; import java.util.ArrayList; import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; import jdk.test.lib.ByteCodeLoader; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import static java.lang.constant.ConstantDescs.MTD_void; import static org.junit.jupiter.api.Assertions.*; class MalformedSignatureTest { private static final String BASIC_BAD_SIGNATURE_TEXT = "i_aM_NoT_A_Signature"; static Class<?> sampleClass, sampleRecord; @BeforeAll static void setup() throws Exception { var compiledDir = Path.of(System.getProperty("test.classes")); var cf = ClassFile.of(); // Transform that installs malformed signature strings to classes, // fields, methods, and record components. var badSignatureTransform = new ClassTransform() { private SignatureAttribute badSignature; @Override public void atStart(ClassBuilder builder) { badSignature = SignatureAttribute.of(builder.constantPool().utf8Entry(BASIC_BAD_SIGNATURE_TEXT)); } @Override public void accept(ClassBuilder builder, ClassElement element) { switch (element) { case SignatureAttribute _ -> {} // dropping case FieldModel f -> builder .transformField(f, FieldTransform.dropping(SignatureAttribute.class::isInstance) .andThen(FieldTransform.endHandler(fb -> fb.with(badSignature)))); case MethodModel m -> builder .transformMethod(m, MethodTransform.dropping(SignatureAttribute.class::isInstance) .andThen(MethodTransform.endHandler(fb -> fb.with(badSignature)))); case RecordAttribute rec -> builder.with(RecordAttribute.of(rec.components().stream().map(comp -> RecordComponentInfo.of(comp.name(), comp.descriptor(), Stream.concat( Stream.of(badSignature), comp.attributes().stream() .filter(Predicate.not(SignatureAttribute.class::isInstance))) .toList())) .toList())); default -> builder.with(element); } } @Override public void atEnd(ClassBuilder builder) { builder.with(badSignature); } }; var plainBytes = cf.transformClass(cf.parse(compiledDir.resolve("SampleClass.class")), badSignatureTransform); sampleClass = ByteCodeLoader.load("SampleClass", plainBytes); var recordBytes = cf.transformClass(cf.parse(compiledDir.resolve("SampleRecord.class")), badSignatureTransform); sampleRecord = ByteCodeLoader.load("SampleRecord", recordBytes); } /** * Ensures the reflective generic inspection of a malformed Class throws * GenericSignatureFormatError while the non-generic inspection is fine. */ @Test void testBasicClass() { assertEquals(ArrayList.class, sampleClass.getSuperclass()); assertArrayEquals(new Class<?>[] {Predicate.class}, sampleClass.getInterfaces()); var ex = assertThrows(GenericSignatureFormatError.class, sampleClass::getGenericSuperclass); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); ex = assertThrows(GenericSignatureFormatError.class, sampleClass::getGenericInterfaces); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); } /** * Ensures the reflective generic inspection of a malformed Field throws * GenericSignatureFormatError while the non-generic inspection is fine. */ @Test void testBasicField() throws ReflectiveOperationException { var field = sampleClass.getDeclaredField("field"); assertEquals(Optional.class, field.getType()); var ex = assertThrows(GenericSignatureFormatError.class, field::getGenericType); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); } /** * Ensures the reflective generic inspection of a malformed Constructor throws * GenericSignatureFormatError while the non-generic inspection is fine. */ @Test void testBasicConstructor() throws ReflectiveOperationException { var constructor = sampleClass.getDeclaredConstructors()[0]; assertArrayEquals(new Class<?>[] {Optional.class}, constructor.getParameterTypes()); assertArrayEquals(new Class<?>[] {RuntimeException.class}, constructor.getExceptionTypes()); var ex = assertThrows(GenericSignatureFormatError.class, constructor::getGenericParameterTypes); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); ex = assertThrows(GenericSignatureFormatError.class, constructor::getGenericExceptionTypes); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); } /** * Ensures the reflective generic inspection of a malformed Method throws * GenericSignatureFormatError while the non-generic inspection is fine. */ @Test void testBasicMethod() throws ReflectiveOperationException { var method = sampleClass.getDeclaredMethods()[0]; assertEquals(Optional.class, method.getReturnType()); assertArrayEquals(new Class<?>[] {Optional.class}, method.getParameterTypes()); assertArrayEquals(new Class<?>[] {RuntimeException.class}, method.getExceptionTypes()); var ex = assertThrows(GenericSignatureFormatError.class, method::getGenericReturnType); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); ex = assertThrows(GenericSignatureFormatError.class, method::getGenericParameterTypes); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); ex = assertThrows(GenericSignatureFormatError.class, method::getGenericExceptionTypes); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); } /** * Ensures the reflective generic inspection of a malformed RecordComponent throws * GenericSignatureFormatError while the non-generic inspection is fine. */ @Test void testBasicRecordComponent() { var rcs = sampleRecord.getRecordComponents(); assertNotNull(rcs); assertEquals(1, rcs.length); var rc = rcs[0]; assertNotNull(rc); assertEquals(Optional.class, rc.getType()); assertEquals(BASIC_BAD_SIGNATURE_TEXT, rc.getGenericSignature()); var ex = assertThrows(GenericSignatureFormatError.class, rc::getGenericType); assertTrue(ex.getMessage().contains(BASIC_BAD_SIGNATURE_TEXT)); } static String[] badMethodSignatures() { return new String[] { // Missing ":" after first type bound "<T:Lfoo/tools/nsc/symtab/Names;Lfoo/tools/nsc/symtab/Symbols;", // Arrays improperly indicated for exception information "<E:Ljava/lang/Exception;>(TE;[Ljava/lang/RuntimeException;)V^[TE;", }; } /** * Ensures that particular strings are invalid as method signature strings. */ @MethodSource("badMethodSignatures") @ParameterizedTest void testSignatureForMethod(String badSig) throws Throwable { var className = "BadSignature"; var bytes = ClassFile.of().build(ClassDesc.of(className), clb -> clb.withMethod("test", MTD_void, 0, mb -> mb .withCode(CodeBuilder::return_) .with(SignatureAttribute.of(clb.constantPool().utf8Entry(badSig))))); var cl = ByteCodeLoader.load(className, bytes); var method = cl.getDeclaredMethod("test"); var ex = assertThrows(GenericSignatureFormatError.class, method::getGenericParameterTypes); //assertTrue(ex.getMessage().contains(badSig), "Missing bad signature in error message"); } } // Sample classes shared with TypeNotPresentInSignatureTest abstract class SampleClass extends ArrayList<RuntimeException> implements Predicate<RuntimeException> { // class Optional<RuntimeException> field; // field <T extends RuntimeException> SampleClass(Optional<RuntimeException> param) throws T { } // constructor <T extends RuntimeException> Optional<RuntimeException> method(Optional<RuntimeException> param) throws T { return null; } // method } record SampleRecord(Optional<RuntimeException> component) { }