DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Serialização em Java na atualidade e novas abordagens em 2025

O padrão de proxy de serialização (recomendada pelo livro) ainda é uma solução válida e segura no Java, especialmente para classes com invariantes complexas ou que exigem imutabilidade real. No entanto, com as evoluções da linguagem e das práticas de desenvolvimento, há abordagens mais modernas e recomendadas para muitos cenários.

Abordagens mais modernas para segurança na serialização e desserialização

1- Evitar completamente a serialização nativa do Java (Serializable)

  • O próprio criador do Java (Joshua Bloch) recomenda evitar Serializable devido aos riscos de segurança e complexidade.
  • Em vez disso, é melhor utilizar formatos de serialização mais seguros, como JSON, XML ou Protobuf, que oferecem mais controle sobre o que está sendo serializado.

Alternativas:

  • Usar Jackson (com.fasterxml.jackson.databind) para JSON.
  • Utilizar Protocol Buffers (protobuf) / Apache Avro para uma serialização mais eficiente e segura.

Links:
https://www.linkedin.com/pulse/o-linkedin-substituiu-json-por-protobuf-e-conseguiu-uma-deschamps-s2jkf/

2- Uso de classes imutáveis e transient

  • Objetos imutáveis são naturalmente mais seguros para serialização.

Usar Classes Imutáveis Modernas
Substitua tipos mutáveis (ex.: Date, ArrayList) por classes imutáveis do java.time (LocalDate, Instant) ou coleções imutáveis (List.of(), Set.copyOf()).

Records (Java 16+):

public record Period(LocalDate start, LocalDate end) { 
    // Validação no construtor compacto
    public Period {
        if (end.isBefore(start)) throw new IllegalArgumentException();
    }
}
Enter fullscreen mode Exit fullscreen mode

Simplifica a criação de classes imutáveis e elimina a necessidade de cópias defensivas.

  • Marcar campos sensíveis como transient impede que sejam serializados.

Exemplo:

public final class SecureData implements Serializable {
    private static final long serialVersionUID = 1L;

    private final String publicData;
    private transient String sensitiveData; // Não será serializado

    public SecureData(String publicData, String sensitiveData) {
        this.publicData = publicData;
        this.sensitiveData = sensitiveData;
    }
}

Enter fullscreen mode Exit fullscreen mode

3- ObjectInputFilter (Desde Java 9)

  • Java 9 introduziu o ObjectInputFilter, que permite definir filtros de segurança para impedir ataques de desserialização de objetos inesperados ou perigosos.

Exemplo:

ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
    "com.meusistema.SeguraClass;!*"
);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.ser"));
ois.setObjectInputFilter(filter);

Enter fullscreen mode Exit fullscreen mode

Benefício: Permite controlar quais classes podem ser desserializadas.

4- Biblioteca Kryo (Mais segura e rápida)

  • Kryo é uma alternativa moderna e eficiente para serialização, sendo mais rápida e mais segura que a serialização padrão do Java.
Kryo kryo = new Kryo();
Output output = new Output(new FileOutputStream("data.bin"));
kryo.writeObject(output, myObject);
output.close();

Enter fullscreen mode Exit fullscreen mode

Leitura:
https://medium.com/@prekshaan95/kryo-serialization-and-deserialization-in-java-9e6da25e2a76

Benefício: Melhor desempenho e segurança, usado em frameworks como Akka.

5- Serialização Customizada com writeObject() e readObject()

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    throw new InvalidObjectException("Desserialização não permitida!");
}

Enter fullscreen mode Exit fullscreen mode

Benefício: Bloqueia ataques de desserialização.

6- Serialização com Frameworks Seguros
Spring Boot / Micronaut / Quarkus:

  • Frameworks modernos evitam a serialização nativa do Java, preferindo JSON via REST APIs.
  • Usam DTOs (Data Transfer Objects) imutáveis para transferência segura de dados.

7- Padrão de Serialização Baseada em Construtores
Em vez de depender de proxies, use construtores ou factories para reconstruir objetos após a desserialização:

public class Period implements Serializable {
    private final LocalDate start;
    private final LocalDate end;

    // Construtor público com validação
    public Period(LocalDate start, LocalDate end) {
        if (end.isBefore(start)) throw new IllegalArgumentException();
        this.start = start;
        this.end = end;
    }

    private Object readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        return new Period(start, end); // Reconstrução segura
    }
}
Enter fullscreen mode Exit fullscreen mode

Quando o Proxy de Serialização Ainda é Útil?

  • Cenários críticos: Sistemas financeiros, APIs de segurança, onde a validação rigorosa é essencial.
  • Legado: Projetos que não podem migrar para formatos modernos (ex.: sistemas embarcados, aplicações empresariais antigas).

Comparativo: Proxy vs. Alternativas Modernas

Image description

Conclusão: Qual abordagem usar?

Image description

Se a segurança for crítica, evite Serializable e use JSON ou Protobuf. Se ainda precisar usar Serializable, aplique ObjectInputFilter e classes imutáveis.

Top comments (0)