< prev index next >
src/java.base/share/classes/java/util/Properties.java
Print this page
*** 32,41 ****
--- 32,47 ----
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
+ import java.io.ObjectInputStream;
+ import java.io.ObjectOutputStream;
+ import java.util.concurrent.ConcurrentHashMap;
+ import java.util.function.BiConsumer;
+ import java.util.function.BiFunction;
+ import java.util.function.Function;
import jdk.internal.util.xml.PropertiesDefaultHandler;
/**
* The {@code Properties} class represents a persistent set of
*** 142,151 ****
--- 148,160 ----
* Creates an empty property list with the specified defaults.
*
* @param defaults the defaults.
*/
public Properties(Properties defaults) {
+ // use package-private constructor to
+ // initialize unused fields with dummy values
+ super((Void) null);
this.defaults = defaults;
}
/**
* Calls the <tt>Hashtable</tt> method {@code put}. Provided for
*** 158,168 ****
* @return the previous value of the specified key in this property
* list, or {@code null} if it did not have one.
* @see #getProperty
* @since 1.2
*/
! public synchronized Object setProperty(String key, String value) {
return put(key, value);
}
/**
--- 167,177 ----
* @return the previous value of the specified key in this property
* list, or {@code null} if it did not have one.
* @see #getProperty
* @since 1.2
*/
! public Object setProperty(String key, String value) {
return put(key, value);
}
/**
*** 310,320 ****
* @throws IllegalArgumentException if a malformed Unicode escape
* appears in the input.
* @throws NullPointerException if {@code reader} is null.
* @since 1.6
*/
! public synchronized void load(Reader reader) throws IOException {
Objects.requireNonNull(reader, "reader parameter is null");
load0(new LineReader(reader));
}
/**
--- 319,329 ----
* @throws IllegalArgumentException if a malformed Unicode escape
* appears in the input.
* @throws NullPointerException if {@code reader} is null.
* @since 1.6
*/
! public void load(Reader reader) throws IOException {
Objects.requireNonNull(reader, "reader parameter is null");
load0(new LineReader(reader));
}
/**
*** 336,346 ****
* @throws IllegalArgumentException if the input stream contains a
* malformed Unicode escape sequence.
* @throws NullPointerException if {@code inStream} is null.
* @since 1.2
*/
! public synchronized void load(InputStream inStream) throws IOException {
Objects.requireNonNull(inStream, "inStream parameter is null");
load0(new LineReader(inStream));
}
private void load0 (LineReader lr) throws IOException {
--- 345,355 ----
* @throws IllegalArgumentException if the input stream contains a
* malformed Unicode escape sequence.
* @throws NullPointerException if {@code inStream} is null.
* @since 1.2
*/
! public void load(InputStream inStream) throws IOException {
Objects.requireNonNull(inStream, "inStream parameter is null");
load0(new LineReader(inStream));
}
private void load0 (LineReader lr) throws IOException {
*** 827,849 ****
if (comments != null) {
writeComments(bw, comments);
}
bw.write("#" + new Date().toString());
bw.newLine();
! synchronized (this) {
! for (Enumeration<?> e = keys(); e.hasMoreElements();) {
! String key = (String)e.nextElement();
! String val = (String)get(key);
key = saveConvert(key, true, escUnicode);
/* No need to escape embedded and trailing spaces for value, hence
* pass false to flag.
*/
val = saveConvert(val, false, escUnicode);
bw.write(key + "=" + val);
bw.newLine();
}
- }
bw.flush();
}
/**
* Loads all of the properties represented by the XML document on the
--- 836,856 ----
if (comments != null) {
writeComments(bw, comments);
}
bw.write("#" + new Date().toString());
bw.newLine();
! for (Map.Entry<Object, Object> e : entrySet()) {
! String key = (String)e.getKey();
! String val = (String)e.getValue();
key = saveConvert(key, true, escUnicode);
/* No need to escape embedded and trailing spaces for value, hence
* pass false to flag.
*/
val = saveConvert(val, false, escUnicode);
bw.write(key + "=" + val);
bw.newLine();
}
bw.flush();
}
/**
* Loads all of the properties represented by the XML document on the
*** 874,884 ****
* @see #storeToXML(OutputStream, String, String)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5
*/
! public synchronized void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException
{
Objects.requireNonNull(in);
PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
handler.load(this, in);
--- 881,891 ----
* @see #storeToXML(OutputStream, String, String)
* @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
* Encoding in Entities</a>
* @since 1.5
*/
! public void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException
{
Objects.requireNonNull(in);
PropertiesDefaultHandler handler = new PropertiesDefaultHandler();
handler.load(this, in);
*** 969,979 ****
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
public String getProperty(String key) {
! Object oval = super.get(key);
String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}
/**
--- 976,986 ----
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
public String getProperty(String key) {
! Object oval = map.get(key);
String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}
/**
*** 1007,1017 ****
* @see java.util.Enumeration
* @see java.util.Properties#defaults
* @see #stringPropertyNames
*/
public Enumeration<?> propertyNames() {
! Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
return h.keys();
}
/**
--- 1014,1024 ----
* @see java.util.Enumeration
* @see java.util.Properties#defaults
* @see #stringPropertyNames
*/
public Enumeration<?> propertyNames() {
! Hashtable<String, Object> h = new Hashtable<>();
enumerate(h);
return h.keys();
}
/**
*** 1031,1041 ****
* including the keys in the default property list.
* @see java.util.Properties#defaults
* @since 1.6
*/
public Set<String> stringPropertyNames() {
! Hashtable<String, String> h = new Hashtable<>();
enumerateStringProperties(h);
return h.keySet();
}
/**
--- 1038,1048 ----
* including the keys in the default property list.
* @see java.util.Properties#defaults
* @since 1.6
*/
public Set<String> stringPropertyNames() {
! Map<String, String> h = new HashMap<>();
enumerateStringProperties(h);
return h.keySet();
}
/**
*** 1046,1060 ****
* @throws ClassCastException if any key in this property list
* is not a string.
*/
public void list(PrintStream out) {
out.println("-- listing properties --");
! Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
! for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
! String key = e.nextElement();
! String val = (String)h.get(key);
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
}
out.println(key + "=" + val);
}
--- 1053,1067 ----
* @throws ClassCastException if any key in this property list
* is not a string.
*/
public void list(PrintStream out) {
out.println("-- listing properties --");
! Map<String, Object> h = new HashMap<>();
enumerate(h);
! for (Map.Entry<String, Object> e : h.entrySet()) {
! String key = e.getKey();
! String val = (String)e.getValue();
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
}
out.println(key + "=" + val);
}
*** 1074,1123 ****
* method is duplicated in order to ensure that a non-1.1 compiler can
* compile this file.
*/
public void list(PrintWriter out) {
out.println("-- listing properties --");
! Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
! for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
! String key = e.nextElement();
! String val = (String)h.get(key);
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
}
out.println(key + "=" + val);
}
}
/**
! * Enumerates all key/value pairs in the specified hashtable.
! * @param h the hashtable
* @throws ClassCastException if any of the property keys
* is not of String type.
*/
! private synchronized void enumerate(Hashtable<String,Object> h) {
if (defaults != null) {
defaults.enumerate(h);
}
! for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
! String key = (String)e.nextElement();
! h.put(key, get(key));
}
}
/**
! * Enumerates all key/value pairs in the specified hashtable
* and omits the property if the key or value is not a string.
! * @param h the hashtable
*/
! private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
if (defaults != null) {
defaults.enumerateStringProperties(h);
}
! for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
! Object k = e.nextElement();
! Object v = get(k);
if (k instanceof String && v instanceof String) {
h.put((String) k, (String) v);
}
}
}
--- 1081,1130 ----
* method is duplicated in order to ensure that a non-1.1 compiler can
* compile this file.
*/
public void list(PrintWriter out) {
out.println("-- listing properties --");
! Map<String, Object> h = new HashMap<>();
enumerate(h);
! for (Map.Entry<String, Object> e : h.entrySet()) {
! String key = e.getKey();
! String val = (String)e.getValue();
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
}
out.println(key + "=" + val);
}
}
/**
! * Enumerates all key/value pairs in the specified Map.
! * @param h the Map
* @throws ClassCastException if any of the property keys
* is not of String type.
*/
! private void enumerate(Map<String, Object> h) {
if (defaults != null) {
defaults.enumerate(h);
}
! for (Map.Entry<Object, Object> e : entrySet()) {
! String key = (String)e.getKey();
! h.put(key, e.getValue());
}
}
/**
! * Enumerates all key/value pairs in the specified Map
* and omits the property if the key or value is not a string.
! * @param h the Map
*/
! private void enumerateStringProperties(Map<String, String> h) {
if (defaults != null) {
defaults.enumerateStringProperties(h);
}
! for (Map.Entry<Object, Object> e : entrySet()) {
! Object k = e.getKey();
! Object v = e.getValue();
if (k instanceof String && v instanceof String) {
h.put((String) k, (String) v);
}
}
}
*** 1132,1137 ****
--- 1139,1369 ----
/** A table of hex digits */
private static final char[] hexDigit = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
+
+ //
+ // Hashtable methods overridden and delegated to a ConcurrentHashMap instance
+
+ private transient ConcurrentHashMap<Object, Object> map =
+ new ConcurrentHashMap<>(8);
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ @Override
+ public Enumeration<Object> keys() {
+ return map.keys();
+ }
+
+ @Override
+ public Enumeration<Object> elements() {
+ return map.elements();
+ }
+
+ @Override
+ public boolean contains(Object value) {
+ return map.contains(value);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public Object get(Object key) {
+ return map.get(key);
+ }
+
+ @Override
+ public Object put(Object key, Object value) {
+ return map.put(key, value);
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return map.remove(key);
+ }
+
+ @Override
+ public void putAll(Map<?, ?> t) {
+ map.putAll(t);
+ }
+
+ @Override
+ public void clear() {
+ map.clear();
+ }
+
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+
+ @Override
+ public Set<Object> keySet() {
+ return map.keySet();
+ }
+
+ @Override
+ public Set<Map.Entry<Object, Object>> entrySet() {
+ return map.entrySet();
+ }
+
+ @Override
+ public Collection<Object> values() {
+ return map.values();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return map.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override
+ public Object getOrDefault(Object key, Object defaultValue) {
+ return map.getOrDefault(key, defaultValue);
+ }
+
+ @Override
+ public void forEach(BiConsumer<? super Object, ? super Object> action) {
+ map.forEach(action);
+ }
+
+ @Override
+ public void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
+ map.replaceAll(function);
+ }
+
+ @Override
+ public Object putIfAbsent(Object key, Object value) {
+ return map.putIfAbsent(key, value);
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return map.remove(key, value);
+ }
+
+ @Override
+ public boolean replace(Object key, Object oldValue, Object newValue) {
+ return map.replace(key, oldValue, newValue);
+ }
+
+ @Override
+ public Object replace(Object key, Object value) {
+ return map.replace(key, value);
+ }
+
+ @Override
+ public Object computeIfAbsent(Object key,
+ Function<? super Object, ?> mappingFunction) {
+ return map.computeIfAbsent(key, mappingFunction);
+ }
+
+ @Override
+ public Object computeIfPresent(Object key,
+ BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+ return map.computeIfPresent(key, remappingFunction);
+ }
+
+ @Override
+ public Object compute(Object key,
+ BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+ return map.compute(key, remappingFunction);
+ }
+
+ @Override
+ public Object merge(Object key, Object value,
+ BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+ return map.merge(key, value, remappingFunction);
+ }
+
+ //
+ // Special Hashtable methods
+
+ @Override
+ protected void rehash() {
+ // no-op
+ }
+
+ @Override
+ public Object clone() {
+ Properties clone = (Properties) cloneHashtable();
+ clone.map = new ConcurrentHashMap<>(map);
+ return clone;
+ }
+
+ //
+ // Hashtable serialization overrides
+ // (these should emit and consume Hashtable-compatible stream)
+
+ @Override
+ void writeHashtable(ObjectOutputStream s) throws IOException {
+ List<Object> entryStack = new ArrayList<>(map.size() * 2); // an estimate
+
+ for (Map.Entry<Object, Object> entry : map.entrySet()) {
+ entryStack.add(entry.getValue());
+ entryStack.add(entry.getKey());
+ }
+
+ // Write out the simulated threshold, loadfactor
+ float loadFactor = 0.75f;
+ int count = entryStack.size() / 2;
+ int length = (int)(count / loadFactor) + (count / 20) + 3;
+ if (length > count && (length & 1) == 0) {
+ length--;
+ }
+ synchronized (map) { // in case of multiple concurrent serializations
+ defaultWriteHashtable(s, length, loadFactor);
+ }
+
+ // Write out simulated length and real count of elements
+ s.writeInt(length);
+ s.writeInt(count);
+
+ // Write out the key/value objects from the stacked entries
+ for (int i = entryStack.size() - 1; i >= 0; i--) {
+ s.writeObject(entryStack.get(i));
+ }
+ }
+
+ @Override
+ void readHashtable(ObjectInputStream s) throws IOException,
+ ClassNotFoundException {
+ // Read in the threshold and loadfactor
+ s.defaultReadObject();
+
+ // Read the original length of the array and number of elements
+ int origlength = s.readInt();
+ int elements = s.readInt();
+
+ // create CHM of appropriate capacity
+ map = new ConcurrentHashMap<>(elements);
+
+ // Read all the key/value objects
+ for (; elements > 0; elements--) {
+ Object key = s.readObject();
+ Object value = s.readObject();
+ map.put(key, value);
+ }
+ }
}
< prev index next >