인터랙티브 폴리라인 PDF 만들기 with GroupDocs Annotation - Java 튜토리얼

소개

프로그래밍 방식으로 PDF 문서에 복잡한 경로, 연결 또는 관계를 강조 표시해 본 적이 있나요? 혼자가 아닙니다. 많은 개발자들이 특히 폴리라인과 같은 비선형 주석을 다룰 때 문서에 인터랙티브한 시각 요소를 추가하는 데 어려움을 겪습니다.

이 포괄적인 가이드에서는 인터랙티브 폴리라인 PDF 주석을 만들면서 전문적인 외관을 제공하고 사용자에게 기대되는 인터랙티브성을 제공하는 방법을 다룹니다. 환경 설정부터 고급 커스터마이징까지 모두 설명하고, spring boot pdf annotation 서비스에 통합하고 generate svg path java 코드를 즉석에서 생성하는 방법도 보여드립니다.

빠른 답변

  • 폴리라인 주석의 주요 목적은 무엇인가요? 여러 점을 연결하여 PDF에 복잡하고 인터랙티브한 경로를 만듭니다.
  • Java에서 가장 쉬운 라이브러리는? GroupDocs.Annotation for Java.
  • Spring Boot와 함께 사용할 수 있나요? 예 – Spring Boot 통합 섹션을 참고하세요.
  • 라인 형태는 어떻게 정의하나요? SVG 경로 문자열을 제공하면 됩니다(예: generate svg path java 사용).
  • 라이선스가 필요하나요? 개발 단계에서는 체험 라이선스로 충분하지만, 배포 시에는 정식 라이선스가 필요합니다.

왜 GroupDocs.Annotation for Java를 선택해야 할까요?

구현에 들어가기 전에 가장 큰 질문, 즉 다른 솔루션보다 GroupDocs.Annotation을 선택해야 하는 이유를 살펴보겠습니다.

수동 PDF 조작 라이브러리(iText, PDFBox 등)와 비교했을 때 GroupDocs.Annotation은:

  • 바로 사용할 수 있는 사전 구축 주석 타입 제공
  • 내장된 사용자 인터랙션 처리
  • PDF뿐 아니라 다양한 포맷과 호환
  • 보일러플레이트 코드 크게 감소

클라이언트‑사이드 JavaScript 솔루션과 비교했을 때는:

  • 서버‑사이드 처리로 보안 강화
  • 브라우저 기능에 의존하지 않음
  • 모든 환경에서 일관된 렌더링
  • 대용량 문서에 대한 엔터프라이즈급 성능

결론은? GroupDocs.Annotation은 특히 create interactive polyline pdf 시나리오처럼 정밀한 좌표 처리가 필요한 경우 기능과 단순성 사이의 완벽한 균형을 제공합니다.

학습 목표

이 튜토리얼을 마치면 다음을 수행할 수 있습니다:

  • Java 프로젝트에 GroupDocs.Annotation을 올바르게 설정하기
  • 인터랙티브 폴리라인 PDF 주석을 커스텀 속성과 함께 생성하기
  • 흔히 발생하는 구현 문제 해결하기(복잡한 부분까지 다룹니다)
  • 엔터프라이즈 규모 문서 처리 성능 최적화하기
  • Spring Boot PDF annotation 등 인기 Java 프레임워크와 통합하기

전제 조건 및 환경 설정

개발 환경을 준비해 보겠습니다. 다음이 필요합니다:

필수 요구 사항:

  • Java Development Kit (JDK) 8 이상 (JDK 11+ 권장)
  • Maven 3.6+ 또는 Gradle 6+
  • IntelliJ IDEA 또는 Eclipse 같은 IDE
  • Java 프로그래밍 및 Maven 의존성 관리 기본 이해

추가 권장 사항:

  • PDF 구조 개념에 대한 친숙함
  • 어노테이션 기반 Java 애플리케이션 경험
  • generate svg path java 커스터마이징을 위한 SVG 경로 표기법 이해

Maven 설정

GroupDocs.Annotation을 Maven 프로젝트에 추가합니다. pom.xml에 넣어야 할 전체 설정은 다음과 같습니다:

<repositories>
   <repository>
      <id>repository.groupdocs.com</id>
      <name>GroupDocs Repository</name>
      <url>https://releases.groupdocs.com/annotation/java/</url>
   </repository>
</repositories>

<dependencies>
   <dependency>
      <groupId>com.groupdocs</groupId>
      <artifactId>groupdocs-annotation</artifactId>
      <version>25.2</version>
   </dependency>
</dependencies>

: 항상 GroupDocs 웹사이트에서 최신 버전을 확인하세요. 버전 25.2는 폴리라인 렌더링 성능이 크게 향상되었지만, 최신 버전에는 추가 기능이 있을 수 있습니다.

라이선스 설정

많은 개발자가 처음에 막히는 부분입니다. GroupDocs.Annotation은 프로덕션 사용 시 라이선스가 필요하지만, 선택지가 있습니다:

개발/테스트용:

프로덕션용:

  • GroupDocs 구매 페이지에서 구독 구매
  • 라이선스 비용은 배포 형태(단일 애플리케이션 vs. 사이트‑와이드)에 따라 달라집니다

기본 환경 초기화

주석을 만들기 전에 Annotator 클래스를 초기화해야 합니다. 이는 모든 주석 작업의 진입점입니다:

import com.groupdocs.annotation.Annotator;

// Initialize Annotator with your document
Annotator annotator = new Annotator("YOUR_DOCUMENT_DIRECTORY/input.pdf");

중요 참고: 메모리 누수를 방지하려면 항상 try‑with‑resources를 사용하거나 Annotator 인스턴스를 명시적으로 해제하세요. 아래에 올바른 패턴을 보여드립니다.

단계별 구현 가이드

이제 재미있는 부분—첫 폴리라인 주석을 만들어 보겠습니다. 각 단계를 명확히 설명합니다.

폴리라인 주석 이해하기

코드에 들어가기 전에 폴리라인 주석이 실제로 무엇을 하는지 정리합니다. 두 점을 연결하는 단순 라인 주석과 달리, 폴리라인은 여러 점을 연결해 복잡한 경로를 만들 수 있습니다. 예시:

  • 기술 다이어그램 – 신호 경로나 워크플로우 연결 표시
  • 교육 콘텐츠 – 기하학 개념이나 프로세스 흐름 시각화
  • 법률 문서 – 조항 간 관계 강조
  • 지도 및 청사진 – 경로나 구조 연결 표시

핵심 장점은 인터랙티브성입니다. 사용자는 주석 위에 마우스를 올리거나 클릭하고, 구현에 따라 수정까지 할 수 있습니다.

단계 1: 주석 답글 만들기

전문 주석 시스템은 보통 댓글 기능을 포함합니다. 폴리라인에 연결할 답글을 설정하는 방법은 다음과 같습니다:

import com.groupdocs.annotation.models.Reply;
import java.util.Calendar;

// Create reply instances with comments
Reply reply1 = new Reply();
reply1.setComment("First comment");
reply1.setRepliedOn(Calendar.getInstance().getTime());

Reply reply2 = new Reply();
reply2.setComment("Second comment");
reply2.setRepliedOn(Calendar.getInstance().getTime());

왜 중요한가: 답글은 주석에 컨텍스트를 제공합니다. 협업 환경에서는 특정 경로나 연결을 강조한 이유를 설명하는 데 필수적입니다.

단계 2: 답글 조직하기

다음으로 답글을 컬렉션에 정리해 주석에 첨부합니다:

import java.util.ArrayList;
import java.util.List;

// Add replies to a list
List<Reply> replies = new ArrayList<>();
replies.add(reply1);
replies.add(reply2);

베스트 프랙티스: 당장 답글이 필요 없더라도 구조를 미리 잡아두면 나중에 협업 기능을 추가하기 쉽습니다.

단계 3: 폴리라인 생성 및 설정

이 단계가 핵심입니다. PolylineAnnotation 클래스는 다양한 커스터마이징 옵션을 제공합니다:

import com.groupdocs.annotation.models.PenStyle;
import com.groupdocs.annotation.models.Rectangle;
import com.groupdocs.annotation.models.annotationmodels.PolylineAnnotation;

// Initialize polyline annotation
PolylineAnnotation polyline = new PolylineAnnotation();
polyline.setBox(new Rectangle(250, 35, 102, 12)); // Position and size
polyline.setMessage("This is a polyline annotation"); // Annotation message
polyline.setOpacity(0.7); // Opacity (0-1)
polyline.setPageNumber(0); // Page index (0-based)
polyline.setPenColor(65535); // Color in ARGB format
polyline.setPenStyle(PenStyle.DOT); // Pen style options
polyline.setPenWidth((byte) 3); // Pen width in pixels

// Associate replies and define the path
polyline.setReplies(replies);
polyline.setSvgPath("M250.8280751173709,48.209295774647885l0.6986854460093896,0l0.6986854460093896,-1.3973708920187793...");

속성 이해하기:

  • Box Rectangle – 주석의 경계 영역 정의
  • Opacity – 0.7은 가독성을 유지하면서 가시성을 확보
  • PenColor – ARGB 형식(예: 65535는 파란색)
  • PenStyleDOT은 점선 스타일, 임시 또는 제안 경로 표시에 적합
  • SVGPath – 실제 라인 좌표를 정의하는 문자열(아래에서 자세히 설명)

단계 4: 주석 추가하기

설정이 끝났으면 문서에 주석을 추가하는 것은 간단합니다:

// Add the annotation using Annotator
annotator.add(polyline);

단계 5: 저장 및 정리

마지막으로 주석이 적용된 문서를 저장하고 리소스를 적절히 해제합니다:

String outputPath = "YOUR_OUTPUT_DIRECTORY/Annotated.pdf";
annotator.save(outputPath); // Save annotated document

// Dispose of annotator resources
annotator.dispose();

메모리 관리 팁: Annotator 인스턴스를 반드시 해제하세요. 다수의 문서를 처리하는 웹 애플리케이션에서는 메모리 누수가 애플리케이션 충돌을 일으킬 수 있습니다.

SVG 경로 다루기

SVG 경로는 폴리라인 주석에서 가장 복잡한 부분이므로 실용적인 예제로 나눠 설명합니다.

기본 경로 명령

SVG 경로는 명령 기반 구문을 사용합니다:

  • M: Move to (시작점)
  • L: Line to (점까지 선 그리기)
  • l: Relative line to (상대 좌표)

간단한 예 – L자 형태 경로:

M10,10 L50,10 L50,50

복잡한 예 – 코드 블록에 있는 긴 문자열은 여러 연결 구간을 가진 복잡한 형태를 만듭니다.

프로그래밍 방식으로 경로 생성하기

동적 애플리케이션에서는 좌표 배열로부터 SVG 경로를 생성할 수 있습니다:

public String generatePolylinePath(Point[] points) {
    if (points.length == 0) return "";
    
    StringBuilder path = new StringBuilder();
    path.append("M").append(points[0].x).append(",").append(points[0].y);
    
    for (int i = 1; i < points.length; i++) {
        path.append("L").append(points[i].x).append(",").append(points[i].y);
    }
    
    return path.toString();
}

이 방법은 generate svg path java 코드를 사용자 인터랙션이나 데이터 분석 결과에 기반해 자동 생성할 때 특히 유용합니다.

실제 활용 사례

폴리라인 주석이 빛을 발하는 실전 시나리오를 살펴봅시다:

기술 문서

시나리오: 구성 요소 간 데이터 흐름을 보여주는 소프트웨어 아키텍처 다이어그램 작성

// Create annotation for data flow path
PolylineAnnotation dataFlow = new PolylineAnnotation();
dataFlow.setMessage("Data flow from API to Database");
dataFlow.setPenColor(0xFF0000FF); // Blue for data flow
dataFlow.setPenStyle(PenStyle.SOLID);
dataFlow.setPenWidth((byte) 2);
// SVG path would show the actual route through your architecture

교육 자료

시나리오: 기하학 증명을 위한 인터랙티브 경로 강조가 필요한 수학 교과서

// Highlight geometric proof steps
PolylineAnnotation proofStep = new PolylineAnnotation();
proofStep.setMessage("Proof step 3: Angle bisector construction");
proofStep.setPenColor(0xFF00FF00); // Green for completed steps
proofStep.setOpacity(0.8); // Slightly transparent to not obscure text

법률 문서 검토

시나리오: 조항 간 관계를 시각화해야 하는 계약 분석

// Connect related contract sections
PolylineAnnotation clauseConnection = new PolylineAnnotation();
clauseConnection.setMessage("This clause relates to section 4.2");
clauseConnection.setPenStyle(PenStyle.DASH); // Dashed for suggestions
clauseConnection.setPenColor(0xFFFF9900); // Orange for attention

인기 Java 프레임워크와 통합

Spring Boot 통합

spring boot pdf annotation 프로젝트에서는 주석 관리를 위한 서비스를 만들게 됩니다:

@Service
public class DocumentAnnotationService {
    
    public String addPolylineAnnotation(String documentPath, 
                                       PolylineConfig config) {
        try (Annotator annotator = new Annotator(documentPath)) {
            PolylineAnnotation polyline = createPolylineFromConfig(config);
            annotator.add(polyline);
            
            String outputPath = generateOutputPath(documentPath);
            annotator.save(outputPath);
            return outputPath;
        }
    }
    
    private PolylineAnnotation createPolylineFromConfig(PolylineConfig config) {
        // Implementation details based on your config structure
        // This pattern keeps your annotation logic organized and testable
    }
}

REST API 통합

동적 주석 생성을 위한 엔드포인트 생성:

@RestController
@RequestMapping("/api/annotations")
public class AnnotationController {
    
    @Autowired
    private DocumentAnnotationService annotationService;
    
    @PostMapping("/polyline")
    public ResponseEntity<String> addPolylineAnnotation(
            @RequestBody PolylineRequest request) {
        
        try {
            String result = annotationService.addPolylineAnnotation(
                request.getDocumentPath(), 
                request.getConfig()
            );
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.badRequest()
                .body("Error adding annotation: " + e.getMessage());
        }
    }
}

이 패턴을 사용하면 프론트엔드 애플리케이션이 사용자 인터랙션에 따라 폴리라인 주석을 동적으로 추가할 수 있습니다.

성능 최적화 및 베스트 프랙티스

메모리 관리

여러 문서나 대용량 파일을 처리할 때는 리소스 관리를 철저히 해야 합니다:

// Use try-with-resources for automatic cleanup
public void processMultipleDocuments(List<String> documentPaths) {
    for (String path : documentPaths) {
        try (Annotator annotator = new Annotator(path)) {
            // Process document
            addPolylineAnnotations(annotator);
            annotator.save(generateOutputPath(path));
        } // Automatic disposal happens here
    }
}

배치 처리

대규모 작업에는 배치 처리를 고려하세요:

public void batchAddPolylines(String documentPath, 
                             List<PolylineConfig> configs) {
    try (Annotator annotator = new Annotator(documentPath)) {
        // Add all annotations before saving
        for (PolylineConfig config : configs) {
            PolylineAnnotation polyline = createFromConfig(config);
            annotator.add(polyline);
        }
        // Single save operation is more efficient
        annotator.save(generateOutputPath(documentPath));
    }
}

SVG 경로 최적화

복잡한 SVG 경로는 렌더링 속도를 저하시킬 수 있습니다. 최적화 전략:

  1. 경로 단순화 – 불필요한 좌표 정밀도 제거
  2. 상대 명령 사용l을 사용해 파일 크기 감소
  3. 유사 주석 배치 – 속성이 비슷한 주석을 그룹화
// Optimize coordinate precision
public String optimizePath(String svgPath) {
    return svgPath.replaceAll("(\\d+\\.\\d{3})\\d+", "$1");
}

흔히 발생하는 문제와 해결책

문제 1: “주석이 보이지 않음”

증상: 오류 없이 코드가 실행되지만 폴리라인이 나타나지 않음.

주요 원인:

  • 페이지 번호 오류(0‑기반임을 기억)
  • SVG 경로 좌표가 문서 범위를 벗어남
  • 투명도가 너무 낮거나 펜 두께가 너무 얇음

해결 방법:

// Debug your annotation placement
PolylineAnnotation polyline = new PolylineAnnotation();
polyline.setPageNumber(0); // Ensure correct page
polyline.setOpacity(1.0); // Full opacity for testing
polyline.setPenWidth((byte) 5); // Thicker line for visibility

// Log the bounding box to verify coordinates
Rectangle box = polyline.getBox();
System.out.println("Annotation bounds: " + box.getX() + "," + box.getY());

문제 2: “대용량 문서에서 OutOfMemoryError”

증상: 큰 PDF 또는 다수의 문서를 처리할 때 애플리케이션이 충돌함.

해결 방법:

// Implement proper memory management
public void processLargeDocument(String documentPath) {
    // Process in smaller batches
    int maxAnnotationsPerBatch = 50;
    List<PolylineConfig> allConfigs = getAnnotationConfigs();
    
    for (int i = 0; i < allConfigs.size(); i += maxAnnotationsPerBatch) {
        try (Annotator annotator = new Annotator(documentPath)) {
            int end = Math.min(i + maxAnnotationsPerBatch, allConfigs.size());
            List<PolylineConfig> batch = allConfigs.subList(i, end);
            
            processBatch(annotator, batch);
            annotator.save(generateBatchOutputPath(documentPath, i));
        }
        // Force garbage collection between batches if needed
        System.gc();
    }
}

문제 3: “SVG 경로 형식 오류”

증상: SVG 경로 설정 시 예외 발생.

주요 원인:

  • 잘못된 SVG 구문
  • 시작에 Move 명령 누락
  • 좌표 값 오류

해결 방법:

// Validate SVG path before using
public boolean isValidSVGPath(String path) {
    // Basic validation - should start with M or m
    if (!path.matches("^[Mm]\\d+.*")) {
        return false;
    }
    
    // Additional validation logic here
    return true;
}

// Use validated paths only
if (isValidSVGPath(pathString)) {
    polyline.setSvgPath(pathString);
} else {
    throw new IllegalArgumentException("Invalid SVG path: " + pathString);
}

문제 4: “라이선스 검증 실패”

증상: 프로덕션 환경에서 라이선스 관련 예외 발생.

해결 방법:

// Proper license initialization
public class AnnotationConfig {
    
    @PostConstruct
    public void initializeLicense() {
        try {
            // Load license from classpath or file system
            String licensePath = getClass().getClassLoader()
                .getResource("GroupDocs.Annotation.lic").getPath();
            
            License license = new License();
            license.setLicense(licensePath);
            
            System.out.println("GroupDocs.Annotation license loaded successfully");
        } catch (Exception e) {
            System.err.println("Failed to load license: " + e.getMessage());
            // Handle license failure appropriately
        }
    }
}

고급 커스터마이징 기법

동적 색상 할당

데이터 또는 사용자 선호도에 따라 색상을 지정하는 폴리라인 만들기:

public class ColorHelper {
    private static final Map<String, Integer> CATEGORY_COLORS = Map.of(
        "error", 0xFFFF0000,      // Red
        "warning", 0xFFFF9900,    // Orange  
        "info", 0xFF0099FF,       // Blue
        "success", 0xFF00FF00     // Green
    );
    
    public static int getColorForCategory(String category) {
        return CATEGORY_COLORS.getOrDefault(category, 0xFF000000); // Default black
    }
}

커스텀 속성을 가진 인터랙티브 주석

주석에 메타데이터를 추가해 인터랙티브성을 강화합니다:

// Create custom annotation with metadata
PolylineAnnotation polyline = new PolylineAnnotation();
polyline.setMessage("Process Flow: " + processName);

// Add custom properties (stored in message or replies)
Reply metadataReply = new Reply();
metadataReply.setComment("metadata:{\"processId\":\"12345\",\"priority\":\"high\"}");
polyline.setReplies(Arrays.asList(metadataReply));

이 접근법을 사용하면 프론트엔드 애플리케이션이 메타데이터를 추출해 풍부한 사용자 경험을 제공할 수 있습니다.

구현 테스트

단위 테스트

주석 로직에 대한 포괄적인 테스트 작성:

@Test
public void testPolylineAnnotationCreation() {
    // Arrange
    String documentPath = "test-documents/sample.pdf";
    PolylineConfig config = new PolylineConfig();
    config.setMessage("Test polyline");
    config.setPath("M10,10L50,50");
    
    // Act
    try (Annotator annotator = new Annotator(documentPath)) {
        PolylineAnnotation polyline = createPolylineFromConfig(config);
        annotator.add(polyline);
        
        // Assert
        assertNotNull(polyline);
        assertEquals("Test polyline", polyline.getMessage());
        assertEquals(0.7, polyline.getOpacity(), 0.01);
    }
}

통합 테스트

실제 문서를 사용해 전체 워크플로우 테스트:

@Test
public void testEndToEndAnnotationWorkflow() {
    // Test complete process from document input to annotated output
    String inputPath = "test-documents/input.pdf";
    String outputPath = "test-output/annotated.pdf";
    
    DocumentAnnotationService service = new DocumentAnnotationService();
    String result = service.addPolylineAnnotation(inputPath, createTestConfig());
    
    // Verify output file exists and contains annotations
    assertTrue(Files.exists(Paths.get(result)));
    
    // Additional verification logic
    verifyAnnotationExists(result);
}

결론

이제 인터랙티브 폴리라인 PDF 주석을 GroupDocs.Annotation for Java로 구현하는 방법을 마스터했습니다. 폴리라인 주석은 정적 텍스트를 넘어서는 인터랙티브하고 전문적인 문서를 만들 수 있는 가능성을 열어줍니다.

핵심 요점:

  • Maven 설정과 라이선스만 이해하면 설정은 간단합니다
  • SVG 경로를 활용하면 복잡한 연결 라인을 자유롭게 만들 수 있습니다
  • 리소스 관리가 프로덕션 애플리케이션의 핵심입니다
  • 통합 패턴(Spring Boot, REST)을 통해 기존 Java 애플리케이션에 손쉽게 주석을 추가할 수 있습니다

문서 관리 시스템, 교육 플랫폼, 기술 문서 도구 등 어떤 분야를 구축하든 폴리라인 주석은 사용자에게 필요한 시각적 명확성과 인터랙티브성을 제공합니다.

다음 단계

주석 실력을 한 단계 끌어올리고 싶나요? 다음을 탐색해 보세요:

  • 복잡한 영역 강조를 위한 Area 주석
  • 방향 표시를 위한 Arrow 주석
  • 브랜드 및 보안을 위한 Watermark 주석
  • 실시간 주석 편집을 위한 문서 뷰어와의 통합

자주 묻는 질문

Q: 폴리라인 주석을 만든 뒤 수정할 수 있나요?
A: 가능합니다. 다만 기존 주석을 제거하고 업데이트된 속성으로 새 주석을 추가해야 합니다. GroupDocs.Annotation은 기존 주석의 직접 수정은 지원하지 않습니다.

Q: 폴리라인에 포함할 수 있는 최대 점 개수는?
A: 명확한 제한은 없지만, 점이 매우 많을 경우(1000개 이상) 성능이 저하됩니다. 최적 결과를 위해 100점 이하로 유지하는 것이 좋습니다.

Q: PDF 뷰어에서 사용자가 폴리라인 주석과 상호작용할 수 있나요?
A: 호환 가능한 PDF 리더에서는 사용자가 주석을 클릭해 댓글 및 답글을 확인할 수 있습니다. 인터랙티브 수준은 사용 중인 PDF 뷰어에 따라 달라집니다.

Q: 문서 유형마다 좌표 시스템이 다른데 어떻게 처리하나요?
A: GroupDocs.Annotation은 내부적으로 좌표 시스템을 정규화하지만, 특정 문서 유형에 대해 테스트가 필요합니다. PDF 좌표는 좌하단이 원점이며, 일부 포맷은 좌상단이 원점입니다.

Q: 원본 문서 없이 주석 데이터를 내보낼 수 있나요?
A: 가능합니다. GroupDocs.Annotation은 주석 메타데이터를 XML 또는 JSON 형태로 추출하는 메서드를 제공하며, 이를 별도로 저장하고 나중에 재적용할 수 있습니다.

Q: 많은 폴리라인 주석을 추가하면 성능에 어떤 영향이 있나요?
A: 각 주석은 최소한의 오버헤드만 추가하지만, 복잡한 SVG 경로와 다수의 주석은 렌더링을 느리게 할 수 있습니다. 배치 처리와 SVG 경로 최적화를 활용해 최상의 성능을 유지하세요.

Q: GroupDocs.Annotation을 업그레이드할 때 버전 호환성을 어떻게 관리하나요?
A: 먼저 소수의 문서로 테스트하세요. GroupDocs는 주석 데이터에 대한 하위 호환성을 유지하지만, 주요 버전 간에 API 메서드가 변경될 수 있습니다.

리소스 및 추가 읽을거리


최종 업데이트: 2026-03-03
테스트 환경: GroupDocs.Annotation 25.2 for Java
작성자: GroupDocs