/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import org.springframework.lang.Nullable;
Specialization of Properties
that sorts properties alphanumerically based on their keys. This can be useful when storing the Properties
instance in a properties file, since it allows such files to be generated in a repeatable manner with consistent ordering of properties.
Comments in generated properties files can also be optionally omitted.
Author: Sam Brannen See Also: Since: 5.2
/**
* Specialization of {@link Properties} that sorts properties alphanumerically
* based on their keys.
*
* <p>This can be useful when storing the {@link Properties} instance in a
* properties file, since it allows such files to be generated in a repeatable
* manner with consistent ordering of properties.
*
* <p>Comments in generated properties files can also be optionally omitted.
*
* @author Sam Brannen
* @since 5.2
* @see java.util.Properties
*/
@SuppressWarnings("serial")
class SortedProperties extends Properties {
static final String EOL = System.lineSeparator();
private static final Comparator<Object> keyComparator = Comparator.comparing(String::valueOf);
private static final Comparator<Entry<Object, Object>> entryComparator = Entry.comparingByKey(keyComparator);
private final boolean omitComments;
Construct a new SortedProperties
instance that honors the supplied omitComments
flag. Params: - omitComments –
true
if comments should be omitted when storing properties in a file
/**
* Construct a new {@code SortedProperties} instance that honors the supplied
* {@code omitComments} flag.
* @param omitComments {@code true} if comments should be omitted when
* storing properties in a file
*/
SortedProperties(boolean omitComments) {
this.omitComments = omitComments;
}
Construct a new SortedProperties
instance with properties populated from the supplied Properties
object and honoring the supplied omitComments
flag. Default properties from the supplied Properties
object will not be copied.
Params: - properties – the
Properties
object from which to copy the initial properties - omitComments –
true
if comments should be omitted when storing properties in a file
/**
* Construct a new {@code SortedProperties} instance with properties populated
* from the supplied {@link Properties} object and honoring the supplied
* {@code omitComments} flag.
* <p>Default properties from the supplied {@code Properties} object will
* not be copied.
* @param properties the {@code Properties} object from which to copy the
* initial properties
* @param omitComments {@code true} if comments should be omitted when
* storing properties in a file
*/
SortedProperties(Properties properties, boolean omitComments) {
this(omitComments);
putAll(properties);
}
@Override
public void store(OutputStream out, @Nullable String comments) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
super.store(baos, (this.omitComments ? null : comments));
String contents = baos.toString(StandardCharsets.ISO_8859_1.name());
for (String line : contents.split(EOL)) {
if (!(this.omitComments && line.startsWith("#"))) {
out.write((line + EOL).getBytes(StandardCharsets.ISO_8859_1));
}
}
}
@Override
public void store(Writer writer, @Nullable String comments) throws IOException {
StringWriter stringWriter = new StringWriter();
super.store(stringWriter, (this.omitComments ? null : comments));
String contents = stringWriter.toString();
for (String line : contents.split(EOL)) {
if (!(this.omitComments && line.startsWith("#"))) {
writer.write(line + EOL);
}
}
}
@Override
public void storeToXML(OutputStream out, @Nullable String comments) throws IOException {
super.storeToXML(out, (this.omitComments ? null : comments));
}
@Override
public void storeToXML(OutputStream out, @Nullable String comments, String encoding) throws IOException {
super.storeToXML(out, (this.omitComments ? null : comments), encoding);
}
Return a sorted enumeration of the keys in this Properties
object. See Also:
/**
* Return a sorted enumeration of the keys in this {@link Properties} object.
* @see #keySet()
*/
@Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(keySet());
}
Return a sorted set of the keys in this Properties
object. The keys will be converted to strings if necessary using String.valueOf(Object)
and sorted alphanumerically according to the natural order of strings.
/**
* Return a sorted set of the keys in this {@link Properties} object.
* <p>The keys will be converted to strings if necessary using
* {@link String#valueOf(Object)} and sorted alphanumerically according to
* the natural order of strings.
*/
@Override
public Set<Object> keySet() {
Set<Object> sortedKeys = new TreeSet<>(keyComparator);
sortedKeys.addAll(super.keySet());
return Collections.synchronizedSet(sortedKeys);
}
Return a sorted set of the entries in this Properties
object. The entries will be sorted based on their keys, and the keys will be converted to strings if necessary using String.valueOf(Object)
and compared alphanumerically according to the natural order of strings.
/**
* Return a sorted set of the entries in this {@link Properties} object.
* <p>The entries will be sorted based on their keys, and the keys will be
* converted to strings if necessary using {@link String#valueOf(Object)}
* and compared alphanumerically according to the natural order of strings.
*/
@Override
public Set<Entry<Object, Object>> entrySet() {
Set<Entry<Object, Object>> sortedEntries = new TreeSet<>(entryComparator);
sortedEntries.addAll(super.entrySet());
return Collections.synchronizedSet(sortedEntries);
}
}