How to search signatures with predicate functions
Leave feedback
On this page
Search with Predicate Functions
Overview
The Signature class of GroupDocs.Signature provides search methods that accept predicate functions (java.util.function.Predicate) to filter signatures based on custom criteria. This allows you to perform more flexible and targeted signature searches by applying custom filtering logic to the search results.
Benefits
Flexible Filtering: Filter signatures based on any custom criteria using lambda expressions
Search First: All signatures matching the search options are found. search(Predicate) takes no options and searches for text, image, digital, barcode, QR-code and metadata signatures.
Filter Results: The predicate is applied to filter the search results
Return Filtered Results: Only signatures matching the predicate are returned
Signaturesignature=newSignature("document.pdf");try{// Search for text signatures
List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(newTextSearchOptions());// Filter to only signatures containing "Approved"
SearchResultresult=signature.search(searchOptions,sig->siginstanceofTextSignature&&((TextSignature)sig).getText().contains("Approved"));for(BaseSignaturesig:result.getSignatures()){System.out.println("Found: "+((TextSignature)sig).getText());}}finally{signature.dispose();}
Example 2: Search All Signature Types with Filtering
Signaturesignature=newSignature("document.pdf");try{// Search all signature types and filter by type
List<BaseSignature>result=signature.search(sig->sig.getSignatureType()==SignatureType.Digital);System.out.println("Found "+result.size()+" digital signatures");}finally{signature.dispose();}
Example 3: Search and Filter by Multiple Criteria
Signaturesignature=newSignature("document.pdf");try{List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(newTextSearchOptions());searchOptions.add(newBarcodeSearchOptions());// Filter signatures by page and type
SearchResultresult=signature.search(searchOptions,sig->sig.getPageNumber()==1&&(sig.getSignatureType()==SignatureType.Text||sig.getSignatureType()==SignatureType.Barcode));System.out.println("Found "+result.getSignatures().size()+" signatures on page 1");}finally{signature.dispose();}
Example 4: Search Digital Signatures by Sign Time
Signaturesignature=newSignature("document.pdf");try{DatestartDate=newGregorianCalendar(2024,Calendar.JANUARY,1).getTime();DateendDate=newGregorianCalendar(2024,Calendar.DECEMBER,31,23,59,59).getTime();// Search all signatures and keep digital signatures signed in 2024
List<BaseSignature>result=signature.search(sig->{if(!(siginstanceofDigitalSignature)){returnfalse;}DatesignTime=((DigitalSignature)sig).getSignTime();returnsignTime!=null&&!signTime.before(startDate)&&!signTime.after(endDate);});System.out.println("Found "+result.size()+" signatures in 2024");}finally{signature.dispose();}
Example 5: Search and Filter by Signature Size
Signaturesignature=newSignature("document.pdf");try{List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(newImageSearchOptions());// Filter image signatures by size
SearchResultresult=signature.search(searchOptions,sig->{if(siginstanceofImageSignature){ImageSignatureimgSig=(ImageSignature)sig;returnimgSig.getWidth()>200&&imgSig.getHeight()>200;}returnfalse;});System.out.println("Found "+result.getSignatures().size()+" large image signatures");}finally{signature.dispose();}
Example 6: Find Signatures in Specific Region
Signaturesignature=newSignature("document.pdf");try{// Define a region (rectangle)
intregionLeft=100;intregionTop=100;intregionWidth=200;intregionHeight=200;List<BaseSignature>result=signature.search(sig->sig.getLeft()>=regionLeft&&sig.getTop()>=regionTop&&sig.getLeft()+sig.getWidth()<=regionLeft+regionWidth&&sig.getTop()+sig.getHeight()<=regionTop+regionHeight);System.out.println("Found "+result.size()+" signatures in the specified region");}finally{signature.dispose();}
Example 7: Search Signatures with Specific Properties
Signaturesignature=newSignature("document.pdf");try{List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(newQrCodeSearchOptions());// Search for QR codes with specific data
SearchResultresult=signature.search(searchOptions,sig->{if(siginstanceofQrCodeSignature){Stringtext=((QrCodeSignature)sig).getText();returntext!=null&&(text.startsWith("https://")||text.contains("contract-id:"));}returnfalse;});for(QrCodeSignatureqrSig:result.toList(QrCodeSignature.class)){System.out.println("QR Code: "+qrSig.getText());}}finally{signature.dispose();}
Example 8: Search by Signature Type and Page
Signaturesignature=newSignature("document.pdf");try{// Search all signatures and filter by type and page
List<BaseSignature>result=signature.search(sig->sig.getSignatureType()==SignatureType.Text&&sig.getPageNumber()==1);System.out.println("Found "+result.size()+" text signatures on page 1");}finally{signature.dispose();}
Example 9: Search a Single Signature Type with a Typed Predicate
The typed overload passes the signature class, so the predicate gets that class directly and no cast is needed:
// Search QR-code signatures and keep only those on the first page
QrCodeSearchOptionsoptions=newQrCodeSearchOptions();List<QrCodeSignature>signatures=signature.search(QrCodeSignature.class,options,qrSig->qrSig.getPageNumber()==1&&qrSig.getText()!=null);for(QrCodeSignatureqrSig:signatures){System.out.println("QR Code on page 1: "+qrSig.getText());}
Common Use Cases
1. Find Signatures by Author
Signaturesignature=newSignature("document.pdf");try{List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(newDigitalSearchOptions());// Keep digital signatures whose certificate subject contains "John Doe"
SearchResultresult=signature.search(searchOptions,sig->{if(!(siginstanceofDigitalSignature)){returnfalse;}X509Certificatecertificate=((DigitalSignature)sig).getX509Certificate();returncertificate!=null&&certificate.getSubjectX500Principal().getName().contains("John Doe");});System.out.println("Found "+result.getSignatures().size()+" signatures by John Doe");}finally{signature.dispose();}
Signaturesignature=newSignature("document.pdf");try{// Find signatures in bottom-right corner that are large
List<BaseSignature>result=signature.search(sig->sig.getLeft()>400&&sig.getTop()>600&&sig.getWidth()>150&&sig.getHeight()>50);System.out.println("Found "+result.size()+" large signatures in bottom-right");}finally{signature.dispose();}
4. Search Multiple Signature Types with Complex Filtering
Signaturesignature=newSignature("document.pdf");try{List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(newTextSearchOptions());searchOptions.add(newImageSearchOptions());searchOptions.add(newQrCodeSearchOptions());// Find signatures that are either text with specific content,
// or QR codes with URLs, or large images
SearchResultresult=signature.search(searchOptions,sig->{if(siginstanceofTextSignature){return((TextSignature)sig).getText().contains("APPROVED");}if(siginstanceofQrCodeSignature){return((QrCodeSignature)sig).getText().startsWith("http");}if(siginstanceofImageSignature){returnsig.getWidth()>300&&sig.getHeight()>300;}returnfalse;});System.out.println("Found "+result.getSignatures().size()+" matching signatures");}finally{signature.dispose();}
Best Practices
1. Use Specific Predicates
Good:
// Specific and clear predicate
SearchResultspecific=signature.search(searchOptions,sig->siginstanceofTextSignature&&"Approved".equals(((TextSignature)sig).getText()));
Avoid:
// Too generic, returns every signature of every type
List<BaseSignature>everything=signature.search(sig->true);
2. Handle Null Checks
// Safe predicate with null checks
SearchResultsafe=signature.search(searchOptions,sig->{if(sig==null)returnfalse;if(siginstanceofTextSignature){Stringtext=((TextSignature)sig).getText();returntext!=null&&!text.isEmpty()&&text.contains("Contract");}returnfalse;});
3. Combine Multiple Conditions
// Clear, readable predicate with multiple conditions
SearchResultcombined=signature.search(searchOptions,sig->sig.getPageNumber()==1&&sig.getSignatureType()==SignatureType.Text&&siginstanceofTextSignature&&((TextSignature)sig).getText().length()>10);
4. Reusable Predicates
java.util.function.Predicate provides the and, or and negate methods to combine predicates:
// Use specific search options to narrow down the initial search
TextSearchOptionstextOptions=newTextSearchOptions("Contract");List<SearchOptions>searchOptions=newArrayList<SearchOptions>();searchOptions.add(textOptions);// Then apply additional filtering with the predicate
SearchResultresult=signature.search(searchOptions,sig->sig.getPageNumber()==1);
Error Handling
Null Parameter Validation
search(Predicate) requires a predicate: passing null throws an unchecked exception with the message “Value cannot be null. Parameter name: predicate”. The overloads that take search options treat a null predicate as “no filter” and return all found signatures.
Signaturesignature=newSignature("document.pdf");try{// A null predicate is rejected by search(Predicate)
List<BaseSignature>result=signature.search((Predicate<BaseSignature>)null);}catch(RuntimeExceptionex){System.out.println("Error: "+ex.getMessage());}finally{signature.dispose();}
Return Values
search(List<SearchOptions>, Predicate<BaseSignature>): Returns SearchResult. Its getSignatures() list holds the filtered signatures. The statistics of the search, such as getProcessingTime(), are not filled in for this filtered result.
search(Predicate<BaseSignature>): Returns List<BaseSignature> - A list of filtered signatures
search(Class<T>, SearchOptions, Predicate<T>): Returns List<T> - A typed list of filtered signatures
Empty Results: Returns empty collection if no signatures match the predicate
Working with SearchResult
SearchResultresult=signature.search(searchOptions,predicate);// Access filtered signatures
List<BaseSignature>signatures=result.getSignatures();// Convert to a typed list
List<TextSignature>textSignatures=result.toList(TextSignature.class);
toList converts every item of the result to the requested class and puts null in place of an item of another class, so use it when the search options cover a single signature type.
Comparison: With vs Without Predicate
Without Predicate
// Get all search results
SearchResultresult=signature.search(searchOptions);List<BaseSignature>allSignatures=result.getSignatures();// Manual filtering
List<BaseSignature>filtered=allSignatures.stream().filter(sig->sig.getPageNumber()==1).collect(Collectors.toList());
With Predicate
// Filtered during search (more concise)
SearchResultresult=signature.search(searchOptions,sig->sig.getPageNumber()==1);List<BaseSignature>filtered=result.getSignatures();
Advantages:
More concise code
Cleaner API
Single method call instead of search + filter
Summary
The predicate-based search methods provide a powerful and flexible way to search for signatures in GroupDocs.Signature. They allow you to:
Filter signatures based on any custom criteria
Search across all signature types or specific types
Write more readable and maintainable code
Handle complex filtering scenarios with ease
Use these methods when you need to find a subset of signatures based on specific criteria, rather than searching all signatures and filtering manually.
More resources
GitHub Examples
You may easily run the code above and see the feature in action in our GitHub examples: