|
| 1 | +/* |
| 2 | + * Copyright 2002-2019 the original author or authors. |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * https://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +package org.springframework.context.index.processor; |
| 18 | + |
| 19 | +import java.io.ByteArrayOutputStream; |
| 20 | +import java.io.IOException; |
| 21 | +import java.io.OutputStream; |
| 22 | +import java.io.StringWriter; |
| 23 | +import java.io.Writer; |
| 24 | +import java.nio.charset.StandardCharsets; |
| 25 | +import java.util.Collections; |
| 26 | +import java.util.Comparator; |
| 27 | +import java.util.Enumeration; |
| 28 | +import java.util.Map.Entry; |
| 29 | +import java.util.Properties; |
| 30 | +import java.util.Set; |
| 31 | +import java.util.TreeSet; |
| 32 | + |
| 33 | +/** |
| 34 | + * Specialization of {@link Properties} that sorts properties alphanumerically |
| 35 | + * based on their keys. |
| 36 | + * |
| 37 | + * <p>This can be useful when storing the {@link Properties} instance in a |
| 38 | + * properties file, since it allows such files to be generated in a repeatable |
| 39 | + * manner with consistent ordering of properties. |
| 40 | + * |
| 41 | + * <p>Comments in generated properties files can also be optionally omitted. |
| 42 | + * |
| 43 | + * @author Sam Brannen |
| 44 | + * @since 5.2 |
| 45 | + * @see java.util.Properties |
| 46 | + */ |
| 47 | +@SuppressWarnings("serial") |
| 48 | +class SortedProperties extends Properties { |
| 49 | + |
| 50 | + static final String EOL = System.lineSeparator(); |
| 51 | + |
| 52 | + private static final Comparator<Object> keyComparator = // |
| 53 | + (key1, key2) -> String.valueOf(key1).compareTo(String.valueOf(key2)); |
| 54 | + |
| 55 | + private static final Comparator<Entry<Object, Object>> entryComparator = // |
| 56 | + Entry.comparingByKey(keyComparator); |
| 57 | + |
| 58 | + private final boolean omitComments; |
| 59 | + |
| 60 | + |
| 61 | + /** |
| 62 | + * Construct a new {@code SortedProperties} instance that honors the supplied |
| 63 | + * {@code omitComments} flag. |
| 64 | + * |
| 65 | + * @param omitComments {@code true} if comments should be omitted when |
| 66 | + * storing properties in a file |
| 67 | + */ |
| 68 | + SortedProperties(boolean omitComments) { |
| 69 | + this.omitComments = omitComments; |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Construct a new {@code SortedProperties} instance with properties populated |
| 74 | + * from the supplied {@link Properties} object and honoring the supplied |
| 75 | + * {@code omitComments} flag. |
| 76 | + * |
| 77 | + * <p>Default properties from the supplied {@code Properties} object will |
| 78 | + * not be copied. |
| 79 | + * |
| 80 | + * @param properties the {@code Properties} object from which to copy the |
| 81 | + * initial properties |
| 82 | + * @param omitComments {@code true} if comments should be omitted when |
| 83 | + * storing properties in a file |
| 84 | + */ |
| 85 | + SortedProperties(Properties properties, boolean omitComments) { |
| 86 | + this(omitComments); |
| 87 | + putAll(properties); |
| 88 | + } |
| 89 | + |
| 90 | + @Override |
| 91 | + public void store(OutputStream out, String comments) throws IOException { |
| 92 | + ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| 93 | + super.store(baos, (this.omitComments ? null : comments)); |
| 94 | + String contents = new String(baos.toByteArray(), StandardCharsets.ISO_8859_1); |
| 95 | + for (String line : contents.split(EOL)) { |
| 96 | + if (!this.omitComments || !line.startsWith("#")) { |
| 97 | + out.write((line + EOL).getBytes(StandardCharsets.ISO_8859_1)); |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + @Override |
| 103 | + public void store(Writer writer, String comments) throws IOException { |
| 104 | + StringWriter stringWriter = new StringWriter(); |
| 105 | + super.store(stringWriter, (this.omitComments ? null : comments)); |
| 106 | + String contents = stringWriter.toString(); |
| 107 | + for (String line : contents.split(EOL)) { |
| 108 | + if (!this.omitComments || !line.startsWith("#")) { |
| 109 | + writer.write(line + EOL); |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + @Override |
| 115 | + public void storeToXML(OutputStream out, String comments) throws IOException { |
| 116 | + super.storeToXML(out, (this.omitComments ? null : comments)); |
| 117 | + } |
| 118 | + |
| 119 | + @Override |
| 120 | + public void storeToXML(OutputStream out, String comments, String encoding) throws IOException { |
| 121 | + super.storeToXML(out, (this.omitComments ? null : comments), encoding); |
| 122 | + } |
| 123 | + |
| 124 | + /** |
| 125 | + * Return a sorted enumeration of the keys in this {@link Properties} object. |
| 126 | + * @see #keySet() |
| 127 | + */ |
| 128 | + @Override |
| 129 | + public synchronized Enumeration<Object> keys() { |
| 130 | + return Collections.enumeration(keySet()); |
| 131 | + } |
| 132 | + |
| 133 | + /** |
| 134 | + * Return a sorted set of the keys in this {@link Properties} object. |
| 135 | + * <p>The keys will be converted to strings if necessary using |
| 136 | + * {@link String#valueOf(Object)} and sorted alphanumerically according to |
| 137 | + * the natural order of strings. |
| 138 | + */ |
| 139 | + @Override |
| 140 | + public Set<Object> keySet() { |
| 141 | + Set<Object> sortedKeys = new TreeSet<>(keyComparator); |
| 142 | + sortedKeys.addAll(super.keySet()); |
| 143 | + return Collections.synchronizedSet(sortedKeys); |
| 144 | + } |
| 145 | + |
| 146 | + /** |
| 147 | + * Return a sorted set of the entries in this {@link Properties} object. |
| 148 | + * <p>The entries will be sorted based on their keys, and the keys will be |
| 149 | + * converted to strings if necessary using {@link String#valueOf(Object)} |
| 150 | + * and compared alphanumerically according to the natural order of strings. |
| 151 | + */ |
| 152 | + @Override |
| 153 | + public Set<Entry<Object, Object>> entrySet() { |
| 154 | + Set<Entry<Object, Object>> sortedEntries = new TreeSet<>(entryComparator); |
| 155 | + sortedEntries.addAll(super.entrySet()); |
| 156 | + return Collections.synchronizedSet(sortedEntries); |
| 157 | + } |
| 158 | + |
| 159 | +} |
0 commit comments