Главная страница
Навигация по странице:

  • SealedObject

  • SignedObject

  • Ответы на вопросы по ревью 4. Java io. Ключевым понятием здесь является понятие потока


    Скачать 1.93 Mb.
    НазваниеJava io. Ключевым понятием здесь является понятие потока
    Дата03.07.2022
    Размер1.93 Mb.
    Формат файлаdoc
    Имя файлаОтветы на вопросы по ревью 4.doc
    ТипДокументы
    #623608
    страница26 из 39
    1   ...   22   23   24   25   26   27   28   29   ...   39

    Проверка десериализованного объекта, ObjectInputValidation и validateObject


    Если есть необходимость выполнения контроля за значениями десериализованного/восстановленного объекта, то можно использовать интерфейс ObjectInputValidation с переопределением метода validateObject. В следующем листинге представлены изменения, которые следует внести в описание класса Person, чтобы контролировать возраст.

    // Добавление интерфейса ObjectInputValidation

    public class Person implements java.io.Serializable,

    java.io.ObjectInputValidation {

    ...

    @Override

    public void validateObject() throws InvalidObjectException {

    if ((age < 39) || (age > 60))

    throw new InvalidObjectException("Invalid age");

    }

    }

    Если вызвать метод validateObject после десериализации объекта, то будет вызвано исключение InvalidObjectException при значении возраста за пределами 39...60.

    Подписывание сериализованных данных


    Чтобы убедиться, что данные не были изменены в файле или при пересылке по сети их можно «подписать». Несмотря на то, что управление подписями реализовать можно и с помощью методов writeObject и readObject, для этого есть более подходящий способ.

    Если требуется зашифровать и подписать объект, то проще всего поместить его в оберточный класс javax.crypto.SealedObject и/или java.security.SignedObject. Данные классы являются сериализуемыми, поэтому при оборачивании объекта в SealedObject создается подобие "подарочной упаковки" вокруг исходного объекта. Для шифрования необходимо создать симметричный ключ, управление которым должно осуществляться отдельно. Аналогично, для проверки данных можно использовать класс SignedObject, для работы с которым также нужен симметричный ключ, управляемый отдельно. Эти два объекта позволяют упаковывать и подписывать сериализованные данные, не отвлекаясь на детали проверки и шифрования цифровых подписей.

    Листинг теста подписи объекта


    @Test

    public void testSigning()

    {

    try {

    //Generate a 1024-bit Digital Signature Algorithm (DSA) key pair

    KeyPairGenerator keyPairGenerator =

    KeyPairGenerator.getInstance("DSA");

    keyPairGenerator.initialize(1024);

    KeyPair keyPair = keyPairGenerator.genKeyPair();

    PrivateKey privateKey = keyPair.getPrivate();

    PublicKey publicKey = keyPair.getPublic();
    // Подписывать можно только сериализуемый объект

    String unsignedObject = alex.toString();

    Signature signature =

    Signature.getInstance(privateKey.getAlgorithm());

    SignedObject signedObject = new SignedObject(unsignedObject,

    privateKey,

    signature);

    // Verify the signed object

    signature = Signature.getInstance(publicKey.getAlgorithm());

    boolean verified = signedObject.verify(publicKey, signature);
    assertTrue("Проверка 'подписанного' объекта", verified);
    // Retrieve the object

    unsignedObject = (String) signedObject.getObject();

    assertEquals("Проверка описания 'подписанного' объекта",

    unsignedObject, alex.toString());

    } catch (SignatureException e) {

    } catch (InvalidKeyException e) {

    } catch (NoSuchAlgorithmException e) {

    } catch (ClassNotFoundException e) {

    } catch (IOException e) {

    fail("Exception thrown during test: " + e.toString());

    }

    }

    Прокси-класс для сериализации


    Иногда класс может включать элемент, который позволяет получить значения отдельных полей класса по определенному алгоритму. В этих случаях необязательно сериализовывать весь объект. Можно было бы пометить восстанавливаемые поля как «транзитные». Однако в классе всё равно требуется явно указывать код (определять метод), который при обращении к полю каждый раз проверял бы его инициализацию. Для этих целей лучше использовать специальный прокси-класс, из которого можно восстановить объект.

    Листинг прокси-класса


    В прокси-классе определим метод readResolve, которой будет вызываться во время десериализации объекта, чтобы вернуть объект-замену. Конструктор прокси-класса будет упаковывать объект PersonY во внутреннее поле data.

    public class PersonProxy implements java.io.Serializable

    {

    private static final long serialVersionUID = 1L;
    public String data;

    public PersonProxy(PersonY original)

    {

    data = original.getFirstName() + "," + original.getLastName() +

    "," + String.valueOf(original.getAge());

    if (original.getSpouse() != null) {

    PersonY spouse = original.getSpouse();

    data = data + "," + spouse.getFirstName() + "," +

    spouse.getLastName() + "," +

    String.valueOf(spouse.getAge());

    }

    }

    private Object readResolve() throws java.io.ObjectStreamException

    {

    String[] pieces = data.split(",");

    PersonY result = new PersonY(pieces[0], pieces[1],

    Integer.parseInt(pieces[2]));

    if (pieces.length > 3) {

    result.setSpouse(new PersonY(pieces[3], pieces[4],

    Integer.parseInt(pieces[5])));

    result.getSpouse().setSpouse(result);

    }

    return result;

    }

    }

    Класс PersonY создадим на основе базового класса Person с добавлением метода writeReplace следующего вида :

    private Object writeReplace() throws java.io.ObjectStreamException

    {

    return new PersonProxy(this);

    }

    Вместе методы writeReplace и readResolve позволяют классу PersonY упаковывать все данные (или их наиболее важную часть) в объект класса PersonProxy, помещать его в поток и затем распаковать его при десериализации.

    Пример тестирования прокси-класса JUnitPersonProxy


    public class JUnitPersonProxy

    {

    private static final String FILE_proxy = "proxy.ser";

    private static final String FNAME_Alex = "Алексей" ;

    private static final String FNAME_Olga = "Ольга" ;

    private static final String LAST_NAME = "Иванов" ;

    private static final int AGE_Alex = 39 ;
    private static PersonY alex = null ;

    private static PersonY olga = null ;

    @BeforeClass

    public static void setUpBeforeClass() throws Exception {

    try {

    alex = new PersonY(FNAME_Alex, LAST_NAME, AGE_Alex);

    olga = new PersonY(FNAME_Olga, LAST_NAME, 38);
    alex.setSpouse(olga);

    olga.setSpouse(alex);
    // Сохранение сериализованных прокси-объектов

    PersonProxy proxy_alex = new PersonProxy(alex);

    PersonProxy proxy_olga = new PersonProxy(olga);
    FileOutputStream fos = new FileOutputStream(FILE_proxy);

    ObjectOutputStream oos = new ObjectOutputStream(fos);

    oos.writeObject(proxy_alex);

    oos.writeObject(proxy_olga);

    oos.close();

    } catch (Exception e) {

    fail("Exception thrown during test: " + e.toString());

    }

    }
    @AfterClass

    public static void tearDownAfterClass() throws Exception {

    // Удаление файла

    new File(FILE_proxy).delete();

    }

    @Test

    public void testProxy()

    {

    try {

    FileInputStream fis = new FileInputStream(FILE_proxy);

    ObjectInputStream ois = new ObjectInputStream(fis);

    PersonY alex = (PersonY) ois.readObject();

    PersonY olga = (PersonY) ois.readObject();

    ois.close();
    assertEquals(alex.getFirstName(), FNAME_Alex);

    assertEquals(alex.getLastName() , LAST_NAME);

    assertEquals(olga.getFirstName(), FNAME_Olga);

    assertEquals(olga.getFirstName(), FNAME_Olga);

    assertEquals(alex.getAge() , AGE_Alex);

    assertEquals(alex.getSpouse().getFirstName(), FNAME_Olga);

    // Описание объекта

    } catch (Exception e) {

    fail("Exception thrown during test: " + e.toString());

    }

    }

    }
    1   ...   22   23   24   25   26   27   28   29   ...   39


    написать администратору сайта