Skip to content

Commit

Permalink
Resource bugfixes for missing registration errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksandar Gradinac authored and loicottet committed Aug 14, 2023
1 parent 74ad47b commit 63b91c7
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public class BundleContentSubstitutedLocalizationSupport extends LocalizationSup

private final Map<Class<?>, StoredBundle> storedBundles = new ConcurrentHashMap<>();

private final Set<String> existingBundles = ConcurrentHashMap.newKeySet();

public BundleContentSubstitutedLocalizationSupport(Locale defaultLocale, Set<Locale> locales, Charset defaultCharset, List<String> requestedPatterns, ForkJoinPool pool) {
super(defaultLocale, locales, defaultCharset);
this.pool = pool;
Expand Down Expand Up @@ -163,4 +165,23 @@ public boolean shouldCompressBundle(ResourceBundle bundle) {
public void prepareNonCompliant(Class<?> clazz) throws ReflectiveOperationException {
storedBundles.put(clazz, new DelayedBundle(clazz));
}

@Override
public boolean isNotIncluded(String bundleName) {
return !existingBundles.contains(bundleName);
}

@Override
public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) {
super.prepareBundle(bundleName, bundle, locale);
/* Initialize ResourceBundle.keySet eagerly */
bundle.keySet();
this.existingBundles.add(control.toBundleName(bundleName, locale));
}

@Override
public void prepareClassResourceBundle(String basename, Class<?> bundleClass) {
super.prepareClassResourceBundle(basename, bundleClass);
this.existingBundles.add(bundleClass.getName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package com.oracle.svm.core.jdk.localization;

import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.IllformedLocaleException;
import java.util.Locale;
Expand All @@ -41,6 +42,7 @@
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.hosted.RuntimeReflection;
import org.graalvm.nativeimage.impl.ConfigurationCondition;
import org.graalvm.nativeimage.impl.RuntimeReflectionSupport;
import org.graalvm.nativeimage.impl.RuntimeResourceSupport;

import com.oracle.svm.core.SubstrateUtil;
Expand Down Expand Up @@ -107,6 +109,7 @@ public void prepareBundle(String bundleName, ResourceBundle bundle, Locale local
}
ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(), resultingPattern + "\\.properties");
} else {
registerRequiredReflectionForBundle(bundleName, Set.of(locale));
RuntimeReflection.register(bundle.getClass());
RuntimeReflection.registerForReflectiveInstantiation(bundle.getClass());
onBundlePrepared(bundle);
Expand All @@ -128,6 +131,28 @@ private String getBundleName(String fixedBundleName, Locale locale) {
}
}

public void registerRequiredReflectionForBundle(String baseName, Collection<Locale> wantedLocales) {
int i = baseName.lastIndexOf('.');
if (i > 0) {
String name = baseName.substring(i + 1) + "Provider";
String providerName = baseName.substring(0, i) + ".spi." + name;
ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), providerName);
}

ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), baseName);

for (Locale locale : wantedLocales) {
registerRequiredReflectionForBundleAndLocale(baseName, locale);
}
}

private void registerRequiredReflectionForBundleAndLocale(String baseName, Locale baseLocale) {
for (Locale locale : control.getCandidateLocales(baseName, baseLocale)) {
String bundleWithLocale = control.toBundleName(baseName, locale);
RuntimeReflection.registerClassLookup(bundleWithLocale);
}
}

/**
* Template method for subclasses to perform additional tasks.
*/
Expand All @@ -153,6 +178,11 @@ public void prepareNonCompliant(Class<?> clazz) throws ReflectiveOperationExcept
/*- By default, there is nothing to do */
}

@SuppressWarnings("unused")
public boolean isNotIncluded(String bundleName) {
return false;
}

/**
* @return locale for given tag or null for invalid ones
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@
*/
package com.oracle.svm.core.jdk.localization.substitutions;

import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.jdk.localization.LocalizationSupport;

import java.util.Locale;
import java.util.ResourceBundle;
import sun.util.resources.Bundles;

@TargetClass(value = java.util.ResourceBundle.class, innerClass = "Control")
@SuppressWarnings({"unused", "static-method"})
Expand All @@ -45,4 +52,34 @@ public boolean needsReload(String baseName, Locale locale,

return false;
}

@Substitute
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);
if (format.equals("java.class") && ImageSingletons.lookup(LocalizationSupport.class).isNotIncluded(bundleName)) {
return null;
}
var bundle = newBundle0(bundleName, format, loader, reload);
if (bundle == null) {
// Try loading legacy ISO language's other bundles
var otherBundleName = Bundles.toOtherBundleName(baseName, bundleName, locale);
if (!bundleName.equals(otherBundleName)) {
bundle = newBundle0(otherBundleName, format, loader, reload);
}
}

return bundle;
}

@Alias
public native String toBundleName(String baseName, Locale locale);

@Alias
private native ResourceBundle newBundle0(String bundleName, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ void handleServiceClassIsReachable(DuringAnalysisAccess access, Class<?> service
if (nullaryConstructor != null) {
RuntimeReflection.register(providerClass);
RuntimeReflection.register(nullaryConstructor);
RuntimeReflection.registerAllDeclaredMethods(providerClass);
registeredProviders.add(provider);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ public void prepareClassResourceBundle(String basename, String className) {
Class<?> bundleClass = findClassByName.apply(className);
UserError.guarantee(ResourceBundle.class.isAssignableFrom(bundleClass), "%s is not a subclass of ResourceBundle", bundleClass.getName());
trace("Adding class based resource bundle: " + className + " " + bundleClass);
support.registerRequiredReflectionForBundle(basename, Set.of());
support.prepareClassResourceBundle(basename, bundleClass);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public void registerClassLookupException(ConfigurationCondition condition, Strin
public void registerClassLookup(ConfigurationCondition condition, String typeName) {
checkNotSealed();
try {
register(condition, Class.forName(typeName, false, null));
register(condition, Class.forName(typeName, false, ClassLoader.getSystemClassLoader()));
} catch (ClassNotFoundException e) {
registerConditionalConfiguration(condition, () -> ClassForNameSupport.registerNegativeQuery(typeName));
} catch (Throwable t) {
Expand Down

0 comments on commit 63b91c7

Please sign in to comment.