Article
Parasoft Jtest is an enterprise-grade Java testing solution that combines static code analysis, unit testing, coverage analysis, and runtime error detection. It helps teams deliver high-quality, secure, and reliable Java applications by identifying defects early in the development lifecycle.
Why Parasoft Jtest?
- Comprehensive Analysis: Combines 1000+ static analysis rules with dynamic testing
- Security Focus: Identifies OWASP Top 10 and CWE vulnerabilities
- Integration: Seamless CI/CD and IDE integration
- Custom Rules: Extensible with custom rule development
- Compliance: Supports security standards (MISRA, CERT, etc.)
- AI-Powered: Smart test generation and impact analysis
Project Setup and Configuration
Maven Integration:
<properties>
<parasoft.jtest.version>2023.1</parasoft.jtest.version>
</properties>
<build>
<plugins>
<!-- Parasoft Jtest Maven Plugin -->
<plugin>
<groupId>com.parasoft</groupId>
<artifactId>parasoft-findings-maven-plugin</artifactId>
<version>${parasoft.jtest.version}</version>
<configuration>
<testConfig>builtin://Recommended</testConfig>
<report>xml</report>
<output>${project.build.directory}/parasoft/reports</output>
<failBuild>true</failBuild>
<maxViolations>0</maxViolations>
</configuration>
<executions>
<execution>
<id>static-analysis</id>
<phase>verify</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- JUnit 5 for generated tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*Jtest.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Gradle Configuration:
plugins {
id 'java'
id 'com.parasoft.findings-gradle' version '2023.1'
}
parasoftFindings {
testConfig = 'builtin://Recommended'
report = 'xml'
output = file("${buildDir}/parasoft/reports")
failBuild = true
maxViolations = 0
}
1. Configuration Files
parasoft.xml - Main Configuration:
<?xml version="1.0" encoding="UTF-8"?> <test-config xmlns="http://www.parasoft.com/parasoft-test-config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.parasoft.com/parasoft-test-config parasoft-test-config.xsd"> <name>Custom Java Analysis</name> <description>Custom static analysis configuration for Java projects</description> <!-- Static Analysis Settings --> <static-analysis> <rule-set name="Security Rules" enabled="true"> <description>Security-focused static analysis rules</description> <!-- OWASP Top 10 Rules --> <rule name="SECURITY.SQL_INJECTION" enabled="true"> <severity>High</severity> <category>Security</category> </rule> <rule name="SECURITY.XSS" enabled="true"> <severity>High</severity> <category>Security</category> </rule> <rule name="SECURITY.PATH_TRAVERSAL" enabled="true"> <severity>High</severity> <category>Security</category> </rule> <rule name="SECURITY.INSECURE_RANDOM" enabled="true"> <severity>Medium</severity> <category>Security</category> </rule> <rule name="SECURITY.HARDCODED_PASSWORD" enabled="true"> <severity>Medium</severity> <category>Security</category> </rule> </rule-set> <rule-set name="Code Quality Rules" enabled="true"> <description>Code quality and maintainability rules</description> <rule name="BD.PB.CONFUSING" enabled="true"> <severity>Medium</severity> <category>Code Quality</category> </rule> <rule name="BD.PB.DEADCODE" enabled="true"> <severity>Low</severity> <category>Code Quality</category> </rule> <rule name="BD.PB.OPTIONAL" enabled="true"> <severity>Low</severity> <category>Code Quality</category> </rule> <rule name="BD.REC.EXCEPTION" enabled="true"> <severity>Medium</severity> <category>Exception Handling</category> </rule> <rule name="BD.RESOURCE.LEAK" enabled="true"> <severity>High</severity> <category>Resource Management</category> </rule> </rule-set> <rule-set name="Performance Rules" enabled="true"> <description>Performance optimization rules</description> <rule name="PERF.STRING_CONCAT_IN_LOOP" enabled="true"> <severity>Medium</severity> <category>Performance</category> </rule> <rule name="PERF.INEFFICIENT_COLLECTION" enabled="true"> <severity>Low</severity> <category>Performance</category> </rule> <rule name="PERF.UNNECESSARY_BOXING" enabled="true"> <severity>Low</severity> <category>Performance</category> </rule> </rule-set> <!-- Custom Rule Parameters --> <parameters> <parameter name="MAX_METHOD_COMPLEXITY" value="15"/> <parameter name="MAX_CLASS_SIZE" value="500"/> <parameter name="MAX_METHOD_LENGTH" value="50"/> <parameter name="MAX_PARAMETERS" value="7"/> </parameters> </static-analysis> <!-- Unit Test Generation Settings --> <test-generation> <enabled>true</enabled> <strategy>structural</strategy> <coverage-criterion>statement, branch</coverage-criterion> <max-test-cases>100</max-test-cases> <template name="JUnit 5"> <import>org.junit.jupiter.api.*</import> <import>static org.junit.jupiter.api.Assertions.*</import> <test-method-annotation>@Test</test-method-annotation> <before-method-annotation>@BeforeEach</before-method-annotation> <after-method-annotation>@AfterEach</after-method-annotation> <before-class-annotation>@BeforeAll</before-class-annotation> <after-class-annotation>@AfterAll</after-class-annotation> </template> </test-generation> <!-- Runtime Error Detection --> <runtime-detection> <enabled>true</enabled> <memory-leak-detection>true</memory-leak-detection> <concurrency-issues>true</concurrency-issues> <resource-leak-detection>true</resource-leak-detection> </runtime-detection> <!-- Suppressions --> <suppressions> <suppress rule=".*" file=".*/test/.*"/> <suppress rule="BD.PB.OPTIONAL" file=".*/legacy/.*"/> <suppress rule="BD.PB.DEADCODE" file=".*/generated/.*"/> </suppressions> </test-config>
2. Custom Rule Development
Custom Security Rule:
package com.example.parasoft.rules;
import com.parasoft.api.*;
import com.parasoft.api.extension.*;
import com.parasoft.api.findings.*;
import com.parasoft.api.results.*;
import com.parasoft.api.tools.*;
public class HardcodedCredentialsRule extends AbstractASTChecker {
private static final String RULE_ID = "CUSTOM.SECURITY.HARDCODED_CREDENTIALS";
private static final String RULE_HEADER = "Avoid hardcoded credentials";
private static final String RULE_DESC = "Hardcoded credentials pose a security risk";
// Common credential patterns
private static final String[] CREDENTIAL_PATTERNS = {
"password", "pwd", "passwd", "secret", "key", "token",
"credential", "auth", "api[_-]?key"
};
@Override
public void initialize(IContext context) {
super.initialize(context);
// Register rule metadata
IRuleMetadata metadata = context.getRuleMetadata();
metadata.setRuleId(RULE_ID);
metadata.setHeader(RULE_HEADER);
metadata.setDescription(RULE_DESC);
metadata.setCategory("Security");
metadata.setSeverity(Severity.HIGH);
metadata.setCertainty(Certainty.HIGH);
}
@Override
public int[] getAcceptedTokens() {
return new int[] {
ITokenConstants.STRING_LITERAL,
ITokenConstants.ASSIGN
};
}
@Override
public void visitToken(IASTToken token) {
if (token.getType() == ITokenConstants.STRING_LITERAL) {
checkStringLiteral(token);
} else if (token.getType() == ITokenConstants.ASSIGN) {
checkAssignment(token);
}
}
private void checkStringLiteral(IASTToken token) {
String text = token.getText();
if (containsSensitiveData(text)) {
reportViolation(token, "Hardcoded sensitive value detected: " + maskSensitiveData(text));
}
}
private void checkAssignment(IASTToken token) {
IASTNode assignment = token.getParent();
if (assignment instanceof IASTAssignment) {
IASTAssignment assign = (IASTAssignment) assignment;
IASTNode lhs = assign.getLeftHandSide();
if (lhs instanceof IASTName) {
String variableName = ((IASTName) lhs).getName();
if (isCredentialVariable(variableName)) {
IASTNode rhs = assign.getRightHandSide();
if (rhs instanceof IASTLiteral && ((IASTLiteral) rhs).isString()) {
String value = ((IASTLiteral) rhs).getStringValue();
if (value != null && !value.trim().isEmpty()) {
reportViolation(token,
"Hardcoded credential assignment to variable: " + variableName);
}
}
}
}
}
}
private boolean containsSensitiveData(String text) {
if (text == null || text.length() < 8) return false;
String lowerText = text.toLowerCase();
// Check for common credential patterns in string
for (String pattern : CREDENTIAL_PATTERNS) {
if (lowerText.contains(pattern)) {
return true;
}
}
// Check if it looks like a token/secret (base64-like, hex, etc.)
if (looksLikeSecret(text)) {
return true;
}
return false;
}
private boolean looksLikeSecret(String text) {
// Remove quotes if present
String cleanText = text.replace("\"", "").replace("'", "");
// Check for base64-like strings
if (cleanText.matches("^[A-Za-z0-9+/]{20,}={0,2}$")) {
return true;
}
// Check for hex strings
if (cleanText.matches("^[A-Fa-f0-9]{32,}$")) {
return true;
}
return false;
}
private boolean isCredentialVariable(String variableName) {
String lowerName = variableName.toLowerCase();
for (String pattern : CREDENTIAL_PATTERNS) {
if (lowerName.contains(pattern)) {
return true;
}
}
return false;
}
private String maskSensitiveData(String text) {
if (text.length() <= 8) {
return "***";
}
return text.substring(0, 4) + "***" + text.substring(text.length() - 4);
}
private void reportViolation(IASTToken token, String message) {
IFinding finding = createFinding(token);
finding.setMessage(message);
reportFinding(finding);
}
}
Custom Code Quality Rule:
package com.example.parasoft.rules;
import com.parasoft.api.*;
import com.parasoft.api.extension.*;
import com.parasoft.api.findings.*;
public class LoggerNamingRule extends AbstractASTChecker {
private static final String RULE_ID = "CUSTOM.CODE.LOGGER_NAMING";
private static final String RULE_HEADER = "Logger naming convention violation";
@Override
public void initialize(IContext context) {
super.initialize(context);
IRuleMetadata metadata = context.getRuleMetadata();
metadata.setRuleId(RULE_ID);
metadata.setHeader(RULE_HEADER);
metadata.setDescription("Logger instances should follow naming conventions");
metadata.setCategory("Code Quality");
metadata.setSeverity(Severity.MEDIUM);
}
@Override
public int[] getAcceptedTokens() {
return new int[] { ITokenConstants.FIELD_DECLARATION };
}
@Override
public void visitToken(IASTToken token) {
IASTNode fieldDecl = token.getParent();
// Check if this is a Logger field
if (isLoggerField(fieldDecl)) {
IASTName fieldName = getFieldName(fieldDecl);
if (fieldName != null && !isValidLoggerName(fieldName.getName())) {
reportViolation(fieldName,
"Logger field should be named 'log' or 'logger', found: " + fieldName.getName());
}
// Check modifiers
checkLoggerModifiers(fieldDecl);
}
}
private boolean isLoggerField(IASTNode fieldDecl) {
IASTType type = fieldDecl.getFirstChildOfType(IASTType.class);
if (type != null) {
String typeName = type.getSignature();
return typeName.contains("Logger") ||
typeName.contains("org.slf4j.Logger") ||
typeName.contains("org.apache.log4j.Logger");
}
return false;
}
private IASTName getFieldName(IASTNode fieldDecl) {
return fieldDecl.getFirstChildOfType(IASTName.class);
}
private boolean isValidLoggerName(String fieldName) {
return "log".equals(fieldName) || "logger".equals(fieldName) ||
"LOG".equals(fieldName) || "LOGGER".equals(fieldName);
}
private void checkLoggerModifiers(IASTNode fieldDecl) {
IASTModifiers modifiers = fieldDecl.getFirstChildOfType(IASTModifiers.class);
if (modifiers != null) {
boolean isStatic = modifiers.isStatic();
boolean isFinal = modifiers.isFinal();
boolean isPrivate = modifiers.isPrivate();
if (!isStatic || !isFinal || !isPrivate) {
reportViolation(modifiers,
"Logger field should be private static final");
}
}
}
private void reportViolation(IASTNode node, String message) {
IFinding finding = createFinding(node);
finding.setMessage(message);
reportFinding(finding);
}
}
3. Test Generation Configuration
JTest Test Generation Template:
package com.example.parasoft.templates;
import com.parasoft.api.*;
import com.parasoft.api.testgen.*;
public class CustomTestTemplate extends AbstractTestTemplate {
@Override
public void generateTestClass(ITestGenerationContext context,
IClass testClass,
IClass sourceClass) {
// Add class-level annotations
testClass.addAnnotation("@DisplayName(\"Test for \" + " +
StringUtil.quote(sourceClass.getName()) + ")");
// Add custom imports
testClass.addImport("org.junit.jupiter.api.*");
testClass.addImport("org.junit.jupiter.params.*");
testClass.addImport("org.mockito.*");
testClass.addImport("static org.junit.jupiter.api.Assertions.*");
testClass.addImport("static org.mockito.Mockito.*");
// Generate setup method
generateSetupMethod(testClass, sourceClass);
// Generate tests for each method
for (IMethod method : sourceClass.getMethods()) {
if (shouldGenerateTest(method)) {
generateTestMethod(context, testClass, sourceClass, method);
}
}
}
private void generateSetupMethod(IClass testClass, IClass sourceClass) {
IMethod setup = testClass.createMethod("setUp");
setup.setReturnType("void");
setup.addAnnotation("@BeforeEach");
// Initialize mocks if needed
if (hasDependencies(sourceClass)) {
setup.addStatement("MockitoAnnotations.openMocks(this)");
}
}
private void generateTestMethod(ITestGenerationContext context,
IClass testClass,
IClass sourceClass,
IMethod method) {
IMethod testMethod = testClass.createMethod("test" +
StringUtil.capitalize(method.getName()));
testMethod.setReturnType("void");
testMethod.addAnnotation("@Test");
testMethod.addAnnotation("@DisplayName(\"Should " + method.getName() + " successfully\")");
// Generate test cases based on method parameters
generateTestCases(context, testMethod, method);
}
private void generateTestCases(ITestGenerationContext context,
IMethod testMethod,
IMethod sourceMethod) {
// Generate normal case
testMethod.addComment("Normal case");
String invocation = buildMethodInvocation(sourceMethod);
if (!sourceMethod.getReturnType().equals("void")) {
testMethod.addStatement("var result = " + invocation);
testMethod.addStatement("assertNotNull(result)");
} else {
testMethod.addStatement(invocation);
}
// Generate edge cases
generateEdgeCases(testMethod, sourceMethod);
// Generate exception cases
generateExceptionCases(testMethod, sourceMethod);
}
private String buildMethodInvocation(IMethod method) {
StringBuilder sb = new StringBuilder();
sb.append(method.getName()).append("(");
List<IParameter> params = method.getParameters();
for (int i = 0; i < params.size(); i++) {
IParameter param = params.get(i);
sb.append(generateTestValue(param.getType()));
if (i < params.size() - 1) {
sb.append(", ");
}
}
sb.append(")");
return sb.toString();
}
private String generateTestValue(String type) {
switch (type) {
case "String":
return "\"test\"";
case "int":
case "Integer":
return "1";
case "long":
case "Long":
return "1L";
case "boolean":
case "Boolean":
return "true";
case "double":
case "Double":
return "1.0";
case "List":
case "Set":
return "java.util.Collections.emptyList()";
case "Map":
return "java.util.Collections.emptyMap()";
default:
return "null";
}
}
private boolean shouldGenerateTest(IMethod method) {
// Skip private methods, getters, setters
return method.isPublic() &&
!method.getName().startsWith("get") &&
!method.getName().startsWith("set") &&
!method.getName().startsWith("is");
}
private boolean hasDependencies(IClass sourceClass) {
// Check if class has fields that might need mocking
return sourceClass.getFields().stream()
.anyMatch(field -> !field.getType().isPrimitive() &&
!field.getType().startsWith("java.lang"));
}
}
4. Integration with Build Tools
Maven Full Configuration:
<!-- Comprehensive Parasoft Maven configuration -->
<profile>
<id>parasoft-analysis</id>
<build>
<plugins>
<plugin>
<groupId>com.parasoft</groupId>
<artifactId>parasoft-findings-maven-plugin</artifactId>
<version>${parasoft.jtest.version}</version>
<configuration>
<!-- Analysis Configuration -->
<testConfig>custom://parasoft.xml</testConfig>
<report>xml,html</report>
<output>${project.build.directory}/parasoft</output>
<!-- Failure Configuration -->
<failBuild>true</failBuild>
<maxViolations>0</maxViolations>
<failOnSeverity>High,Medium</failOnSeverity>
<!-- Filter Configuration -->
<include>**/*.java</include>
<exclude>**/generated/**/*.java,**/test/**/*.java</exclude>
<!-- Memory Configuration -->
<jvmArgs>-Xmx4g -XX:MaxPermSize=512m</jvmArgs>
<!-- Parallel Execution -->
<parallel>true</parallel>
<threadCount>4</threadCount>
</configuration>
<executions>
<execution>
<id>static-analysis</id>
<phase>verify</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
<execution>
<id>test-generation</id>
<phase>test-compile</phase>
<goals>
<goal>generate-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Test Execution with Generated Tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*Jtest.java</include>
</includes>
<excludes>
<exclude>**/Abstract*Test.java</exclude>
</excludes>
<parallel>methods</parallel>
<threadCount>4</threadCount>
</configuration>
</plugin>
<!-- Coverage Reporting -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
5. CI/CD Integration
Jenkins Pipeline:
pipeline {
agent any
tools {
jdk 'jdk17'
maven 'maven-3.8'
}
stages {
stage('Static Analysis') {
steps {
script {
// Run Parasoft Jtest analysis
sh 'mvn -Pparasoft-analysis parasoft-findings:test'
// Publish results
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target/parasoft',
reportFiles: 'report.html',
reportName: 'Parasoft Report'
])
}
}
post {
always {
// Archive findings
archiveArtifacts artifacts: 'target/parasoft/**/*', allowEmptyArchive: true
// Record issues
recordIssues(
tools: [customTool(
pattern: 'target/parasoft/findings.xml',
parser: 'CHECKSTYLE',
name: 'Parasoft Jtest'
)],
qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]]
)
}
}
}
stage('Test Generation & Execution') {
steps {
script {
// Generate tests
sh 'mvn -Pparasoft-analysis parasoft-findings:generate-tests'
// Run all tests including generated ones
sh 'mvn test -Pparasoft-analysis'
}
}
}
stage('Security Analysis') {
steps {
script {
// Run security-focused analysis
sh 'mvn -Pparasoft-security-analysis parasoft-findings:test'
}
}
}
}
post {
always {
// Cleanup
cleanWs()
}
success {
// Notify success
emailext (
subject: "Build Successful: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Parasoft analysis completed successfully",
to: "${env.BUILD_USER_EMAIL}"
)
}
failure {
// Notify failure with analysis details
emailext (
subject: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Parasoft analysis found violations. Check report at ${env.BUILD_URL}",
to: "${env.BUILD_USER_EMAIL}"
)
}
}
}
GitHub Actions:
name: Parasoft Analysis
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
parasoft-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: 'maven'
- name: Cache Parasoft results
uses: actions/cache@v3
with:
path: |
~/.parasoft
target/parasoft
key: ${{ runner.os }}-parasoft-${{ hashFiles('**/pom.xml') }}
- name: Run Parasoft Static Analysis
run: |
mvn -Pparasoft-analysis parasoft-findings:test
env:
PARASOFT_LICENSE: ${{ secrets.PARASOFT_LICENSE }}
- name: Generate Tests
run: |
mvn -Pparasoft-analysis parasoft-findings:generate-tests
- name: Run Generated Tests
run: |
mvn test -Pparasoft-analysis
- name: Upload Parasoft Report
uses: actions/upload-artifact@v3
with:
name: parasoft-report
path: target/parasoft/
retention-days: 30
- name: Check for Critical Violations
run: |
if grep -q "severity=\"High\"" target/parasoft/findings.xml; then
echo "Critical violations found"
exit 1
fi
6. Custom Suppressions and Filters
suppressions.xml:
<?xml version="1.0" encoding="UTF-8"?> <suppressions xmlns="http://www.parasoft.com/suppressions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.parasoft.com/suppressions suppressions.xsd"> <!-- Suppress test code --> <suppress> <rule>.*</rule> <file>.*/src/test/.*</file> </suppress> <!-- Suppress generated code --> <suppress> <rule>.*</rule> <file>.*/target/generated-sources/.*</file> </suppress> <!-- Suppress legacy code --> <suppress> <rule>BD\.PB\..*</rule> <file>.*/legacy/.*</file> </suppress> <!-- Suppress specific rules in DTOs --> <suppress> <rule>BD\.REC\.EXCEPTION</rule> <file>.*/dto/.*</file> </suppress> <!-- Suppress specific methods --> <suppress> <rule>BD\.PB\.DEADCODE</rule> <file>.*</file> <method>main</method> </suppress> <!-- Suppress third-party code --> <suppress> <rule>.*</rule> <file>.*/thirdparty/.*</file> </suppress> <!-- Temporary suppressions --> <suppress> <rule>SECURITY\.HARDCODED_PASSWORD</rule> <file>.*/config/.*</file> <expires>2024-12-31</expires> <comment>Temporary suppression for configuration classes</comment> </suppress> </suppressions>
7. Security-Focused Configuration
parasoft-security.xml:
<?xml version="1.0" encoding="UTF-8"?> <test-config xmlns="http://www.parasoft.com/parasoft-test-config"> <name>Security Analysis</name> <static-analysis> <!-- OWASP Top 10 2021 --> <rule-set name="OWASP Top 10" enabled="true"> <rule name="SECURITY.SQL_INJECTION" enabled="true"> <severity>High</severity> </rule> <rule name="SECURITY.XSS" enabled="true"> <severity>High</severity> </rule> <rule name="SECURITY.INSECURE_DESERIALIZATION" enabled="true"> <severity>High</severity> </rule> <rule name="SECURITY.INSECURE_COMPONENT" enabled="true"> <severity>Medium</severity> </rule> <rule name="SECURITY.INSECURE_CONFIGURATION" enabled="true"> <severity>Medium</severity> </rule> </rule-set> <!-- CWE Top 25 --> <rule-set name="CWE Top 25" enabled="true"> <rule name="CWE-78" enabled="true"> <severity>High</severity> </rule> <rule name="CWE-79" enabled="true"> <severity>High</severity> </rule> <rule name="CWE-89" enabled="true"> <severity>High</severity> </rule> <rule name="CWE-120" enabled="true"> <severity>Medium</severity> </rule> <rule name="CWE-22" enabled="true"> <severity>High</severity> </rule> </rule-set> <!-- Custom Security Rules --> <rule-set name="Custom Security" enabled="true"> <rule name="CUSTOM.SECURITY.HARDCODED_CREDENTIALS" enabled="true"> <severity>High</severity> </rule> <rule name="CUSTOM.SECURITY.INSECURE_COMMUNICATION" enabled="true"> <severity>Medium</severity> </rule> <rule name="CUSTOM.SECURITY.SENSITIVE_DATA_LOGGING" enabled="true"> <severity>Medium</severity> </rule> </rule-set> <!-- Crypto Rules --> <rule-set name="Cryptography" enabled="true"> <rule name="SECURITY.WEAK_CRYPTO" enabled="true"> <severity>High</severity> </rule> <rule name="SECURITY.WEAK_RANDOM" enabled="true"> <severity>Medium</severity> </rule> <rule name="SECURITY.HARDCODED_SALT" enabled="true"> <severity>Medium</severity> </rule> </rule-set> </static-analysis> <!-- Data Flow Analysis --> <data-flow> <enabled>true</enabled> <taint-analysis>true</taint-analysis> <sources> <source>HttpServletRequest.getParameter</source> <source>HttpServletRequest.getHeader</source> <source>HttpServletRequest.getCookie</source> </sources> <sinks> <sink>java.sql.Statement.execute</sink> <sink>java.sql.PreparedStatement.execute</sink> <sink>javax.servlet.http.HttpServletResponse.getWriter</sink> </sinks> </data-flow> </test-config>
8. Best Practices and Tips
Incremental Adoption:
<!-- parasoft-gradual.xml --> <test-config> <name>Gradual Adoption</name> <static-analysis> <!-- Phase 1: Critical security issues only --> <rule-set name="Critical Security" enabled="true"> <rule name="SECURITY.SQL_INJECTION" enabled="true"> <severity>High</severity> </rule> <rule name="SECURITY.XSS" enabled="true"> <severity>High</severity> </rule> </rule-set> <!-- Phase 2: Add important quality rules --> <rule-set name="Important Quality" enabled="false"> <rule name="BD.RESOURCE.LEAK" enabled="true"> <severity>High</severity> </rule> <rule name="BD.PB.NULL" enabled="true"> <severity>Medium</severity> </rule> </rule-set> <!-- Phase 3: Add all other rules --> <rule-set name="All Other Rules" enabled="false"> <rule name=".*" enabled="true"/> </rule-set> </static-analysis> </test-config>
Performance Optimization:
<configuration>
<!-- Memory settings -->
<jvmArgs>-Xmx4g -XX:MaxPermSize=512m -XX:+UseG1GC</jvmArgs>
<!-- Parallel execution -->
<parallel>true</parallel>
<threadCount>${cpu.count}</threadCount>
<!-- Incremental analysis -->
<incremental>true</incremental>
<cache>true</cache>
<!-- Exclude large dependencies -->
<exclude>**/node_modules/**,**/vendor/**,**/lib/**</exclude>
</configuration>
Conclusion
Parasoft Jtest provides enterprise-grade static analysis and testing capabilities for Java applications. Key benefits include:
- Comprehensive Analysis: 1000+ built-in rules covering security, quality, and performance
- Security Focus: OWASP Top 10, CWE, and custom security rule support
- Test Generation: AI-powered test generation with high coverage
- Integration: Seamless CI/CD and IDE integration
- Customization: Extensible with custom rules and configurations
- Compliance: Support for security and safety standards
By implementing the configurations and patterns shown above, you can establish a robust quality gate that catches defects early, improves code security, and maintains high development standards across your Java projects.
Secure Java Dependency Management, Vulnerability Scanning & Software Supply Chain Protection (SBOM, SCA, CI Security & License Compliance)
https://macronepal.com/blog/github-code-scanning-in-java-complete-guide/
Explains GitHub Code Scanning for Java using tools like CodeQL to automatically analyze source code and detect security vulnerabilities directly inside CI/CD pipelines before deployment.
https://macronepal.com/blog/license-compliance-in-java-comprehensive-guide/
Explains software license compliance in Java projects, ensuring dependencies follow legal requirements (MIT, Apache, GPL, etc.) and preventing license violations in enterprise software.
https://macronepal.com/blog/container-security-for-java-uncovering-vulnerabilities-with-grype/
Explains using Grype to scan Java container images and filesystems for known CVEs in OS packages and application dependencies to improve container security.
https://macronepal.com/blog/syft-sbom-generation-in-java-comprehensive-software-bill-of-materials-for-jvm-applications/
Explains using Syft to generate SBOMs (Software Bill of Materials) for Java applications, listing all dependencies, libraries, and components for supply chain transparency.
https://macronepal.com/blog/comprehensive-dependency-analysis-generating-and-scanning-sboms-with-trivy-for-java/
Explains using Trivy to generate SBOMs and scan Java dependencies and container images for vulnerabilities, integrating security checks into CI/CD pipelines.
https://macronepal.com/blog/dependabot-for-java-in-java/
Explains GitHub Dependabot for Java projects, which automatically detects vulnerable dependencies and creates pull requests to update them securely.
https://macronepal.com/blog/parasoft-jtest-in-java-comprehensive-guide-to-code-analysis-and-testing/
Explains Parasoft Jtest, a static analysis and testing tool for Java that helps detect bugs, security issues, and code quality problems early in development.
https://macronepal.com/blog/snyk-open-source-in-java-comprehensive-dependency-vulnerability-management-2/
Explains Snyk Open Source for Java, which continuously scans dependencies for vulnerabilities and provides automated fix suggestions and monitoring.
https://macronepal.com/blog/owasp-dependency-check-in-java-complete-vulnerability-scanning-guide/
Explains OWASP Dependency-Check, which scans Java dependencies against the National Vulnerability Database (NVD) to detect known security vulnerabilities.
https://macronepal.com/blog/securing-your-dependencies-a-java-developers-guide-to-whitesource-mend-bolt/
Explains Mend (WhiteSource) Bolt for Java, a dependency management and SCA tool that provides vulnerability detection, license compliance, and security policy enforcement in enterprise environments.