Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions src/java.base/share/classes/java/util/ResourceBundle.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import java.net.URLConnection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.spi.ResourceBundleControlProvider;
import java.util.spi.ResourceBundleProvider;
Expand Down Expand Up @@ -487,7 +488,20 @@ public String getBaseBundleName() {
/**
* A Set of the keys contained only in this ResourceBundle.
*/
private volatile Set<String> keySet;
private final Supplier<Set<String>> keySet = StableValue.supplier(
new Supplier<>() { public Set<String> get() { return keySet0(); }});

private Set<String> keySet0() {
final Set<String> keys = new HashSet<>();
final Enumeration<String> enumKeys = getKeys();
while (enumKeys.hasMoreElements()) {
final String key = enumKeys.nextElement();
if (handleGetObject(key) != null) {
keys.add(key);
}
}
return keys;
}

/**
* Sole constructor. (For invocation by subclass constructors, typically
Expand Down Expand Up @@ -2298,22 +2312,7 @@ public Set<String> keySet() {
* @since 1.6
*/
protected Set<String> handleKeySet() {
if (keySet == null) {
synchronized (this) {
if (keySet == null) {
Set<String> keys = new HashSet<>();
Enumeration<String> enumKeys = getKeys();
while (enumKeys.hasMoreElements()) {
String key = enumKeys.nextElement();
if (handleGetObject(key) != null) {
keys.add(key);
}
}
keySet = keys;
}
}
}
return keySet;
return keySet.get();
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -30,6 +30,7 @@
import java.util.Enumeration;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.function.Supplier;

/**
* BreakIteratorResourceBundle is an abstract class for loading BreakIterator
Expand All @@ -49,7 +50,15 @@ public abstract class BreakIteratorResourceBundle extends ResourceBundle {
// those keys must be added to NON_DATA_KEYS.
private static final Set<String> NON_DATA_KEYS = Set.of("BreakIteratorClasses");

private volatile Set<String> keys;
private final Supplier<Set<String>> keys = StableValue.supplier(
new Supplier<>() { public Set<String> get() { return keys0(); }});

private Set<String> keys0() {
final ResourceBundle info = getBreakIteratorInfo();
final Set<String> k = info.keySet();
k.removeAll(NON_DATA_KEYS);
return k;
}

/**
* Returns an instance of the corresponding {@code BreakIteratorInfo} (basename).
Expand Down Expand Up @@ -84,16 +93,6 @@ public Enumeration<String> getKeys() {

@Override
protected Set<String> handleKeySet() {
if (keys == null) {
ResourceBundle info = getBreakIteratorInfo();
Set<String> k = info.keySet();
k.removeAll(NON_DATA_KEYS);
synchronized (this) {
if (keys == null) {
keys = k;
}
}
}
return keys;
return keys.get();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -44,8 +44,11 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.function.Supplier;

import sun.util.ResourceBundleEnumeration;

/**
Expand All @@ -69,12 +72,9 @@ protected OpenListResourceBundle() {
// Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
@Override
protected Object handleGetObject(String key) {
if (key == null) {
throw new NullPointerException();
}

loadLookupTablesIfNecessary();
return lookup.get(key); // this class ignores locales
Objects.requireNonNull(key);
return lookup.get()
.get(key); // this class ignores locales
}

/**
Expand All @@ -93,65 +93,20 @@ public Enumeration<String> getKeys() {
*/
@Override
protected Set<String> handleKeySet() {
loadLookupTablesIfNecessary();
return lookup.keySet();
return lookup.get()
.keySet();
}

@Override
public Set<String> keySet() {
if (keyset != null) {
return keyset;
}
Set<String> ks = createSet();
ks.addAll(handleKeySet());
if (parent != null) {
ks.addAll(parent.keySet());
}
synchronized (this) {
if (keyset == null) {
keyset = ks;
}
}
return keyset;
return keyset.get();
}

/**
* See ListResourceBundle class description.
*/
protected abstract Object[][] getContents();

/**
* Load lookup tables if they haven't been loaded already.
*/
void loadLookupTablesIfNecessary() {
if (lookup == null) {
loadLookup();
}
}

/**
* We lazily load the lookup hashtable. This function does the
* loading.
*/
private void loadLookup() {
Object[][] contents = getContents();
Map<String, Object> temp = createMap(contents.length);
for (int i = 0; i < contents.length; ++i) {
// key must be non-null String, value must be non-null
String key = (String) contents[i][0];
Object value = contents[i][1];
if (key == null || value == null) {
throw new NullPointerException();
}
temp.put(key, value);
}
synchronized (this) {
if (lookup == null) {
lookup = temp;
}
}
}

/**
* Lets subclasses provide specialized Map implementations.
* Default uses HashMap.
Expand All @@ -164,6 +119,31 @@ protected <E> Set<E> createSet() {
return new HashSet<>();
}

private volatile Map<String, Object> lookup;
private volatile Set<String> keyset;
private final Supplier<Map<String, Object>> lookup = StableValue.supplier(
new Supplier<>() { public Map<String, Object> get() { return lookup0(); }});

private Map<String, Object> lookup0() {
final Object[][] contents = getContents();
final Map<String, Object> temp = createMap(contents.length);
for (Object[] content : contents) {
// key must be non-null String, value must be non-null
final String key = Objects.requireNonNull((String) content[0]);
final Object value = Objects.requireNonNull(content[1]);
temp.put(key, value);
}
return temp;
}

private final Supplier<Set<String>> keyset = StableValue.supplier(
new Supplier<>() { public Set<String> get() { return keyset0(); }});

private Set<String> keyset0() {
final Set<String> ks = createSet();
ks.addAll(handleKeySet());
if (parent != null) {
ks.addAll(parent.keySet());
}
return ks;
}

}