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

Run snakeyaml without java.desktop module #12

Merged
merged 3 commits into from
May 17, 2024

Conversation

JaroslavTulach
Copy link

@JaroslavTulach JaroslavTulach commented May 13, 2024

I am experimenting with jlink trying to create a small (headless) JDK while still using snakeyaml. I created a small sample program in Demo.java file:

import java.util.Map;
import org.yaml.snakeyaml.Yaml;

public class Demo {

    public static void main(String[] args) {
        Yaml yaml = new Yaml();
        String document = "hello: 25";
        Map map = (Map) yaml.load(document);
        Object h = map.get("hello");
        System.out.println("h: " + h);
    }
}

I compile it and run successfully with JDK21:

$ jdk21/bin/javac -d . -cp snakeyaml-1.28.jar  Demo.java
$ jdk21/bin/java -cp .:snakeyaml-1.28.jar Demo
h: 25

however when I try to run it without java.desktop module, everything fails.

To reproduce

First of all let's build a small JDK via jlink command. I use:

$ jdk21/bin/jlink --output smalljdk --add-modules java.base

this generates a small, restricted JDK in smalljdk directory. Running with regular snakeyaml-1.28 then fails with a linkage error:

$ smalljdk/bin/java -cp .:snakeyaml-1.28.jar Demo
Exception in thread "main" java.lang.NoClassDefFoundError: java/beans/IntrospectionException
        at org.yaml.snakeyaml.constructor.BaseConstructor.getPropertyUtils(BaseConstructor.java:559)
        at org.yaml.snakeyaml.constructor.BaseConstructor.addTypeDescription(BaseConstructor.java:579)
        at org.yaml.snakeyaml.constructor.Constructor.<init>(Constructor.java:103)
        at org.yaml.snakeyaml.constructor.Constructor.<init>(Constructor.java:80)
        at org.yaml.snakeyaml.constructor.Constructor.<init>(Constructor.java:62)
        at org.yaml.snakeyaml.constructor.Constructor.<init>(Constructor.java:48)
        at org.yaml.snakeyaml.Yaml.<init>(Yaml.java:66)
        at Demo.main(Demo.java:7)
Caused by: java.lang.ClassNotFoundException: java.beans.IntrospectionException
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)

the problem is that PropertyUtils class is referencing java.beans classes (part of java.desktop JDK module) and those are not available. One of these classes is even in the signature of the isTransient method and thus the JDK verifier refuses to load the PropertyUtils class.

This PR fixes that by restructuring the code, so only MethodProperty class references the java.beans package. As this class isn't used in BeanAccess.FIELD mode, the following passes with the new snakeyaml JAR file:

snakeyaml$ smalljdk/bin/java -cp .:target/snakeyaml-2.3-SNAPSHOT.jar Demo
h: 25

These changes are not only useful for our project, but for everyone trying to use snakeyaml on a headless JDK without java.desktop. Please consider accepting my refactoring.

@JaroslavTulach JaroslavTulach changed the title Run snakeyaml without java desktop Run snakeyaml without java.desktop module May 13, 2024
@asomov
Copy link
Contributor

asomov commented May 13, 2024

synced

@JaroslavTulach
Copy link
Author

Can this refactoring be considered for integration? Right now I have to patch your library and it doesn't feel comfortable.

@asomov asomov requested a review from maslovalex May 15, 2024 05:48
@@ -57,6 +52,13 @@ public PropertyUtils() {
if (platformFeatureDetector.isRunningOnAndroid()) {
beanAccess = BeanAccess.FIELD;
}

/* when running with jlink restricted JDK without java.desktop package */
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move this detection into the PlatformFeatureDetector maybe in something like isIntrospectorAvailable ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2ca1828. Is that OK?

@asomov asomov merged commit cfd3676 into snakeyaml:master May 17, 2024
2 checks passed
@asomov
Copy link
Contributor

asomov commented May 17, 2024

Can you please expose instruction how to use it ? Is there a link to a wiki ?

It will be delivered in version 2.3
https://bitbucket.org/snakeyaml/snakeyaml/wiki/Changes

@JaroslavTulach
Copy link
Author

Thank you for accepting my contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants