Browse Source

Remove use of Guava in main sources of sonar-plugin-api

tags/8.0
Duarte Meneses 5 years ago
parent
commit
0f63c1e2bd
73 changed files with 542 additions and 441 deletions
  1. 1
    2
      sonar-plugin-api/build.gradle
  2. 6
    6
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java
  3. 10
    10
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java
  4. 14
    18
      sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java
  5. 24
    34
      sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java
  6. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/code/internal/DefaultSignificantCode.java
  7. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/coverage/internal/DefaultCoverage.java
  8. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
  9. 5
    4
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/error/internal/DefaultAnalysisError.java
  10. 2
    2
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java
  11. 2
    2
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/DefaultStorable.java
  12. 9
    11
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
  13. 5
    5
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
  14. 5
    6
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java
  15. 3
    3
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java
  16. 3
    3
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
  17. 6
    7
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
  18. 7
    6
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java
  19. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRule.java
  20. 4
    3
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java
  21. 7
    10
      sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/RangeDistributionBuilder.java
  22. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestComponent.java
  23. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestIssue.java
  24. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestMeasure.java
  25. 8
    10
      sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestMeasureComputerContext.java
  26. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestMeasureComputerDefinition.java
  27. 1
    6
      sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java
  28. 3
    3
      sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java
  29. 3
    3
      sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyFieldDefinition.java
  30. 13
    11
      sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java
  31. 0
    2
      sonar-plugin-api/src/main/java/org/sonar/api/config/internal/MultivalueProperty.java
  32. 7
    5
      sonar-plugin-api/src/main/java/org/sonar/api/internal/MetadataLoader.java
  33. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/internal/SonarRuntimeImpl.java
  34. 9
    5
      sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
  35. 5
    5
      sonar-plugin-api/src/main/java/org/sonar/api/resources/AbstractLanguage.java
  36. 2
    3
      sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java
  37. 16
    14
      sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypeTree.java
  38. 0
    2
      sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java
  39. 4
    5
      sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java
  40. 16
    13
      sonar-plugin-api/src/main/java/org/sonar/api/rules/AnnotationRuleParser.java
  41. 5
    6
      sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java
  42. 1
    2
      sonar-plugin-api/src/main/java/org/sonar/api/rules/XMLRuleParser.java
  43. 1
    2
      sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/Display.java
  44. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/UserIdentity.java
  45. 6
    10
      sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtRemediationFunction.java
  46. 4
    4
      sonar-plugin-api/src/main/java/org/sonar/api/server/profile/BuiltInQualityProfilesDefinition.java
  47. 19
    35
      sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java
  48. 12
    14
      sonar-plugin-api/src/main/java/org/sonar/api/server/ws/Request.java
  49. 19
    20
      sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
  50. 4
    2
      sonar-plugin-api/src/main/java/org/sonar/api/server/ws/internal/SimpleGetRequest.java
  51. 26
    7
      sonar-plugin-api/src/main/java/org/sonar/api/server/ws/internal/ValidatingRequest.java
  52. 6
    5
      sonar-plugin-api/src/main/java/org/sonar/api/task/TaskDefinition.java
  53. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/user/UserGroupValidation.java
  54. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/utils/DateUtils.java
  55. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/utils/Paging.java
  56. 25
    23
      sonar-plugin-api/src/main/java/org/sonar/api/utils/Preconditions.java
  57. 8
    9
      sonar-plugin-api/src/main/java/org/sonar/api/utils/UriReader.java
  58. 18
    19
      sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java
  59. 4
    6
      sonar-plugin-api/src/main/java/org/sonar/api/utils/command/Command.java
  60. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/AlwaysIncreasingSystem2.java
  61. 2
    2
      sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptors.java
  62. 5
    6
      sonar-plugin-api/src/main/java/org/sonar/api/web/Dashboard.java
  63. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java
  64. 0
    3
      sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
  65. 1
    1
      sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RuleTagsToTypeConverterTest.java
  66. 1
    1
      sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java
  67. 91
    0
      sonar-plugin-api/src/test/java/org/sonar/api/utils/ExceptionCauseMatcher.java
  68. 1
    2
      sonar-plugin-api/src/test/java/org/sonar/api/utils/KeyValueFormatTest.java
  69. 2
    4
      sonar-plugin-api/src/test/java/org/sonar/api/utils/PathUtilsTest.java
  70. 55
    0
      sonar-plugin-api/src/test/java/org/sonar/api/utils/TestUtils.java
  71. 9
    22
      sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandExecutorTest.java
  72. 1
    1
      sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleFormatterTest.java
  73. 1
    1
      sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogInterceptorsTest.java

+ 1
- 2
sonar-plugin-api/build.gradle View File

@@ -13,7 +13,6 @@ dependencies {
compile 'commons-io:commons-io'
compile 'commons-lang:commons-lang'
compile 'com.google.code.gson:gson'
compile 'com.google.guava:guava'
compile 'org.apache.commons:commons-csv'

// shaded, but not relocated
@@ -30,10 +29,10 @@ dependencies {
compileOnly 'junit:junit'
compileOnly 'org.slf4j:slf4j-api'

testCompile 'com.google.guava:guava'
testCompile 'com.tngtech.java:junit-dataprovider'
testCompile 'org.assertj:assertj-core'
testCompile 'org.mockito:mockito-core'
testCompile project(':sonar-testing-harness')
}

sourceSets {

+ 6
- 6
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultFileSystem.java View File

@@ -19,16 +19,16 @@
*/
package org.sonar.api.batch.fs.internal;

import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.SetMultimap;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.StreamSupport;
@@ -188,8 +188,8 @@ public class DefaultFileSystem implements FileSystem {
*/
private static class MapCache extends Cache {
private final Map<String, InputFile> fileMap = new HashMap<>();
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
private final Map<String, Set<InputFile>> filesByNameCache = new HashMap<>();
private final Map<String, Set<InputFile>> filesByExtensionCache = new HashMap<>();
private SortedSet<String> languages = new TreeSet<>();

@Override
@@ -218,8 +218,8 @@ public class DefaultFileSystem implements FileSystem {
languages.add(inputFile.language());
}
fileMap.put(inputFile.relativePath(), inputFile);
filesByNameCache.put(inputFile.filename(), inputFile);
filesByExtensionCache.put(FileExtensionPredicate.getExtension(inputFile), inputFile);
filesByNameCache.computeIfAbsent(inputFile.filename(), x -> new HashSet<>()).add(inputFile);
filesByExtensionCache.computeIfAbsent(FileExtensionPredicate.getExtension(inputFile), x -> new HashSet<>()).add(inputFile);
}

@Override

+ 10
- 10
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.fs.internal;

import com.google.common.base.Preconditions;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -45,7 +44,8 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextPointer;
import org.sonar.api.batch.fs.TextRange;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

/**
* @since 4.2
@@ -96,7 +96,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
public InputStream inputStream() throws IOException {
return contents != null ? new ByteArrayInputStream(contents.getBytes(charset()))
: new BOMInputStream(Files.newInputStream(path()),
ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE);
}

@Override
@@ -313,8 +313,8 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile

public TextPointer newPointer(int globalOffset) {
checkMetadata();
Preconditions.checkArgument(globalOffset >= 0, "%s is not a valid offset for a file", globalOffset);
Preconditions.checkArgument(globalOffset <= lastValidOffset(), "%s is not a valid offset for file %s. Max offset is %s", globalOffset, this, lastValidOffset());
checkArgument(globalOffset >= 0, "%s is not a valid offset for a file", globalOffset);
checkArgument(globalOffset <= lastValidOffset(), "%s is not a valid offset for file %s. Max offset is %s", globalOffset, this, lastValidOffset());
int line = findLine(globalOffset);
int startLineOffset = originalLineStartOffsets()[line - 1];
// In case the global offset is between \r and \n, move the pointer to a valid location
@@ -332,11 +332,11 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
}

private void checkValid(TextPointer pointer, String owner) {
Preconditions.checkArgument(pointer.line() >= 1, "%s is not a valid line for a file", pointer.line());
Preconditions.checkArgument(pointer.line() <= this.metadata.lines(), "%s is not a valid line for %s. File %s has %s line(s)", pointer.line(), owner, this, metadata.lines());
Preconditions.checkArgument(pointer.lineOffset() >= 0, "%s is not a valid line offset for a file", pointer.lineOffset());
checkArgument(pointer.line() >= 1, "%s is not a valid line for a file", pointer.line());
checkArgument(pointer.line() <= this.metadata.lines(), "%s is not a valid line for %s. File %s has %s line(s)", pointer.line(), owner, this, metadata.lines());
checkArgument(pointer.lineOffset() >= 0, "%s is not a valid line offset for a file", pointer.lineOffset());
int lineLength = lineLength(pointer.line());
Preconditions.checkArgument(pointer.lineOffset() <= lineLength,
checkArgument(pointer.lineOffset() <= lineLength,
"%s is not a valid line offset for %s. File %s has %s character(s) at line %s", pointer.lineOffset(), owner, this, lineLength, pointer.line());
}

@@ -345,7 +345,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile
}

private static TextRange newRangeValidPointers(TextPointer start, TextPointer end, boolean acceptEmptyRange) {
Preconditions.checkArgument(acceptEmptyRange ? (start.compareTo(end) <= 0) : (start.compareTo(end) < 0),
checkArgument(acceptEmptyRange ? (start.compareTo(end) <= 0) : (start.compareTo(end) < 0),
"Start pointer %s should be before end pointer %s", start, end);
return new DefaultTextRange(start, end);
}

+ 14
- 18
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultActiveRules.java View File

@@ -19,34 +19,32 @@
*/
package org.sonar.api.batch.rule.internal;

import com.google.common.collect.ImmutableListMultimap;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.rule.RuleKey;

import javax.annotation.concurrent.Immutable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.rule.RuleKey;

@Immutable
public class DefaultActiveRules implements ActiveRules {
private final ImmutableListMultimap<String, ActiveRule> activeRulesByRepository;
private final Map<String, List<ActiveRule>> activeRulesByRepository = new HashMap<>();
private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndKey = new HashMap<>();
private final Map<String, Map<String, ActiveRule>> activeRulesByRepositoryAndInternalKey = new HashMap<>();
private final ImmutableListMultimap<String, ActiveRule> activeRulesByLanguage;
private final Map<String, List<ActiveRule>> activeRulesByLanguage = new HashMap<>();

public DefaultActiveRules(Collection<NewActiveRule> newActiveRules) {
ImmutableListMultimap.Builder<String, ActiveRule> repoBuilder = ImmutableListMultimap.builder();
ImmutableListMultimap.Builder<String, ActiveRule> langBuilder = ImmutableListMultimap.builder();
for (NewActiveRule newAR : newActiveRules) {
DefaultActiveRule ar = new DefaultActiveRule(newAR);
String repo = ar.ruleKey().repository();
repoBuilder.put(repo, ar);
activeRulesByRepository.computeIfAbsent(repo, x -> new ArrayList<>()).add(ar);
if (ar.language() != null) {
langBuilder.put(ar.language(), ar);
activeRulesByLanguage.computeIfAbsent(ar.language(), x -> new ArrayList<>()).add(ar);
}

activeRulesByRepositoryAndKey.computeIfAbsent(repo, r -> new HashMap<>()).put(ar.ruleKey().rule(), ar);
@@ -55,8 +53,6 @@ public class DefaultActiveRules implements ActiveRules {
activeRulesByRepositoryAndInternalKey.computeIfAbsent(repo, r -> new HashMap<>()).put(internalKey, ar);
}
}
activeRulesByRepository = repoBuilder.build();
activeRulesByLanguage = langBuilder.build();
}

@Override
@@ -67,17 +63,17 @@ public class DefaultActiveRules implements ActiveRules {

@Override
public Collection<ActiveRule> findAll() {
return activeRulesByRepository.values();
return activeRulesByRepository.entrySet().stream().flatMap(x -> x.getValue().stream()).collect(Collectors.toList());
}

@Override
public Collection<ActiveRule> findByRepository(String repository) {
return activeRulesByRepository.get(repository);
return activeRulesByRepository.getOrDefault(repository, Collections.emptyList());
}

@Override
public Collection<ActiveRule> findByLanguage(String language) {
return activeRulesByLanguage.get(language);
return activeRulesByLanguage.getOrDefault(language, Collections.emptyList());
}

@Override

+ 24
- 34
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRules.java View File

@@ -19,60 +19,50 @@
*/
package org.sonar.api.batch.rule.internal;

import com.google.common.collect.ImmutableTable;

import com.google.common.collect.HashBasedTable;
import org.sonar.api.batch.rule.Rule;
import com.google.common.collect.Table;
import com.google.common.collect.ImmutableListMultimap;
import org.sonar.api.batch.rule.Rules;
import org.sonar.api.rule.RuleKey;

import javax.annotation.concurrent.Immutable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.batch.rule.Rule;
import org.sonar.api.batch.rule.Rules;
import org.sonar.api.rule.RuleKey;

@Immutable
class DefaultRules implements Rules {
private final ImmutableListMultimap<String, Rule> rulesByRepository;
private final ImmutableTable<String, String, List<Rule>> rulesByRepositoryAndInternalKey;
private final Map<String, List<Rule>> rulesByRepository;
private final Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKey;
private final Map<RuleKey, Rule> rulesByRuleKey;

DefaultRules(Collection<NewRule> newRules) {
Map<String, List<Rule>> rulesByRepositoryBuilder = new HashMap<>();
Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKeyBuilder = new HashMap<>();
Map<RuleKey, Rule> rulesByRuleKeyBuilder = new HashMap<>();
ImmutableListMultimap.Builder<String, Rule> builder = ImmutableListMultimap.builder();
Table<String, String, List<Rule>> tableBuilder = HashBasedTable.create();

for (NewRule newRule : newRules) {
DefaultRule r = new DefaultRule(newRule);
rulesByRuleKeyBuilder.put(r.key(), r);
builder.put(r.key().repository(), r);
addToTable(tableBuilder, r);
rulesByRepositoryBuilder.computeIfAbsent(r.key().repository(), x -> new ArrayList<>()).add(r);
addToTable(rulesByRepositoryAndInternalKeyBuilder, r);
}

rulesByRuleKey = Collections.unmodifiableMap(rulesByRuleKeyBuilder);
rulesByRepository = builder.build();
rulesByRepositoryAndInternalKey = ImmutableTable.copyOf(tableBuilder);
rulesByRepository = Collections.unmodifiableMap(rulesByRepositoryBuilder);
rulesByRepositoryAndInternalKey = Collections.unmodifiableMap(rulesByRepositoryAndInternalKeyBuilder);
}

private static void addToTable(Table<String, String, List<Rule>> table, DefaultRule r) {
private static void addToTable(Map<String, Map<String, List<Rule>>> rulesByRepositoryAndInternalKeyBuilder, DefaultRule r) {
if (r.internalKey() == null) {
return;
}

List<Rule> ruleList = table.get(r.key().repository(), r.internalKey());

if (ruleList == null) {
ruleList = new LinkedList<>();
}

ruleList.add(r);
table.put(r.key().repository(), r.internalKey(), ruleList);
rulesByRepositoryAndInternalKeyBuilder
.computeIfAbsent(r.key().repository(), x -> new HashMap<>())
.computeIfAbsent(r.internalKey(), x -> new ArrayList<>())
.add(r);
}

@Override
@@ -82,18 +72,18 @@ class DefaultRules implements Rules {

@Override
public Collection<Rule> findAll() {
return rulesByRepository.values();
return rulesByRepository.values().stream().flatMap(List::stream).collect(Collectors.toList());
}

@Override
public Collection<Rule> findByRepository(String repository) {
return rulesByRepository.get(repository);
return rulesByRepository.getOrDefault(repository, Collections.emptyList());
}

@Override
public Collection<Rule> findByInternalKey(String repository, String internalKey) {
List<Rule> rules = rulesByRepositoryAndInternalKey.get(repository, internalKey);
return rules != null ? rules : Collections.<Rule>emptyList();
return rulesByRepositoryAndInternalKey
.getOrDefault(repository, Collections.emptyMap())
.getOrDefault(internalKey, Collections.emptyList());
}
}

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/code/internal/DefaultSignificantCode.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.code.internal;

import com.google.common.base.Preconditions;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.annotation.Nullable;
@@ -28,6 +27,7 @@ import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.sensor.code.NewSignificantCode;
import org.sonar.api.batch.sensor.internal.DefaultStorable;
import org.sonar.api.batch.sensor.internal.SensorStorage;
import org.sonar.api.utils.Preconditions;

public class DefaultSignificantCode extends DefaultStorable implements NewSignificantCode {
private SortedMap<Integer, TextRange> significantCodePerLine = new TreeMap<>();

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/coverage/internal/DefaultCoverage.java View File

@@ -30,8 +30,8 @@ import org.sonar.api.batch.sensor.coverage.NewCoverage;
import org.sonar.api.batch.sensor.internal.DefaultStorable;
import org.sonar.api.batch.sensor.internal.SensorStorage;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultCoverage extends DefaultStorable implements NewCoverage {


+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java View File

@@ -30,9 +30,9 @@ import org.sonar.api.batch.sensor.internal.SensorStorage;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
private static final Logger LOG = Loggers.get(DefaultCpdTokens.class);

+ 5
- 4
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/error/internal/DefaultAnalysisError.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.error.internal;

import com.google.common.base.Preconditions;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextPointer;
import org.sonar.api.batch.sensor.error.AnalysisError;
@@ -28,6 +27,8 @@ import org.sonar.api.batch.sensor.internal.DefaultStorable;
import org.sonar.api.batch.sensor.internal.SensorStorage;

import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultAnalysisError extends DefaultStorable implements NewAnalysisError, AnalysisError {
private InputFile inputFile;
@@ -59,8 +60,8 @@ public class DefaultAnalysisError extends DefaultStorable implements NewAnalysis

@Override
public NewAnalysisError onFile(InputFile inputFile) {
Preconditions.checkArgument(inputFile != null, "Cannot use a inputFile that is null");
Preconditions.checkState(this.inputFile == null, "onFile() already called");
checkArgument(inputFile != null, "Cannot use a inputFile that is null");
checkState(this.inputFile == null, "onFile() already called");
this.inputFile = inputFile;
return this;
}
@@ -73,7 +74,7 @@ public class DefaultAnalysisError extends DefaultStorable implements NewAnalysis

@Override
public NewAnalysisError at(TextPointer location) {
Preconditions.checkState(this.location == null, "at() already called");
checkState(this.location == null, "at() already called");
this.location = location;
return this;
}

+ 2
- 2
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/internal/DefaultHighlighting.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.highlighting.internal;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -33,6 +32,7 @@ import org.sonar.api.batch.sensor.internal.DefaultStorable;
import org.sonar.api.batch.sensor.internal.SensorStorage;

import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultHighlighting extends DefaultStorable implements NewHighlighting {

@@ -122,6 +122,6 @@ public class DefaultHighlighting extends DefaultStorable implements NewHighlight
}

private void checkInputFileNotNull() {
Preconditions.checkState(inputFile != null, "Call onFile() first");
checkState(inputFile != null, "Call onFile() first");
}
}

+ 2
- 2
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/DefaultStorable.java View File

@@ -19,12 +19,12 @@
*/
package org.sonar.api.batch.sensor.internal;

import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkState;

public abstract class DefaultStorable {

@@ -41,7 +41,7 @@ public abstract class DefaultStorable {

public final void save() {
requireNonNull(this.storage, "No persister on this object");
Preconditions.checkState(!saved, "This object was already saved");
checkState(!saved, "This object was already saved");
doSave();
this.saved = true;
}

+ 9
- 11
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java View File

@@ -19,13 +19,11 @@
*/
package org.sonar.api.batch.sensor.internal;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.sonar.api.batch.sensor.code.internal.DefaultSignificantCode;
import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
@@ -40,11 +38,11 @@ import org.sonar.api.batch.sensor.rule.AdHocRule;
import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkArgument;

class InMemorySensorStorage implements SensorStorage {

Table<String, String, Measure> measuresByComponentAndMetric = HashBasedTable.create();
Map<String, Map<String, Measure>> measuresByComponentAndMetric = new HashMap<>();

Collection<Issue> allIssues = new ArrayList<>();
Collection<ExternalIssue> allExternalIssues = new ArrayList<>();
@@ -53,7 +51,7 @@ class InMemorySensorStorage implements SensorStorage {

Map<String, DefaultHighlighting> highlightingByComponent = new HashMap<>();
Map<String, DefaultCpdTokens> cpdTokensByComponent = new HashMap<>();
Multimap<String, DefaultCoverage> coverageByComponent = ArrayListMultimap.create();
Map<String, List<DefaultCoverage>> coverageByComponent = new HashMap<>();
Map<String, DefaultSymbolTable> symbolsPerComponent = new HashMap<>();
Map<String, String> contextProperties = new HashMap<>();
Map<String, DefaultSignificantCode> significantCodePerComponent = new HashMap<>();
@@ -63,10 +61,10 @@ class InMemorySensorStorage implements SensorStorage {
// Emulate duplicate measure check
String componentKey = measure.inputComponent().key();
String metricKey = measure.metric().key();
if (measuresByComponentAndMetric.contains(componentKey, metricKey)) {
if (measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).containsKey(metricKey)) {
throw new IllegalStateException("Can not add the same measure twice");
}
measuresByComponentAndMetric.row(componentKey).put(metricKey, measure);
measuresByComponentAndMetric.computeIfAbsent(componentKey, x -> new HashMap<>()).put(metricKey, measure);
}

@Override
@@ -92,7 +90,7 @@ class InMemorySensorStorage implements SensorStorage {
@Override
public void store(DefaultCoverage defaultCoverage) {
String fileKey = defaultCoverage.inputFile().key();
coverageByComponent.put(fileKey, defaultCoverage);
coverageByComponent.computeIfAbsent(fileKey, x -> new ArrayList<>()).add(defaultCoverage);
}

@Override
@@ -131,7 +129,7 @@ class InMemorySensorStorage implements SensorStorage {
public void store(DefaultExternalIssue issue) {
allExternalIssues.add(issue);
}
@Override
public void store(DefaultSignificantCode significantCode) {
String fileKey = significantCode.inputFile().key();

+ 5
- 5
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java View File

@@ -215,7 +215,7 @@ public class SensorContextTester implements SensorContext {
}

public Collection<Measure> measures(String componentKey) {
return sensorStorage.measuresByComponentAndMetric.row(componentKey).values();
return sensorStorage.measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).values();
}

public <G extends Serializable> Measure<G> measure(String componentKey, Metric<G> metric) {
@@ -223,7 +223,7 @@ public class SensorContextTester implements SensorContext {
}

public <G extends Serializable> Measure<G> measure(String componentKey, String metricKey) {
return sensorStorage.measuresByComponentAndMetric.row(componentKey).get(metricKey);
return sensorStorage.measuresByComponentAndMetric.getOrDefault(componentKey, Collections.emptyMap()).get(metricKey);
}

@Override
@@ -259,7 +259,7 @@ public class SensorContextTester implements SensorContext {

@CheckForNull
public Integer lineHits(String fileKey, int line) {
return sensorStorage.coverageByComponent.get(fileKey).stream()
return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
.map(c -> c.hitsByLine().get(line))
.flatMap(Stream::of)
.filter(Objects::nonNull)
@@ -273,7 +273,7 @@ public class SensorContextTester implements SensorContext {

@CheckForNull
public Integer conditions(String fileKey, int line) {
return sensorStorage.coverageByComponent.get(fileKey).stream()
return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
.map(c -> c.conditionsByLine().get(line))
.flatMap(Stream::of)
.filter(Objects::nonNull)
@@ -282,7 +282,7 @@ public class SensorContextTester implements SensorContext {

@CheckForNull
public Integer coveredConditions(String fileKey, int line) {
return sensorStorage.coverageByComponent.get(fileKey).stream()
return sensorStorage.coverageByComponent.getOrDefault(fileKey, Collections.emptyList()).stream()
.map(c -> c.coveredConditionsByLine().get(line))
.flatMap(Stream::of)
.filter(Objects::nonNull)

+ 5
- 6
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/AbstractDefaultIssue.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.issue.internal;

import com.google.common.base.Preconditions;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
@@ -38,10 +37,10 @@ import org.sonar.api.batch.sensor.issue.IssueLocation;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
import org.sonar.api.utils.PathUtils;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Collections.unmodifiableList;
import static java.util.stream.Collectors.toList;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable {
protected IssueLocation primaryLocation;
@@ -72,10 +71,10 @@ public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> exten
}

public T at(NewIssueLocation primaryLocation) {
Preconditions.checkArgument(primaryLocation != null, "Cannot use a location that is null");
checkArgument(primaryLocation != null, "Cannot use a location that is null");
checkState(this.primaryLocation == null, "at() already called");
this.primaryLocation = rewriteLocation((DefaultIssueLocation) primaryLocation);
Preconditions.checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component");
checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component");
return (T) this;
}

@@ -110,7 +109,7 @@ public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> exten
DefaultIssueLocation fixedLocation = new DefaultIssueLocation();
fixedLocation.on(project);
StringBuilder fullMessage = new StringBuilder();
if (!isNullOrEmpty(path)) {
if (path != null && !path.isEmpty()) {
fullMessage.append("[").append(path).append("] ");
}
fullMessage.append(location.message());

+ 3
- 3
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultExternalIssue.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.issue.internal;

import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.rule.Severity;
@@ -29,9 +28,10 @@ import org.sonar.api.batch.sensor.issue.NewExternalIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIssue> implements ExternalIssue, NewExternalIssue {
private Long effort;
@@ -50,7 +50,7 @@ public class DefaultExternalIssue extends AbstractDefaultIssue<DefaultExternalIs

@Override
public DefaultExternalIssue remediationEffortMinutes(@Nullable Long effort) {
Preconditions.checkArgument(effort == null || effort >= 0, format("effort must be greater than or equal 0 (got %s)", effort));
checkArgument(effort == null || effort >= 0, format("effort must be greater than or equal 0 (got %s)", effort));
this.effort = effort;
return this;
}

+ 3
- 3
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.issue.internal;

import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.rule.Severity;
@@ -29,9 +28,10 @@ import org.sonar.api.batch.sensor.issue.IssueLocation;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.rule.RuleKey;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements Issue, NewIssue {
private RuleKey ruleKey;
@@ -57,7 +57,7 @@ public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements

@Override
public DefaultIssue gap(@Nullable Double gap) {
Preconditions.checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap));
checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap));
this.gap = gap;
return this;
}

+ 6
- 7
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java View File

@@ -19,19 +19,18 @@
*/
package org.sonar.api.batch.sensor.issue.internal;

import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.issue.IssueLocation;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;

import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.abbreviate;
import static org.apache.commons.lang.StringUtils.trim;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {

@@ -42,15 +41,15 @@ public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
@Override
public DefaultIssueLocation on(InputComponent component) {
checkArgument(component != null, "Component can't be null");
Preconditions.checkState(this.component == null, "on() already called");
checkState(this.component == null, "on() already called");
this.component = component;
return this;
}

@Override
public DefaultIssueLocation at(TextRange location) {
Preconditions.checkState(this.component != null, "at() should be called after on()");
Preconditions.checkState(this.component.isFile(), "at() should be called only for an InputFile.");
checkState(this.component != null, "at() should be called after on()");
checkState(this.component.isFile(), "at() should be called only for an InputFile.");
DefaultInputFile file = (DefaultInputFile) this.component;
file.validate(location);
this.textRange = location;

+ 7
- 6
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.measure.internal;

import com.google.common.base.Preconditions;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.apache.commons.lang.builder.EqualsBuilder;
@@ -32,6 +31,8 @@ import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.measure.NewMeasure;

import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultMeasure<G extends Serializable> extends DefaultStorable implements Measure<G>, NewMeasure<G> {

@@ -50,15 +51,15 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl

@Override
public DefaultMeasure<G> on(InputComponent component) {
Preconditions.checkArgument(component != null, "Component can't be null");
Preconditions.checkState(this.component == null, "on() already called");
checkArgument(component != null, "Component can't be null");
checkState(this.component == null, "on() already called");
this.component = component;
return this;
}

@Override
public DefaultMeasure<G> forMetric(Metric<G> metric) {
Preconditions.checkState(this.metric == null, "Metric already defined");
checkState(this.metric == null, "Metric already defined");
requireNonNull(metric, "metric should be non null");
this.metric = metric;
return this;
@@ -66,7 +67,7 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl

@Override
public DefaultMeasure<G> withValue(G value) {
Preconditions.checkState(this.value == null, "Measure value already defined");
checkState(this.value == null, "Measure value already defined");
requireNonNull(value, "Measure value can't be null");
this.value = value;
return this;
@@ -91,7 +92,7 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl
public void doSave() {
requireNonNull(this.value, "Measure value can't be null");
requireNonNull(this.metric, "Measure metric can't be null");
Preconditions.checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type %s", this.metric.valueType());
checkState(this.metric.valueType().equals(this.value.getClass()), "Measure value should be of type %s", this.metric.valueType());
storage.store(this);
}


+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/rule/internal/DefaultAdHocRule.java View File

@@ -28,8 +28,8 @@ import org.sonar.api.batch.sensor.rule.AdHocRule;
import org.sonar.api.batch.sensor.rule.NewAdHocRule;
import org.sonar.api.rules.RuleType;

import static com.google.common.base.Preconditions.checkState;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultAdHocRule extends DefaultStorable implements AdHocRule, NewAdHocRule {
private Severity severity;

+ 4
- 3
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/internal/DefaultSymbolTable.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.batch.sensor.symbol.internal;

import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -34,6 +33,8 @@ import org.sonar.api.batch.sensor.symbol.NewSymbol;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;

import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

public class DefaultSymbolTable extends DefaultStorable implements NewSymbolTable {

@@ -129,7 +130,7 @@ public class DefaultSymbolTable extends DefaultStorable implements NewSymbolTabl
@Override
public NewSymbol newReference(TextRange range) {
requireNonNull(range, "Provided range is null");
Preconditions.checkArgument(!declaration.overlap(range), "Overlapping symbol declaration and reference for symbol at %s", declaration);
checkArgument(!declaration.overlap(range), "Overlapping symbol declaration and reference for symbol at %s", declaration);
references.add(range);
return this;
}
@@ -143,6 +144,6 @@ public class DefaultSymbolTable extends DefaultStorable implements NewSymbolTabl
}

private void checkInputFileNotNull() {
Preconditions.checkState(inputFile != null, "Call onFile() first");
checkState(inputFile != null, "Call onFile() first");
}
}

+ 7
- 10
sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/RangeDistributionBuilder.java View File

@@ -19,8 +19,6 @@
*/
package org.sonar.api.ce.measure;

import com.google.common.collect.Multiset;
import com.google.common.collect.TreeMultiset;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@@ -40,7 +38,7 @@ import org.sonar.api.utils.KeyValueFormat;
*/
public class RangeDistributionBuilder {

private Multiset<Number> distributionSet;
private Map<Number, Integer> distributionSet;
private boolean isEmpty = true;
private Number[] bottomLimits;
private boolean isValid = true;
@@ -114,7 +112,10 @@ public class RangeDistributionBuilder {
System.arraycopy(bottomLimits, 0, this.bottomLimits, 0, this.bottomLimits.length);
Arrays.sort(this.bottomLimits);
changeDoublesToInts();
distributionSet = TreeMultiset.create(NumberComparator.INSTANCE);
distributionSet = new TreeMap<>(NumberComparator.INSTANCE);
for (Number n : this.bottomLimits) {
distributionSet.put(n, 0);
}
}

private void changeDoublesToInts() {
@@ -156,7 +157,7 @@ public class RangeDistributionBuilder {
private void addValue(Number value, int count) {
for (int i = bottomLimits.length - 1; i >= 0; i--) {
if (greaterOrEqualsThan(value, bottomLimits[i])) {
this.distributionSet.add(bottomLimits[i], count);
this.distributionSet.compute(bottomLimits[i], (k, v) -> v + count);
return;
}
}
@@ -186,11 +187,7 @@ public class RangeDistributionBuilder {
if (bottomLimits == null || bottomLimits.length == 0) {
return Collections.emptyMap();
}
Map<Number, Integer> map = new TreeMap<>();
for (Number value : bottomLimits) {
map.put(value, distributionSet.count(value));
}
return map;
return distributionSet;
}

private static boolean greaterOrEqualsThan(Number n1, Number n2) {

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestComponent.java View File

@@ -24,8 +24,8 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.ce.measure.Component;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkState;

@Immutable
public class TestComponent implements Component {

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestIssue.java View File

@@ -28,8 +28,8 @@ import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;

@Immutable
public class TestIssue implements Issue {

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestMeasure.java View File

@@ -22,8 +22,8 @@ package org.sonar.api.ce.measure.test;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.ce.measure.Measure;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkState;

@Immutable
public class TestMeasure implements Measure {

+ 8
- 10
sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestMeasureComputerContext.java View File

@@ -19,9 +19,8 @@
*/
package org.sonar.api.ce.measure.test;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -33,9 +32,9 @@ import org.sonar.api.ce.measure.Issue;
import org.sonar.api.ce.measure.Measure;
import org.sonar.api.ce.measure.Settings;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext;
import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition;
import static org.sonar.api.utils.Preconditions.checkArgument;

public class TestMeasureComputerContext implements MeasureComputerContext {

@@ -44,7 +43,7 @@ public class TestMeasureComputerContext implements MeasureComputerContext {
private final Settings settings;

private Map<String, Measure> componentMeasureByMetricKey = new HashMap<>();
private Multimap<String, Measure> childrenComponentMeasureByMetricKey = ArrayListMultimap.create();
private Map<String, List<Measure>> childrenComponentMeasureByMetricKey = new HashMap<>();
private List<Issue> issues = new ArrayList<>();

public TestMeasureComputerContext(Component component, Settings settings, MeasureComputerDefinition definition) {
@@ -73,7 +72,7 @@ public class TestMeasureComputerContext implements MeasureComputerContext {
@Override
public Iterable<Measure> getChildrenMeasures(String metric) {
validateInputMetric(metric);
return childrenComponentMeasureByMetricKey.get(metric);
return childrenComponentMeasureByMetricKey.getOrDefault(metric, Collections.emptyList());
}

@Override
@@ -88,7 +87,7 @@ public class TestMeasureComputerContext implements MeasureComputerContext {

public void addChildrenMeasures(String metricKey, Integer... values) {
for (Integer value : values) {
childrenComponentMeasureByMetricKey.put(metricKey, TestMeasure.createMeasure(value));
childrenComponentMeasureByMetricKey.computeIfAbsent(metricKey, x -> new ArrayList<>()).add(TestMeasure.createMeasure(value));
}
}

@@ -104,7 +103,7 @@ public class TestMeasureComputerContext implements MeasureComputerContext {

public void addChildrenMeasures(String metricKey, Double... values) {
for (Double value : values) {
childrenComponentMeasureByMetricKey.put(metricKey, TestMeasure.createMeasure(value));
childrenComponentMeasureByMetricKey.computeIfAbsent(metricKey, x -> new ArrayList<>()).add(TestMeasure.createMeasure(value));
}
}

@@ -120,7 +119,7 @@ public class TestMeasureComputerContext implements MeasureComputerContext {

public void addChildrenMeasures(String metricKey, Long... values) {
for (Long value : values) {
childrenComponentMeasureByMetricKey.put(metricKey, TestMeasure.createMeasure(value));
childrenComponentMeasureByMetricKey.computeIfAbsent(metricKey, x -> new ArrayList<>()).add(TestMeasure.createMeasure(value));
}
}

@@ -136,7 +135,6 @@ public class TestMeasureComputerContext implements MeasureComputerContext {
componentMeasureByMetricKey.put(metricKey, TestMeasure.createMeasure(value));
}


public void addInputMeasure(String metricKey, boolean value) {
componentMeasureByMetricKey.put(metricKey, TestMeasure.createMeasure(value));
}
@@ -147,7 +145,7 @@ public class TestMeasureComputerContext implements MeasureComputerContext {

public void addChildrenMeasures(String metricKey, String... values) {
for (String value : values) {
childrenComponentMeasureByMetricKey.put(metricKey, TestMeasure.createMeasure(value));
childrenComponentMeasureByMetricKey.computeIfAbsent(metricKey, x -> new ArrayList<>()).add(TestMeasure.createMeasure(value));
}
}


+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/ce/measure/test/TestMeasureComputerDefinition.java View File

@@ -26,10 +26,10 @@ import org.sonar.api.ce.measure.MeasureComputer;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableSet;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;

public class TestMeasureComputerDefinition implements MeasureComputer.MeasureComputerDefinition {


+ 1
- 6
sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java View File

@@ -30,8 +30,8 @@ import java.util.Optional;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* This class can be used to test {@link PostProjectAnalysisTask} implementations, see example below:
@@ -41,21 +41,17 @@ import static java.util.Objects.requireNonNull;
* import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newConditionBuilder;
* import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newProjectBuilder;
* import static org.sonar.api.ce.posttask.PostProjectAnalysisTaskTester.newQualityGateBuilder;
*
* public class CaptorPostProjectAnalysisTaskTest {
* private class CaptorPostProjectAnalysisTask implements PostProjectAnalysisTask {
* private ProjectAnalysis projectAnalysis;
*
* {@literal @}Override
* public void finished(ProjectAnalysis analysis) {
* this.projectAnalysis = analysis;
* }
* }
*
* {@literal @}Test
* public void execute_is_passed_a_non_null_ProjectAnalysis_object() {
* CaptorPostProjectAnalysisTask postProjectAnalysisTask = new CaptorPostProjectAnalysisTask();
*
* PostProjectAnalysisTaskTester.of(postProjectAnalysisTask)
* .withCeTask(
* newCeTaskBuilder()
@@ -83,7 +79,6 @@ import static java.util.Objects.requireNonNull;
* .build(QualityGate.EvaluationStatus.OK, "value"))
* .build())
* .execute();
*
* assertThat(postProjectAnalysisTask.projectAnalysis).isNotNull();
* }
* }

+ 3
- 3
sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyDefinition.java View File

@@ -34,13 +34,12 @@ import org.apache.commons.lang.math.NumberUtils;
import org.sonar.api.ExtensionPoint;
import org.sonar.api.Property;
import org.sonar.api.PropertyType;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.server.ServerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.Collections.unmodifiableSet;
@@ -54,6 +53,7 @@ import static org.sonar.api.PropertyType.LONG;
import static org.sonar.api.PropertyType.PROPERTY_SET;
import static org.sonar.api.PropertyType.REGULAR_EXPRESSION;
import static org.sonar.api.PropertyType.SINGLE_SELECT_LIST;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Declare a plugin property. Values are available at runtime through the component {@link Configuration}.
@@ -461,7 +461,7 @@ public final class PropertyDefinition {
* only in General Settings.
*
* @throws IllegalArgumentException only qualifiers {@link Qualifiers#PROJECT PROJECT}, {@link Qualifiers#MODULE MODULE}, {@link Qualifiers#APP APP},
* {@link Qualifiers#VIEW VIEW} and {@link Qualifiers#SUBVIEW SVW} are allowed.
* {@link Qualifiers#VIEW VIEW} and {@link Qualifiers#SUBVIEW SVW} are allowed.
* @throws IllegalArgumentException only qualifiers {@link Qualifiers#PROJECT PROJECT}, {@link Qualifiers#MODULE MODULE},
* {@link Qualifiers#VIEW VIEW} and {@link Qualifiers#SUBVIEW SVW} are allowed.
*/

+ 3
- 3
sonar-plugin-api/src/main/java/org/sonar/api/config/PropertyFieldDefinition.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.config;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
@@ -28,6 +27,7 @@ import org.sonar.api.PropertyField;
import org.sonar.api.PropertyType;

import static java.util.Arrays.asList;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 3.3
@@ -151,8 +151,8 @@ public final class PropertyFieldDefinition {
}

public PropertyFieldDefinition build() {
Preconditions.checkArgument(!StringUtils.isEmpty(key), "Key must be set");
Preconditions.checkArgument(!StringUtils.isEmpty(name), "Name must be set");
checkArgument(!StringUtils.isEmpty(key), "Key must be set");
checkArgument(!StringUtils.isEmpty(name), "Name must be set");
return new PropertyFieldDefinition(this);
}
}

+ 13
- 11
sonar-plugin-api/src/main/java/org/sonar/api/config/Settings.java View File

@@ -19,8 +19,8 @@
*/
package org.sonar.api.config;

import com.google.common.base.Splitter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -31,8 +31,8 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.DateUtils;
import org.sonarsource.api.sonarlint.SonarLintSide;
@@ -160,6 +160,7 @@ public abstract class Settings {
/**
* Effective value as boolean. It is {@code false} if {@link #getString(String)}
* does not return {@code "true"}, even if it's not a boolean representation.
*
* @return {@code true} if the effective value is {@code "true"}, else {@code false}.
*/
public boolean getBoolean(String key) {
@@ -169,6 +170,7 @@ public abstract class Settings {

/**
* Effective value as {@code int}.
*
* @return the value as {@code int}. If the property does not have value nor default value, then {@code 0} is returned.
* @throws NumberFormatException if value is not empty and is not a parsable integer
*/
@@ -182,6 +184,7 @@ public abstract class Settings {

/**
* Effective value as {@code long}.
*
* @return the value as {@code long}. If the property does not have value nor default value, then {@code 0L} is returned.
* @throws NumberFormatException if value is not empty and is not a parsable {@code long}
*/
@@ -225,6 +228,7 @@ public abstract class Settings {

/**
* Effective value as {@code Float}.
*
* @return the value as {@code Float}. If the property does not have value nor default value, then {@code null} is returned.
* @throws NumberFormatException if value is not empty and is not a parsable number
*/
@@ -243,6 +247,7 @@ public abstract class Settings {

/**
* Effective value as {@code Double}.
*
* @return the value as {@code Double}. If the property does not have value nor default value, then {@code null} is returned.
* @throws NumberFormatException if value is not empty and is not a parsable number
*/
@@ -278,11 +283,9 @@ public abstract class Settings {
return ArrayUtils.EMPTY_STRING_ARRAY;
}

List<String> values = new ArrayList<>();
for (String v : Splitter.on(",").trimResults().split(value)) {
values.add(v.replace("%2C", ","));
}
return values.toArray(new String[values.size()]);
return Arrays.stream(value.split(",", -1)).map(String::trim)
.map(s -> s.replace("%2C", ","))
.toArray(String[]::new);
}

return getStringArrayBySeparator(key, ",");
@@ -358,11 +361,10 @@ public abstract class Settings {
* Change a property value in a restricted scope only, depending on execution context. New value
* is <b>never</b> persisted. New value is ephemeral and kept in memory only:
* <ul>
* <li>during current analysis in the case of scanner stack</li>
* <li>during processing of current HTTP request in the case of web server stack</li>
* <li>during execution of current task in the case of Compute Engine stack</li>
* <li>during current analysis in the case of scanner stack</li>
* <li>during processing of current HTTP request in the case of web server stack</li>
* <li>during execution of current task in the case of Compute Engine stack</li>
* </ul>
*
* Property is temporarily removed if the parameter {@code value} is {@code null}
*/
public Settings setProperty(String key, @Nullable String value) {

+ 0
- 2
sonar-plugin-api/src/main/java/org/sonar/api/config/internal/MultivalueProperty.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.config.internal;

import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
@@ -127,7 +126,6 @@ public class MultivalueProperty {
* <li>{@code "a,\" \",b" => "ab"]}</li>
* </ul>
*/
@VisibleForTesting
static String trimFieldsAndRemoveEmptyFields(String str) {
char[] chars = str.toCharArray();
char[] res = new char[chars.length];

+ 7
- 5
sonar-plugin-api/src/main/java/org/sonar/api/internal/MetadataLoader.java View File

@@ -19,10 +19,12 @@
*/
package org.sonar.api.internal;

import com.google.common.io.Resources;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.sonar.api.SonarEdition;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.Version;
@@ -46,9 +48,9 @@ public class MetadataLoader {
public static Version loadVersion(System2 system) {
try {
URL url = system.getResource(VERSION_FILE_PATH);
String versionInFile = Resources.toString(url, StandardCharsets.UTF_8);
String versionInFile = new String(Files.readAllBytes(Paths.get(url.toURI())), StandardCharsets.UTF_8);
return Version.parse(versionInFile);
} catch (IOException e) {
} catch (IOException | URISyntaxException e) {
throw new IllegalStateException("Can not load " + VERSION_FILE_PATH + " from classpath", e);
}
}
@@ -59,9 +61,9 @@ public class MetadataLoader {
if (url == null) {
return SonarEdition.COMMUNITY;
}
String editionInFile = Resources.toString(url, StandardCharsets.UTF_8);
String editionInFile = new String(Files.readAllBytes(Paths.get(url.toURI())), StandardCharsets.UTF_8);
return parseEdition(editionInFile);
} catch (IOException e) {
} catch (IOException | URISyntaxException e) {
throw new IllegalStateException("Can not load " + EDITION_FILE_PATH + " from classpath", e);
}
}

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/internal/SonarRuntimeImpl.java View File

@@ -27,8 +27,8 @@ import org.sonar.api.SonarQubeSide;
import org.sonar.api.SonarRuntime;
import org.sonar.api.utils.Version;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 6.0

+ 9
- 5
sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java View File

@@ -31,9 +31,8 @@ import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.server.ServerSide;

import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Used to define a metric in a plugin. Should be used with {@link Metrics} extension point.
@@ -219,7 +218,7 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
* @param userManaged whether the metric is user managed
*/
private Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, @Nullable String domain,
boolean userManaged) {
boolean userManaged) {
this.key = key;
this.description = description;
this.type = type;
@@ -739,15 +738,20 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
if (ValueType.PERCENT == this.type) {
this.bestValue = (direction == DIRECTION_BETTER) ? 100.0 : 0.0;
this.worstValue = (direction == DIRECTION_BETTER) ? 0.0 : 100.0;
this.decimalScale = firstNonNull(decimalScale, DEFAULT_DECIMAL_SCALE);
this.decimalScale = coalesce(decimalScale, DEFAULT_DECIMAL_SCALE);

} else if (ValueType.FLOAT == this.type) {
this.decimalScale = firstNonNull(decimalScale, DEFAULT_DECIMAL_SCALE);
this.decimalScale = coalesce(decimalScale, DEFAULT_DECIMAL_SCALE);
}
return new Metric<>(this);
}
}

@CheckForNull
private static <T> T coalesce(@Nullable T a, @Nullable T b) {
return a == null ? b : a;
}

@Override
public String key() {
return getKey();

+ 5
- 5
sonar-plugin-api/src/main/java/org/sonar/api/resources/AbstractLanguage.java View File

@@ -19,10 +19,10 @@
*/
package org.sonar.api.resources;

import com.google.common.base.Preconditions;

import java.util.Locale;

import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Inherit this class to define a new language like PLSQL, PHP or C#
*
@@ -34,7 +34,7 @@ public abstract class AbstractLanguage implements Language {

/**
* Better to use AbstractLanguage(key, name). In this case, key and name will be the same
*
*
* @param key The key of the language. Must not be more than 20 chars.
*/
public AbstractLanguage(String key) {
@@ -44,11 +44,11 @@ public abstract class AbstractLanguage implements Language {
/**
* Should be the constructor used to build an AbstractLanguage.
*
* @param key the key that will be used to retrieve the language. Must not be more than 20 chars. This key is important as it will be used to teint rules repositories...
* @param key the key that will be used to retrieve the language. Must not be more than 20 chars. This key is important as it will be used to teint rules repositories...
* @param name the display name of the language in the interface
*/
public AbstractLanguage(String key, String name) {
Preconditions.checkArgument(key.length() <= 20, "The following language key exceeds 20 characters: '" + key + "'");
checkArgument(key.length() <= 20, "The following language key exceeds 20 characters: '" + key + "'");
this.key = key.toLowerCase(Locale.ENGLISH);
this.name = name;
}

+ 2
- 3
sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.resources;

import com.google.common.base.Preconditions;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
@@ -27,6 +26,7 @@ import javax.annotation.concurrent.Immutable;

import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* <p>Experimental extension to declare types of resources.
@@ -36,7 +36,6 @@ import static org.apache.commons.lang.StringUtils.isEmpty;
* the resource being displayed.
* <br>
* Currently, the following properties can be defined:
*
* <ul>
* <li>"deletable": if set to "true", then this resource can be deleted/purged.</li>
* <li>"supportsMeasureFilters": if set to "true", then this resource can be displayed in measure filters</li>
@@ -148,7 +147,7 @@ public class ResourceType {
*/
public static Builder builder(String qualifier) {
requireNonNull(qualifier);
Preconditions.checkArgument(qualifier.length() <= 10, "Qualifier is limited to 10 characters");
checkArgument(qualifier.length() <= 10, "Qualifier is limited to 10 characters");
return new Builder(qualifier);
}


+ 16
- 14
sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypeTree.java View File

@@ -19,21 +19,21 @@
*/
package org.sonar.api.resources;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.server.ServerSide;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Collections.unmodifiableList;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 2.14
@@ -44,12 +44,12 @@ import static java.util.Objects.requireNonNull;
public class ResourceTypeTree {

private final List<ResourceType> types;
private final ListMultimap<String, String> relations;
private final Map<String, List<String>> relations;
private final ResourceType root;

private ResourceTypeTree(Builder builder) {
this.types = unmodifiableList(new ArrayList<>(builder.types));
this.relations = ImmutableListMultimap.copyOf(builder.relations);
this.relations = Collections.unmodifiableMap(builder.relations);
this.root = builder.root;
}

@@ -58,7 +58,7 @@ public class ResourceTypeTree {
}

public List<String> getChildren(String qualifier) {
return relations.get(qualifier);
return relations.getOrDefault(qualifier, Collections.emptyList());
}

public ResourceType getRootType() {
@@ -66,10 +66,11 @@ public class ResourceTypeTree {
}

public List<String> getLeaves() {
return unmodifiableList(relations.values()
return relations.values()
.stream()
.filter(qualifier -> relations.get(qualifier).isEmpty())
.collect(Collectors.toList()));
.flatMap(Collection::stream)
.filter(qualifier -> !relations.containsKey(qualifier))
.collect(Collectors.toList());
}

@Override
@@ -83,7 +84,8 @@ public class ResourceTypeTree {

public static final class Builder {
private List<ResourceType> types = new ArrayList<>();
private ListMultimap<String, String> relations = ArrayListMultimap.create();
private Map<String, List<String>> relations = new HashMap<>();
private List<String> children = new ArrayList<>();
private ResourceType root;

private Builder() {
@@ -100,12 +102,12 @@ public class ResourceTypeTree {
requireNonNull(parentQualifier);
requireNonNull(childrenQualifiers);
checkArgument(childrenQualifiers.length > 0, "childrenQualifiers can't be empty");
relations.putAll(parentQualifier, Arrays.asList(childrenQualifiers));
relations.computeIfAbsent(parentQualifier, x -> new ArrayList<>()).addAll(Arrays.asList(childrenQualifiers));
children.addAll(Arrays.asList(childrenQualifiers));
return this;
}

public ResourceTypeTree build() {
Collection<String> children = relations.values();
for (ResourceType type : types) {
if (!children.contains(type.getQualifier())) {
root = type;

+ 0
- 2
sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.resources;

import com.google.common.annotations.Beta;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -37,7 +36,6 @@ import static java.util.Objects.requireNonNull;
/**
* @since 2.14
*/
@Beta
@ServerSide
@ComputeEngineSide
public class ResourceTypes {

+ 4
- 5
sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleKey.java View File

@@ -19,12 +19,12 @@
*/
package org.sonar.api.rule;

import com.google.common.base.Preconditions;
import java.io.Serializable;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Key of a rule. Unique among all the rule repositories.
@@ -50,8 +50,8 @@ public class RuleKey implements Serializable, Comparable<RuleKey> {
* Create a key. Parameters are NOT null.
*/
public static RuleKey of(String repository, String rule) {
Preconditions.checkArgument(!isEmpty(repository), "Repository must be set");
Preconditions.checkArgument(!isEmpty(rule), "Rule must be set");
checkArgument(!isEmpty(repository), "Repository must be set");
checkArgument(!isEmpty(rule), "Rule must be set");
return new RuleKey(repository, rule);
}

@@ -61,7 +61,7 @@ public class RuleKey implements Serializable, Comparable<RuleKey> {
*/
public static RuleKey parse(String s) {
int semiColonPos = s.indexOf(':');
Preconditions.checkArgument(semiColonPos > 0, "Invalid rule key: " + s);
checkArgument(semiColonPos > 0, "Invalid rule key: " + s);
String key = s.substring(0, semiColonPos);
String repo = s.substring(semiColonPos + 1);
return RuleKey.of(key, repo);
@@ -81,7 +81,6 @@ public class RuleKey implements Serializable, Comparable<RuleKey> {
return rule;
}


@Override
public boolean equals(@Nullable Object o) {
if (this == o) {

+ 16
- 13
sonar-plugin-api/src/main/java/org/sonar/api/rules/AnnotationRuleParser.java View File

@@ -19,13 +19,13 @@
*/
package org.sonar.api.rules;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.PropertyType;
import org.sonar.api.ce.ComputeEngineSide;
@@ -101,16 +101,19 @@ public final class AnnotationRuleParser {
}
}

private static final Function<Class<?>, PropertyType> TYPE_FOR_CLASS = Functions.forMap(
ImmutableMap.<Class<?>, PropertyType>builder()
.put(Integer.class, PropertyType.INTEGER)
.put(int.class, PropertyType.INTEGER)
.put(Float.class, PropertyType.FLOAT)
.put(float.class, PropertyType.FLOAT)
.put(Boolean.class, PropertyType.BOOLEAN)
.put(boolean.class, PropertyType.BOOLEAN)
.build(),
PropertyType.STRING);
private static final Map<Class<?>, PropertyType> TYPE_FOR_CLASS_MAP = new HashMap<>();

static {
TYPE_FOR_CLASS_MAP.put(Integer.class, PropertyType.INTEGER);
TYPE_FOR_CLASS_MAP.put(int.class, PropertyType.INTEGER);
TYPE_FOR_CLASS_MAP.put(Float.class, PropertyType.FLOAT);
TYPE_FOR_CLASS_MAP.put(float.class, PropertyType.FLOAT);
TYPE_FOR_CLASS_MAP.put(Boolean.class, PropertyType.BOOLEAN);
TYPE_FOR_CLASS_MAP.put(boolean.class, PropertyType.BOOLEAN);

}

private static final Function<Class<?>, PropertyType> TYPE_FOR_CLASS = type -> TYPE_FOR_CLASS_MAP.getOrDefault(type, PropertyType.STRING);

static PropertyType guessType(Class<?> type) {
return TYPE_FOR_CLASS.apply(type);

+ 5
- 6
sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.rules;

import com.google.common.base.Joiner;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;
@@ -325,7 +324,7 @@ public class Rule {
*/
public Rule setStatus(String status) {
if (!STATUS_LIST.contains(status)) {
throw new SonarException("The status of a rule can only contain : " + Joiner.on(", ").join(STATUS_LIST));
throw new SonarException("The status of a rule can only contain : " + String.join(", ", STATUS_LIST));
}
this.status = status;
return this;
@@ -408,8 +407,8 @@ public class Rule {
/**
* For internal use only.
*
* @deprecated since 4.4, use {@link #getCharacteristicKey()}
* @since 4.3
* @deprecated since 4.4, use {@link #getCharacteristicKey()}
*/
@CheckForNull
@Deprecated
@@ -420,8 +419,8 @@ public class Rule {
/**
* For internal use only.
*
* @deprecated since 4.4, use {@link #setCharacteristicKey(String)}
* @since 4.3
* @deprecated since 4.4, use {@link #setCharacteristicKey(String)}
*/
@Deprecated
public Rule setCharacteristicId(@Nullable Integer characteristicId) {
@@ -431,8 +430,8 @@ public class Rule {
/**
* For internal use only.
*
* @deprecated since 4.4, use {@link #getDefaultCharacteristicKey()}
* @since 4.3
* @deprecated since 4.4, use {@link #getDefaultCharacteristicKey()}
*/
@CheckForNull
@Deprecated
@@ -443,8 +442,8 @@ public class Rule {
/**
* For internal use only.
*
* @deprecated since 4.4, use {@link #setDefaultCharacteristicKey(String)}
* @since 4.3
* @deprecated since 4.4, use {@link #setDefaultCharacteristicKey(String)}
*/
@Deprecated
public Rule setDefaultCharacteristicId(@Nullable Integer defaultCharacteristicId) {

+ 1
- 2
sonar-plugin-api/src/main/java/org/sonar/api/rules/XMLRuleParser.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.rules;

import com.google.common.base.Strings;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -150,7 +149,7 @@ public final class XMLRuleParser {
tags.add(StringUtils.trim(cursor.collectDescendantText(false)));
}
}
if (Strings.isNullOrEmpty(rule.getKey())) {
if (rule.getKey() == null || rule.getKey().isEmpty()) {
throw new SonarException("Node <key> is missing in <rule>");
}
rule.setTags(tags.toArray(new String[tags.size()]));

+ 1
- 2
sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/Display.java View File

@@ -22,8 +22,8 @@ package org.sonar.api.server.authentication;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;

import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Display information provided by the Identity Provider to be displayed into the login form.
@@ -47,7 +47,6 @@ public final class Display {
* URL path to the provider icon, as deployed at runtime, for example "/static/authgithub/github.svg" (in this
* case "authgithub" is the plugin key. Source file is "src/main/resources/static/github.svg").
* It can also be an external URL, for example "http://www.mydomain/myincon.png".
*
* Must not be blank.
* <br>
* The recommended format is SVG with a size of 24x24 pixels.

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/UserIdentity.java View File

@@ -26,10 +26,10 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.user.UserGroupValidation;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* User information provided by the Identity Provider to be register into the platform.

+ 6
- 10
sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtRemediationFunction.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.server.debt.internal;

import com.google.common.base.MoreObjects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
@@ -27,7 +26,7 @@ import org.apache.commons.lang.builder.EqualsBuilder;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.Duration;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkArgument;

public class DefaultDebtRemediationFunction implements DebtRemediationFunction {

@@ -72,7 +71,6 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction {
return gapMultiplier();
}


@Override
@CheckForNull
public String gapMultiplier() {
@@ -94,7 +92,6 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction {
return baseEffort;
}


private void validate() {
checkArgument(type != null, "Remediation function type cannot be null");
switch (type) {
@@ -136,13 +133,12 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction {
return result;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(DebtRemediationFunction.class)
.add("type", type)
.add("gap multiplier", gapMultiplier)
.add("base effort", baseEffort)
.toString();
return "DebtRemediationFunction{" +
"type=" + type + ", " +
"gap multiplier=" + gapMultiplier + ", " +
"base effort=" + baseEffort
+ "}";
}
}

+ 4
- 4
sonar-plugin-api/src/main/java/org/sonar/api/server/profile/BuiltInQualityProfilesDefinition.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.api.server.profile;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -35,17 +34,17 @@ import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.ServerSide;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Define built-in quality profiles which are automatically registered during SonarQube startup.
* We no more provide any facility to load profiles from XML file or annotated classes, but it should
* be straightforward to implement (adapt code of deprecated {@link org.sonar.api.profiles.AnnotationProfileParser}
* be straightforward to implement (adapt code of deprecated {@link org.sonar.api.profiles.AnnotationProfileParser}
* or {@link org.sonar.api.profiles.XMLProfileParser} for example).
*
* @since 6.6
@@ -73,7 +72,7 @@ public interface BuiltInQualityProfilesDefinition {
private void registerProfile(NewBuiltInQualityProfileImpl newProfile) {
String language = newProfile.language();
String name = newProfile.name();
Preconditions.checkArgument(!profilesByLanguageAndName.computeIfAbsent(language, l -> new LinkedHashMap<>()).containsKey(name),
checkArgument(!profilesByLanguageAndName.computeIfAbsent(language, l -> new LinkedHashMap<>()).containsKey(name),
"There is already a quality profile with name '%s' for language '%s'", name, language);
profilesByLanguageAndName.get(language).put(name, new BuiltInQualityProfileImpl(newProfile));
}
@@ -289,6 +288,7 @@ public interface BuiltInQualityProfilesDefinition {

/**
* Override default rule severity in this quality profile. By default the active rule will have the default rule severity.
*
* @param severity See {@link Severity} constants.
*/
public NewBuiltInActiveRule overrideSeverity(String severity) {

+ 19
- 35
sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java View File

@@ -19,8 +19,6 @@
*/
package org.sonar.api.server.rule;

import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
@@ -49,8 +47,6 @@ import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.log.Loggers;
import org.sonarsource.api.sonarlint.SonarLintSide;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.emptyList;
@@ -59,6 +55,8 @@ import static java.util.Collections.unmodifiableMap;
import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.apache.commons.lang.StringUtils.trimToNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

/**
* Defines some coding rules of the same repository. For example the Java Findbugs plugin provides an implementation of
@@ -69,37 +67,28 @@ import static org.apache.commons.lang.StringUtils.trimToNull;
* <h3>How to use</h3>
* <pre>
* public class MyJsRulesDefinition implements RulesDefinition {
*
* {@literal @}Override
* public void define(Context context) {
* NewRepository repository = context.createRepository("my_js", "js").setName("My Javascript Analyzer");
*
* // define a rule programmatically. Note that rules
* // could be loaded from files (JSON, XML, ...)
* NewRule x1Rule = repository.createRule("x1")
* .setName("No empty line")
* .setHtmlDescription("Generate an issue on empty lines")
*
* // optional tags
* .setTags("style", "stupid")
*
* // optional status. Default value is READY.
* .setStatus(RuleStatus.BETA)
*
* // default severity when the rule is activated on a Quality profile. Default value is MAJOR.
* .setSeverity(Severity.MINOR);
*
* // optional type for SonarQube Quality Model. Default is RulesDefinition.Type.CODE_SMELL.
* .setType(RulesDefinition.Type.BUG)
*
* x1Rule
* .setDebtRemediationFunction(x1Rule.debtRemediationFunctions().linearWithOffset("1h", "30min"));
*
* x1Rule.createParam("acceptWhitespace")
* .setDefaultValue("false")
* .setType(RuleParamType.BOOLEAN)
* .setDescription("Accept whitespaces on the line");
*
* // don't forget to call done() to finalize the definition
* repository.done();
* }
@@ -111,13 +100,10 @@ import static org.apache.commons.lang.StringUtils.trimToNull;
* <br>
* <pre>
* public class MyJsRulesDefinition implements RulesDefinition {
*
* private final RulesDefinitionXmlLoader xmlLoader;
*
* public MyJsRulesDefinition(RulesDefinitionXmlLoader xmlLoader) {
* this.xmlLoader = xmlLoader;
* }
*
* {@literal @}Override
* public void define(Context context) {
* NewRepository repository = context.createRepository("my_js", "js").setName("My Javascript Analyzer");
@@ -133,15 +119,12 @@ import static org.apache.commons.lang.StringUtils.trimToNull;
* <br>
* <pre>
* public class MyJsRulesDefinition implements RulesDefinition {
*
* private final RulesDefinitionXmlLoader xmlLoader;
* private final RulesDefinitionI18nLoader i18nLoader;
*
* public MyJsRulesDefinition(RulesDefinitionXmlLoader xmlLoader, RulesDefinitionI18nLoader i18nLoader) {
* this.xmlLoader = xmlLoader;
* this.i18nLoader = i18nLoader;
* }
*
* {@literal @}Override
* public void define(Context context) {
* NewRepository repository = context.createRepository("my_js", "js").setName("My Javascript Analyzer");
@@ -404,7 +387,7 @@ public interface RulesDefinition {
/**
* Creates a repository of rules from external rule engines.
* The repository key will be "external_[engineId]".
*
*
* @since 7.2
*/
public NewRepository createExternalRepository(String engineId, String language) {
@@ -1013,9 +996,9 @@ public interface RulesDefinition {
* <p>
* Deprecated keys should be added with this method in order, oldest first, for documentation purpose.
*
* @since 7.1
* @throws IllegalArgumentException if {@code repository} or {@code key} is {@code null} or empty.
* @see Rule#deprecatedRuleKeys
* @since 7.1
*/
public NewRule addDeprecatedRuleKey(String repository, String key) {
deprecatedRuleKeys.add(RuleKey.of(repository, key));
@@ -1067,15 +1050,17 @@ public interface RulesDefinition {
this.gapDescription = newRule.gapDescription;
this.scope = newRule.scope == null ? RuleScope.MAIN : newRule.scope;
this.type = newRule.type == null ? RuleTagsToTypeConverter.convert(newRule.tags) : newRule.type;
this.tags = ImmutableSortedSet.copyOf(Sets.difference(newRule.tags, RuleTagsToTypeConverter.RESERVED_TAGS));
this.securityStandards = ImmutableSortedSet.copyOf(newRule.securityStandards);
Set<String> tagsBuilder = new TreeSet<>(newRule.tags);
tagsBuilder.removeAll(RuleTagsToTypeConverter.RESERVED_TAGS);
this.tags = Collections.unmodifiableSet(tagsBuilder);
this.securityStandards = Collections.unmodifiableSet(new TreeSet<>(newRule.securityStandards));
Map<String, Param> paramsBuilder = new HashMap<>();
for (NewParam newParam : newRule.paramsByKey.values()) {
paramsBuilder.put(newParam.key, new Param(newParam));
}
this.params = Collections.unmodifiableMap(paramsBuilder);
this.activatedByDefault = newRule.activatedByDefault;
this.deprecatedRuleKeys = ImmutableSortedSet.copyOf(newRule.deprecatedRuleKeys);
this.deprecatedRuleKeys = Collections.unmodifiableSet(new TreeSet<>(newRule.deprecatedRuleKeys));
}

public Repository repository() {
@@ -1207,35 +1192,34 @@ public interface RulesDefinition {
* <br>
* Consider the following use case scenario:
* <ul>
* <li>Rule {@code Foo:A} is defined in version 1 of the plugin
* <li>Rule {@code Foo:A} is defined in version 1 of the plugin
* <pre>
* NewRepository newRepository = context.createRepository("Foo", "my_language");
* NewRule r = newRepository.createRule("A");
* </pre>
* </li>
* <li>Rule's key is renamed to B in version 2 of the plugin
* </li>
* <li>Rule's key is renamed to B in version 2 of the plugin
* <pre>
* NewRepository newRepository = context.createRepository("Foo", "my_language");
* NewRule r = newRepository.createRule("B")
* .addDeprecatedRuleKey("Foo", "A");
* </pre>
* </li>
* <li>All rules, including {@code Foo:B}, are moved to a new repository Bar in version 3 of the plugin
* </li>
* <li>All rules, including {@code Foo:B}, are moved to a new repository Bar in version 3 of the plugin
* <pre>
* NewRepository newRepository = context.createRepository("Bar", "my_language");
* NewRule r = newRepository.createRule("B")
* .addDeprecatedRuleKey("Foo", "A")
* .addDeprecatedRuleKey("Bar", "B");
* </pre>
* </li>
* </li>
* </ul>
*
* With all deprecated keys defined in version 3 of the plugin, SonarQube will be able to support "issue re-keying"
* for this rule in all cases:
* <ul>
* <li>plugin upgrade from v1 to v2,</li>
* <li>plugin upgrade from v2 to v3</li>
* <li>AND plugin upgrade from v1 to v3</li>
* <li>plugin upgrade from v1 to v2,</li>
* <li>plugin upgrade from v2 to v3</li>
* <li>AND plugin upgrade from v1 to v3</li>
* </ul>
* <p>
* Finally, repository/key pairs must be unique across all rules and their deprecated keys.
@@ -1247,8 +1231,8 @@ public interface RulesDefinition {
* {@link NewRule#addDeprecatedRuleKey(String, String) addDeprecatedRuleKey}. This allows to describe the history
* of a rule's repositories and keys over time. Oldest repository and key must be specified first.
*
* @since 7.1
* @see NewRule#addDeprecatedRuleKey(String, String)
* @since 7.1
*/
public Set<RuleKey> deprecatedRuleKeys() {
return deprecatedRuleKeys;

+ 12
- 14
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/Request.java View File

@@ -19,11 +19,10 @@
*/
package org.sonar.api.server.ws;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import java.io.BufferedReader;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -31,16 +30,17 @@ import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.utils.DateUtils;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.DateUtils.parseDateQuietly;
import static org.sonar.api.utils.DateUtils.parseDateTimeQuietly;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 4.2
@@ -218,13 +218,11 @@ public abstract class Request {
if (value == null) {
return null;
}
Iterable<String> values = Splitter.on(',').omitEmptyStrings().trimResults().split(value);
List<E> result = new ArrayList<>();
for (String s : values) {
result.add(Enum.valueOf(enumClass, s));
}

return result;
return Arrays.stream(value.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(x -> Enum.valueOf(enumClass, x))
.collect(Collectors.toList());
}

@CheckForNull
@@ -319,11 +317,12 @@ public abstract class Request {
public abstract Optional<String> header(String name);

public Map<String, String> getHeaders() {
return ImmutableMap.of();
return Collections.emptyMap();
}

/**
* Allows a web service to call another web service.
*
* @see LocalConnector
* @since 5.5
*/
@@ -331,6 +330,7 @@ public abstract class Request {

/**
* Return path of the request
*
* @since 6.0
*/
public abstract String getPath();
@@ -353,7 +353,6 @@ public abstract class Request {

/**
* @return the value of the parameter
*
* @throws IllegalStateException if param is not present.
*/
@CheckForNull
@@ -424,7 +423,6 @@ public abstract class Request {

/**
* @return the value of the parameter
*
* @throws IllegalStateException if param is not present.
*/
@Override

+ 19
- 20
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java View File

@@ -43,13 +43,12 @@ import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkState;

/**
* Defines a web service.
@@ -64,7 +63,6 @@ import static java.util.Objects.requireNonNull;
* public void define(Context context) {
* NewController controller = context.createController("api/hello");
* controller.setDescription("Web service example");
*
* // create the URL /api/hello/show
* controller.createAction("show")
* .setDescription("Entry point")
@@ -80,7 +78,6 @@ import static java.util.Objects.requireNonNull;
* }
* })
* .createParam("key").setDescription("Example key").setRequired(true);
*
* // important to apply changes
* controller.done();
* }
@@ -396,6 +393,7 @@ public interface WebService extends Definable<WebService.Context> {

/**
* Add predefined parameters related to pagination of results with a maximum page size.
*
* @since 7.1
*/
public NewAction addPagingParamsSince(int defaultPageSize, int maxPageSize, String version) {
@@ -523,8 +521,8 @@ public interface WebService extends Definable<WebService.Context> {
this.changelog = newAction.changelog;

checkState(this.handler != null, "RequestHandler is not set on action %s", path);
logWarningIf(isNullOrEmpty(this.description), "Description is not set on action " + path);
logWarningIf(isNullOrEmpty(this.since), "Since is not set on action " + path);
logWarningIf(this.description == null || this.description.isEmpty(), "Description is not set on action " + path);
logWarningIf(this.since == null || this.since.isEmpty(), "Since is not set on action " + path);
logWarningIf(!this.post && this.responseExample == null, "The response example is not set on action " + path);

Map<String, Param> paramsBuilder = new HashMap<>();
@@ -664,8 +662,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 5.3
* @see Param#since()
* @since 5.3
*/
public NewParam setSince(@Nullable String since) {
this.since = since;
@@ -693,8 +691,8 @@ public interface WebService extends Definable<WebService.Context> {

/**
* @param deprecatedSince Version when the old key was replaced/deprecated. Ex: 5.6
* @since 6.4
* @see Param#deprecatedKey()
* @since 6.4
*/
public NewParam setDeprecatedKey(@Nullable String key, @Nullable String deprecatedSince) {
this.deprecatedKey = key;
@@ -708,8 +706,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 5.6
* @see Param#description()
* @since 5.6
*/
public NewParam setDescription(@Nullable String description, Object... descriptionArgument) {
this.description = description == null ? null : String.format(description, descriptionArgument);
@@ -719,8 +717,8 @@ public interface WebService extends Definable<WebService.Context> {
/**
* Is the parameter required or optional ? Default value is false (optional).
*
* @since 4.4
* @see Param#isRequired()
* @since 4.4
*/
public NewParam setRequired(boolean b) {
this.required = b;
@@ -732,8 +730,8 @@ public interface WebService extends Definable<WebService.Context> {
* displayed only when the check-box "Show Internal API" is selected. By default
* a parameter is not internal.
*
* @since 6.2
* @see Param#isInternal()
* @since 6.2
*/
public NewParam setInternal(boolean b) {
this.internal = b;
@@ -741,8 +739,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 4.4
* @see Param#exampleValue()
* @since 4.4
*/
public NewParam setExampleValue(@Nullable Object s) {
this.exampleValue = (s != null) ? s.toString() : null;
@@ -753,8 +751,8 @@ public interface WebService extends Definable<WebService.Context> {
* Exhaustive list of possible values when it makes sense, for example
* list of severities.
*
* @since 4.4
* @see Param#possibleValues()
* @since 4.4
*/
public <T> NewParam setPossibleValues(@Nullable T... values) {
return setPossibleValues(values == null ? Collections.emptyList() : asList(values));
@@ -762,6 +760,7 @@ public interface WebService extends Definable<WebService.Context> {

/**
* Shortcut for {@code setPossibleValues("true", "false", "yes", "no")}
*
* @since 4.4
*/
public NewParam setBooleanPossibleValues() {
@@ -772,8 +771,8 @@ public interface WebService extends Definable<WebService.Context> {
* Exhaustive list of possible values when it makes sense, for example
* list of severities.
*
* @since 4.4
* @see Param#possibleValues()
* @since 4.4
*/
public <T> NewParam setPossibleValues(@Nullable Collection<T> values) {
if (values == null || values.isEmpty()) {
@@ -788,8 +787,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 4.4
* @see Param#defaultValue()
* @since 4.4
*/
public NewParam setDefaultValue(@Nullable Object o) {
this.defaultValue = (o != null) ? o.toString() : null;
@@ -797,8 +796,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 6.4
* @see Param#maxValuesAllowed()
* @since 6.4
*/
public NewParam setMaxValuesAllowed(@Nullable Integer maxValuesAllowed) {
this.maxValuesAllowed = maxValuesAllowed;
@@ -806,8 +805,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 7.0
* @see Param#maximumLength()
* @since 7.0
*/
public NewParam setMaximumLength(@Nullable Integer maximumLength) {
this.maximumLength = maximumLength;
@@ -815,8 +814,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 7.0
* @see Param#minimumLength()
* @since 7.0
*/
public NewParam setMinimumLength(@Nullable Integer minimumLength) {
this.minimumLength = minimumLength;
@@ -824,8 +823,8 @@ public interface WebService extends Definable<WebService.Context> {
}

/**
* @since 7.0
* @see Param#maximumValue()
* @since 7.0
*/
public NewParam setMaximumValue(@Nullable Integer maximumValue) {
this.maximumValue = maximumValue;

+ 4
- 2
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/internal/SimpleGetRequest.java View File

@@ -19,12 +19,13 @@
*/
package org.sonar.api.server.ws.internal;

import com.google.common.base.Splitter;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
@@ -89,7 +90,8 @@ public class SimpleGetRequest extends Request {
if (value == null) {
return null;
}
return Splitter.on(',').omitEmptyStrings().trimResults().splitToList(value);

return Arrays.stream(value.split(",")).map(String::trim).filter(x -> !x.isEmpty()).collect(Collectors.toList());
}

@Override

+ 26
- 7
sonar-plugin-api/src/main/java/org/sonar/api/server/ws/internal/ValidatingRequest.java View File

@@ -19,9 +19,8 @@
*/
package org.sonar.api.server.ws.internal;

import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -31,19 +30,19 @@ import org.sonar.api.server.ws.LocalConnector;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang.StringUtils.defaultString;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 4.2
*/
public abstract class ValidatingRequest extends Request {

private static final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
private static final String COMMA_SPLITTER = ",";
private WebService.Action action;
private LocalConnector localConnector;

@@ -69,10 +68,9 @@ public abstract class ValidatingRequest extends Request {
@CheckForNull
public String param(String key) {
WebService.Param definition = action.param(key);

String rawValue = readParam(key, definition);
String rawValueOrDefault = defaultString(rawValue, definition.defaultValue());
String value = rawValueOrDefault == null ? null : CharMatcher.WHITESPACE.trimFrom(rawValueOrDefault);
String value = rawValueOrDefault == null ? null : trim(rawValueOrDefault);
validateRequiredValue(key, definition, rawValue);
if (value == null) {
return null;
@@ -91,6 +89,23 @@ public abstract class ValidatingRequest extends Request {
return validateValues(values, definition);
}

private static String trim(String s) {
int begin;
for (begin = 0; begin < s.length(); begin++) {
if (!Character.isWhitespace(s.charAt(begin))) {
break;
}
}

int end;
for (end = s.length(); end > begin; end--) {
if (!Character.isWhitespace(s.charAt(end - 1))) {
break;
}
}
return s.substring(begin, end);
}

@Override
@CheckForNull
public InputStream paramAsInputStream(String key) {
@@ -111,7 +126,10 @@ public abstract class ValidatingRequest extends Request {
if (value == null) {
return null;
}
List<String> values = COMMA_SPLITTER.splitToList(value);
List<String> values = Arrays.stream(value.split(COMMA_SPLITTER))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toList());
return validateValues(values, definition);
}

@@ -123,6 +141,7 @@ public abstract class ValidatingRequest extends Request {
return null;
}
return values.stream()
.filter(s -> !s.isEmpty())
.map(value -> Enum.valueOf(enumClass, value))
.collect(Collectors.toList());
}

+ 6
- 5
sonar-plugin-api/src/main/java/org/sonar/api/task/TaskDefinition.java View File

@@ -19,13 +19,14 @@
*/
package org.sonar.api.task;

import com.google.common.base.Preconditions;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.ExtensionPoint;
import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.ScannerSide;

import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Register and describe a {@link TaskExtension}.
*
@@ -117,10 +118,10 @@ public class TaskDefinition implements Comparable<TaskDefinition> {
}

public TaskDefinition build() {
Preconditions.checkArgument(!StringUtils.isEmpty(key), "Task key must be set");
Preconditions.checkArgument(Pattern.matches(KEY_PATTERN, key), "Task key '" + key + "' must match " + KEY_PATTERN);
Preconditions.checkArgument(!StringUtils.isEmpty(description), "Description must be set for task '" + key + "'");
Preconditions.checkArgument(taskClass != null, "Class must be set for task '" + key + "'");
checkArgument(!StringUtils.isEmpty(key), "Task key must be set");
checkArgument(Pattern.matches(KEY_PATTERN, key), "Task key '" + key + "' must match " + KEY_PATTERN);
checkArgument(!StringUtils.isEmpty(description), "Description must be set for task '" + key + "'");
checkArgument(taskClass != null, "Class must be set for task '" + key + "'");
return new TaskDefinition(this);
}
}

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/user/UserGroupValidation.java View File

@@ -22,7 +22,7 @@ package org.sonar.api.user;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.security.DefaultGroups;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkArgument;

public class UserGroupValidation {


+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/utils/DateUtils.java View File

@@ -30,7 +30,7 @@ import java.util.Date;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* Parses and formats <a href="https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html#rfc822timezone">RFC 822</a> dates.

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/utils/Paging.java View File

@@ -19,7 +19,7 @@
*/
package org.sonar.api.utils;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 3.6

sonar-plugin-api/src/main/java/org/sonar/api/measures/MultisetDistributionFormat.java → sonar-plugin-api/src/main/java/org/sonar/api/utils/Preconditions.java View File

@@ -17,34 +17,36 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.measures;
package org.sonar.api.utils;

import com.google.common.collect.Multiset;
import org.sonar.api.utils.KeyValueFormat;
public class Preconditions {
public static void checkArgument(boolean condition, String message) {
if (!condition) {
throw new IllegalArgumentException(message);
}
}

/**
* Format internal {@link com.google.common.collect.Multiset} of {@link CountDistributionBuilder}
* and {@link RangeDistributionBuilder}
*/
class MultisetDistributionFormat {
public static void checkArgument(boolean condition) {
if (!condition) {
throw new IllegalArgumentException();
}
}

private MultisetDistributionFormat() {
// only statics
public static void checkArgument(boolean condition, String format, Object... args) {
if (!condition) {
throw new IllegalArgumentException(String.format(format, args));
}
}

public static void checkState(boolean condition, String message) {
if (!condition) {
throw new IllegalStateException(message);
}
}

static String format(Multiset countBag) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Object obj : countBag.elementSet()) {
if (!first) {
sb.append(KeyValueFormat.PAIR_SEPARATOR);
}
sb.append(obj.toString());
sb.append(KeyValueFormat.FIELD_SEPARATOR);
// -1 allows to include zero values
sb.append(countBag.count(obj) - 1);
first = false;
public static void checkState(boolean condition, String format, Object... args) {
if (!condition) {
throw new IllegalStateException(String.format(format, args));
}
return sb.toString();
}
}

+ 8
- 9
sonar-plugin-api/src/main/java/org/sonar/api/utils/UriReader.java View File

@@ -19,20 +19,19 @@
*/
package org.sonar.api.utils;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.scanner.ScannerSide;
import org.sonar.api.server.ServerSide;

/**
@@ -103,24 +102,24 @@ public class UriReader {

@Override
public String[] getSupportedSchemes() {
return new String[]{"file"};
return new String[] {"file"};
}

@Override
protected byte[] readBytes(URI uri) {
try {
return Files.toByteArray(new File(uri));
return Files.readAllBytes(Paths.get(uri));
} catch (IOException e) {
throw Throwables.propagate(e);
throw new RuntimeException(e);
}
}

@Override
protected String readString(URI uri, Charset charset) {
try {
return Files.toString(new File(uri), charset);
return new String(Files.readAllBytes(Paths.get(uri)), charset);
} catch (IOException e) {
throw Throwables.propagate(e);
throw new RuntimeException(e);
}
}


+ 18
- 19
sonar-plugin-api/src/main/java/org/sonar/api/utils/Version.java View File

@@ -19,8 +19,7 @@
*/
package org.sonar.api.utils;

import com.google.common.base.Splitter;
import java.util.List;
import java.util.regex.Pattern;
import javax.annotation.concurrent.Immutable;

import static java.lang.Integer.parseInt;
@@ -53,8 +52,7 @@ public class Version implements Comparable<Version> {
private static final int DEFAULT_PATCH = 0;
private static final String DEFAULT_QUALIFIER = "";
private static final String QUALIFIER_SEPARATOR = "-";
private static final char SEQUENCE_SEPARATOR = '.';
private static final Splitter SEQUENCE_SPLITTER = Splitter.on(SEQUENCE_SEPARATOR);
private static final String SEQUENCE_SEPARATOR = ".";

private final int major;
private final int minor;
@@ -85,6 +83,7 @@ public class Version implements Comparable<Version> {
/**
* Build number if the fourth field, for example {@code 12345} for "6.3.0.12345".
* If absent, then value is zero.
*
* @since 6.3
*/
public long buildNumber() {
@@ -101,19 +100,19 @@ public class Version implements Comparable<Version> {
/**
* Convert a {@link String} to a Version. Supported formats:
* <ul>
* <li>1</li>
* <li>1.2</li>
* <li>1.2.3</li>
* <li>1-beta-1</li>
* <li>1.2-beta-1</li>
* <li>1.2.3-beta-1</li>
* <li>1.2.3.4567</li>
* <li>1.2.3.4567-beta-1</li>
* <li>1</li>
* <li>1.2</li>
* <li>1.2.3</li>
* <li>1-beta-1</li>
* <li>1.2-beta-1</li>
* <li>1.2.3-beta-1</li>
* <li>1.2.3.4567</li>
* <li>1.2.3.4567-beta-1</li>
* </ul>
* Note that the optional qualifier is the part after the first "-".
*
* @throws IllegalArgumentException if parameter is badly formatted, for example
* if it defines 5 integer-sequences.
* if it defines 5 integer-sequences.
*/
public static Version parse(String text) {
String s = trimToEmpty(text);
@@ -121,20 +120,20 @@ public class Version implements Comparable<Version> {
if (!qualifier.isEmpty()) {
s = substringBefore(s, QUALIFIER_SEPARATOR);
}
List<String> fields = SEQUENCE_SPLITTER.splitToList(s);
String[] fields = s.split(Pattern.quote(SEQUENCE_SEPARATOR));
int major = 0;
int minor = 0;
int patch = DEFAULT_PATCH;
long buildNumber = DEFAULT_BUILD_NUMBER;
int size = fields.size();
int size = fields.length;
if (size > 0) {
major = parseFieldAsInt(fields.get(0));
major = parseFieldAsInt(fields[0]);
if (size > 1) {
minor = parseFieldAsInt(fields.get(1));
minor = parseFieldAsInt(fields[1]);
if (size > 2) {
patch = parseFieldAsInt(fields.get(2));
patch = parseFieldAsInt(fields[2]);
if (size > 3) {
buildNumber = parseFieldAsLong(fields.get(3));
buildNumber = parseFieldAsLong(fields[3]);
if (size > 4) {
throw new IllegalArgumentException("Maximum 4 fields are accepted: " + text);
}

+ 4
- 6
sonar-plugin-api/src/main/java/org/sonar/api/utils/command/Command.java View File

@@ -19,8 +19,6 @@
*/
package org.sonar.api.utils.command;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
@@ -32,6 +30,7 @@ import org.sonar.api.utils.System2;

import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 2.7
@@ -46,7 +45,7 @@ public class Command {
private final System2 system;

Command(String executable, System2 system) {
Preconditions.checkArgument(!StringUtils.isBlank(executable), "Command executable can not be blank");
checkArgument(!StringUtils.isBlank(executable), "Command executable can not be blank");
this.executable = executable;
this.env = new HashMap<>(system.envVariables());
this.system = system;
@@ -138,7 +137,6 @@ public class Command {
/**
* Set to <code>true</code> if a new shell should be used to execute the command.
* This is useful when the executed command is a script with no execution rights (+x on unix).
*
* On windows, the command will be executed with <code>cmd /C executable</code>.
* On other platforms, the command will be executed with <code>sh executable</code>.
*
@@ -166,11 +164,11 @@ public class Command {
}

public String toCommandLine() {
return Joiner.on(" ").join(toStrings(false));
return String.join(" ", toStrings(false));
}

@Override
public String toString() {
return Joiner.on(" ").join(toStrings(true));
return String.join(" ", toStrings(true));
}
}

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/AlwaysIncreasingSystem2.java View File

@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import org.sonar.api.utils.System2;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* A subclass of {@link System2} which implementation of {@link System2#now()} always return a bigger value than the

+ 2
- 2
sonar-plugin-api/src/main/java/org/sonar/api/utils/log/LogInterceptors.java View File

@@ -19,7 +19,7 @@
*/
package org.sonar.api.utils.log;

import com.google.common.base.Preconditions;
import static org.sonar.api.utils.Preconditions.checkArgument;

class LogInterceptors {

@@ -33,7 +33,7 @@ class LogInterceptors {
}

static void set(LogInterceptor li) {
Preconditions.checkArgument(li != null);
checkArgument(li != null);
instance = li;
}
}

+ 5
- 6
sonar-plugin-api/src/main/java/org/sonar/api/web/Dashboard.java View File

@@ -19,12 +19,12 @@
*/
package org.sonar.api.web;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* Definition of a dashboard.
@@ -40,7 +40,7 @@ public final class Dashboard {

private String description;
private DashboardLayout layout = DashboardLayout.TWO_COLUMNS;
private ListMultimap<Integer, Widget> widgetsByColumn = ArrayListMultimap.create();
private Map<Integer, List<Widget>> widgetsByColumn = new HashMap<>();
private boolean activated = true;
private boolean global = false;

@@ -56,7 +56,6 @@ public final class Dashboard {

/**
* Add a widget with the given parameters, and return the newly created {@link Widget} object if one wants to add parameters to it.
*
* <p>The widget ids are listed by the web service /api/widgets
*
* @param widgetId id of an existing widget
@@ -68,12 +67,12 @@ public final class Dashboard {
}

Widget widget = new Widget(widgetId);
widgetsByColumn.put(columnId, widget);
widgetsByColumn.computeIfAbsent(columnId, x -> new ArrayList<>()).add(widget);
return widget;
}

public Collection<Widget> getWidgets() {
return widgetsByColumn.values();
return widgetsByColumn.values().stream().flatMap(List::stream).collect(Collectors.toList());
}

public List<Widget> getWidgetsOfColumn(int columnId) {

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java View File

@@ -32,10 +32,10 @@ import javax.servlet.Filter;
import org.sonar.api.ExtensionPoint;
import org.sonar.api.server.ServerSide;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import static org.apache.commons.lang.StringUtils.substringBeforeLast;
import static org.sonar.api.utils.Preconditions.checkArgument;

/**
* @since 3.1

+ 0
- 3
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java View File

@@ -26,7 +26,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
@@ -53,8 +52,6 @@ import org.sonar.api.rules.RuleType;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.assertj.core.data.MapEntry.entry;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class SensorContextTesterTest {


+ 1
- 1
sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RuleTagsToTypeConverterTest.java View File

@@ -22,7 +22,7 @@ package org.sonar.api.server.rule;
import java.util.Collections;
import org.junit.Test;
import org.sonar.api.rules.RuleType;
import org.sonar.test.TestUtils;
import org.sonar.api.utils.TestUtils;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

+ 1
- 1
sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java View File

@@ -32,7 +32,7 @@ import org.sonar.api.rules.RuleType;
import org.sonar.api.server.debt.DebtRemediationFunction;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.test.ExceptionCauseMatcher.hasType;
import static org.sonar.api.utils.ExceptionCauseMatcher.hasType;

public class RulesDefinitionXmlLoaderTest {


+ 91
- 0
sonar-plugin-api/src/test/java/org/sonar/api/utils/ExceptionCauseMatcher.java View File

@@ -0,0 +1,91 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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 3 of the License, or (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.utils;

import java.util.Objects;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

/**
* Matchers designed to be used as an argument of {@link org.junit.rules.ExpectedException#expectCause(Matcher)} such as:
*
* <pre>
* expectedException.expect(VisitException.class);
* expectedException.expectCause(hasType(IllegalArgumentException.class).andMessage("file and otherFile Components can not be the same"));
* </pre>
*
* Class strongly inspired from {@code CauseMatcher} class from {@code http://blog.codeleak.pl/2014/03/junit-expectedexception-rule-beyond.html}
*/
@Immutable
public class ExceptionCauseMatcher extends TypeSafeMatcher<Throwable> {
private static final String EXPECT_NO_MESSAGE_CONSTANT = "RQXG8QTUCXOT7HZ3APPKBKUE5";

private final Class<? extends Throwable> type;
@CheckForNull
private final String expectedMessage;

private ExceptionCauseMatcher(Class<? extends Throwable> type, @Nullable String expectedMessage) {
this.type = type;
this.expectedMessage = expectedMessage;
}

public static ExceptionCauseMatcher hasType(Class<? extends Throwable> type) {
return new ExceptionCauseMatcher(type, null);
}

public ExceptionCauseMatcher andMessage(String expectedMessage) {
return new ExceptionCauseMatcher(type, Objects.requireNonNull(expectedMessage));
}

public ExceptionCauseMatcher andNoMessage() {
return new ExceptionCauseMatcher(type, EXPECT_NO_MESSAGE_CONSTANT);
}

@Override
protected boolean matchesSafely(Throwable item) {
if (!type.isAssignableFrom(item.getClass())) {
return false;
}
if (expectedMessage == null) {
return true;
}
if (EXPECT_NO_MESSAGE_CONSTANT.equals(expectedMessage)) {
return item.getMessage() == null;
}
return item.getMessage().contains(expectedMessage);
}

@Override
public void describeTo(Description description) {
description.appendText("of type ")
.appendValue(type);
if (EXPECT_NO_MESSAGE_CONSTANT.equals(expectedMessage)) {
description.appendText(" and no message");
} else if (expectedMessage != null) {
description.appendText(" and message ")
.appendValue(expectedMessage);
}
description.appendText(" but");
}
}

+ 1
- 2
sonar-plugin-api/src/test/java/org/sonar/api/utils/KeyValueFormatTest.java View File

@@ -28,7 +28,6 @@ import java.util.Map;
import java.util.TreeMap;
import org.junit.Test;
import org.sonar.api.rules.RulePriority;
import org.sonar.test.TestUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
@@ -36,7 +35,7 @@ import static org.assertj.core.api.Assertions.entry;
public class KeyValueFormatTest {

@Test
public void test_parser() throws Exception {
public void test_parser() {
KeyValueFormat.FieldParser reader = new KeyValueFormat.FieldParser("abc=def;ghi=jkl");
assertThat(reader.nextKey()).isEqualTo("abc");
assertThat(reader.nextVal()).isEqualTo("def");

+ 2
- 4
sonar-plugin-api/src/test/java/org/sonar/api/utils/PathUtilsTest.java View File

@@ -19,15 +19,13 @@
*/
package org.sonar.api.utils;

import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;
import org.sonar.test.TestUtils;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;

+ 55
- 0
sonar-plugin-api/src/test/java/org/sonar/api/utils/TestUtils.java View File

@@ -0,0 +1,55 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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 3 of the License, or (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.api.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/**
* Utilities for unit tests
*
* @since 2.2
*/
public final class TestUtils {

private TestUtils() {
}

/**
* Asserts that all constructors are private, usually for helper classes with
* only static methods. If a constructor does not have any parameters, then
* it's instantiated.
*/
public static boolean hasOnlyPrivateConstructors(Class clazz) {
boolean ok = true;
for (Constructor constructor : clazz.getDeclaredConstructors()) {
ok &= Modifier.isPrivate(constructor.getModifiers());
if (constructor.getParameterTypes().length == 0) {
constructor.setAccessible(true);
try {
constructor.newInstance();
} catch (Exception e) {
throw new IllegalStateException(String.format("Fail to instantiate %s", clazz), e);
}
}
}
return ok;
}
}

+ 9
- 22
sonar-plugin-api/src/test/java/org/sonar/api/utils/command/CommandExecutorTest.java View File

@@ -56,18 +56,10 @@ public class CommandExecutorTest {
public void should_consume_StdOut_and_StdErr() throws Exception {
// too many false-positives on MS windows
if (!SystemUtils.IS_OS_WINDOWS) {
final StringBuilder stdOutBuilder = new StringBuilder();
StreamConsumer stdOutConsumer = new StreamConsumer() {
public void consumeLine(String line) {
stdOutBuilder.append(line).append(SystemUtils.LINE_SEPARATOR);
}
};
final StringBuilder stdErrBuilder = new StringBuilder();
StreamConsumer stdErrConsumer = new StreamConsumer() {
public void consumeLine(String line) {
stdErrBuilder.append(line).append(SystemUtils.LINE_SEPARATOR);
}
};
StringBuilder stdOutBuilder = new StringBuilder();
StreamConsumer stdOutConsumer = line -> stdOutBuilder.append(line).append(SystemUtils.LINE_SEPARATOR);
StringBuilder stdErrBuilder = new StringBuilder();
StreamConsumer stdErrConsumer = line -> stdErrBuilder.append(line).append(SystemUtils.LINE_SEPARATOR);
Command command = Command.create(getScript("output")).setDirectory(workDir);
int exitCode = CommandExecutor.create().execute(command, stdOutConsumer, stdErrConsumer, 1000L);
assertThat(exitCode).isEqualTo(0);
@@ -97,16 +89,11 @@ public class CommandExecutorTest {
CommandExecutor.create().execute(command, NOP_CONSUMER, BAD_CONSUMER, 1500L);
}

private static final StreamConsumer NOP_CONSUMER = new StreamConsumer() {
public void consumeLine(String line) {
// nop
}
private static final StreamConsumer NOP_CONSUMER = line -> {
};

private static final StreamConsumer BAD_CONSUMER = new StreamConsumer() {
public void consumeLine(String line) {
throw new RuntimeException();
}
private static final StreamConsumer BAD_CONSUMER = line -> {
throw new RuntimeException();
};

@Test
@@ -129,7 +116,7 @@ public class CommandExecutorTest {
public void should_stop_after_timeout() throws IOException {
try {
String executable = getScript("forever");
CommandExecutor.create().execute(Command.create(executable).setDirectory(workDir), 1000L);
CommandExecutor.create().execute(Command.create(executable).setDirectory(workDir), 100);
fail();
} catch (TimeoutException e) {
// ok
@@ -140,7 +127,7 @@ public class CommandExecutorTest {
public void should_stop_after_timeout_and_new_shell() throws IOException {
try {
String executable = getScript("forever");
CommandExecutor.create().execute(Command.create(executable).setNewShell(true).setDirectory(workDir), 1000L);
CommandExecutor.create().execute(Command.create(executable).setNewShell(true).setDirectory(workDir), 100);
fail();
} catch (TimeoutException e) {
// ok

+ 1
- 1
sonar-plugin-api/src/test/java/org/sonar/api/utils/log/ConsoleFormatterTest.java View File

@@ -20,7 +20,7 @@
package org.sonar.api.utils.log;

import org.junit.Test;
import org.sonar.test.TestUtils;
import org.sonar.api.utils.TestUtils;

import static org.assertj.core.api.Assertions.assertThat;


+ 1
- 1
sonar-plugin-api/src/test/java/org/sonar/api/utils/log/LogInterceptorsTest.java View File

@@ -20,7 +20,7 @@
package org.sonar.api.utils.log;

import org.junit.Test;
import org.sonar.test.TestUtils;
import org.sonar.api.utils.TestUtils;

import static org.assertj.core.api.Assertions.assertThat;


Loading…
Cancel
Save