This is an old revision of the document!


Laboratorul 12: Programare Avansată Java

Obiective

Serializare și Deserializare

Ce este serializarea?

Serializarea reprezintă procesul prin care un obiect Java este transformat într-o reprezentare transferabilă, de regulă o secvență de bytes sau un format text, astfel încât să poată fi:

  • salvat pe disc
  • transmis prin rețea
  • stocat temporar (cache)
  • restaurat ulterior în memorie

Operația inversă se numește deserializare și presupune refacerea obiectului original din această reprezentare.

De ce avem nevoie de serializare?

Serializarea este folosită în special pentru:

  • salvarea stării unei aplicații
  • persistarea temporară a obiectelor
  • transfer de date între procese sau servicii
  • sisteme de cache distribuit
  • mecanisme de rollback / snapshot

Serializarea nu înlocuiește o bază de date. Este un mecanism de transport sau stocare temporară, nu unul de persistență relațională.

Serializarea nativă Java

Interfața Serializable

Pentru ca un obiect să poată fi serializat de JVM folosind mecanismul nativ, clasa sa trebuie să implementeze interfața: java.io.Serializable.

public class User implements Serializable {
    private String name;
    private int age;
}

Această interfață:

  • este un marker interface (deci nu definește metode),
  • este verificată de JVM la runtime,
  • permite folosirea claselor ObjectOutputStream și ObjectInputStream.

Dacă un obiect nu este serializabil, JVM aruncă NotSerializableException.

Exemplu complet: serializare și deserializare

1. Clasa model

import java.io.Serializable;
 
public class Person implements Serializable {
    private String name;
    private int age;
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    @Override
    public String toString() {
        return name + " (" + age + ")";
    }
}

2. Serializarea unui obiect

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
 
public class SerializeDemo {
    public static void main(String[] args) throws Exception {
        Person p = new Person("Ana", 30);
 
        ObjectOutputStream out =
            new ObjectOutputStream(new FileOutputStream("person.ser"));
 
        out.writeObject(p);
        out.close();
 
        System.out.println("Object serialized.");
    }
}

3. Deserializarea unui obiect

import java.io.FileInputStream;
import java.io.ObjectInputStream;
 
public class DeserializeDemo {
    public static void main(String[] args) throws Exception {
        ObjectInputStream in =
            new ObjectInputStream(new FileInputStream("person.ser"));
 
        Person p = (Person) in.readObject();
        in.close();
 
        System.out.println("Deserialized: " + p);
    }
}

Output

Output

Object serialized.
Deserialized: Ana (30)

Câmpuri transient

Nu toate câmpurile unui obiect ar trebui serializate. Exemple tipice:

  • parole
  • token-uri
  • conexiuni
  • cache-uri

Pentru a exclude un câmp de la serializare folosim cuvântul cheie transient.

public class Account implements Serializable {
    private String username;
    private transient String password;
}

Deoarece am declarat password ca fiind transient, acesta nu este salvat, iar după deserializare devine null.

Versionarea serializării

Câmpul serialVersionUID identifică versiunea unei clase serializate.

private static final long serialVersionUID = 1L;

Acest identificator este folosit de JVM pentru a verifica dacă o clasă este compatibilă cu obiectul serializat, astfel putem garanta compatibilitatea operațiilor.

Dacă nu este declarat explicit:

  • JVM generează unul automat.
  • orice mică modificare va genera un nou UID.

Serializare modernă: Jackson (JSON)

Ce este Jackson?

Jackson este o bibliotecă externă foarte populară care permite:

  • serializarea obiectelor Java în JSON,
  • deserializarea JSON-ului în obiecte Java.

Spre deosebire de serializarea nativă:

  • nu folosește format binar,
  • nu necesită Serializable,
  • este independentă de JVM.

De ce este Jackson preferat în aplicațiile moderne?

De ce este Jackson preferat în aplicațiile moderne?

  • JSON este lizibil și ușor de debugat,
  • este interoperabil cu alte limbaje,
  • permite control fin prin adnotări,
  • este mult mai sigur decât serializarea nativă.

Este standardul de facto pentru:

  • API-uri REST,
  • microservicii,
  • testare și integrare.

Exemplu cu Jackson

1. Dependința Jackson

Într-un proiect real (Maven), Jackson se adaugă astfel:

pom.xml
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.16.1</version>
</dependency>

Multe proiecte au deja această dependență când se folosește Spring Boot pentru crearea unui API.

2. Clasa model

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
 
public class User {
 
    private String name;
    private int age;
 
    @JsonIgnore
    private String password;
 
    public User() {
        // constructor fără parametri NECESAR pentru deserializare
    }
 
    public User(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }
 
    public String getName() {
        return name;
    }
 
    public int getAge() {
        return age;
    }
 
    @JsonProperty("years")
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getPassword() {
        return password;
    }
 
    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

  • constructorul fără parametri este obligatoriu pentru Jackson
  • @JsonIgnore exclude câmpul din JSON
  • @JsonProperty permite maparea numelor diferite din JSON

3. Serializare: obiect → JSON

import com.fasterxml.jackson.databind.ObjectMapper;
 
public class JacksonSerializeDemo {
 
    public static void main(String[] args) throws Exception {
 
        ObjectMapper mapper = new ObjectMapper();
 
        User user = new User("Ana", 30, "secret123");
 
        String json = mapper.writeValueAsString(user);
 
        System.out.println("JSON rezultat:");
        System.out.println(json);
    }
}

output

output

{"name":"Ana","age":30}

Câmpul password nu apare deoarece are adnotarea @JsonIgnore.

4. Deserializare: JSON → obiect

import com.fasterxml.jackson.databind.ObjectMapper;
 
public class JacksonDeserializeDemo {
 
    public static void main(String[] args) throws Exception {
 
        ObjectMapper mapper = new ObjectMapper();
 
        String json = """
        {
          "name": "Ion",
          "years": 25,
          "password": "shouldBeIgnored"
        }
        """;
 
        User user = mapper.readValue(json, User.class);
 
        System.out.println("Obiect deserializat:");
        System.out.println(user);
    }
}

output

output

User{name='Ion', age=25}

  • yearsage datorită @JsonProperty
  • password este ignorat
  • Jackson a folosit constructorul fără parametri + setter-ele

5. Serializare în fișier și citire din fișier

Scriere în fișier

mapper.writeValue(new File("user.json"), user);

Citire din fișier

User user = mapper.readValue(new File("user.json"), User.class);
poo-ca-cd/laboratoare/programare-avansata-java.1768160426.txt.gz · Last modified: 2026/01/11 21:40 by florian_luis.micu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0