Introdução

Quando equipes jurídicas ou analistas forenses precisam provar que um documento não foi adulterado, simplesmente observar o conteúdo visível não é suficiente. Propriedades ocultas — como autor, data de criação ou número de revisão — podem revelar quem manipulou um arquivo e quando. Detectar essas mudanças sutis entre versões de documentos é um ponto de dor comum que frequentemente requer inspeção manual de cada propriedade, uma tarefa demorada e propensa a erros.

GroupDocs.Metadata para Java fornece uma maneira programática de extrair todos os campos de metadados e calcular uma diferença estruturada entre duas versões. Neste tutorial compararemos três abordagens práticas: uma diferença completa de metadados, detecção focada de alterações de propriedade e análise de histórico de revisões. Cada método é demonstrado com código conciso, pronto para copiar e colar, e também mostraremos como exportar os resultados para CSV ou JSON para relatórios de auditoria.

Encontrei isso ao revisar um contrato que havia sido editado por várias partes ao longo de meses; o texto visível parecia idêntico, mas os campos de propriedade haviam mudado silenciosamente.

Como posso saber quais campos de metadados mudaram entre duas versões de documento?

GroupDocs.Metadata carrega cada arquivo, extrai todas as propriedades acessíveis em um mapa e, em seguida, itera sobre as chaves para classificar adições, remoções e modificações. A biblioteca lida com tags incorporadas e personalizadas, de modo que você obtém uma visão completa sem precisar escrever analisadores específicos de formato. O resultado é um objeto MetadataDiff que pode ser consultado ou serializado para relatórios de conformidade.

Pré-requisitos

  • Java 8 ou superior
  • GroupDocs.Metadata para Java 24.7 ([licença temporária][TEMP_LICENSE_URL])
  • Dois arquivos de documento que você deseja comparar (por exemplo, contract_v1.pdf e contract_v2.pdf)

Instalação

Adicione a dependência via Maven:

<dependency>
    <groupId>com.groupdocs</groupId>
    <artifactId>groupdocs-metadata</artifactId>
    <version>24.7</version>
</dependency>

Método 1 – Diferença Completa de Metadados

Este método extrai todos os metadados de ambas as versões e relata entradas adicionadas, removidas e alteradas.

// CompareMetadataSets.run – returns a MetadataDiff object
Map<String, String> v1 = ExtractAllMetadata.run(pathV1);
Map<String, String> v2 = ExtractAllMetadata.run(pathV2);
MetadataDiff diff = new MetadataDiff();

// Detect added and changed properties
for (Map.Entry<String, String> e : v2.entrySet()) {
    String key = e.getKey();
    String val = e.getValue();
    if (!v1.containsKey(key)) {
        diff.added.put(key, val);               // New property in v2
    } else if (!v1.get(key).equals(val)) {
        diff.changed.put(key, new String[]{v1.get(key), val}); // Value changed
    }
}
// Detect removed properties
for (Map.Entry<String, String> e : v1.entrySet()) {
    if (!v2.containsKey(e.getKey())) {
        diff.removed.put(e.getKey(), e.getValue());
    }
}
return diff;

Pontos principais:

  • Abrangente: Captura todas as tags, incluindo as personalizadas.
  • Lógica simples de mapa: Não requer biblioteca externa de diff.
  • Objeto de resultado: Os mapas added, removed e changed estão prontos para processamento adicional.

💡 Dica: Use este método quando precisar de um registro completo para conformidade regulatória.

Método 2 – Detectar Alterações de Propriedade

Disputas legais frequentemente giram em torno de quem criou ou editou um documento. Este método foca em tags relacionadas a pessoas, como Creator, Editor, Manager e Company.

// DetectOwnershipChanges.run – returns a map of changed ownership fields
Map<String, String> v1 = readOwnership(pathV1);
Map<String, String> v2 = readOwnership(pathV2);
Set<String> allKeys = new HashSet<>(v1.keySet());
allKeys.addAll(v2.keySet());
Map<String, String[]> changes = new LinkedHashMap<>();
for (String key : allKeys) {
    String oldVal = v1.getOrDefault(key, "<missing>");
    String newVal = v2.getOrDefault(key, "<missing>");
    if (!oldVal.equals(newVal)) {
        changes.put(key, new String[]{oldVal, newVal});
    }
}
return changes;

readOwnership extrai apenas as tags relevantes:

Map<String, String> result = new LinkedHashMap<>();
try (Metadata metadata = new Metadata(path)) {
    if (metadata.getFileFormat() == FileFormat.Unknown) return result;
    for (MetadataProperty p : metadata.findProperties(
            new ContainsTagSpecification(Tags.getPerson().getCreator())
                .or(new ContainsTagSpecification(Tags.getPerson().getEditor()))
                .or(new ContainsTagSpecification(Tags.getPerson().getManager()))
                .or(new ContainsTagSpecification(Tags.getCorporate().getCompany())))) {
        String value = "";
        if (p.getValue() != null && p.getValue().getRawValue() != null) {
            value = String.valueOf(p.getValue().getRawValue());
        }
        result.put(p.getName(), value);
    }
}
return result;

Pontos principais:

  • Direcionado: Apenas propriedades que carregam identidade são examinadas.
  • Saída clara: Retorna um mapa onde cada entrada mostra valores [antigo, novo].
  • Pronto para conformidade: Ideal para e‑discovery ou disputas de propriedade de contrato.

💡 Dica: Combine este método com o diff completo se precisar de amplitude e profundidade.

Método 3 – Detectar Alterações no Histórico de Revisões

Números de revisão, carimbos de edição e datas de impressão são invisíveis para os usuários finais, mas cruciais para linhas do tempo forenses. Este método isola tags relacionadas ao tempo.

Map<String, String> v1 = read