Skip to content

[GR-34444] Ensure java.lang.Module#isReflectivelyExportedOrOpen works as expected #3911

@olpaw

Description

@olpaw

Currently java.lang.Module#isReflectivelyExportedOrOpen simply returns true at image-runtime. This is needed to e.g. make e.g. ResourceBundle lookups at image runtime working. The ResourceBundle lookup code involves:

        public ResourceBundle newBundle(String baseName, Locale locale, String format,
                                        ClassLoader loader, boolean reload)
                    throws IllegalAccessException, InstantiationException, IOException {
            /*
             * Legacy mechanism to locate resource bundle in unnamed module only
             * that is visible to the given loader and accessible to the given caller.
             */
            String bundleName = toBundleName(baseName, locale);
            ResourceBundle bundle = null;
            if (format.equals("java.class")) {
                try {
                    Class<?> c = loader.loadClass(bundleName);
                    // If the class isn't a ResourceBundle subclass, throw a
                    // ClassCastException.
                    if (ResourceBundle.class.isAssignableFrom(c)) {
                        @SuppressWarnings("unchecked")
                        Class<ResourceBundle> bundleClass = (Class<ResourceBundle>)c;
                        Module m = bundleClass.getModule();

                        // To access a resource bundle in a named module,
                        // either class-based or properties-based, the resource
                        // bundle must be opened unconditionally,
                        // same rule as accessing a resource file.
                        if (m.isNamed() && !m.isOpen(bundleClass.getPackageName())) {
                            throw new IllegalAccessException("unnamed module can't load " + // 🗲🗲🗲
                                bundleClass.getName() + " in " + m.toString());
                        }
                        ...

After #3445 got merged this code can now fail with IllegalAccessException (see 🗲🗲🗲) due to moduleinfo no knowing that m.isOpen(bundleClass.getPackageName()) should be true.

As a temporary workaround substitution:

    @SuppressWarnings({"unused", "static-method"})
    @Substitute
    public boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) {
        return true;
    }

was added to Target_java_lang_Module_JDK11OrLater.

A proper fix would remove that workaround and instead make sure that m.isOpen(bundleClass.getPackageName()) gives the right answer. The hosted isOpen relationships between modules need to be carried over to module-info at runtime.

A good example that demonstrates if this is working correctly is using ResourceBundle.getBundle("sun.security.util.Resources") at image runtime. The image builder arguments always contains

--add-exports=java.base/sun.security.util=org.graalvm.nativeimage.builder

thus the bundle lookup at image built-time succeeds. But for the bundle lookup to also succeed at image runtime this opening up needs to be translated to the corresponding opening-up at image runtime.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions