Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native images unable to access declared annotations of Java records #3984

Closed
zakkak opened this issue Nov 3, 2021 · 14 comments
Closed

Native images unable to access declared annotations of Java records #3984

zakkak opened this issue Nov 3, 2021 · 14 comments

Comments

@zakkak
Copy link
Collaborator

zakkak commented Nov 3, 2021

Describe the issue
Native images unable to access declared annotations of Java records through java.lang.reflect.RecordComponent.declaredAnnotations.

A simple application like the following cannot compile into a native image:

import java.lang.annotation.Annotation;
import java.lang.reflect.RecordComponent;

public class Main {

	public static void main(String[] args) {
		RecordComponent[] recordComponents = F.class.getRecordComponents();
		for (RecordComponent component: recordComponents) {
			System.out.println(component);
			Annotation[] annotations = component.getAnnotations();
			for (Annotation annotation : annotations) {
				System.out.println(annotation);
			}
		}

		F x = new F("x");
		System.out.println(x);
	}

	static record F(String name) {
	}
}

Steps to reproduce the issue
Please include both build steps as well as run steps

cd /tmp
git clone --branch record-annotations-21.3 https://github.com/zakkak/issue-reproducers reproducers
cd reproducers
mvn package
export JAVA_HOME=/opt/jvms/graalvm-ce-java17-21.3.0
$JAVA_HOME/bin/native-image --initialize-at-build-time --diagnostics-mode \
  --no-fallback -H:+ReportExceptionStackTraces \
  -H:ReflectionConfigurationFiles=./META-INF/native-image/reflect-config.json \
  -jar target/reproducer-1.0-SNAPSHOT.jar
./reproducer-1.0-SNAPSHOT

Describe GraalVM and your environment:

  • GraalVM version: CE 21.3.0
  • JDK major version: 17
  • OS: Fedora 34
  • Architecture: AMD64

More details

The build fails with:

Error: com.oracle.svm.hosted.substitute.DeletedElementException: Unsupported method java.lang.Class.getConstantPool() is reachable: The declaring class of this element has been substituted, but this element is not present in the substitution class
To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime. The unsupported element is then reported at run time when it is accessed the first time.
Detailed message:
Trace: 
	at parsing java.lang.System$2.getConstantPool(System.java:2262)
Call path from entry point to java.lang.System$2.getConstantPool(Class): 
	at java.lang.System$2.getConstantPool(System.java:2262)
	at java.lang.reflect.RecordComponent.declaredAnnotations(RecordComponent.java:198)
	at java.lang.reflect.RecordComponent.getDeclaredAnnotations(RecordComponent.java:224)
	at java.lang.reflect.RecordComponent.getAnnotations(RecordComponent.java:215)
	at com.oracle.svm.core.JavaMainWrapper.runCore(JavaMainWrapper.java:147)
	at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:183)
...
@oubidar-Abderrahim
Copy link
Member

Thank you for reporting this, we will take a look into it and get back to you

@oubidar-Abderrahim oubidar-Abderrahim removed their assignment Nov 11, 2021
@renannprado
Copy link

When I run with the java-agent and then run exec:exec@native, the binary is built but I get the below error:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Failed to access RecordComponents of type com.server.shared.ServerMetaData
at [Source: (File); line: 1, column: 1]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1904)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:268)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:642)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4806)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4676)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3495)
at com.test.MainClient.call(MainClient.java:51)
at com.test.MainClient.call(MainClient.java:25)
at picocli.CommandLine.executeUserObject(CommandLine.java:1953)
at picocli.CommandLine.access$1300(CommandLine.java:145)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)
at picocli.CommandLine.execute(CommandLine.java:2078)
at com.test.MainClient.main(MainClient.java:40)

@maxandersen
Copy link

Any updates for this ? at the moment this prevents usage of one of Java 17's primary features record to be used for json serilization with jackson or actually any kind of annotation based use.

@jerboaa
Copy link
Collaborator

jerboaa commented Jan 19, 2022

I can have a look at this.

@loicottet
Copy link
Member

I am currently working on solving this as part of a larger refactoring of our reflection implementation. I'll update again when I have a better idea of when the fix will be ready.

@jerboaa
Copy link
Collaborator

jerboaa commented Jan 25, 2022

A more comprehensive test/reproducer is (as it verifies more RecordComponent methods):

$ cat run-test.sh
GRAALVM_HOME=$1

rm -rf META-INF
rm *.class
cat > RecordAnnotations.java <<EOF
import java.lang.annotation.Annotation;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Type;
import java.util.Arrays;

public class RecordAnnotations {

	public static void main(String[] args) {
		RecordComponent[] recordComponents = F.class.getRecordComponents();
		for (RecordComponent component: recordComponents) {
			System.out.println("component: " + component);
			Annotation[] annotations = component.getAnnotations();
			AnnotatedType annoType = component.getAnnotatedType();
			Type t = component.getGenericType();
			System.out.println("generic type: " + t);
			System.out.println("annotated type: " + annoType);
			System.out.println("annotated type annotations: " + Arrays.asList(annoType.getAnnotations()));
			for (Annotation annotation : annotations) {
				System.out.println("annotation: " + annotation);
			}
			Annotation ann = component.getAnnotation(RCA.class);
			System.out.println("RCA annotation: " + ann);
		}

		F x = new F("x", 1);
		System.out.println("Record: " + x);
	}

	@Retention(RetentionPolicy.RUNTIME)
        @Target({ ElementType.RECORD_COMPONENT, ElementType.FIELD })
        @interface RCA {}

	@Retention(RetentionPolicy.RUNTIME)
        @Target({ ElementType.RECORD_COMPONENT, ElementType.FIELD, ElementType.TYPE })
        @interface RCA2 {}

	@RCA2
	static record F(@RCA @RCA2 String name, int i) {
	}
}
EOF
$GRAALVM_HOME/bin/javac RecordAnnotations.java
mkdir -p META-INF/native-image
cat > META-INF/native-image/reflect-config.json <<EOF
[
  {
    "name" : "RecordAnnotations\$F",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredClasses" : true,
    "allPublicClasses" : true
  }
]
EOF
$GRAALVM_HOME/bin/native-image --diagnostics-mode   --no-fallback -H:+ReportExceptionStackTraces   -H:ReflectionConfigurationFiles=./META-INF/native-image/reflect-config.json RecordAnnotations

$ bash run-test.sh /path/to/graalvm/home

@jerboaa
Copy link
Collaborator

jerboaa commented Jan 26, 2022

@loicottet Here is a quick patch I did solving just this issue. Would this be worthwhile proposing as a PR? The idea would be to have a stand-alone fix which could be considered for backport to 21.3.

master...jerboaa:record_annotations

@jerboaa
Copy link
Collaborator

jerboaa commented Jan 31, 2022

I am currently working on solving this as part of a larger refactoring of our reflection implementation. I'll update again when I have a better idea of when the fix will be ready.

@loicottet Any idea yet when this would land? If far off, could we perhaps consider an intermediate fix in the meantime? For Quarkus it would be good to know a rough timeline for this issue being fixed. Thanks very much!

@zakkak zakkak added the Java17 label Feb 4, 2022
@loicottet
Copy link
Member

The current timeline is to have this refactoring included in the 22.1 release, so probably around a month

@geoand
Copy link

geoand commented Feb 15, 2022

It would be great to have @jerboaa 's fix in a patch of 21.3?

@loicottet
Copy link
Member

I am currently reviewing @jerboaa's fix to include it in 21.3

@Aleksandr-Filichkin
Copy link

still see this problem with 22.00.2

@jerboaa
Copy link
Collaborator

jerboaa commented Mar 18, 2022

GraalVM 22.1 and 21.3.2 will have the fix (to be released in April 2022). Meanwhile if you are interested in native image only, you can try a build from here: https://github.com/graalvm/mandrel/releases/tag/mandrel-21.3.1.1-Final

@zakkak
Copy link
Collaborator Author

zakkak commented Mar 21, 2022

Fixed by #4222 (for 22.1.0) and 2274655 (for 21.3.2)

@zakkak zakkak closed this as completed Mar 21, 2022
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 23, 2022
This adds a simple app using record annotations, for which a
native image gets generated. This is a regression test for
the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 23, 2022
This adds a simple app using record annotations, for which a
native image gets generated. This is a regression test for
the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 23, 2022
This adds a simple app using record annotations, for which a
native image gets generated. This is a regression test for
the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 24, 2022
This adds a JDK 17+ test project and adds a regression test
for the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 24, 2022
This adds a JDK 17+ test project and adds a regression test
for the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 24, 2022
This adds a JDK 17+ test project and adds a regression test
for the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 24, 2022
This adds a JDK 17+ test project and adds a regression test
for the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 24, 2022
This adds a JDK 17+ test project and adds a regression test
for the fix described in issue oracle#3984
jerboaa added a commit to jerboaa/graal that referenced this issue Mar 24, 2022
This adds a JDK 17+ test project and adds a regression test
for the fix described in issue oracle#3984
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants