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

XMLDecoder in native image fails with ArrayIndexOutOfBoundsException #10509

Open
1 of 2 tasks
paddy-axio opened this issue Jan 17, 2025 · 3 comments
Open
1 of 2 tasks
Assignees

Comments

@paddy-axio
Copy link

paddy-axio commented Jan 17, 2025

Describe the Issue

When trying to deserialize an XML representation of a Java Bean using java.beans.XMLDecoder, the native image fails with an ArrayIndexOutOfBoundsException.
The same code works well when packaged as a runnable Jar. However, it fails when run as a native image. I have also tried to include the bean class (test.Person) in reflect-config and also serialization-config hints.

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15)

Operating System and Version

Darwin Kernel Version 23.0.0

Troubleshooting Confirmation

Run Command

./App

Expected Behavior

Person object is constructed successfully and the below string is printed

Hello from Person{firstName='John', lastName='Doe', age=50}

Actual Behavior

Running the native App results in error as below

java.lang.InstantiationException: com.sun.beans.decoder.JavaElementHandler
Continuing ...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
        at java.desktop@21/java.beans.XMLDecoder.readObject(XMLDecoder.java:253)
        at test.XmlDecoderTest.decodeTestPerson(XmlDecoderTest.java:13)
        at test.XmlDecoderTest.main(XmlDecoderTest.java:8)
        at java.base@21/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

Steps to Reproduce

XmlDecoderTest.java

package test;

import java.beans.XMLDecoder;
import java.io.ByteArrayInputStream;

public class XmlDecoderTest {
    public static void main(String[] args) {
        System.out.println(decodeTestPerson());
    }

    public static String decodeTestPerson() {
        XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(getXmlEncodedPerson().getBytes()));
        Object readObject = decoder.readObject();
        Person decodedPerson = (Person) readObject;
        return "Hello from " + decodedPerson;
    }

    private static String getXmlEncodedPerson() {
        return """
                <?xml version="1.0" encoding="UTF-8"?>
                <java version="21.0.1" class="java.beans.XMLDecoder">
                 <object class="test.Person">
                  <void property="age">
                   <int>50</int>
                  </void>
                  <void property="firstName">
                   <string>John</string>
                  </void>
                  <void property="lastName">
                   <string>Doe</string>
                  </void>
                 </object>
                </java>
                """;
    }
}

Person.java

package test;

import java.io.Serializable;

public class Person implements Serializable {
    private String firstName;
    private String lastName;
    private Integer age;

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", age=" + age +
                '}';
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

** Build **
javac -d build test/XmlDecoderTest.java
jar --create --file App.jar --main-class test.XmlDecoderTest -C build .
native-image -jar App.jar

** Test jar **
java -jar App.jar

** Test native-image **
./App

Additional Context

No response

Run-Time Log Output and Error Messages

java.lang.InstantiationException: com.sun.beans.decoder.JavaElementHandler
Continuing ...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at java.desktop@21/java.beans.XMLDecoder.readObject(XMLDecoder.java:253)
at test.XmlDecoderTest.decodeTestPerson(XmlDecoderTest.java:13)
at test.XmlDecoderTest.main(XmlDecoderTest.java:8)
at java.base@21/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

@selhagani
Copy link
Member

Hi @paddy-axio,

Thank you for reaching out to us about this.
Could you please try retesting with our latest GraalVM release? you can find it here: https://github.com/graalvm/graalvm-ce-builds/releases/

@paddy-axio
Copy link
Author

Hi @selhagani,
Thanks for looking into this.

I can confirm that the behavior is the same with Oracle GraalVM 23+37.1 (build 23+37-jvmci-b01). It still shows the below error when run as a native image whereas it works just fine as a jar.

java.lang.InstantiationException: com.sun.beans.decoder.JavaElementHandler
Continuing ...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
        at java.desktop@23/java.beans.XMLDecoder.readObject(XMLDecoder.java:253)
        at test.XmlDecoderTest.decodeTestPerson(XmlDecoderTest.java:13)
        at test.XmlDecoderTest.main(XmlDecoderTest.java:8)
        at java.base@23/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

@wirthi
Copy link
Member

wirthi commented Jan 20, 2025

Hi @paddy-axio

thanks for reporting this, and especially for the simple reproducer with step-by-step instructions, that makes it super easy to exactly reproduce your problem.

I can confirm I get the same error when using your steps; I can also confirm it works when I gather configuration information and build the image as described in https://www.graalvm.org/latest/reference-manual/native-image/metadata/AutomaticMetadataCollection/

So after building the class files, run the application once (in JIT mode) and add -agentlib:native-image-agent=config-output-dir=..... Output to e.g. build/META-INF/native-image/. Then build the JAR file with those files included, and native-image will use the configuration information to build the image.

App.jar roughly doubled in size for me, App (executable) got slightly bigger (+400k), but now it works:

$ ./App 
Hello from Person{firstName='John', lastName='Doe', age=50}

I think we need to add that information to the Troubleshooting guide.

Best,
Christian

@wirthi wirthi assigned wirthi and unassigned selhagani Jan 20, 2025
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

3 participants