Wznawiam temat serializacji danych w języku Java (radzę zobaczyć poprzednią część jeśli nie wiecie o czym mowa). Wyobraźmy sobie taką sytuację. Mamy naszą klasę, implementujemy interfejs "Serializable" i każemy programowi zapisać wszystkie dane składowe...oprócz jednej! Takiej małej składowej, która powinna być pomijana ze względu na wartość unikalną dla konkretnego uruchomienia aplikacji. O Boże! Czy to znaczy, że z powodu takiej błahostki, serializacja obiektów idzie w drzazgi i trzeba od razu przerzucać cały system przechowywania do pliku tekstowego? Niekoniecznie! Twórcy języka i o takiej sytuacji pomyśleli więc mogę ją teraz zaprezentować. Poznajcie kolejne słowo kluczowe związane z wykluczaniem danych składowych do zapisu, "transient" w języku Java!

"TRANSIENT" W JĘZYKU JAVA TO SERIALIZACJA OBIEKTÓW Z WYKLUCZENIEM

Modyfikator "transient" zapobiega uwzględnianiu pewnej danej składowej przy serializacji danych gdy mamy pewność, że ona pod żadnym pozorem nie powinna być brana pod uwagę. Mogą być takie sytuacje, które wymagają wykluczeń pewnych danych. Na przykład operacja uzyskania dostępu do konta bankowego. Przecież nie ma najmniejszego sensu serializowania podanego hasła do konta, bo wtedy całe zabezpieczenie na nic! Serializacja obiektów kont bankowych musi wówczas wstawić "transient" przy polu hasła (prawdopodobnie "String"), aby wymusić na użytkowniku ponowne wprowadzenie hasła do systemu. Powyższe słówko przydaje się również w sytuacjach, gdy pewne dane składowe są obliczane podczas wykonywania programu i te wartości muszą być unikatowe przy każdym uruchomieniu! Dla przykładu jakieś nawiązywanie połączeń sieciowych. Choć można uznać za logiczne przechowywanie loginów naszych znajomych, to jednak samo połączenie nie może zostać zapisane, ponieważ proces ich inicjowania i utrzymywania jest zależny od wielu czynników, na przykład od systemu operacyjnego.

Słowo kluczowe "transient" w języku Java

Modyfikator "transient" w języku Java odpowiada za "wykluczanie" danych składowych podczas serializacji danych.

PRZYKŁAD KODU ŹRÓDŁOWEGO

Serializacja obiektów po raz kolejny doczeka się kodu źródłowego. Patrzymy na poniższy program i staramy się go samodzielnie przeanalizować:

KLASA "MAIN"

public class Main
{
	public static void main(String[] args)
	{
		new Serialization();
		new Deserialization();
	}
}

KLASA "ACCOUNT"

import java. io. Serializable;

public class Account implements Serializable
{
	private String login;
	private transient String password;

	public Account(String login, String password)
	{
		this.login = login;
		this.password = password;

		System.out.println("Konto zostało utworzone.");
	}

	@Override
	public String toString()
	{
		return "Login: " + login + ", Hasło: " + password;
	}
}

KLASA "SERIALIZATION"

import java. io.*;

public class Serialization
{
	private static final String SAVE_FILENAME = "accounts.dat";

	private Account accountA, accountB;

	public Serialization()
	{
		createInstances();

		try
		{
			serialize();
			printAccounts();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private void createInstances()
	{
		accountA = new Account("gierka876", "zagrajZeMna01");
		accountB = new Account("sfinks56", "prosteZasady_4");
	}

	private void serialize() throws IOException
	{
		FileOutputStream fos = new FileOutputStream(SAVE_FILENAME);
		ObjectOutputStream oos = new ObjectOutputStream(fos);

		oos.writeObject(accountA);
		oos.writeObject(accountB);
		oos.close();
	}

	private void printAccounts()
	{
		System.out.println(accountA);
		System.out.println(accountB);
	}
}

KLASA "DESERIALIZATION"

import java. io.*;

public class Deserialization
{
	private static final String SAVE_FILENAME = "accounts.dat";

	private Account accountA, accountB;

	public Deserialization()
	{
		try
		{
			deserialise();
			printAccounts();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	private void deserialize() throws IOException, ClassNotFoundException
	{
		FileInputStream fis = new FileInputStream(SAVE_FILENAME);
		ObjectInputStream ois = new ObjectInputStream(fis);

		accountA = (Account)ois.readObject();
		accountB = (Account)ois.readObject();

		ois.close();
	}

	private void printAccounts()
	{
		System.out.println(accountA);
		System.out.println(accountB);
	}
}

Aby zobaczyć cały efekt od początku do końca, trzeba odpowiednio przełączyć klasy. Jeśli ma się odbyć serializacja obiektów, to tworzenie instancji klasy "Serialization" ma być odkomentowane. Jeśli ma iść w drugą stronę, zakomentować "Serialization" i utworzyć instancję klasy "Deserialization". Gdy tak uczynimy, ujrzymy wczytywanie obu kont bankowych, ale bez hasła (wartość będzie "null"), dzięki użyciu modyfikatora "transient" w języku Java.

Jeśli nie wierzycie, OK! Usuńcie sobie to słowo i dokonajcie ponownego zapisu i odczytu, a sami zobaczycie że hasło zostanie zachowane. Pomijając fakt, iż taki system nie nadawałby się do niczego, to powyższy przykład dobitnie pokazuje jak działa "omijanie" danej składowej.

Serializacja obiektów musi być przeprowadzana zdroworozsądkowo, aby pewne dane naprawdę odstąpić od przechowania nie tylko ze względów bezpieczeństwa, ale też możliwości prawidłowego działania aplikacji. Nie ma problemu jeśli po serializacji usuwamy ten modyfikator, aczkolwiek jeśli "transient" został teraz dodany, a w czasie zapisu był "zwykłą" daną składową, możemy mieć duże problemy, które są związane z opisanym już zagadnieniem, "serialVersionUID".


Oto koniec artykułu. Bądźcie ostrożni przy serializowaniu danych i to w obie strony!

PODOBNE ARTYKUŁY