How to Implement Virus Scan with Java
Java applications that accept files from users or process data from external sources face a constant threat: malware. A single infected file uploaded through a web form, imported from a partner API, or pulled from cloud storage can compromise your server, spread to downstream systems, and put your users’ data at risk. Regulatory frameworks like GDPR, HIPAA, and SOC 2 increasingly expect organizations to scan incoming files before processing them. Relying on perimeter security alone is not enough—your application needs to verify every file it touches.

In this guide, you will learn how to integrate virus and malware scanning directly into your Java application using the attachmentAV API. The API is powered by Sophos, requires no local antivirus installation, and offers both synchronous and asynchronous scanning modes to fit different use cases.
Install and configure the SDK
Find the latest version of the virus-scan-sdk on Maven Central and add it to the dependencies of your project.
<dependency>
<groupId>com.attachmentav</groupId>
<artifactId>virus-scan-sdk</artifactId>
<version>0.6.0</version>
</dependency>
An active subscription and API key is required. Replace <API_KEY_PLACEHOLDER> with your API key.
import com.attachmentav.api.AttachmentAvApi;
import com.attachmentav.client.ApiClient;
import com.attachmentav.client.ApiException;
import com.attachmentav.client.Configuration;
import com.attachmentav.model.ScanResult;
import com.attachmentav.model.SyncDownloadScanRequest;
// ...
ApiClient client = Configuration.getDefaultApiClient();
client.setApiKey("<API_KEY_PLACEHOLDER>");
AttachmentAvApi api = new AttachmentAvApi();
The SDK is configured to use the API endpoint in Europe (eu.developer.attachmentav.com) by default. To use a different region—United States, Canada, or India—call client.setBasePath(...) with the appropriate endpoint URL. See the API Definition for details.
Scan files and URLs for viruses and malware synchronously
The synchronous mode returns the scan result directly in the HTTP response. This is the simplest way to integrate scanning and works well for files up to 200 MB (URL/S3) or 10 MB (binary upload) with a 60-second timeout.
Scan a file by uploading its binary content.
ScanResult result = api.scanSyncBinaryPost(new File("/path/to/file"));
System.out.println("Scan Result: " + result.getStatus());
Scan a file available at a public URL without downloading it yourself first.
SyncDownloadScanRequest request = new SyncDownloadScanRequest();
request.setDownloadUrl("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf");
ScanResult result = api.scanSyncDownloadPost(request);
System.out.println("Scan Result: " + result.getStatus());
The ScanResult object contains a status field with one of three values: clean, infected, or no (when the file could not be scanned). For infected files, the finding field identifies the specific threat detected.
Scan files and URLs for viruses and malware asynchronously
When using the async response mode, the scan result is not immediately returned; instead, you can use two approaches to asynchronously retrieve the scan result:
- Callback: Pass a callback_url and attachmentAV invokes the callback URL with an HTTP(S) POST request. The scan result is submitted in the request body.
- Polling: Pass a trace_id without callback_url and poll the API endpoint GET
/v1/scan/async/resultto retrieve the scan result. Scan results are stored for 24 hours.
The big benefit of the async response mode is a significantly higher maximum file size limit of up to 5 GB.
Async scan a URL with polling
The example below submits a URL for scanning and then polls for the result. A unique traceId ties the scan job to the result. The API returns a 404 while the scan is still in progress, so the code retries every 5 seconds up to 10 times before giving up.
String traceId = UUID.randomUUID().toString();
AsyncDownloadScanRequest request = new AsyncDownloadScanRequest();
request.setTraceId(traceId);
request.setDownloadUrl("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf");
api.scanAsyncDownloadPost(request);
System.out.println("Async download submitted. Start to poll for scan result...");
int i = 0;
while (true) {
try {
System.out.println('.');
ScanResult scanResult = api.scanAsyncResultGet(traceId);
System.out.println("Async download scan result: " + scanResult);
System.exit(0);
} catch (ApiException e) {
if (e.getCode() == 404) {
i++;
if (i < 10) {
Thread.sleep(5000);
} else {
System.err.println("Async download scan result not found");
System.exit(1);
}
} else {
throw e;
}
}
}
Instead of polling, you can also pass a callback_url when submitting the scan job. attachmentAV will then POST the scan result directly to your endpoint once the scan is complete, so your application does not need to poll at all. See the callback for details on the callback payload and how to verify its signature.
Async scan a file stored on Amazon S3
If your files are stored in Amazon S3, attachmentAV can fetch them directly—no need to download and re-upload. A bucket policy granting attachmentAV read access is required.
String traceId = UUID.randomUUID().toString();
AsyncS3ScanRequest request = new AsyncS3ScanRequest();
request.setTraceId(traceId);
request.setBucket("<BUCKET_NAME_PLACEHOLDER>");
request.setKey("<OBJECT_KEY_PLACEHOLDER>");
//request.setVersion("<OBJECT_VERSION_PLACEHOLDER>"); // for versioned buckets only
api.scanAsyncS3Post(request);
System.out.println("Async S3 submitted. Start to poll for scan result...");
int i = 0;
while (true) {
try {
System.out.println('.');
ScanResult scanResult = api.scanAsyncResultGet(traceId);
System.out.println("Async download scan result: " + scanResult);
System.exit(0);
} catch (ApiException e) {
if (e.getCode() == 404) {
i++;
if (i < 10) {
Thread.sleep(5000);
} else {
System.err.println("Async download scan result not found");
System.exit(1);
}
} else {
throw e;
}
}
}
Choosing between sync and async
| Sync | Async | |
|---|---|---|
| Max file size (binary upload) | 10 MB | — |
| Max file size (URL / S3) | 200 MB | 5 GB |
| Result delivery | Immediate in HTTP response | Callback URL or polling |
| Best for | Small files, real-time validation | Large files, background processing |
Use the synchronous mode when you need an immediate answer—for example, scanning a user upload before saving it. Use the asynchronous mode for larger files or when you want to decouple scanning from request handling.
Get started with attachmentAV
Adding virus and malware scanning to a Java application takes only a few lines of code with the attachmentAV SDK. Whether you need to scan user uploads synchronously or process large files asynchronously from S3, attachmentAV and its Sophos-powered engine have you covered.
Ready to protect your Java application? Sign up for attachmentAV and start scanning files in minutes.
Published on January 1, 1 | Written by Andreas