You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ReportParser.java 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.scanner.externalissue;
  21. import com.google.gson.Gson;
  22. import com.google.gson.JsonIOException;
  23. import com.google.gson.JsonSyntaxException;
  24. import java.io.IOException;
  25. import java.io.Reader;
  26. import java.nio.charset.StandardCharsets;
  27. import java.nio.file.Files;
  28. import java.nio.file.Path;
  29. import javax.annotation.Nullable;
  30. import org.apache.commons.lang.StringUtils;
  31. public class ReportParser {
  32. private Gson gson = new Gson();
  33. private Path filePath;
  34. public ReportParser(Path filePath) {
  35. this.filePath = filePath;
  36. }
  37. public Report parse() {
  38. try (Reader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) {
  39. return validate(gson.fromJson(reader, Report.class));
  40. } catch (JsonIOException | IOException e) {
  41. throw new IllegalStateException("Failed to read external issues report '" + filePath + "'", e);
  42. } catch (JsonSyntaxException e) {
  43. throw new IllegalStateException("Failed to read external issues report '" + filePath + "': invalid JSON syntax", e);
  44. }
  45. }
  46. private Report validate(Report report) {
  47. for (Issue issue : report.issues) {
  48. mandatoryField(issue.primaryLocation, "primaryLocation");
  49. mandatoryField(issue.engineId, "engineId");
  50. mandatoryField(issue.ruleId, "ruleId");
  51. mandatoryField(issue.severity, "severity");
  52. mandatoryField(issue.type, "type");
  53. mandatoryField(issue.primaryLocation, "primaryLocation");
  54. mandatoryFieldPrimaryLocation(issue.primaryLocation.filePath, "filePath");
  55. mandatoryFieldPrimaryLocation(issue.primaryLocation.message, "message");
  56. if (issue.primaryLocation.textRange != null) {
  57. mandatoryFieldPrimaryLocation(issue.primaryLocation.textRange.startLine, "startLine of the text range");
  58. }
  59. if (issue.secondaryLocations != null) {
  60. for (Location l : issue.secondaryLocations) {
  61. mandatoryFieldSecondaryLocation(l.filePath, "filePath");
  62. mandatoryFieldSecondaryLocation(l.textRange, "textRange");
  63. mandatoryFieldSecondaryLocation(l.textRange.startLine, "startLine of the text range");
  64. }
  65. }
  66. }
  67. return report;
  68. }
  69. private void mandatoryFieldPrimaryLocation(@Nullable Object value, String fieldName) {
  70. if (value == null) {
  71. throw new IllegalStateException(String.format("Failed to parse report '%s': missing mandatory field '%s' in the primary location of the issue.", filePath, fieldName));
  72. }
  73. }
  74. private void mandatoryFieldSecondaryLocation(@Nullable Object value, String fieldName) {
  75. if (value == null) {
  76. throw new IllegalStateException(String.format("Failed to parse report '%s': missing mandatory field '%s' in a secondary location of the issue.", filePath, fieldName));
  77. }
  78. }
  79. private void mandatoryField(@Nullable Object value, String fieldName) {
  80. if (value == null) {
  81. throw new IllegalStateException(String.format("Failed to parse report '%s': missing mandatory field '%s'.", filePath, fieldName));
  82. }
  83. }
  84. private void mandatoryField(@Nullable String value, String fieldName) {
  85. if (StringUtils.isBlank(value)) {
  86. throw new IllegalStateException(String.format("Failed to parse report '%s': missing mandatory field '%s'.", filePath, fieldName));
  87. }
  88. }
  89. static class Report {
  90. Issue[] issues;
  91. public Report() {
  92. // http://stackoverflow.com/a/18645370/229031
  93. }
  94. }
  95. static class Issue {
  96. String engineId;
  97. String ruleId;
  98. String severity;
  99. String type;
  100. @Nullable
  101. Integer effortMinutes;
  102. Location primaryLocation;
  103. @Nullable
  104. Location[] secondaryLocations;
  105. public Issue() {
  106. // http://stackoverflow.com/a/18645370/229031
  107. }
  108. }
  109. static class Location {
  110. @Nullable
  111. String message;
  112. String filePath;
  113. @Nullable
  114. TextRange textRange;
  115. public Location() {
  116. // http://stackoverflow.com/a/18645370/229031
  117. }
  118. }
  119. static class TextRange {
  120. Integer startLine;
  121. @Nullable
  122. Integer startColumn;
  123. @Nullable
  124. Integer endLine;
  125. @Nullable
  126. Integer endColumn;
  127. public TextRange() {
  128. // http://stackoverflow.com/a/18645370/229031
  129. }
  130. }
  131. }