Análise do Comportamento
Ao integrar a biblioteca ProtoStuff em ambientes Java, a presença da anotação @Deprecated em atributos de classes de dados pode causar a perda silenciosa de valores durante o ciclo de serialização e desserialização. Por padrão, o mecanismo de geração de esquemas ignora automaticamente eses campos, retornando null na reconstrução do objeto. A seguir, detalha-se a reprodução técnica e a estratégia para manter a compatibilidade dos dados.
Dependências Utilizadas
O cenário foi validado com as seguintes coordenadas Maven:
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.5.9</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.5.9</version>
</dependency>
Validação do Fluxo de Conversão
Considere a estrutura de dados abaixo, onde o segundo campo recebe a marcação de descontinuação:
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class RegistroLegado implements Serializable {
private String chavePrimaria;
@Deprecated
private String chaveAnterior;
}
Ao converter a instância para um array de bytes e reconstruí-la utilizando o esquema padrão, o campo obsoleto permanece não inicializado:
@Test
public void testarCicloCompletoPadrao() {
RegistroLegado origem = new RegistroLegado("VALOR_ATUAL", "VALOR_ANTIGO");
Schema<RegistroLegado> esquemaAutomatico = RuntimeSchema.getSchema(RegistroLegado.class);
LinkedBuffer areaTrabalho = LinkedBuffer.allocate(768);
byte[] payload;
try {
payload = ProtostuffIOUtil.toByteArray(origem, esquemaAutomatico, areaTrabalho);
} finally {
areaTrabalho.clear();
}
RegistroLegado destino = esquemaAutomatico.newMessage();
ProtostuffIOUtil.mergeFrom(payload, destino, esquemaAutomatico);
assert destino.getChaveAnterior() == null;
}
Para isolar a fase exata onde a informação é descartada, realiza-se um cruzamento com um modelo alternativo que não possui a anotação:
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class RegistroCorrente implements Serializable {
private String chavePrimaria;
private String chaveAnterior;
}
Serializando um objeto RegistroLegado e direcionando o resultado para uma instância de RegistroCorrente, o valor continua ausente. Isso comprova que a omissão ocorre durente a etapa de encoding, pois o campo nunca é escrito no stream de bytes. O processo inverso (serializar RegistroCorrente e desserializar para RegistroLegado) também falha em popular o campo descontinuado, mesmo quando o dado está presente no payload original.
Estratégia de Contorno via Esquema Explícito
O comportamneto padrão da biblioteca alinha-se à intenção semântica da anotação, assumindo que campos descontinuados devem ser excluídos do ciclo de vida dos dados. Para forçar a inclusão desses atributos, é possível substituir a geração automática por um mapeamento manual durante a criação do esquema:
@Test
public void contornarFiltroDeAnnotacao() {
RegistroLegado entrada = new RegistroLegado("COD_X", "COD_Y");
Map<String, String> dicionarioCampos = new HashMap<>();
dicionarioCampos.put("chavePrimaria", "chavePrimaria");
dicionarioCampos.put("chaveAnterior", "chaveAnterior");
Schema<RegistroLegado> esquemaManual = RuntimeSchema.createFrom(
RegistroLegado.class,
dicionarioCampos,
RuntimeEnv.ID_STRATEGY
);
LinkedBuffer bufferSerializacao = LinkedBuffer.allocate(768);
byte[] fluxoDados;
try {
fluxoDados = ProtostuffIOUtil.toByteArray(entrada, esquemaManual, bufferSerializacao);
} finally {
bufferSerializacao.clear();
}
RegistroLegado saida = esquemaManual.newMessage();
ProtostuffIOUtil.mergeFrom(fluxoDados, saida, esquemaManual);
assert "COD_Y".equals(saida.getChaveAnterior());
}
Ao fornecer explicitamente o conjunto de campos via createFrom, o motor de reflexão do ProtoStuff ignora as verificações padrão de anotações e inclui o atributo descontinuado nas rotinas de conversão, garantindo a integridade dos dados durante a transição entre versões.