Package com.veeva.vault.sdk.api.annotation


package com.veeva.vault.sdk.api.annotation
This package provides interfaces to manage document annotations in Vault.

When viewing documents in the Vault UI, users can add and reply to annotations. There are multiple types of annotations, including Sticky Note (note__sys), Line (line__sys), Anchor (anchor__sys), and Reply (reply__sys). The interfaces in this package allow you to read information for all annotation types, and to save and delete them.

You can find full lists and descriptions of annotation types, fields, placemarks, and references in the Developer Portal.

The following example uses AnnotationService to read all note and line annotations on a document:

 // Read all note and line annotations on document 123 v1.0
 Set<String> types = VaultCollections.newSet();
 types.add("note__sys");
 types.add("line__sys");
 annotationService.readAnnotations(
     annotationService.newReadAnnotationRequestBuilder()
         .withDocumentVersionId("123_1_0")
         // If we didn't set withAnnotationTypes, Vault would attempt to read
         // all visible, non-reply annotation types
         .withAnnotationTypes(types)
         .build()
 ).onError(
     errorResult -> {
         // Check for batch-level errors such as a missing document
         if (errorResult.getType() ==
             AnnotationReadErrorType.DOCUMENT_NOT_FOUND) {
             // Handle this error here
         }
     }
 ).onSuccess(
     response -> response.streamResults().forEach(annotation -> {

         // For each of the resulting annotations, retrieve field
         // values and the annotation placemark
         String state = annotation.getValue(
             "state__sys",
             AnnotationValueType.STRING);
         String color = annotation.getValue(
             "color__sys",
             AnnotationValueType.STRING);
         String comment = annotation.getValue(
             "comment__sys",
             AnnotationValueType.STRING);
         BigDecimal page = annotation.getPlacemark().getValue(
             "page_number__sys",
             AnnotationPlacemarkValueType.NUMBER);

         // Retrieve specific coordinates for the placemark. There will be 8*n
         // coordinates, where n is the number of rectangles that make up the
         // annotation placemark. The coordinates for each rectangle are in
         // the order (x1, y1, x2, y2, x3, y3, x4, y4). Each two coordinates
         // specify the location of a corner of the rectangle.
         List<BigDecimal> coordinates = annotation.getPlacemark().getValue(
             "coordinates__sys",
             AnnotationPlacemarkValueType.NUMBER_LIST
         );
         for (int i = 8; i <= coordinates.size(); i = i + 8) {
             List<BigDecimal> oneRectangle = coordinates.subList(i - 8, i);
             // We can work with the coordinate values for each rectangle
             // here
         }

         // Retrieve replies for the given annotation
         annotationService.readReplies(
             annotationService.newReadReplyRequestBuilder()
                 .withParentId(
                     annotation.getValue(
                         "id__sys",
                         AnnotationValueType.STRING
                     )
                 ).build()
         ).onSuccess(
             replyResponse -> replyResponse.streamResults()
                 .forEach(reply -> {

                     // Stream the replies
                     String replyState = reply.getValue(
                         "state__sys",
                         AnnotationValueType.STRING);
                     String replyColor = reply.getValue(
                         "color__sys",
                         AnnotationValueType.STRING);
                     String replyComment = reply.getValue(
                         "comment__sys",
                         AnnotationValueType.STRING);
                 })
         ).onError(
             errorResult -> {
                 // Check for errors when fetching replies
                 if (errorResult.getType() ==
                     AnnotationReadErrorType.ANNOTATION_NOT_FOUND) {
                     // Handle this error here
                 }
             }
         ).execute();
     })
 ).execute();
 

You can also use AnnotationService to create and update annotations. The following example creates a new note annotation and updates an existing link annotation on the same document:

 List<Annotation> annotations = VaultCollections.asList(
     // NEW NOTE WITH AREA SELECTION
     annotationService.newAnnotationBuilder()
         .withTypeName("note__sys")
         .withValue("document_version_id__sys", "1234_0_1")
         // User mentions are validated
         .withValue("comment__sys", "mention for [+sample.user@veeva.com]")
         .withValue("color__sys", "orange_light__sys")
         .withValue("state__sys", "open__sys")
         .appendReplies(VaultCollections.asList(
                 annotationService.newAnnotationBuilder()
                     .withTypeName("reply__sys")
                     .withValue("color__sys", "green_dark__sys")
                     .withValue("comment__sys", "make sure you follow up")
                     // Don't specify placemark, it's implied for replies
                     .build()
             )
         )
         .withPlacemark(
             annotationService.newPlacemarkBuilder()
                 .withTypeName("rectangle__sys")
                 .withValue("page_number__sys", BigDecimal.valueOf(1))
                 .withValue("x_coordinate__sys", BigDecimal.valueOf(5.0))
                 .withValue("y_coordinate__sys", BigDecimal.valueOf(5.0))
                 .withValue("height__sys", BigDecimal.valueOf(1.0))
                 .withValue("width__sys", BigDecimal.valueOf(1.0))
                 .withValue("style__sys", "rectangle_dashed__sys")
                 .build()
         )
         .build(),

     // UPDATE DOCUMENT LINK
     annotationService.newAnnotationBuilderWithId("57")
         .withReferences(VaultCollections.asList(
                 annotationService.newReferenceBuilder()
                     .withTypeName("document__sys")
                     .withValue("document_version_id__sys", "12345_2_0")
                     .withValue("annotation__sys", "102")
                     .build()
             )
         )
         .build()
 );

 // Perform the batch save operation
 annotationService.batchSaveAnnotations(
     annotationService.newBatchSaveRequestBuilder()
         .withAnnotations(annotations)
         .build()
 ).onSuccesses(successList -> {
         for (AnnotationBatchSaveSuccess success : successList) {
             int requestIndex = success.getInputPosition();
             // Stream the IDs of the new annotations created or updated by the
             // request index above
             success.streamSavedAnnotations().forEach(
                 newAnnotationId -> {
                     // Use the newAnnotationId as needed
                 }
             );
         }
     }
 ).onErrors(batchErrors -> {
         for (AnnotationBatchSaveError batchError : batchErrors) {
             int requestIndex = batchError.getInputPosition();
             String errorMessage = batchError.getError().getMessage();
             AnnotationBatchSaveErrorType errorType = batchError.getError()
                 .getType();
             // Use the above error information as needed
         }
     }
 ).ignoreErrors().execute();
 

In the event that a document has identical content on multiple pages, you can copy annotations on text selections from one page to another. The example below illustrates how to retrieve information from a note annotation on page 1 of a document and create an identical annotation with the same text selection and comment on page 2:

 annotationService.readAnnotations(
     // Set up the read operation to read the annotation by ID
     annotationService.newReadAnnotationRequestBuilder()
         .withAnnotationIds(VaultCollections.asList("100"))
         .build()
 ).onSuccess(
     response -> response.streamResults().forEach(annotation -> {

         List<Annotation> annotations = VaultCollections.asList(
             // Create a new annotation on the same document as the original
             // annotation, copying the comment and text indexes, but set it to
             // page 2
             annotationService.newAnnotationBuilder()
                 .withTypeName("note__sys")
                 .withValue("document_version_id__sys",
                     annotation.getValue("document_version_id__sys",
                         AnnotationValueType.STRING))
                 .withValue("comment__sys",
                     annotation.getValue("comment__sys",
                         AnnotationValueType.STRING))
                 .withPlacemark(
                     annotationService.newPlacemarkBuilder()
                         .withTypeName("text__sys")
                         .withValue("page_number__sys", BigDecimal.valueOf(2))
                         .withValue("text_start_index__sys",
                             annotation.getPlacemark().getValue(
                                 "text_start_index__sys",
                                 AnnotationPlacemarkValueType.NUMBER))
                         .withValue("text_end_index__sys",
                             annotation.getPlacemark().getValue(
                                 "text_end_index__sys",
                                 AnnotationPlacemarkValueType.NUMBER))
                         .build()
                 )
                 .build()
         );

         annotationService.batchSaveAnnotations(
             annotationService.newBatchSaveRequestBuilder()
                 .withAnnotations(annotations)
                 .build()
         ).execute();
     })
 ).execute();
 

Use AnnotationMetadataService to read metadata about annotation types, fields, placemarks, and references. The following example illustrates how to read the allowed colors and text styles for the Note annotation type:

 // Get metadata for the Note annotation type
 AnnotationType noteType = annotationMetadataService.getType(
     annotationMetadataService.newTypeRequestBuilder()
         .withName("note__sys")
         .build()
 );

 // Get metadata for the Color annotation field
 AnnotationField colorField = annotationMetadataService.getField(
     annotationMetadataService.newFieldRequestBuilder()
         .withName("color__sys")
         .build()
 );

 // Get the allowed values for Color for Note types. First, double-check that
 // Color is a field that has a value set, and double-check that Color is an
 // allowed field for Notes.
 Collection<String> allowedColors = new HashSet<>();
 if (colorField.hasValueSet() &&
     noteType.getFields().contains(colorField.getName())) {
     allowedColors.addAll(
         annotationMetadataService.getValueSet(
             annotationMetadataService.newValueSetRequestBuilder(
                     AnnotationValueType.STRING)
                 .withField(colorField.getName())
                 .withType(noteType.getName())
                 .build()
         )
     );
 }

 // Get metadata for the Text annotation placemark type
 AnnotationPlacemarkType textType = annotationMetadataService.getPlacemarkType(
     annotationMetadataService.newPlacemarkTypeRequestBuilder()
         .withName("text__sys")
         .build()
 );

 // Get metadata for the Style annotation placemark field
 AnnotationPlacemarkField styleField = annotationMetadataService
     .getPlacemarkField(
         annotationMetadataService.newPlacemarkFieldRequestBuilder()
             .withName("style__sys")
             .build()
     );

 // Get the allowed values for Style for Text types. First, check that
 // Style is a field that has a value set, Text is an allowed placemark
 // type for Note annotation types, and Style is an allowed field for
 // Text placemarks.
 Collection<String> allowedStyles = new HashSet<>();
 if (styleField.hasValueSet() &&
     noteType.getAllowedPlacemarkTypes().contains(textType.getName()) &&
     textType.getFields().contains(styleField.getName())) {
     allowedStyles.addAll(
         annotationMetadataService.getPlacemarkValueSet(
             annotationMetadataService.newPlacemarkValueSetRequestBuilder(
                     AnnotationPlacemarkValueType.STRING)
                 .withField(styleField.getName())
                 .withType(textType.getName())
                 .build()
         )
     );
 }