forked from checkstyle/checkstyle
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue checkstyle#6311: OrderedPropertiesCheck check that properties a…
…re ordered
- Loading branch information
Thomas Senger
committed
Jun 10, 2019
1 parent
64a31ff
commit 8180644
Showing
27 changed files
with
621 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -933,6 +933,7 @@ optgroup | |
optimisation | ||
Optimizable | ||
oraclejdk | ||
orderedproperties | ||
orderingandspacing | ||
orekit | ||
Orgorgan | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
237 changes: 237 additions & 0 deletions
237
src/main/java/com/puppycrawl/tools/checkstyle/checks/OrderedPropertiesCheck.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
//////////////////////////////////////////////////////////////////////////////// | ||
// checkstyle: Checks Java source code for adherence to a set of rules. | ||
// Copyright (C) 2001-2019 the original author or authors. | ||
// | ||
// This library is free software; you can redistribute it and/or | ||
// modify it under the terms of the GNU Lesser General Public | ||
// License as published by the Free Software Foundation; either | ||
// version 2.1 of the License, or (at your option) any later version. | ||
// | ||
// This library is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
// Lesser General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Lesser General Public | ||
// License along with this library; if not, write to the Free Software | ||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
//////////////////////////////////////////////////////////////////////////////// | ||
|
||
package com.puppycrawl.tools.checkstyle.checks; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.file.Files; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Enumeration; | ||
import java.util.List; | ||
import java.util.Properties; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import com.puppycrawl.tools.checkstyle.StatelessCheck; | ||
import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; | ||
import com.puppycrawl.tools.checkstyle.api.FileText; | ||
|
||
/** | ||
* <p>Since Checkstyle 8.21</p> | ||
* <p>Detects if keys in properties files are in correct order.</p> | ||
* <p> | ||
* Rationale: Unsorted property makes merges more easy. While there are no errors in | ||
* runtime. | ||
* This check is valuable only on files with string resources where order of lines | ||
* does not matter at all, but this can be improved. | ||
* E.g.: checkstyle/src/main/resources/com/puppycrawl/tools/checkstyle/messages.properties | ||
* You may suppress warnings of this check for files that have an logical structure like | ||
* build files or log4j configuration files. See SuppressionFilter. | ||
* <pre /> | ||
* </p> | ||
* <p>Known limitation: The key should not contain a newline. | ||
* The string compare will work, but not the line number reporting.</p> | ||
* <ul> | ||
* <li>Property {@code fileExtensions} - file type extension of the files to check. | ||
* Default value is .properties.</li> | ||
* </ul> | ||
* <p>To configure the check:</p> | ||
* <pre><module name="OrderedProperties" /></pre> | ||
* <p>Example properties file:</p> | ||
* <pre> | ||
* @=64 | ||
* A=65 | ||
* a=97 | ||
* key=107 than nothing | ||
* key.sub=k is 107 and dot is 46 | ||
* key.png=value - violation | ||
* </pre> | ||
* <p>We check order of key's only. Here we would like to use an Locale independent | ||
* order mechanism, an binary order. The order is case insensitive and ascending.</p> | ||
* <ul> | ||
* <li>The @ sign is on position 64 and comes first.</li> | ||
* <li>The capital A is on 65 and the lowercase a is on position 97 on the ascii table.</li> | ||
* <li>Key and key.sub are in correct order here, because only keys are relevant. | ||
* Therefore on line 5 you have only "key" an nothing behind. | ||
* On line 6 you have "key." The dot is on position 46 which is higher than nothing. | ||
* key.png will reported as violation because "png" comes before "sub".</li> | ||
* </ul> | ||
* @since null | ||
*/ | ||
@StatelessCheck | ||
public class OrderedPropertiesCheck extends AbstractFileSetCheck { | ||
|
||
/** | ||
* Localization key for check violation. | ||
*/ | ||
public static final String MSG_KEY = "properties.notSorted.property"; | ||
/** | ||
* Localization key for IO exception occurred on file open. | ||
*/ | ||
public static final String MSG_IO_EXCEPTION_KEY = "unable.open.cause"; | ||
/** | ||
* Pattern matching single space. | ||
*/ | ||
private static final Pattern SPACE_PATTERN = Pattern.compile(" "); | ||
|
||
/** | ||
* Construct the check with default values. | ||
*/ | ||
public OrderedPropertiesCheck() { | ||
setFileExtensions("properties"); | ||
} | ||
|
||
/** | ||
* Processes the file and check order. | ||
* @param file the file to be processed | ||
* @param fileText the contents of the file. | ||
* @noinspection EnumerationCanBeIteration | ||
*/ | ||
@Override | ||
protected void processFiltered(File file, FileText fileText) { | ||
final SequencedProperties properties = new SequencedProperties(); | ||
try (InputStream inputStream = Files.newInputStream(file.toPath())) { | ||
properties.load(inputStream); | ||
} | ||
catch (IOException | IllegalArgumentException ex) { | ||
log(1, MSG_IO_EXCEPTION_KEY, file.getPath(), ex.getLocalizedMessage()); | ||
} | ||
|
||
String previousProp = ""; | ||
int startLineNo = 0; | ||
|
||
final Enumeration<Object> keys = properties.keys(); | ||
|
||
while (keys.hasMoreElements()) { | ||
|
||
final String propKey = (String) keys.nextElement(); | ||
|
||
if (String.CASE_INSENSITIVE_ORDER.compare(previousProp, propKey) > 0) { | ||
|
||
final int lineNo = getLineNumber(startLineNo, fileText, previousProp, propKey); | ||
log(lineNo + 1, MSG_KEY, propKey, previousProp); | ||
// start searching at position of the last reported validation | ||
startLineNo = lineNo; | ||
} | ||
|
||
previousProp = propKey; | ||
} | ||
} | ||
|
||
/** | ||
* Method returns the index number where the key is detected (starting at 0). | ||
* To assure that we get the correct line it starts at the point | ||
* of the last occurrence. | ||
* Also the previousProp should be in file before propKey. | ||
* | ||
* @param startLineNo start searching at line | ||
* @param fileText {@link FileText} object contains the lines to process | ||
* @param previousProp key name found last iteration, works only if valid | ||
* @param propKey key name to look for | ||
* @return index number of first occurrence. If no key found in properties file, 0 is returned | ||
*/ | ||
private static int getLineNumber(int startLineNo, FileText fileText, | ||
String previousProp, String propKey) { | ||
|
||
final int indexOfPreviousProp = getIndex(startLineNo, fileText, previousProp); | ||
return getIndex(indexOfPreviousProp, fileText, propKey); | ||
} | ||
|
||
/** | ||
* Inner method to get the index number of the position of keyName. | ||
* | ||
* @param startLineNo start searching at line | ||
* @param fileText {@link FileText} object contains the lines to process | ||
* @param keyName key name to look for | ||
* @return index number of first occurrence. If no key found in properties file, 0 is returned | ||
*/ | ||
private static int getIndex(int startLineNo, FileText fileText, String keyName) { | ||
final Pattern keyPattern = getKeyPattern(keyName); | ||
int indexNumber = 0; | ||
final Matcher matcher = keyPattern.matcher(""); | ||
for (int index = startLineNo; index < fileText.size(); index++) { | ||
final String line = fileText.get(index); | ||
matcher.reset(line); | ||
if (matcher.matches()) { | ||
indexNumber = index; | ||
break; | ||
} | ||
} | ||
return indexNumber; | ||
} | ||
|
||
/** | ||
* Method returns regular expression pattern given key name. | ||
* | ||
* @param keyName | ||
* key name to look for | ||
* @return regular expression pattern given key name | ||
*/ | ||
private static Pattern getKeyPattern(String keyName) { | ||
|
||
final String keyPatternString = "^" + SPACE_PATTERN.matcher(keyName) | ||
.replaceAll(Matcher.quoteReplacement("\\\\ ")) + "[\\s:=].*"; | ||
return Pattern.compile(keyPatternString); | ||
} | ||
|
||
/** | ||
* Private property implementation that keeps order of properties like in file. | ||
* | ||
* @noinspection ClassExtendsConcreteCollection, SerializableHasSerializationMethods, | ||
* NonSerializableFieldInSerializableClass | ||
*/ | ||
private static class SequencedProperties extends Properties { | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
/** | ||
* Holding the keys in the same order than in the file. | ||
*/ | ||
private final List<Object> keyList = new ArrayList<>(); | ||
|
||
/** | ||
* Returns a copy of the keys. | ||
*/ | ||
@Override | ||
public synchronized Enumeration<Object> keys() { | ||
return Collections.enumeration(keyList); | ||
} | ||
|
||
/** | ||
* Puts the value into list by its key. | ||
* @noinspection UseOfPropertiesAsHashtable | ||
* | ||
* @param key the hashtable key | ||
* @param value the value | ||
* @return the previous value of the specified key in this hashtable, | ||
* or null if it did not have one | ||
* @throws NullPointerException - if the key or value is null | ||
*/ | ||
@Override | ||
public synchronized Object put(Object key, Object value) { | ||
|
||
keyList.add(key); | ||
|
||
return super.put(key, value); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.