SonarJava is a static code analyzer for Java that helps maintain code quality, security, and maintainability. This guide demonstrates comprehensive integration and usage of SonarJava in Java projects.
Why Use SonarJava?
- Code Quality: Detect bugs, vulnerabilities, and code smells
- Security: Identify security vulnerabilities and hotspots
- Maintainability: Measure technical debt and code complexity
- Consistency: Enforce coding standards and best practices
- Continuous Inspection: Integrate with CI/CD pipelines
Prerequisites
- SonarQube server (local or cloud)
- Java 8+ project
- Maven/Gradle build tool
- SonarJava plugin installed in SonarQube
Step 1: Project Dependencies and Configuration
Maven (pom.xml):
<properties>
<sonar.host.url>http://localhost:9000</sonar.host.url>
<sonar.login>${env.SONAR_TOKEN}</sonar.login>
<sonar.projectKey>my-java-app</sonar.projectKey>
<sonar.projectName>My Java Application</sonar.projectName>
<sonar.projectVersion>1.0.0</sonar.projectVersion>
<sonar.sources>src/main/java</sonar.sources>
<sonar.tests>src/test/java</sonar.tests>
<sonar.java.source>11</sonar.java.source>
<sonar.java.target>11</sonar.java.target>
<sonar.coverage.jacoco.xmlReportPaths>target/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
<sonar.junit.reportPaths>target/surefire-reports</sonar.junit.reportPaths>
</properties>
<build>
<plugins>
<!-- SonarQube Maven Plugin -->
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</plugin>
<!-- JaCoCo for Code Coverage -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Surefire for Test Reports -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
<configuration>
<reportFormat>xml</reportFormat>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Gradle (build.gradle):
plugins {
id 'java'
id 'jacoco'
id 'org.sonarqube' version '4.0.0.2929'
}
sonarqube {
properties {
property 'sonar.host.url', 'http://localhost:9000'
property 'sonar.login', System.getenv('SONAR_TOKEN')
property 'sonar.projectKey', 'my-java-app'
property 'sonar.projectName', 'My Java Application'
property 'sonar.sources', 'src/main/java'
property 'sonar.tests', 'src/test/java'
property 'sonar.java.source', '11'
property 'sonar.java.target', '11'
property 'sonar.coverage.jacoco.xmlReportPaths', 'build/reports/jacoco/test/jacocoTestReport.xml'
property 'sonar.junit.reportPaths', 'build/test-results/test'
}
}
jacocoTestReport {
reports {
xml.required = true
html.required = true
}
}
test {
useJUnitPlatform()
testLogging {
events 'passed', 'skipped', 'failed'
}
finalizedBy jacocoTestReport
}
Step 2: SonarQube Quality Profile Configuration
sonar-project.properties:
# Project identification sonar.projectKey=my-java-app sonar.projectName=My Java Application sonar.projectVersion=1.0.0 # Source code configuration sonar.sources=src/main/java sonar.tests=src/test/java sonar.java.binaries=target/classes sonar.java.libraries=target/dependency/*.jar # Language and version sonar.language=java sonar.java.source=11 sonar.java.target=11 # Test and coverage sonar.coverage.exclusions=**/test/**,**/generated/**,**/model/**,**/dto/** sonar.junit.reportPaths=target/surefire-reports sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml # Exclusions sonar.exclusions=**/generated/**,**/target/**,**/test/**,**/resources/** sonar.test.exclusions=**/test/resources/** # Quality Gate sonar.qualitygate.wait=true sonar.qualitygate.timeout=300 # Custom rules configuration sonar.java.spotbugs.effort=max sonar.java.spotbugs.threshold=high # Security hotspots sonar.security.config=sonar-security.xml # Duplication sonar.cpd.exclusions=**/test/**,**/generated/** sonar.cpd.minimumTokens=100
Step 3: Custom Quality Gates and Rules
sonar-quality-gate.json:
{
"name": "My Java Application Quality Gate",
"conditions": [
{
"metric": "new_bugs",
"op": "GT",
"error": "0",
"warning": "0"
},
{
"metric": "new_vulnerabilities",
"op": "GT",
"error": "0",
"warning": "0"
},
{
"metric": "new_security_hotspots",
"op": "GT",
"error": "0",
"warning": "0"
},
{
"metric": "new_code_smells",
"op": "GT",
"error": "10",
"warning": "5"
},
{
"metric": "coverage",
"op": "LT",
"error": "80",
"warning": "85"
},
{
"metric": "duplicated_lines_density",
"op": "GT",
"error": "5",
"warning": "3"
},
{
"metric": "maintainability_rating",
"op": "GT",
"error": "2",
"warning": "1"
},
{
"metric": "reliability_rating",
"op": "GT",
"error": "2",
"warning": "1"
},
{
"metric": "security_rating",
"op": "GT",
"error": "2",
"warning": "1"
}
]
}
Step 4: Security Configuration
sonar-security.xml:
<?xml version="1.0" encoding="UTF-8"?> <sonar-security-config> <!-- SQL Injection --> <rule> <key>sql-injection</key> <parameters> <parameter> <name>sinks</name> <value>java.sql.Statement, java.sql.PreparedStatement</value> </parameter> </parameters> </rule> <!-- XSS Protection --> <rule> <key>xss</key> <parameters> <parameter> <name>sinks</name> <value>javax.servlet.http.HttpServletResponse</value> </parameter> </parameters> </rule> <!-- Input Validation --> <rule> <key>input-validation</key> <parameters> <parameter> <name>sources</name> <value>javax.servlet.http.HttpServletRequest</value> </parameter> </parameters> </rule> <!-- Cryptographic Weakness --> <rule> <key>crypto-weak</key> <parameters> <parameter> <name>weakAlgorithms</name> <value>MD5,SHA1,DES</value> </parameter> </parameters> </rule> </sonar-security-config>
Step 5: Code Analysis Service
@Service
@Slf4j
public class SonarAnalysisService {
private final ObjectMapper objectMapper;
private final RestTemplate restTemplate;
public SonarAnalysisService(ObjectMapper objectMapper, RestTemplateBuilder restTemplateBuilder) {
this.objectMapper = objectMapper;
this.restTemplate = restTemplateBuilder.build();
}
// Analyze code quality metrics
public CodeQualityReport analyzeCodeQuality(String projectKey) {
try {
Map<String, Object> measures = getProjectMeasures(projectKey);
List<Issue> issues = getProjectIssues(projectKey);
CodeCoverage coverage = getCodeCoverage(projectKey);
return CodeQualityReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.measures(measures)
.issues(issues)
.coverage(coverage)
.qualityGateStatus(evaluateQualityGate(measures))
.build();
} catch (Exception e) {
log.error("Failed to analyze code quality for project: {}", projectKey, e);
throw new SonarAnalysisException("Code quality analysis failed", e);
}
}
// Get security hotspots
public List<SecurityHotspot> getSecurityHotspots(String projectKey) {
try {
String url = String.format("/api/hotspots/search?projectKey=%s", projectKey);
Map<String, Object> response = restTemplate.getForObject(url, Map.class);
return parseSecurityHotspots(response);
} catch (Exception e) {
log.error("Failed to get security hotspots for project: {}", projectKey, e);
return Collections.emptyList();
}
}
// Analyze technical debt
public TechnicalDebtReport analyzeTechnicalDebt(String projectKey) {
try {
Map<String, Object> measures = getProjectMeasures(projectKey);
return TechnicalDebtReport.builder()
.projectKey(projectKey)
.totalDebtMinutes(getLongMeasure(measures, "sqale_index"))
.debtRatio(getDoubleMeasure(measures, "sqale_debt_ratio"))
.reliabilityRemediation(getLongMeasure(measures, "reliability_remediation_effort"))
.securityRemediation(getLongMeasure(measures, "security_remediation_effort"))
.maintainabilityRating(getIntMeasure(measures, "sqale_rating"))
.build();
} catch (Exception e) {
log.error("Failed to analyze technical debt for project: {}", projectKey, e);
throw new SonarAnalysisException("Technical debt analysis failed", e);
}
}
// Code smell analysis
public CodeSmellReport analyzeCodeSmells(String projectKey) {
try {
List<Issue> issues = getProjectIssues(projectKey);
Map<String, Long> smellsByType = issues.stream()
.filter(issue -> "CODE_SMELL".equals(issue.getType()))
.collect(Collectors.groupingBy(
Issue::getSeverity,
Collectors.counting()
));
return CodeSmellReport.builder()
.projectKey(projectKey)
.totalCodeSmells(smellsByType.values().stream().mapToLong(Long::longValue).sum())
.blockerSmells(smellsByType.getOrDefault("BLOCKER", 0L))
.criticalSmells(smellsByType.getOrDefault("CRITICAL", 0L))
.majorSmells(smellsByType.getOrDefault("MAJOR", 0L))
.minorSmells(smellsByType.getOrDefault("MINOR", 0L))
.build();
} catch (Exception e) {
log.error("Failed to analyze code smells for project: {}", projectKey, e);
throw new SonarAnalysisException("Code smell analysis failed", e);
}
}
private Map<String, Object> getProjectMeasures(String projectKey) {
String url = String.format("/api/measures/component?component=%s&metricKeys=%s",
projectKey, "bugs,vulnerabilities,code_smells,coverage,duplicated_lines_density");
return restTemplate.getForObject(url, Map.class);
}
private List<Issue> getProjectIssues(String projectKey) {
String url = String.format("/api/issues/search?componentKeys=%s", projectKey);
Map<String, Object> response = restTemplate.getForObject(url, Map.class);
return parseIssues(response);
}
private CodeCoverage getCodeCoverage(String projectKey) {
Map<String, Object> measures = getProjectMeasures(projectKey);
return CodeCoverage.builder()
.lineCoverage(getDoubleMeasure(measures, "coverage"))
.branchCoverage(getDoubleMeasure(measures, "branch_coverage"))
.linesToCover(getIntMeasure(measures, "lines_to_cover"))
.uncoveredLines(getIntMeasure(measures, "uncovered_lines"))
.build();
}
private QualityGateStatus evaluateQualityGate(Map<String, Object> measures) {
// Implementation to evaluate quality gate status
return QualityGateStatus.PASSED;
}
private Double getDoubleMeasure(Map<String, Object> measures, String metric) {
// Implementation to extract double measure
return 0.0;
}
private Integer getIntMeasure(Map<String, Object> measures, String metric) {
// Implementation to extract integer measure
return 0;
}
private Long getLongMeasure(Map<String, Object> measures, String metric) {
// Implementation to extract long measure
return 0L;
}
private List<Issue> parseIssues(Map<String, Object> response) {
// Implementation to parse issues from response
return Collections.emptyList();
}
private List<SecurityHotspot> parseSecurityHotspots(Map<String, Object> response) {
// Implementation to parse security hotspots
return Collections.emptyList();
}
}
// Data models for analysis results
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class CodeQualityReport {
private String projectKey;
private Instant timestamp;
private Map<String, Object> measures;
private List<Issue> issues;
private CodeCoverage coverage;
private QualityGateStatus qualityGateStatus;
private String summary;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class TechnicalDebtReport {
private String projectKey;
private Long totalDebtMinutes;
private Double debtRatio;
private Long reliabilityRemediation;
private Long securityRemediation;
private Integer maintainabilityRating;
private String assessment;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class CodeSmellReport {
private String projectKey;
private Long totalCodeSmells;
private Long blockerSmells;
private Long criticalSmells;
private Long majorSmells;
private Long minorSmells;
private List<String> topSmellTypes;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class CodeCoverage {
private Double lineCoverage;
private Double branchCoverage;
private Integer linesToCover;
private Integer uncoveredLines;
private Integer coveredLines;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class Issue {
private String key;
private String type;
private String severity;
private String component;
private String message;
private Integer line;
private String rule;
private String status;
private String resolution;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class SecurityHotspot {
private String key;
private String component;
private String securityCategory;
private String vulnerabilityProbability;
private String message;
private Integer line;
}
enum QualityGateStatus {
PASSED, FAILED, WARNING, NONE
}
class SonarAnalysisException extends RuntimeException {
public SonarAnalysisException(String message) {
super(message);
}
public SonarAnalysisException(String message, Throwable cause) {
super(message, cause);
}
}
Step 6: Custom Rules and Quality Checks
@Component
@Slf4j
public class CustomQualityChecks {
private final SonarAnalysisService analysisService;
public CustomQualityChecks(SonarAnalysisService analysisService) {
this.analysisService = analysisService;
}
// Check if project meets quality standards
public QualityAssessment assessProjectQuality(String projectKey) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
TechnicalDebtReport debtReport = analysisService.analyzeTechnicalDebt(projectKey);
CodeSmellReport smellReport = analysisService.analyzeCodeSmells(projectKey);
List<SecurityHotspot> hotspots = analysisService.getSecurityHotspots(projectKey);
return QualityAssessment.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.overallScore(calculateOverallScore(qualityReport, debtReport, smellReport))
.qualityGateStatus(qualityReport.getQualityGateStatus())
.securityScore(calculateSecurityScore(hotspots, qualityReport))
.maintainabilityScore(calculateMaintainabilityScore(debtReport, smellReport))
.reliabilityScore(calculateReliabilityScore(qualityReport))
.recommendations(generateRecommendations(qualityReport, debtReport, smellReport, hotspots))
.build();
}
// Security compliance check
public SecurityCompliance checkSecurityCompliance(String projectKey) {
List<SecurityHotspot> hotspots = analysisService.getSecurityHotspots(projectKey);
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
long criticalVulnerabilities = qualityReport.getIssues().stream()
.filter(issue -> "VULNERABILITY".equals(issue.getType()) && "CRITICAL".equals(issue.getSeverity()))
.count();
long blockerVulnerabilities = qualityReport.getIssues().stream()
.filter(issue -> "VULNERABILITY".equals(issue.getType()) && "BLOCKER".equals(issue.getSeverity()))
.count();
return SecurityCompliance.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.totalSecurityHotspots((long) hotspots.size())
.criticalVulnerabilities(criticalVulnerabilities)
.blockerVulnerabilities(blockerVulnerabilities)
.complianceScore(calculateSecurityComplianceScore(hotspots, criticalVulnerabilities, blockerVulnerabilities))
.securityRating(determineSecurityRating(hotspots, criticalVulnerabilities, blockerVulnerabilities))
.build();
}
// Code review automation
public CodeReviewReport generateCodeReviewReport(String projectKey) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
CodeSmellReport smellReport = analysisService.analyzeCodeSmells(projectKey);
List<ReviewComment> comments = generateReviewComments(qualityReport.getIssues());
return CodeReviewReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.totalComments(comments.size())
.criticalComments((int) comments.stream().filter(c -> "CRITICAL".equals(c.getSeverity())).count())
.majorComments((int) comments.stream().filter(c -> "MAJOR".equals(c.getSeverity())).count())
.minorComments((int) comments.stream().filter(c -> "MINOR".equals(c.getSeverity())).count())
.comments(comments)
.overallAssessment(generateOverallAssessment(qualityReport, smellReport))
.build();
}
// Technical debt analysis
public DebtAnalysis analyzeTechnicalDebt(String projectKey) {
TechnicalDebtReport debtReport = analysisService.analyzeTechnicalDebt(projectKey);
CodeSmellReport smellReport = analysisService.analyzeCodeSmells(projectKey);
return DebtAnalysis.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.totalTechnicalDebt(debtReport.getTotalDebtMinutes())
.debtBreakdown(calculateDebtBreakdown(debtReport, smellReport))
.remediationPlan(generateRemediationPlan(debtReport, smellReport))
.priorityAreas(identifyPriorityAreas(debtReport, smellReport))
.build();
}
private double calculateOverallScore(CodeQualityReport quality, TechnicalDebtReport debt, CodeSmellReport smells) {
// Implementation to calculate overall quality score
return 0.0;
}
private double calculateSecurityScore(List<SecurityHotspot> hotspots, CodeQualityReport quality) {
// Implementation to calculate security score
return 0.0;
}
private double calculateMaintainabilityScore(TechnicalDebtReport debt, CodeSmellReport smells) {
// Implementation to calculate maintainability score
return 0.0;
}
private double calculateReliabilityScore(CodeQualityReport quality) {
// Implementation to calculate reliability score
return 0.0;
}
private double calculateSecurityComplianceScore(List<SecurityHotspot> hotspots, long criticalVulns, long blockerVulns) {
// Implementation to calculate security compliance score
return 0.0;
}
private String determineSecurityRating(List<SecurityHotspot> hotspots, long criticalVulns, long blockerVulns) {
// Implementation to determine security rating
return "UNKNOWN";
}
private List<ReviewComment> generateReviewComments(List<Issue> issues) {
// Implementation to generate review comments from issues
return Collections.emptyList();
}
private String generateOverallAssessment(CodeQualityReport quality, CodeSmellReport smells) {
// Implementation to generate overall assessment
return "UNKNOWN";
}
private Map<String, Double> calculateDebtBreakdown(TechnicalDebtReport debt, CodeSmellReport smells) {
// Implementation to calculate debt breakdown
return Collections.emptyMap();
}
private List<String> generateRemediationPlan(TechnicalDebtReport debt, CodeSmellReport smells) {
// Implementation to generate remediation plan
return Collections.emptyList();
}
private List<String> identifyPriorityAreas(TechnicalDebtReport debt, CodeSmellReport smells) {
// Implementation to identify priority areas
return Collections.emptyList();
}
private List<String> generateRecommendations(CodeQualityReport quality, TechnicalDebtReport debt,
CodeSmellReport smells, List<SecurityHotspot> hotspots) {
// Implementation to generate recommendations
return Collections.emptyList();
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class QualityAssessment {
private String projectKey;
private Instant timestamp;
private Double overallScore;
private QualityGateStatus qualityGateStatus;
private Double securityScore;
private Double maintainabilityScore;
private Double reliabilityScore;
private List<String> recommendations;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class SecurityCompliance {
private String projectKey;
private Instant timestamp;
private Long totalSecurityHotspots;
private Long criticalVulnerabilities;
private Long blockerVulnerabilities;
private Double complianceScore;
private String securityRating;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class CodeReviewReport {
private String projectKey;
private Instant timestamp;
private Integer totalComments;
private Integer criticalComments;
private Integer majorComments;
private Integer minorComments;
private List<ReviewComment> comments;
private String overallAssessment;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class DebtAnalysis {
private String projectKey;
private Instant timestamp;
private Long totalTechnicalDebt;
private Map<String, Double> debtBreakdown;
private List<String> remediationPlan;
private List<String> priorityAreas;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class ReviewComment {
private String component;
private Integer line;
private String severity;
private String message;
private String rule;
private String suggestion;
}
Step 7: CI/CD Integration Service
@Service
@Slf4j
public class CiCdIntegrationService {
private final SonarAnalysisService analysisService;
private final CustomQualityChecks qualityChecks;
public CiCdIntegrationService(SonarAnalysisService analysisService,
CustomQualityChecks qualityChecks) {
this.analysisService = analysisService;
this.qualityChecks = qualityChecks;
}
// Pre-merge quality check
public MergeQualityCheck checkMergeQuality(String projectKey, String branch) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
QualityAssessment assessment = qualityChecks.assessProjectQuality(projectKey);
SecurityCompliance security = qualityChecks.checkSecurityCompliance(projectKey);
boolean canMerge = evaluateMergeCriteria(qualityReport, assessment, security);
return MergeQualityCheck.builder()
.projectKey(projectKey)
.branch(branch)
.timestamp(Instant.now())
.canMerge(canMerge)
.qualityGateStatus(qualityReport.getQualityGateStatus())
.qualityScore(assessment.getOverallScore())
.securityScore(security.getComplianceScore())
.blockingIssues(identifyBlockingIssues(qualityReport, security))
.warnings(identifyWarnings(qualityReport, assessment))
.recommendations(generateMergeRecommendations(qualityReport, assessment, security))
.build();
}
// Release quality gate
public ReleaseQualityCheck checkReleaseQuality(String projectKey, String version) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
QualityAssessment assessment = qualityChecks.assessProjectQuality(projectKey);
SecurityCompliance security = qualityChecks.checkSecurityCompliance(projectKey);
boolean canRelease = evaluateReleaseCriteria(qualityReport, assessment, security);
return ReleaseQualityCheck.builder()
.projectKey(projectKey)
.version(version)
.timestamp(Instant.now())
.canRelease(canRelease)
.qualityGateStatus(qualityReport.getQualityGateStatus())
.codeCoverage(qualityReport.getCoverage().getLineCoverage())
.securityRating(security.getSecurityRating())
.technicalDebt(analysisService.analyzeTechnicalDebt(projectKey).getTotalDebtMinutes())
.blockingIssues(identifyReleaseBlockers(qualityReport, security))
.metrics(generateReleaseMetrics(qualityReport, assessment, security))
.build();
}
// Quality trend analysis
public QualityTrend analyzeQualityTrend(String projectKey, Duration period) {
// Implementation to analyze quality trends over time
return QualityTrend.builder()
.projectKey(projectKey)
.period(period)
.trendData(collectTrendData(projectKey, period))
.build();
}
// Generate quality report for stakeholders
public StakeholderReport generateStakeholderReport(String projectKey) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
QualityAssessment assessment = qualityChecks.assessProjectQuality(projectKey);
TechnicalDebtReport debtReport = analysisService.analyzeTechnicalDebt(projectKey);
SecurityCompliance security = qualityChecks.checkSecurityCompliance(projectKey);
return StakeholderReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.executiveSummary(generateExecutiveSummary(qualityReport, assessment, debtReport, security))
.keyMetrics(generateKeyMetrics(qualityReport, assessment, debtReport, security))
.riskAssessment(assessRisks(qualityReport, assessment, security))
.recommendations(generateStakeholderRecommendations(qualityReport, assessment, debtReport, security))
.build();
}
private boolean evaluateMergeCriteria(CodeQualityReport quality, QualityAssessment assessment, SecurityCompliance security) {
return quality.getQualityGateStatus() == QualityGateStatus.PASSED &&
assessment.getOverallScore() >= 80.0 &&
security.getComplianceScore() >= 90.0 &&
security.getCriticalVulnerabilities() == 0 &&
security.getBlockerVulnerabilities() == 0;
}
private boolean evaluateReleaseCriteria(CodeQualityReport quality, QualityAssessment assessment, SecurityCompliance security) {
return quality.getQualityGateStatus() == QualityGateStatus.PASSED &&
assessment.getOverallScore() >= 85.0 &&
security.getComplianceScore() >= 95.0 &&
security.getCriticalVulnerabilities() == 0 &&
security.getBlockerVulnerabilities() == 0 &&
quality.getCoverage().getLineCoverage() >= 80.0;
}
private List<String> identifyBlockingIssues(CodeQualityReport quality, SecurityCompliance security) {
List<String> blockers = new ArrayList<>();
if (security.getCriticalVulnerabilities() > 0) {
blockers.add("Critical security vulnerabilities detected");
}
if (security.getBlockerVulnerabilities() > 0) {
blockers.add("Blocker security vulnerabilities detected");
}
if (quality.getQualityGateStatus() == QualityGateStatus.FAILED) {
blockers.add("Quality gate failed");
}
return blockers;
}
private List<String> identifyWarnings(CodeQualityReport quality, QualityAssessment assessment) {
List<String> warnings = new ArrayList<>();
if (assessment.getOverallScore() < 90.0) {
warnings.add("Quality score below optimal level");
}
if (quality.getCoverage().getLineCoverage() < 80.0) {
warnings.add("Code coverage below target");
}
return warnings;
}
private List<String> identifyReleaseBlockers(CodeQualityReport quality, SecurityCompliance security) {
List<String> blockers = identifyBlockingIssues(quality, security);
if (quality.getCoverage().getLineCoverage() < 80.0) {
blockers.add("Insufficient code coverage for release");
}
return blockers;
}
private Map<String, Object> generateReleaseMetrics(CodeQualityReport quality, QualityAssessment assessment, SecurityCompliance security) {
Map<String, Object> metrics = new HashMap<>();
metrics.put("quality_score", assessment.getOverallScore());
metrics.put("security_score", security.getComplianceScore());
metrics.put("code_coverage", quality.getCoverage().getLineCoverage());
metrics.put("technical_debt_minutes", analysisService.analyzeTechnicalDebt(quality.getProjectKey()).getTotalDebtMinutes());
metrics.put("total_issues", quality.getIssues().size());
return metrics;
}
private Map<String, Object> collectTrendData(String projectKey, Duration period) {
// Implementation to collect trend data
return Collections.emptyMap();
}
private String generateExecutiveSummary(CodeQualityReport quality, QualityAssessment assessment,
TechnicalDebtReport debt, SecurityCompliance security) {
// Implementation to generate executive summary
return "Quality assessment summary";
}
private Map<String, Object> generateKeyMetrics(CodeQualityReport quality, QualityAssessment assessment,
TechnicalDebtReport debt, SecurityCompliance security) {
// Implementation to generate key metrics
return Collections.emptyMap();
}
private String assessRisks(CodeQualityReport quality, QualityAssessment assessment, SecurityCompliance security) {
// Implementation to assess risks
return "Risk assessment";
}
private List<String> generateMergeRecommendations(CodeQualityReport quality, QualityAssessment assessment, SecurityCompliance security) {
// Implementation to generate merge recommendations
return Collections.emptyList();
}
private List<String> generateStakeholderRecommendations(CodeQualityReport quality, QualityAssessment assessment,
TechnicalDebtReport debt, SecurityCompliance security) {
// Implementation to generate stakeholder recommendations
return Collections.emptyList();
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class MergeQualityCheck {
private String projectKey;
private String branch;
private Instant timestamp;
private Boolean canMerge;
private QualityGateStatus qualityGateStatus;
private Double qualityScore;
private Double securityScore;
private List<String> blockingIssues;
private List<String> warnings;
private List<String> recommendations;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ReleaseQualityCheck {
private String projectKey;
private String version;
private Instant timestamp;
private Boolean canRelease;
private QualityGateStatus qualityGateStatus;
private Double codeCoverage;
private String securityRating;
private Long technicalDebt;
private List<String> blockingIssues;
private Map<String, Object> metrics;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class QualityTrend {
private String projectKey;
private Duration period;
private Map<String, Object> trendData;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class StakeholderReport {
private String projectKey;
private Instant timestamp;
private String executiveSummary;
private Map<String, Object> keyMetrics;
private String riskAssessment;
private List<String> recommendations;
}
Step 8: Code Quality Best Practices Enforcement
```java
@Component
@Slf4j
public class CodeQualityEnforcer {
private final SonarAnalysisService analysisService;
private final CustomQualityChecks qualityChecks;
public CodeQualityEnforcer(SonarAnalysisService analysisService,
CustomQualityChecks qualityChecks) {
this.analysisService = analysisService;
this.qualityChecks = qualityChecks;
}
// Enforce coding standards
public ComplianceReport enforceCodingStandards(String projectKey) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
CodeSmellReport smellReport = analysisService.analyzeCodeSmells(projectKey);
return ComplianceReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.standardsCompliance(evaluateStandardsCompliance(qualityReport, smellReport))
.violations(identifyStandardsViolations(qualityReport))
.improvementAreas(identifyImprovementAreas(qualityReport, smellReport))
.enforcementActions(generateEnforcementActions(qualityReport, smellReport))
.build();
}
// Security standards enforcement
public SecurityComplianceReport enforceSecurityStandards(String projectKey) {
List<SecurityHotspot> hotspots = analysisService.getSecurityHotspots(projectKey);
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
return SecurityComplianceReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.securityStandardsCompliance(evaluateSecurityCompliance(hotspots, qualityReport))
.securityViolations(identifySecurityViolations(hotspots, qualityReport))
.remediationRequirements(generateSecurityRemediation(hotspots, qualityReport))
.build();
}
// Performance standards enforcement
public PerformanceComplianceReport enforcePerformanceStandards(String projectKey) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
return PerformanceComplianceReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.performanceMetrics(extractPerformanceMetrics(qualityReport))
.performanceIssues(identifyPerformanceIssues(qualityReport))
.optimizationRecommendations(generateOptimizationRecommendations(qualityReport))
.build();
}
// Architecture compliance
public ArchitectureComplianceReport enforceArchitectureStandards(String projectKey) {
CodeQualityReport qualityReport = analysisService.analyzeCodeQuality(projectKey);
return ArchitectureComplianceReport.builder()
.projectKey(projectKey)
.timestamp(Instant.now())
.architectureMetrics(extractArchitectureMetrics(qualityReport))
.architectureViolations(identifyArchitectureViolations(qualityReport))
.refactoringRecommendations(generateRefactoringRecommendations(qualityReport))
.build();
}
private Map<String, Object> evaluateStandardsCompliance(CodeQualityReport quality, CodeSmellReport smells)