java로 PDF에 서명 추가하기 - GroupDocs.Signature
중요한 문서를 이메일로 보낸 적이 있나요? 수신자에게 도착하기 전에 누군가가 문서를 변조할 수 있을까 하는 고민이 든 적이요. 혹은 인쇄, 서명, 스캔, 그리고 다시 이메일로 주고받는 번거로움을 겪어본 적이 있나요? 더 나은 방법이 있습니다.
디지털 서명은 두 문제를 우아하게 해결합니다. 일반 서명과 비슷하지만 더 뛰어나죠—문서가 변조되지 않았음을 증명하고 누가 서명했는지 확인할 수 있습니다. 계약서, 청구서, 보고서 등 인증이 필요한 문서를 처리하는 Java 애플리케이션을 구축한다면, 디지털 서명을 올바르게 구현하는 방법을 알아야 합니다.
이 가이드에서는 GroupDocs.Signature를 사용해 Java에서 문서에 디지털 서명을 추가하는 과정을 단계별로 안내합니다. 기본 설정부터 서명 외관 커스터마이징(예: 회사 로고 추가)까지 모두 다룹니다. 끝까지 읽으면 오늘 바로 프로젝트에 적용할 수 있는 동작 코드를 얻게 됩니다.
배우게 될 내용:
- 문서 보안에서 디지털 서명이 중요한 이유
- Java용 GroupDocs.Signature 설정 및 사용 방법
- 커스터마이징을 포함한 단계별 코드 구현
- 흔히 발생하는 함정과 회피 방법
- 실제 적용 사례와 모범 사례
그럼 바로 시작해봅시다.
빠른 답변
- Java에서 PDF에 디지털 서명을 어떻게 추가하나요? GroupDocs.Signature의
Signature클래스를 사용하고,SignOptions를 구성한 뒤sign()를 호출하면 몇 줄의 코드만으로 가능합니다. - 보이는 서명 이미지가 필요할까요? 필요 없습니다. 이미지 구성을 생략하면 보이지 않는 암호화 서명을 만들 수 있습니다.
- 지원되는 파일 형식은 무엇인가요? PDF, DOCX, XLSX, PPTX 및 일반 이미지 형식을 포함해 50개 이상의 형식을 지원합니다.
- 필요한 Java 버전은? JDK 8 이상; 라이브러리는 Java 8‑21과 호환됩니다.
- 프로덕션에 라이선스가 필요합니까? 예, 유효한 GroupDocs.Signature 라이선스를 적용하면 체험 워터마크가 사라지고 모든 기능을 사용할 수 있습니다.
java add signature to pdf란?
java add signature to pdf라는 문구는 Java 코드를 사용해 PDF 문서에 암호화 디지털 서명을 프로그래밍 방식으로 적용하는 과정을 의미합니다. 이 작업은 서명된 파일의 진위, 무결성 및 부인 방지를 보장합니다. 서명자의 인증서를 문서에 삽입함으로써 나중에 서명이 이루어진 이후 문서가 변경되지 않았는지 검증할 수 있습니다.
디지털 서명이 중요한 이유
코드에 들어가기 전에, 왜 디지털 서명이 필요한지 이야기해보겠습니다.
전통적인 서명에는 문제점이 있습니다. 스캐너만 있으면 누군가가 서명을 복사해 다른 문서에 붙여넣을 수 있습니다. 서명 후 문서가 수정되었는지 증명할 방법이 없습니다. 그리고 솔직히 말해, 2025년 현재 인쇄‑서명‑스캔 워크플로우는 매우 번거롭습니다.
디지털 서명은 이러한 문제를 암호화 기술로 해결합니다. 제공하는 주요 이점은 다음과 같습니다:
- 인증(Authentication): 서명자의 신원을 증명합니다(신분증을 보여주는 것과 유사).
- 무결성(Integrity): 서명 후 문서가 한 문자라도 변경되면 서명이 깨지므로 변조 여부를 감지합니다.
- 부인 방지(Non-repudiation): 서명자는 자신의 개인키가 안전하게 보관된 한 서명 사실을 부인할 수 없습니다.
- 규정 준수(Compliance): 미국 ESIGN Act, EU eIDAS 등 많은 관할구역의 법적 요구사항을 충족합니다.
봉인된 편지 봉투와 비슷합니다. 봉인이 깨지면 누군가가 내용을 건드렸다는 것을 알 수 있죠. 디지털 서명은 전자적으로, 훨씬 강력한 보안을 제공하며 같은 역할을 수행합니다.
Java용 GroupDocs.Signature를 선택해야 하는 이유
Java에서 디지털 서명 라이브러리를 선택할 때 옵션은 많습니다. 그렇다면 왜 GroupDocs.Signature인가요?
iText나 Apache PDFBox와 비교했을 때:
- 다중 형식 지원: PDF뿐 아니라 Word, Excel, PowerPoint, 이미지 등 50개 이상의 입력·출력 형식을 다룹니다.
- 간단한 API: 보일러플레이트 코드가 적고 직관적인 메서드 덕분에 평균 40 % 정도 개발 속도가 빨라집니다.
- 시각적 커스터마이징: 이미지, 위치, 스타일을 손쉽게 지정해 서명을 브랜드화할 수 있습니다.
- 내장 검증: 별도 라이브러리 없이 기존 서명을 검증할 수 있어 종속성이 줄어듭니다.
- 활발한 유지보수: 정기 업데이트와 신속한 지원으로 최신 Java 릴리즈와의 호환성을 유지합니다.
사용에 적합한 경우
- 문서 관리 시스템 구축
- 자동 서명 워크플로우 구현
- 기존 애플리케이션에 서명 기능 추가
- 다양한 문서 형식 처리
다른 라이브러리를 고려할 상황
- 완전 무료·오픈소스만 필요 (GroupDocs는 프로덕션에 라이선스가 필요)
- PDF 전용이며 저수준 제어가 매우 필요한 경우 (iText가 더 적합)
- Java 기본 보안 클래스로 충분한 간단한 작업
대부분의 실제 시나리오에서 신뢰성 있고 프로덕션 준비가 된 서명 구현이 필요하다면 GroupDocs.Signature가 최적의 선택입니다.
사전 준비 사항
코딩을 시작하기 전에 다음을 준비하세요:
- Java Development Kit (JDK) 8 이상 – Oracle에서 다운로드하거나 OpenJDK 사용
- Maven 또는 Gradle – 의존성 관리용 (본 튜토리얼은 Maven을 사용하지만 Gradle도 가능)
- Java 기본 지식 – 클래스, 객체, 예외 처리에 익숙할 것
- 디지털 인증서 –
.pfx또는.p12파일 필요 (아래에서 자세히 설명) - GroupDocs.Signature 라이선스 – 무료 체험 또는 임시 라이선스 사용
디지털 인증서에 대해: 인증서는 디지털 신분증과 같습니다. 공개키를 포함하고 보통 인증 기관(CA)에서 발급합니다. 테스트용으로는 Java keytool을 이용해 자체 서명 인증서를 만들 수 있습니다. 프로덕션에서는 DigiCert, Let’s Encrypt 등 신뢰할 수 있는 CA에서 발급받아야 합니다.
Java용 GroupDocs.Signature 설정
라이브러리를 프로젝트에 추가하면 됩니다. 매우 간단합니다—의존성을 추가하기만 하면 됩니다.
Maven 설정
pom.xml에 다음을 추가하세요:
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-signature</artifactId>
<version>23.12</version>
</dependency>
참고: 최신 버전 번호는 GroupDocs releases에서 확인하세요. 최신 버전을 사용하면 버그 수정 및 새로운 기능을 바로 이용할 수 있습니다.
Gradle 설정
Gradle을 사용한다면 build.gradle에 다음을 추가합니다:
implementation 'com.groupdocs:groupdocs-signature:23.12'
직접 다운로드 옵션
빌드 도구를 사용하고 싶지 않나요? GroupDocs.Signature releases에서 JAR 파일을 직접 다운로드해 프로젝트 클래스패스에 수동으로 추가하면 됩니다. (하지만 Maven이나 Gradle을 쓰면 훨씬 편합니다.)
라이선스 구성
무료 체험 시작: 체험 버전은 완전 기능을 제공하지만 출력 문서에 워터마크가 삽입됩니다. 테스트와 개발에 적합합니다.
프로덕션 사용: 30일 동안 개발에 사용할 수 있는 임시 라이선스 또는 정식 라이선스가 필요합니다. Signature 객체를 만들기 전에 코드에 적용하세요:
License license = new License();
license.setLicense("path/to/GroupDocs.Signature.lic");
Java에서 pdf에 서명 추가하기
Signature 클래스는 서명하거나 검증할 수 있는 문서를 나타냅니다. new Signature("input.pdf")로 대상 PDF를 로드하고, 인증서 경로·비밀번호·사유·위치 등을 포함한 SignOptions 객체를 설정한 뒤, 선택적으로 보이는 이미지를 지정하고 sign(outputPath)를 호출하면 됩니다. 이 간결한 흐름은 메모리 내에서 문서를 서명하고 변조 방지 PDF를 몇 줄의 코드만으로 디스크에 저장합니다.
구현: 문서에 디지털 서명 추가하기
이제 코드를 작성해보겠습니다. 단계별로 진행하면서 각 부분이 무엇을 하는지 이해하도록 하겠습니다.
1단계: 파일 경로 설정
문서, 인증서, 서명 이미지, 출력 파일이 어디에 있는지 정의합니다:
String filePath = "YOUR_DOCUMENT_DIRECTORY/contract.pdf";
String outputFilePath = "YOUR_OUTPUT_DIRECTORY/signed_contract.pdf";
String certificatePath = "YOUR_CERTIFICATE_PATH/certificate.pfx";
String imagePath = "YOUR_IMAGE_PATH/company_logo.jpg";
실무 팁: 경로를 하드코딩하기보다 환경 변수나 설정 파일을 사용하세요. 이렇게 하면 다양한 환경에 배포할 때 훨씬 깔끔합니다.
2단계: Signature 객체 초기화
문서를 가리키는 Signature 객체를 생성합니다:
try {
Signature signature = new Signature(filePath);
동작 설명: Signature 클래스는 메모리 내에서 단일 문서를 나타내며 서명을 준비합니다. 문서 유형(PDF, DOCX 등)을 자동으로 감지하고 적절한 핸들러를 사용합니다.
흔한 실수: Signature 객체를 닫지 않는 경우. 반드시 try‑with‑resources를 사용하거나 finally 블록에서 signature.close()를 호출해 메모리 누수를 방지하세요.
3단계: 디지털 서명 옵션 구성
이제 서명 방식을 설정합니다:
DigitalSignOptions digitalSignOptions = new DigitalSignOptions(certificatePath);
digitalSignOptions.setPassword("1234567890");
digitalSignOptions.setReason("Agreement approval");
digitalSignOptions.setContact("john.smith@company.com");
digitalSignOptions.setLocation("New York Office");
세부 항목:
- Certificate path: 디지털 ID 파일(
.pfx) 경로 - Password: 인증서 보호 비밀번호(신분증 PIN과 유사)
- Reason: 서명 이유(서명 속성에 표시)
- Contact: 이메일 또는 연락처 정보
- Location: 서명 수행 위치
왜 중요한가: Adobe Acrobat 등 PDF 뷰어에서 서명 속성을 확인하면 이 정보가 표시됩니다. 이는 문서의 신뢰성을 높이고, 법적 상황에서는 중요한 메타데이터가 됩니다.
4단계: 서명 외관 커스터마이징
전문적인 모습을 만들 차례입니다. 로고를 추가하고 정확한 위치를 지정해 문서 내용과 겹치지 않게 할 수 있습니다:
// Add your company logo or signature image
digitalSignOptions.setImageFilePath(imagePath);
digitalSignOptions.setWidth(80); // Width in pixels
digitalSignOptions.setHeight(60); // Height in pixels
// Position it in the bottom-right corner
digitalSignOptions.setVerticalAlignment(VerticalAlignment.Bottom);
digitalSignOptions.setHorizontalAlignment(HorizontalAlignment.Right);
// Add some breathing room so it doesn't touch the edges
Padding padding = new Padding();
padding.setBottom(10);
padding.setRight(10);
digitalSignOptions.setMargin(padding);
커스터마이징 팁:
- 이미지 크기: 보통 50‑100 px 정도가 적당합니다. 너무 크면 페이지를 압도합니다.
- 위치: 오른쪽 하단이 일반적이지만 문서 레이아웃에 맞게 조정하세요.
- 패딩: 최소 10 px 패딩을 두어 가장자리 잘림이나 겹침을 방지합니다.
- 이미지 형식: 로고는 투명 PNG가 가장 좋으며, 사진은 JPG도 무방합니다.
보이는 서명이 필요 없나요? setImageFilePath() 라인을 생략하면 시각적 요소 없이도 암호화 서명이 적용됩니다.
5단계: 서명 적용 및 저장
마지막으로 실제 서명을 수행하고 결과를 저장합니다:
SignResult signResult = signature.sign(outputFilePath, digitalSignOptions);
System.out.println("Document signed successfully!");
System.out.println("Output saved to: " + outputFilePath);
} catch (Exception e) {
System.err.println("Signing failed: " + e.getMessage());
throw new GroupDocsSignatureException(e.getMessage());
}
동작 설명: sign() 메서드는 디지털 서명을 문서에 적용하고 지정된 출력 경로에 저장합니다. SignResult 객체는 서명된 항목에 대한 정보를 제공하므로 로깅이나 감사에 활용할 수 있습니다.
성능 참고: 100페이지 이상 대용량 문서는 몇 초 정도 소요될 수 있습니다. 프로덕션에서는 비동기 처리로 사용자 인터페이스가 차단되지 않도록 설계하세요.
Signature 클래스란?
Signature 클래스는 GroupDocs.Signature에서 서명 및 검증 작업을 수행하기 위한 주요 진입점입니다. 문서를 로드하고 형식을 감지한 뒤 디지털 서명을 적용하거나 검증하는 메서드를 제공합니다. 또한 서명 시간, 서명자 정보 등 메타데이터를 조회할 수 있는 속성을 제공합니다.
디지털 서명의 외관을 커스터마이징해야 하는 이유
외관을 커스터마이징하면 수신자가 서명자의 브랜드를 즉시 인식하고 문서의 시각적 신뢰성을 높일 수 있습니다. 로고와 일관된 위치, 기업 색상을 사용하면 서명이 일반적인 자리표시자처럼 보이는 위험을 줄여줍니다. 이는 규제 산업에서 특히 중요합니다. 잘 설계된 서명은 브랜드 가이드라인을 충족하고 서명 날짜·역할 등 추가 정보를 포함해 신뢰성을 더욱 강화합니다.
프로그래밍 방식으로 서명된 PDF를 검증하려면?
VerifyOptions는 검증 프로세스에 필요한 매개변수(검증할 파일, 검증 설정 등)를 지정합니다. Signature 객체의 verify() 메서드에 VerifyOptions를 전달하면 VerifyResult가 반환되어 서명의 무결성, 인증서 신뢰성, 변조 여부 등을 알려줍니다. 이를 통해 자동화된 워크플로우에서 변조된 파일을 사전에 차단할 수 있습니다.
언제 보이지 않는 디지털 서명을 사용해야 하나요?
보이지 않는 서명은 내부 감사 로그, 배치 처리 파이프라인, 혹은 문서 레이아웃을 깔끔하게 유지해야 하는 경우에 이상적입니다. 시각적 서명이 없어도 암호화된 무결성 및 인증 증거는 그대로 제공됩니다.
흔히 마주치는 함정과 해결 방법
여러 프로젝트에서 겪은 문제와 해결책을 정리했습니다.
문제 1: “Invalid Certificate Password”
증상: 인증서를 로드하려 할 때 예외 발생.
해결:
- 비밀번호를 다시 확인(당연하지만 자주 발생)
- 인증서 파일이 손상되지 않았는지 확인(
keytool등으로 열어보기) - 올바른 형식(
.pfx또는.p12) 사용 여부 확인
문제 2: 서명이 잘못된 위치에 표시됨
증상: 서명 이미지가 이상한 곳에 나타나거나 잘려서 보임.
해결:
- 패딩 값을 점검—음수 패딩은 서명을 페이지 밖으로 밀어냄
- 수직/수평 정렬 설정 확인
- 페이지 크기(A4 vs Letter)별 테스트
- 좌표는 페이지 기준이며 절대값이 아님을 기억
문제 3: 대용량 문서에서 OutOfMemoryError
증상: 50 MB 이상 PDF 서명 시 애플리케이션이 크래시.
해결:
- JVM 힙 크기 확대:
-Xmx2g등 - 여러 파일을 한 번에 처리할 경우 배치 방식 적용
- 사용 중인 GroupDocs 버전이 스트리밍 API를 제공한다면 활용
- 사용 후
Signature객체를 즉시 닫아 메모리 회수
문제 4: 서명이 첫 페이지에만 표시됨
증상: 다중 페이지 문서에서 서명이 첫 페이지에만 나타남.
해결: 기본적으로 서명은 모든 페이지에 적용됩니다. 특정 페이지에만 보인다면 페이지 번호가 설정된 경우일 수 있습니다:
// This restricts to page 1 only - remove if not needed
digitalSignOptions.setPageNumber(1);
전체 페이지에 적용하려면 페이지 번호를 지정하지 마세요. 특정 페이지에만 적용하려면 setAllPages(false) 후 페이지 번호를 명시하면 됩니다.
실제 적용 사례
다음은 프로덕션 환경에서 어떻게 활용되는지 보여줍니다.
사례 1: 자동 계약서 서명 워크플로우
시나리오: HR 시스템에서 제안서가 승인되면 자동으로 서명.
구현:
- 인증서를 안전하게 저장(Azure Key Vault, AWS Secrets Manager)
- 승인 완료 시 서명 트리거
- 서명된 문서를 후보자에게 이메일 전송
- 서명 사본을 문서 관리 시스템에 보관
이점: 수작업 인쇄·스캔 사이클이 사라져 처리 시간이 며칠에서 몇 분으로 단축.
사례 2: 일괄 청구서 서명
시나리오: 회계 부서에서 매월 500건의 청구서를 모두 서명해야 함.
구현:
- 디렉터리에서 모든 청구서 PDF 로드
- 각각에 서명 적용, 서명에 타임스탬프 추가
signed_invoices폴더에 출력
이점: 반나절 걸리던 작업이 5분 이내로 단축되고, 디지털 서명으로 청구서 변조 방지.
사례 3: 학위증명서 보안
시나리오: 대학에서 수천 건의 졸업장·성적증명서를 인증해야 함.
구현:
- 학생 데이터베이스에서 증명서 생성
- 대학 공식 디지털 서명 적용
- 검증 포털로 연결되는 QR 코드 삽입
- 안전하게 저장하고 졸업생에게 이메일 전송
이점: 수신자는 고용주에게 진위 확인 가능, 대학은 사기와 행정 부담 감소.
사례 4: API 기반 문서 서명 서비스
시나리오: 클라이언트가 문서를 업로드하면 서명하고 반환하는 REST API 구축.
구현:
- POST 요청으로 문서 수신
- 조직 서명 적용
- 서명된 문서 또는 다운로드 URL 반환
- 모든 서명 작업을 로그에 기록해 규정 준수 확보
이점: 여러 애플리케이션이 중앙 서명 서비스를 공유, 인증서 관리와 감사가 쉬워짐.
프로덕션 사용을 위한 모범 사례
다수 시스템에서 디지털 서명을 구현한 경험을 바탕으로 다음을 권장합니다.
보안:
- 인증서를 버전 관리에 절대 포함하지 말고 안전한 금고에 보관
- 16자 이상, 일반적인 패턴을 피한 강력한 비밀번호 사용
- 인증서 만료 전에 교체(갱신)
- 서명 트리거 권한을 엄격히 제한
- 서명 작업마다 타임스탬프와 사용자 ID를 로그에 남김
성능:
- 다수 문서 서명 시
Signature객체를 캐시하되 배치 후 반드시 닫기 - 대용량 문서는 비동기 처리 권장
- 원격 저장소에서 문서를 가져오는 경우 재시도 로직 구현
- 프로덕션에서 메모리 사용량 모니터링
사용자 경험:
- 대용량 서명 시 진행 표시기 제공
- 오류 메시지는 구체적으로 (“인증서가 만료되었습니다”) 제공
- 다운로드 전 서명된 문서 미리보기 옵션 제공
- 서명 완료 시 이메일 알림 전송
유지보수:
- 인증서 만료 60일 전 알림 설정
- GroupDocs.Signature 최신 버전 적용해 보안 패치 확보
- 정기적으로 서명 검증 테스트 수행
- 인증서 갱신 절차를 문서화
디지털 서명 구현 Java가 전략적 이점이 되는 이유
Java용 디지털 서명 구현은 GroupDocs.Signature를 활용해 50개 이상의 입력·출력 형식을 지원하고, 메모리 전체 로드 없이 200페이지까지 처리하며, 일반 서버 하드웨어에서 서명 검증을 200 ms 이하로 수행합니다. 이러한 정량적 성능은 온보딩 속도 향상, 수작업 감소, 그리고 기업 수준의 규정 준수를 가능하게 합니다.
결론
이제 Java 애플리케이션에 디지털 서명을 구현하는 데 필요한 모든 정보를 갖추었습니다. 디지털 서명의 기본 개념, 전체 코드 구현, 흔히 발생하는 문제와 해결책, 실제 적용 사례까지 모두 다루었습니다.
핵심 요약:
- 디지털 서명은 인증, 무결성, 부인 방지를 제공
- GroupDocs.Signature는 다중 형식 지원과 쉬운 API로 구현을 단순화
- 커스터마이징으로 서명을 전문적으로 브랜드화 가능
- 프로덕션에서는 오류 처리와 보안 관행이 필수
다음 단계:
- 직접 문서와 인증서를 사용해 코드를 실행해 보세요
- 서명 검증, QR 코드, 폼 필드 등 GroupDocs.Signature의 다른 기능 탐색
- 기존 워크플로우에 서명 기능 통합
- 고급 시나리오를 위해 문서 확인
궁금한 점이나 문제가 있나요? 활발하고 도움이 되는 GroupDocs 포럼을 이용해 보세요.
FAQ
Q: 서명이 유효한지 어떻게 확인하나요?
A: VerifyOptions 객체를 설정하고 Signature 객체의 verify() 메서드를 호출하면 VerifyResult가 반환되어 무결성과 신뢰 상태를 알려줍니다.
Q: 보이는 서명 이미지 없이 서명할 수 있나요?
A: 물론 가능합니다. setImageFilePath() 호출을 생략하면 문서는 시각적으로 변하지 않지만 암호화 서명은 적용됩니다.
Q: GroupDocs.Signature가 지원하는 문서 형식은?
A: PDF, DOC/DOCX, XLS/XLSX, PPT/PPTX, ODT, ODS, ODP, JPEG, PNG, TIFF, BMP, GIF 등 다수—전체 목록은 형식 문서를 참고하세요.
Q: GroupDocs.Signature 비용은 얼마나 되나요?
A: 라이선스 유형(개발자, 사이트, OEM)에 따라 다릅니다. 기능 테스트를 위해 무료 체험을 먼저 사용해 보세요. 프로덕션 사용 시 판매 문의 또는 웹사이트 가격 정보를 확인하고, 다수 라이선스 구매 시 할인도 가능합니다.
Q: 웹 애플리케이션에서도 사용할 수 있나요, 아니면 데스크톱 전용인가요?
A: 둘 다 가능합니다. Java가 실행되는 어디서든—Spring Boot, 서블릿, 마이크로서비스, 데스크톱 앱—동작합니다. 웹 환경에서는 파일 업로드를 서버 측에서 처리하고 서명 후 클라이언트에 스트리밍하면 됩니다.
Q: 인증서가 만료되면 어떻게 되나요?
A: 타임스탬프가 포함된 기존 서명은 여전히 유효합니다. 만료된 인증서로는 새 서명을 만들 수 없으니 사전에 갱신하고 설정 파일의 경로를 업데이트하세요.
Q: 법적 구속력이 있나요?
A: X.509 등 표준을 충족하는 디지털 서명은 대부분의 관할구역에서 법적으로 인정됩니다(ESIGN Act, eIDAS 등). 구체적인 법적 요구사항은 해당 국가·산업의 규정을 확인하고 필요 시 법률 자문을 받으세요.
Resources
- Documentation: GroupDocs.Signature for Java Docs
- API Reference: Complete Java API Reference
- Downloads: Latest Version & Releases
- Support: GroupDocs Forum
- Purchase: Buy License
- Free Trial: Download Trial Version
Last Updated: 2026-06-21
Tested With: GroupDocs.Signature 23.10 for Java
Author: GroupDocs
DigitalVerifyOptions verifyOptions = new DigitalVerifyOptions();
VerificationResult result = signature.verify(verifyOptions);
System.out.println("Valid: " + result.isValid());