This is an old revision of the document!
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:
Operația inversă se numește deserializare și presupune refacerea obiectului original din această reprezentare.
Serializarea este folosită în special pentru:
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ță:
ObjectOutputStream și ObjectInputStream.
Dacă un obiect nu este serializabil, JVM aruncă NotSerializableException.
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); } }
Nu toate câmpurile unui obiect ar trebui serializate. Exemple tipice:
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; }
password ca fiind transient, acesta nu este salvat, iar după deserializare devine null.
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.
Jackson este o bibliotecă externă foarte populară care permite:
Spre deosebire de serializarea nativă:
Serializable,De ce este Jackson preferat în aplicațiile moderne?
Este standardul de facto pentru:
1. Dependința Jackson
Într-un proiect real (Maven), Jackson se adaugă astfel:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.16.1</version> </dependency>
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 + "}"; } }
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); } }
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); } }
years → age datorită @JsonPropertypassword este ignorat
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);
Adnotările sunt metadate atașate elementelor din codul Java (clase, metode, câmpuri, parametri).
Ele nu modifică direct logica programului, ci oferă informații suplimentare care pot fi interpretate de:
Cu alte cuvinte, adnotările spun ce este codul, nu ce face.
Adnotările au apărut pentru a elimina:
Astăzi, ele sunt fundamentale în:
@AnnotationName public class Example { }
Adnotările pot avea parametri:
@JsonProperty("user_name") private String name;
sau mai mulți:
@MyAnnotation(value = "test", enabled = true)
Prin @Target putem controla unde este permisă adnotarea:
TYPE – clase, interfețeFIELD – câmpuriMETHOD – metodePARAMETER – parametriCONSTRUCTORLOCAL_VARIABLEExemplu:
@Target(ElementType.FIELD)
@Retention definește cât timp există adnotarea:
@Retention(RetentionPolicy.RUNTIME)
Tipuri:
SOURCE – doar la compilare (ex: @Override)CLASS – în bytecode, dar nu la runtimeRUNTIME – disponibilă prin reflection (cea mai importantă)
@Override public String toString() { ... }
@Deprecated public void oldMethod() { }
@SuppressWarnings("unchecked")
Jackson folosește adnotări pentru a controla serializarea:
@JsonIgnore private String password;
@JsonProperty("years") private int age;
Aceste adnotări:
ObjectMapper1. Definirea adnotării
import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Important { String value() default ""; }
@interface
2. Utilizarea adnotării
public class Person { @Important("primary identifier") private String name; private int age; }
import java.lang.reflect.Field; public class AnnotationDemo { public static void main(String[] args) throws Exception { Class<Person> clazz = Person.class; for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Important.class)) { Important imp = field.getAnnotation(Important.class); System.out.println(field.getName() + " -> " + imp.value()); } } } }