PropertiesConfigurationLayout.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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
- *
- * http://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.apache.commons.configuration2;
- import java.io.IOException;
- import java.io.Reader;
- import java.io.Writer;
- import java.net.URL;
- import java.util.ArrayDeque;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Properties;
- import java.util.Set;
- import java.util.concurrent.atomic.AtomicInteger;
- import org.apache.commons.configuration2.event.ConfigurationEvent;
- import org.apache.commons.configuration2.event.EventListener;
- import org.apache.commons.configuration2.ex.ConfigurationException;
- import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
- import org.apache.commons.lang3.StringUtils;
- /**
- * <p>
- * A helper class used by {@link PropertiesConfiguration} to keep the layout of a properties file.
- * </p>
- * <p>
- * Instances of this class are associated with a {@code PropertiesConfiguration} object. They are responsible for
- * analyzing properties files and for extracting as much information about the file layout (for example empty lines, comments)
- * as possible. When the properties file is written back again it should be close to the original.
- * </p>
- * <p>
- * The {@code PropertiesConfigurationLayout} object associated with a {@code PropertiesConfiguration} object can be
- * obtained using the {@code getLayout()} method of the configuration. Then the methods provided by this class can be
- * used to alter the properties file's layout.
- * </p>
- * <p>
- * Implementation note: This is a very simple implementation, which is far away from being perfect, i.e. the original
- * layout of a properties file won't be reproduced in all cases. One limitation is that comments for multi-valued
- * property keys are concatenated. Maybe this implementation can later be improved.
- * </p>
- * <p>
- * To get an impression how this class works consider the following properties file:
- * </p>
- *
- * <pre>
- * # A demo configuration file
- * # for Demo App 1.42
- *
- * # Application name
- * AppName=Demo App
- *
- * # Application vendor
- * AppVendor=DemoSoft
- *
- *
- * # GUI properties
- * # Window Color
- * windowColors=0xFFFFFF,0x000000
- *
- * # Include some setting
- * include=settings.properties
- * # Another vendor
- * AppVendor=TestSoft
- * </pre>
- *
- * <p>
- * For this example the following points are relevant:
- * </p>
- * <ul>
- * <li>The first two lines are set as header comment. The header comment is determined by the last blank line before the
- * first property definition.</li>
- * <li>For the property {@code AppName} one comment line and one leading blank line is stored.</li>
- * <li>For the property {@code windowColors} two comment lines and two leading blank lines are stored.</li>
- * <li>Include files is something this class cannot deal with well. When saving the properties configuration back, the
- * included properties are simply contained in the original file. The comment before the include property is
- * skipped.</li>
- * <li>For all properties except for {@code AppVendor} the "single line" flag is set. This is relevant only
- * for {@code windowColors}, which has multiple values defined in one line using the separator character.</li>
- * <li>The {@code AppVendor} property appears twice. The comment lines are concatenated, so that
- * {@code layout.getComment("AppVendor");} will result in {@code Application vendor<CR>Another vendor}, with
- * {@code <CR>} meaning the line separator. In addition the "single line" flag is set to <strong>false</strong>
- * for this property. When the file is saved, two property definitions will be written (in series).</li>
- * </ul>
- *
- * @since 1.3
- */
- public class PropertiesConfigurationLayout implements EventListener<ConfigurationEvent> {
- /**
- * A helper class for storing all layout related information for a configuration property.
- */
- static class PropertyLayoutData implements Cloneable {
- /** Stores the comment for the property. */
- private StringBuffer comment;
- /** The separator to be used for this property. */
- private String separator;
- /** Stores the number of blank lines before this property. */
- private int blankLines;
- /** Stores the single line property. */
- private boolean singleLine;
- /**
- * Creates a new instance of {@code PropertyLayoutData}.
- */
- public PropertyLayoutData() {
- singleLine = true;
- separator = PropertiesConfiguration.DEFAULT_SEPARATOR;
- }
- /**
- * Adds a comment for this property. If already a comment exists, the new comment is added (separated by a newline).
- *
- * @param s the comment to add
- */
- public void addComment(final String s) {
- if (s != null) {
- if (comment == null) {
- comment = new StringBuffer(s);
- } else {
- comment.append(CR).append(s);
- }
- }
- }
- /**
- * Creates a copy of this object.
- *
- * @return the copy
- */
- @Override
- public PropertyLayoutData clone() {
- try {
- final PropertyLayoutData copy = (PropertyLayoutData) super.clone();
- if (comment != null) {
- // must copy string buffer, too
- copy.comment = new StringBuffer(getComment());
- }
- return copy;
- } catch (final CloneNotSupportedException cnex) {
- // This cannot happen!
- throw new ConfigurationRuntimeException(cnex);
- }
- }
- /**
- * Gets the number of blank lines before this property.
- *
- * @return the number of blank lines before this property
- * @deprecated Use {#link {@link #getBlankLines()}}.
- */
- @Deprecated
- public int getBlancLines() {
- return getBlankLines();
- }
- /**
- * Gets the number of blank lines before this property.
- *
- * @return the number of blank lines before this property
- * @since 2.8.0
- */
- public int getBlankLines() {
- return blankLines;
- }
- /**
- * Gets the comment for this property. The comment is returned as it is, without processing of comment characters.
- *
- * @return the comment (can be <strong>null</strong>)
- */
- public String getComment() {
- return Objects.toString(comment, null);
- }
- /**
- * Gets the separator that was used for this property.
- *
- * @return the property separator
- */
- public String getSeparator() {
- return separator;
- }
- /**
- * Returns the single line flag.
- *
- * @return the single line flag
- */
- public boolean isSingleLine() {
- return singleLine;
- }
- /**
- * Sets the number of properties before this property.
- *
- * @param blankLines the number of properties before this property
- * @deprecated Use {@link #setBlankLines(int)}.
- */
- @Deprecated
- public void setBlancLines(final int blankLines) {
- setBlankLines(blankLines);
- }
- /**
- * Sets the number of properties before this property.
- *
- * @param blankLines the number of properties before this property
- * @since 2.8.0
- */
- public void setBlankLines(final int blankLines) {
- this.blankLines = blankLines;
- }
- /**
- * Sets the comment for this property.
- *
- * @param s the new comment (can be <strong>null</strong>)
- */
- public void setComment(final String s) {
- if (s == null) {
- comment = null;
- } else {
- comment = new StringBuffer(s);
- }
- }
- /**
- * Sets the separator to be used for the represented property.
- *
- * @param separator the property separator
- */
- public void setSeparator(final String separator) {
- this.separator = separator;
- }
- /**
- * Sets the single line flag.
- *
- * @param singleLine the single line flag
- */
- public void setSingleLine(final boolean singleLine) {
- this.singleLine = singleLine;
- }
- }
- /** Constant for the line break character. */
- private static final String CR = "\n";
- /** Constant for the default comment prefix. */
- private static final String COMMENT_PREFIX = "# ";
- /**
- * Helper method for generating a comment string. Depending on the boolean argument the resulting string either has no
- * comment characters or a leading comment character at each line.
- *
- * @param comment the comment string to be processed
- * @param commentChar determines the presence of comment characters
- * @return the canonical comment string (can be <strong>null</strong>)
- */
- private static String constructCanonicalComment(final String comment, final boolean commentChar) {
- return comment == null ? null : trimComment(comment, commentChar);
- }
- /**
- * Tests whether a line is a comment, i.e. whether it starts with a comment character.
- *
- * @param line the line
- * @return a flag if this is a comment line
- */
- static boolean isCommentLine(final String line) {
- return PropertiesConfiguration.isCommentLine(line);
- }
- /**
- * Either removes the comment character from the given comment line or ensures that the line starts with a comment
- * character.
- *
- * @param s the comment line
- * @param comment if <strong>true</strong>, a comment character will always be enforced; if <strong>false</strong>, it will be removed
- * @return the line without comment character
- */
- static String stripCommentChar(final String s, final boolean comment) {
- if (StringUtils.isBlank(s) || isCommentLine(s) == comment) {
- return s;
- }
- if (!comment) {
- int pos = 0;
- // find first comment character
- while (PropertiesConfiguration.COMMENT_CHARS.indexOf(s.charAt(pos)) < 0) {
- pos++;
- }
- // Remove leading spaces
- pos++;
- while (pos < s.length() && Character.isWhitespace(s.charAt(pos))) {
- pos++;
- }
- return pos < s.length() ? s.substring(pos) : StringUtils.EMPTY;
- }
- return COMMENT_PREFIX + s;
- }
- /**
- * Trims a comment. This method either removes all comment characters from the given string, leaving only the plain
- * comment text or ensures that every line starts with a valid comment character.
- *
- * @param s the string to be processed
- * @param comment if <strong>true</strong>, a comment character will always be enforced; if <strong>false</strong>, it will be removed
- * @return the trimmed comment
- */
- static String trimComment(final String s, final boolean comment) {
- final StringBuilder buf = new StringBuilder(s.length());
- int lastPos = 0;
- int pos;
- do {
- pos = s.indexOf(CR, lastPos);
- if (pos >= 0) {
- final String line = s.substring(lastPos, pos);
- buf.append(stripCommentChar(line, comment)).append(CR);
- lastPos = pos + CR.length();
- }
- } while (pos >= 0);
- if (lastPos < s.length()) {
- buf.append(stripCommentChar(s.substring(lastPos), comment));
- }
- return buf.toString();
- }
- /**
- * Helper method for writing a comment line. This method ensures that the correct line separator is used if the comment
- * spans multiple lines.
- *
- * @param writer the writer
- * @param comment the comment to write
- * @throws IOException if an IO error occurs
- */
- private static void writeComment(final PropertiesConfiguration.PropertiesWriter writer, final String comment) throws IOException {
- if (comment != null) {
- writer.writeln(StringUtils.replace(comment, CR, writer.getLineSeparator()));
- }
- }
- /** Stores a map with the contained layout information. */
- private final Map<String, PropertyLayoutData> layoutData;
- /** Stores the header comment. */
- private String headerComment;
- /** Stores the footer comment. */
- private String footerComment;
- /** The global separator that will be used for all properties. */
- private String globalSeparator;
- /** The line separator. */
- private String lineSeparator;
- /** A counter for determining nested load calls. */
- private final AtomicInteger loadCounter;
- /** Stores the force single line flag. */
- private boolean forceSingleLine;
- /** Seen includes. */
- private final ArrayDeque<URL> seenStack = new ArrayDeque<>();
- /**
- * Creates a new, empty instance of {@code PropertiesConfigurationLayout}.
- */
- public PropertiesConfigurationLayout() {
- this(null);
- }
- /**
- * Creates a new instance of {@code PropertiesConfigurationLayout} and copies the data of the specified layout object.
- *
- * @param c the layout object to be copied
- */
- public PropertiesConfigurationLayout(final PropertiesConfigurationLayout c) {
- loadCounter = new AtomicInteger();
- layoutData = new LinkedHashMap<>();
- if (c != null) {
- copyFrom(c);
- }
- }
- /**
- * Checks if parts of the passed in comment can be used as header comment. This method checks whether a header comment
- * can be defined (i.e. whether this is the first comment in the loaded file). If this is the case, it is searched for
- * the latest blank line. This line will mark the end of the header comment. The return value is the index of the first
- * line in the passed in list, which does not belong to the header comment.
- *
- * @param commentLines the comment lines
- * @return the index of the next line after the header comment
- */
- private int checkHeaderComment(final List<String> commentLines) {
- if (loadCounter.get() == 1 && layoutData.isEmpty()) {
- int index = commentLines.size() - 1;
- // strip comments that belong to first key
- while (index >= 0 && StringUtils.isNotEmpty(commentLines.get(index))) {
- index--;
- }
- // strip blank lines
- while (index >= 0 && StringUtils.isEmpty(commentLines.get(index))) {
- index--;
- }
- if (getHeaderComment() == null) {
- setHeaderComment(extractComment(commentLines, 0, index));
- }
- return index + 1;
- }
- return 0;
- }
- /**
- * Removes all content from this layout object.
- */
- private void clear() {
- seenStack.clear();
- layoutData.clear();
- setHeaderComment(null);
- setFooterComment(null);
- }
- /**
- * Copies the data from the given layout object.
- *
- * @param c the layout object to copy
- */
- private void copyFrom(final PropertiesConfigurationLayout c) {
- c.getKeys().forEach(key -> layoutData.put(key, c.layoutData.get(key).clone()));
- setHeaderComment(c.getHeaderComment());
- setFooterComment(c.getFooterComment());
- }
- /**
- * Extracts a comment string from the given range of the specified comment lines. The single lines are added using a
- * line feed as separator.
- *
- * @param commentLines a list with comment lines
- * @param from the start index
- * @param to the end index (inclusive)
- * @return the comment string (<strong>null</strong> if it is undefined)
- */
- private String extractComment(final List<String> commentLines, final int from, final int to) {
- if (to < from) {
- return null;
- }
- final StringBuilder buf = new StringBuilder(commentLines.get(from));
- for (int i = from + 1; i <= to; i++) {
- buf.append(CR);
- buf.append(commentLines.get(i));
- }
- return buf.toString();
- }
- /**
- * Returns a layout data object for the specified key. If this is a new key, a new object is created and initialized
- * with default values.
- *
- * @param key the key
- * @return the corresponding layout data object
- */
- private PropertyLayoutData fetchLayoutData(final String key) {
- if (key == null) {
- throw new IllegalArgumentException("Property key must not be null!");
- }
- // PropertyLayoutData defaults to singleLine = true
- return layoutData.computeIfAbsent(key, k -> new PropertyLayoutData());
- }
- /**
- * Gets the number of blank lines before this property key. If this key does not exist, 0 will be returned.
- *
- * @param key the property key
- * @return the number of blank lines before the property definition for this key
- * @deprecated Use {@link #getBlankLinesBefore(String)}.
- */
- @Deprecated
- public int getBlancLinesBefore(final String key) {
- return getBlankLinesBefore(key);
- }
- /**
- * Gets the number of blank lines before this property key. If this key does not exist, 0 will be returned.
- *
- * @param key the property key
- * @return the number of blank lines before the property definition for this key
- */
- public int getBlankLinesBefore(final String key) {
- return fetchLayoutData(key).getBlankLines();
- }
- /**
- * Gets the comment for the specified property key in a canonical form. "Canonical" means that either all
- * lines start with a comment character or none. If the {@code commentChar} parameter is <strong>false</strong>, all comment
- * characters are removed, so that the result is only the plain text of the comment. Otherwise it is ensured that each
- * line of the comment starts with a comment character. Also, line breaks in the comment are normalized to the line
- * separator "\n".
- *
- * @param key the key of the property
- * @param commentChar determines whether all lines should start with comment characters or not
- * @return the canonical comment for this key (can be <strong>null</strong>)
- */
- public String getCanonicalComment(final String key, final boolean commentChar) {
- return constructCanonicalComment(getComment(key), commentChar);
- }
- /**
- * Gets the footer comment of the represented properties file in a canonical form. This method works like
- * {@code getCanonicalHeaderComment()}, but reads the footer comment.
- *
- * @param commentChar determines the presence of comment characters
- * @return the footer comment (can be <strong>null</strong>)
- * @see #getCanonicalHeaderComment(boolean)
- * @since 2.0
- */
- public String getCanonicalFooterCooment(final boolean commentChar) {
- return constructCanonicalComment(getFooterComment(), commentChar);
- }
- /**
- * Gets the header comment of the represented properties file in a canonical form. With the {@code commentChar}
- * parameter it can be specified whether comment characters should be stripped or be always present.
- *
- * @param commentChar determines the presence of comment characters
- * @return the header comment (can be <strong>null</strong>)
- */
- public String getCanonicalHeaderComment(final boolean commentChar) {
- return constructCanonicalComment(getHeaderComment(), commentChar);
- }
- /**
- * Gets the comment for the specified property key. The comment is returned as it was set (either manually by calling
- * {@code setComment()} or when it was loaded from a properties file). No modifications are performed.
- *
- * @param key the key of the property
- * @return the comment for this key (can be <strong>null</strong>)
- */
- public String getComment(final String key) {
- return fetchLayoutData(key).getComment();
- }
- /**
- * Gets the footer comment of the represented properties file. This method returns the footer comment exactly as it
- * was set using {@code setFooterComment()} or extracted from the loaded properties file.
- *
- * @return the footer comment (can be <strong>null</strong>)
- * @since 2.0
- */
- public String getFooterComment() {
- return footerComment;
- }
- /**
- * Gets the global separator.
- *
- * @return the global properties separator
- * @since 1.7
- */
- public String getGlobalSeparator() {
- return globalSeparator;
- }
- /**
- * Gets the header comment of the represented properties file. This method returns the header comment exactly as it
- * was set using {@code setHeaderComment()} or extracted from the loaded properties file.
- *
- * @return the header comment (can be <strong>null</strong>)
- */
- public String getHeaderComment() {
- return headerComment;
- }
- /**
- * Gets a set with all property keys managed by this object.
- *
- * @return a set with all contained property keys
- */
- public Set<String> getKeys() {
- return layoutData.keySet();
- }
- /**
- * Gets the line separator.
- *
- * @return the line separator
- * @since 1.7
- */
- public String getLineSeparator() {
- return lineSeparator;
- }
- /**
- * Gets the separator for the property with the given key.
- *
- * @param key the property key
- * @return the property separator for this property
- * @since 1.7
- */
- public String getSeparator(final String key) {
- return fetchLayoutData(key).getSeparator();
- }
- /**
- * Returns the "force single line" flag.
- *
- * @return the force single line flag
- * @see #setForceSingleLine(boolean)
- */
- public boolean isForceSingleLine() {
- return forceSingleLine;
- }
- /**
- * Returns a flag whether the specified property is defined on a single line. This is meaningful only if this property
- * has multiple values.
- *
- * @param key the property key
- * @return a flag if this property is defined on a single line
- */
- public boolean isSingleLine(final String key) {
- return fetchLayoutData(key).isSingleLine();
- }
- /**
- * Reads a properties file and stores its internal structure. The found properties will be added to the specified
- * configuration object.
- *
- * @param config the associated configuration object
- * @param reader the reader to the properties file
- * @throws ConfigurationException if an error occurs
- */
- public void load(final PropertiesConfiguration config, final Reader reader) throws ConfigurationException {
- loadCounter.incrementAndGet();
- @SuppressWarnings("resource") // createPropertiesReader wraps the reader.
- final PropertiesConfiguration.PropertiesReader pReader = config.getIOFactory().createPropertiesReader(reader);
- try {
- while (pReader.nextProperty()) {
- if (config.propertyLoaded(pReader.getPropertyName(), pReader.getPropertyValue(), seenStack)) {
- final boolean contained = layoutData.containsKey(pReader.getPropertyName());
- int blankLines = 0;
- int idx = checkHeaderComment(pReader.getCommentLines());
- while (idx < pReader.getCommentLines().size() && StringUtils.isEmpty(pReader.getCommentLines().get(idx))) {
- idx++;
- blankLines++;
- }
- final String comment = extractComment(pReader.getCommentLines(), idx, pReader.getCommentLines().size() - 1);
- final PropertyLayoutData data = fetchLayoutData(pReader.getPropertyName());
- if (contained) {
- data.addComment(comment);
- data.setSingleLine(false);
- } else {
- data.setComment(comment);
- data.setBlankLines(blankLines);
- data.setSeparator(pReader.getPropertySeparator());
- }
- }
- }
- setFooterComment(extractComment(pReader.getCommentLines(), 0, pReader.getCommentLines().size() - 1));
- } catch (final IOException ioex) {
- throw new ConfigurationException(ioex);
- } finally {
- loadCounter.decrementAndGet();
- }
- }
- /**
- * The event listener callback. Here event notifications of the configuration object are processed to update the layout
- * object properly.
- *
- * @param event the event object
- */
- @Override
- public void onEvent(final ConfigurationEvent event) {
- if (!event.isBeforeUpdate() && loadCounter.get() == 0) {
- if (ConfigurationEvent.ADD_PROPERTY.equals(event.getEventType())) {
- final boolean contained = layoutData.containsKey(event.getPropertyName());
- final PropertyLayoutData data = fetchLayoutData(event.getPropertyName());
- data.setSingleLine(!contained);
- } else if (ConfigurationEvent.CLEAR_PROPERTY.equals(event.getEventType())) {
- layoutData.remove(event.getPropertyName());
- } else if (ConfigurationEvent.CLEAR.equals(event.getEventType())) {
- clear();
- } else if (ConfigurationEvent.SET_PROPERTY.equals(event.getEventType())) {
- fetchLayoutData(event.getPropertyName());
- }
- }
- }
- /**
- * Writes the properties file to the given writer, preserving as much of its structure as possible.
- *
- * @param config the associated configuration object
- * @param writer the writer
- * @throws ConfigurationException if an error occurs
- */
- public void save(final PropertiesConfiguration config, final Writer writer) throws ConfigurationException {
- try {
- @SuppressWarnings("resource") // createPropertiesReader wraps the writer.
- final PropertiesConfiguration.PropertiesWriter pWriter = config.getIOFactory().createPropertiesWriter(writer, config.getListDelimiterHandler());
- pWriter.setGlobalSeparator(getGlobalSeparator());
- if (getLineSeparator() != null) {
- pWriter.setLineSeparator(getLineSeparator());
- }
- if (headerComment != null) {
- writeComment(pWriter, getCanonicalHeaderComment(true));
- }
- boolean firstKey = true;
- for (final String key : getKeys()) {
- if (config.containsKeyInternal(key)) {
- // preset header comment needs to be separated from key
- if (firstKey && headerComment != null && getBlankLinesBefore(key) == 0) {
- pWriter.writeln(null);
- }
- // Output blank lines before property
- for (int i = 0; i < getBlankLinesBefore(key); i++) {
- pWriter.writeln(null);
- }
- // Output the comment
- writeComment(pWriter, getCanonicalComment(key, true));
- // Output the property and its value
- final boolean singleLine = isForceSingleLine() || isSingleLine(key);
- pWriter.setCurrentSeparator(getSeparator(key));
- pWriter.writeProperty(key, config.getPropertyInternal(key), singleLine);
- }
- firstKey = false;
- }
- writeComment(pWriter, getCanonicalFooterCooment(true));
- pWriter.flush();
- } catch (final IOException ioex) {
- throw new ConfigurationException(ioex);
- }
- }
- /**
- * Sets the number of blank lines before the given property key. This can be used for a logical grouping of properties.
- *
- * @param key the property key
- * @param number the number of blank lines to add before this property definition
- * @deprecated use {@link PropertiesConfigurationLayout#setBlankLinesBefore(String, int)}.
- */
- @Deprecated
- public void setBlancLinesBefore(final String key, final int number) {
- setBlankLinesBefore(key, number);
- }
- /**
- * Sets the number of blank lines before the given property key. This can be used for a logical grouping of properties.
- *
- * @param key the property key
- * @param number the number of blank lines to add before this property definition
- * @since 2.8.0
- */
- public void setBlankLinesBefore(final String key, final int number) {
- fetchLayoutData(key).setBlankLines(number);
- }
- /**
- * Sets the comment for the specified property key. The comment (or its single lines if it is a multi-line comment) can
- * start with a comment character. If this is the case, it will be written without changes. Otherwise a default comment
- * character is added automatically.
- *
- * @param key the key of the property
- * @param comment the comment for this key (can be <strong>null</strong>, then the comment will be removed)
- */
- public void setComment(final String key, final String comment) {
- fetchLayoutData(key).setComment(comment);
- }
- /**
- * Sets the footer comment for the represented properties file. This comment will be output at the bottom of the file.
- *
- * @param footerComment the footer comment
- * @since 2.0
- */
- public void setFooterComment(final String footerComment) {
- this.footerComment = footerComment;
- }
- /**
- * Sets the "force single line" flag. If this flag is set, all properties with multiple values are written on
- * single lines. This mode provides more compatibility with {@link Properties}, which cannot deal with
- * multiple definitions of a single property. This mode has no effect if the list delimiter parsing is disabled.
- *
- * @param f the force single line flag
- */
- public void setForceSingleLine(final boolean f) {
- forceSingleLine = f;
- }
- /**
- * Sets the global separator for properties. With this method a separator can be set that will be used for all
- * properties when writing the configuration. This is an easy way of determining the properties separator globally. To
- * be compatible with the properties format only the characters {@code =} and {@code :} (with or without whitespace)
- * should be used, but this method does not enforce this - it accepts arbitrary strings. If the global separator is set
- * to <strong>null</strong>, property separators are not changed. This is the default behavior as it produces results that are
- * closer to the original properties file.
- *
- * @param globalSeparator the separator to be used for all properties
- * @since 1.7
- */
- public void setGlobalSeparator(final String globalSeparator) {
- this.globalSeparator = globalSeparator;
- }
- /**
- * Sets the header comment for the represented properties file. This comment will be output on top of the file.
- *
- * @param comment the comment
- */
- public void setHeaderComment(final String comment) {
- headerComment = comment;
- }
- /**
- * Sets the line separator. When writing the properties configuration, all lines are terminated with this separator. If
- * no separator was set, the platform-specific default line separator is used.
- *
- * @param lineSeparator the line separator
- * @since 1.7
- */
- public void setLineSeparator(final String lineSeparator) {
- this.lineSeparator = lineSeparator;
- }
- /**
- * Sets the separator to be used for the property with the given key. The separator is the string between the property
- * key and its value. For new properties " = " is used. When a properties file is read, the layout tries to
- * determine the separator for each property. With this method the separator can be changed. To be compatible with the
- * properties format only the characters {@code =} and {@code :} (with or without whitespace) should be used, but this
- * method does not enforce this - it accepts arbitrary strings. If the key refers to a property with multiple values
- * that are written on multiple lines, this separator will be used on all lines.
- *
- * @param key the key for the property
- * @param sep the separator to be used for this property
- * @since 1.7
- */
- public void setSeparator(final String key, final String sep) {
- fetchLayoutData(key).setSeparator(sep);
- }
- /**
- * Sets the "single line flag" for the specified property key. This flag is evaluated if the property has
- * multiple values (i.e. if it is a list property). In this case, if the flag is set, all values will be written in a
- * single property definition using the list delimiter as separator. Otherwise multiple lines will be written for this
- * property, each line containing one property value.
- *
- * @param key the property key
- * @param f the single line flag
- */
- public void setSingleLine(final String key, final boolean f) {
- fetchLayoutData(key).setSingleLine(f);
- }
- }