- Compile:
mvn clean compile - Run tests:
mvn test(requires Java 25+;--enable-native-access=ALL-UNNAMEDalready configured in Surefire) - Single test class:
mvn -Dtest=ClassName test - Single test method:
mvn -Dtest=ClassName#methodName test - Package:
mvn package - Verify:
mvn clean verify(compile + test + package) - Coverage:
mvn jacoco:report
- Uses SPI pattern:
ScanManager(singleton) →ScannerProviderimplementations (TwainScannerProvider,WiaScannerProvider) →Scannerimplementations - Public API:
ScanManager.instance(),Scanner,ScanConfig,Protocolenum,ColorModeenum,ScanException - SPI interface:
com.sijareca.scan4java.spi.ScannerProvider(isAvailable(),getScanners()) - TWAIN implementation (
internal/twain): Requires Windows 64-bit +TWAINDSM.DLL; uses JNA forTWAINDSM.DLLbindings - WIA implementation (
internal/wia): Works on any Windows version via COM; transfers scans to temp BMP files - Deduplication:
ScanManager.getScanners()prefers TWAIN over WIA when same device appears in both protocols
- TWAIN requires Windows 64-bit; checked at runtime in
TwainScannerProvider.isAvailable() - WIA works on any Windows version but requires COM initialization
- Both
TwainSessionandWiaSessionimplementAutoCloseable; always use try-with-resources - Tests require
--enable-native-access=ALL-UNNAMEDfor JNA reflection access (pre-configured in pom.xml Surefire plugin) - Adding new protocol: implement
ScannerProvider+Scanner, register inScanManager's provider list - Providers must fail gracefully: return empty list (not null) and don't propagate
ScanExceptionfromgetScanners()
- Main entry point:
ScanManager.instance()(singleton) - Source:
src/main/java/com/sijareca/scan4java- API: root package (
ScanManager,Scanner,ScanConfig, etc.) - SPI:
spipackage (ScannerProvider) - TWAIN:
internal/twainpackage - WIA:
internal/wiapackage
- API: root package (
- Tests:
src/test/java/com/sijareca/scan4java- Follow same package structure as main
- Use JUnit 5 (
org.junit.jupiter) - Native access already configured via Surefire plugin
- TWAIN scanning uses Windows message loop; scans return one
BufferedImageper page - WIA scanning transfers each page to temp BMP file then reads with
ImageIO ScanConfigis immutable; useScanConfig.defaults()as starting point for fluent configuration- All
Scannersetter methods returnthisfor chaining - Physical scanner required for actual scanning; tests run without hardware and expect
ScanException