Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Exercícios Práticos de Serialização

1.Criar uma classe simples serializável
Implemente Serializable e serialize/deserialize um objeto usando ObjectOutputStream e ObjectInputStream.

2. Testar a compatibilidade de versão
Serializar um objeto de uma versão antiga da classe e tentar desserializá-lo após uma mudança na estrutura da classe.
Testar o comportamento do serialVersionUID.

3. Criar uma forma serializada personalizada
Usar writeObject e readObject para definir manualmente a serialização de uma classe.

4. Explorar riscos de segurança
Criar um objeto vulnerável a ataques via serialização (exemplo: permitir modificação de campos privados via desserialização).
Corrigir a vulnerabilidade implementando readObject.

5. Comparar serialização com outras abordagens
Implementar persistência de um objeto com JSON (Gson, Jackson) e comparar com a serialização Java.


1. Faça uma classe serializável e demonstre a serialização e desserialização de um objeto dessa classe.

import java.io.*;// Classe serializávelclass Pessoa implements Serializable {    private static final long serialVersionUID = 1L; // UID para manter compatibilidade    private String nome;    private int idade;    public Pessoa(String nome, int idade) {        this.nome = nome;        this.idade = idade;    }    @Override    public String toString() {        return "Pessoa{nome='" + nome + "', idade=" + idade + "}";    }}public class SerializacaoExemplo {    public static void main(String[] args) {        Pessoa pessoa = new Pessoa("João", 30);        // Serializar objeto        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("pessoa.ser"))) {            out.writeObject(pessoa);            System.out.println("Objeto serializado com sucesso!");        } catch (IOException e) {            e.printStackTrace();        }        // Desserializar objeto        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("pessoa.ser"))) {            Pessoa pessoaLida = (Pessoa) in.readObject();            System.out.println("Objeto desserializado: " + pessoaLida);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Explicação: Esse código cria uma classe Pessoa serializável, salva um objeto em um arquivo e depois o lê de volta.

2. Modifique a classe do exercício anterior para incluir um novo campo e demonstre o problema de compatibilidade ao desserializar um objeto antigo.

import java.io.*;class Pessoa implements Serializable {    private static final long serialVersionUID = 1L; // UID fixo para manter compatibilidade    private String nome;    private int idade;    private String email; // Novo campo adicionado    public Pessoa(String nome, int idade, String email) {        this.nome = nome;        this.idade = idade;        this.email = email;    }    @Override    public String toString() {        return "Pessoa{nome='" + nome + "', idade=" + idade + ", email='" + email + "'}";    }}public class SerializacaoProblema {    public static void main(String[] args) {        // Tentativa de desserializar um objeto criado antes da adição do campo 'email'        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("pessoa.ser"))) {            Pessoa pessoaLida = (Pessoa) in.readObject();            System.out.println("Objeto desserializado: " + pessoaLida);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Explicação: Se um objeto da versão anterior (sem email) for desserializado, pode causar InvalidClassException, pois o serialVersionUID e a estrutura da classe mudaram.

3. Corrija o problema do exercício anterior implementando uma forma serializada compatível usando serialVersionUID.

import java.io.*;class Pessoa implements Serializable {    private static final long serialVersionUID = 1L;    private String nome;    private int idade;    private transient String email; // Campo transient não será serializado    public Pessoa(String nome, int idade, String email) {        this.nome = nome;        this.idade = idade;        this.email = email;    }    @Override    public String toString() {        return "Pessoa{nome='" + nome + "', idade=" + idade + "', email='" + (email != null ? email : "N/A") + "'}";    }}public class SerializacaoCorrigida {    public static void main(String[] args) {        // Desserializar objeto antigo sem email        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("pessoa.ser"))) {            Pessoa pessoaLida = (Pessoa) in.readObject();            System.out.println("Objeto desserializado: " + pessoaLida);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Explicação: O campo email foi marcado como transient, o que impede sua serialização e mantém a compatibilidade.

4. Demonstre como a serialização pode ser uma falha de segurança permitindo a modificação de um objeto privado.

import java.io.*;class Usuario implements Serializable {    private static final long serialVersionUID = 1L;    private String nome;    private String senha; // Senha não protegida!    public Usuario(String nome, String senha) {        this.nome = nome;        this.senha = senha;    }    @Override    public String toString() {        return "Usuario{nome='" + nome + "', senha='" + senha + "'}";    }}public class FalhaSeguranca {    public static void main(String[] args) {        Usuario usuario = new Usuario("admin", "1234");        // Serializar usuário        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("usuario.ser"))) {            out.writeObject(usuario);        } catch (IOException e) {            e.printStackTrace();        }        // Modificar o arquivo manualmente e desserializar (Simulando um ataque)        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("usuario.ser"))) {            Usuario usuarioHackeado = (Usuario) in.readObject();            System.out.println("Usuário comprometido: " + usuarioHackeado);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Explicação: A senha é armazenada em texto plano e pode ser extraída ou modificada por um invasor ao alterar o arquivo serializado.

5. Corrija o problema de segurança do exercício anterior tornando os campos sensíveis transient e implementando writeObject() e readObject().

import java.io.*;class UsuarioSeguro implements Serializable {    private static final long serialVersionUID = 1L;    private String nome;    private transient String senha; // Agora a senha não será serializada    public UsuarioSeguro(String nome, String senha) {        this.nome = nome;        this.senha = senha;    }    private void writeObject(ObjectOutputStream out) throws IOException {        out.defaultWriteObject();        out.writeObject(encrypt(senha)); // Salva senha criptografada    }    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {        in.defaultReadObject();        senha = decrypt((String) in.readObject()); // Recupera senha descriptografada    }    private String encrypt(String senha) {        return senha == null ? null : new StringBuilder(senha).reverse().toString(); // Simples inversão    }    private String decrypt(String senhaCriptografada) {        return senhaCriptografada == null ? null : new StringBuilder(senhaCriptografada).reverse().toString();    }    @Override    public String toString() {        return "UsuarioSeguro{nome='" + nome + "', senha='" + senha + "'}";    }}public class SegurancaCorrigida {    public static void main(String[] args) {        UsuarioSeguro usuario = new UsuarioSeguro("admin", "1234");        // Serializar        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("usuarioSeguro.ser"))) {            out.writeObject(usuario);        } catch (IOException e) {            e.printStackTrace();        }        // Desserializar        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("usuarioSeguro.ser"))) {            UsuarioSeguro usuarioLido = (UsuarioSeguro) in.readObject();            System.out.println("Usuário seguro: " + usuarioLido);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Explicação: O campo senha agora é transient, e os métodos writeObject() e readObject() aplicam uma criptografia simples.

5. Comparar serialização com outras abordagens

5.1 Persistência usando Serialização Java

import java.io.*;// Classe serializávelclass Pessoa implements Serializable {    private static final long serialVersionUID = 1L;    private String nome;    private int idade;    public Pessoa(String nome, int idade) {        this.nome = nome;        this.idade = idade;    }    @Override    public String toString() {        return "Pessoa{nome='" + nome + "', idade=" + idade + "}";    }}public class SerializacaoJava {    public static void main(String[] args) {        Pessoa pessoa = new Pessoa("João", 30);        // Serializar em arquivo        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("pessoa.ser"))) {            out.writeObject(pessoa);            System.out.println("Objeto serializado: " + pessoa);        } catch (IOException e) {            e.printStackTrace();        }        // Desserializar do arquivo        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("pessoa.ser"))) {            Pessoa pessoaLida = (Pessoa) in.readObject();            System.out.println("Objeto desserializado: " + pessoaLida);        } catch (IOException | ClassNotFoundException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Pontos positivos: Integrado ao Java, eficiente em binário.
📌 Pontos negativos: Problemas de compatibilidade ao mudar a classe, não legível para humanos.

5.2 Persistência usando JSON com Gson

import com.google.gson.Gson;import com.google.gson.GsonBuilder;import java.io.*;// Classe normal sem Serializableclass PessoaGson {    private String nome;    private int idade;    public PessoaGson(String nome, int idade) {        this.nome = nome;        this.idade = idade;    }    @Override    public String toString() {        return "PessoaGson{nome='" + nome + "', idade=" + idade + "}";    }}public class PersistenciaGson {    public static void main(String[] args) {        PessoaGson pessoa = new PessoaGson("João", 30);        Gson gson = new GsonBuilder().setPrettyPrinting().create();        // Serializar em JSON        try (FileWriter writer = new FileWriter("pessoa.json")) {            gson.toJson(pessoa, writer);            System.out.println("Objeto serializado em JSON:\n" + gson.toJson(pessoa));        } catch (IOException e) {            e.printStackTrace();        }        // Desserializar do JSON        try (Reader reader = new FileReader("pessoa.json")) {            PessoaGson pessoaLida = gson.fromJson(reader, PessoaGson.class);            System.out.println("Objeto desserializado: " + pessoaLida);        } catch (IOException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Pontos positivos: Legível, fácil de integrar com APIs e persistência de dados.
📌 Pontos negativos: JSON ocupa mais espaço e é um pouco mais lento que binário.

5.3 Persistência usando JSON com Jackson

import com.fasterxml.jackson.databind.ObjectMapper;import java.io.*;// Classe normal sem Serializableclass PessoaJackson {    private String nome;    private int idade;    public PessoaJackson() {} // Jackson precisa de um construtor vazio    public PessoaJackson(String nome, int idade) {        this.nome = nome;        this.idade = idade;    }    @Override    public String toString() {        return "PessoaJackson{nome='" + nome + "', idade=" + idade + "}";    }}public class PersistenciaJackson {    public static void main(String[] args) {        PessoaJackson pessoa = new PessoaJackson("João", 30);        ObjectMapper objectMapper = new ObjectMapper();        // Serializar em JSON        try {            objectMapper.writeValue(new File("pessoa_jackson.json"), pessoa);            System.out.println("Objeto serializado em JSON com Jackson");        } catch (IOException e) {            e.printStackTrace();        }        // Desserializar do JSON        try {            PessoaJackson pessoaLida = objectMapper.readValue(new File("pessoa_jackson.json"), PessoaJackson.class);            System.out.println("Objeto desserializado: " + pessoaLida);        } catch (IOException e) {            e.printStackTrace();        }    }}
Enter fullscreen modeExit fullscreen mode

📌 Pontos positivos: Alto desempenho, flexível, suporta diversas configurações.
📌 Pontos negativos: Requer bibliotecas externas, pode exigir configurações extras.

5.4 Comparação das abordagens

Image description

📌 Conclusão:

  • A serialização Java é eficiente, mas tem problemas de compatibilidade e não é legível.
  • O Gson é simples, fácil de usar e ideal para APIs.
  • O Jackson tem melhor desempenho e é mais configurável, sendo ótimo para grandes aplicações.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Resumos do Livro Java Efetivo feitos pro grupo de estudos Clube do Livro na comunidade de Java Girls Jug.
  • Location
    Florianópolis
  • Education
    Streets
  • Work
    Cibercafé
  • Joined

More fromJava Efetivo (livro)

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp