Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Джош Блох

.pdf
Скачиваний:
57
Добавлен:
08.03.2016
Размер:
27.13 Mб
Скачать

Глава 11 Сериализация

только в рамках пакета, его действие будет распространяться только на подклассы внутри одного и того же пакета. Если он защищенный или открытый, то его действие будет распространяться на все подклассы, не переопределяющие его. Если метод readResolve защищен или явля­ ется открытым и подклассы его не переопределяют, то десериализация и сериализация экземпляра подкласса произведет экземпляр суперклас­ са, который, скорее всего, приведет к ошибке ClassCastException.

Подведем итоги. Вам нужно использовать перечислимые типы, чтобы установить контроль экземпляров над инвариантами, насколь­ ко это возможно. Если это невозможно и вам нужен класс, который был бы и сериализуемым, и с контролем экземпляров, то вам нужен метод read Resolve, чтобы убедиться, что все поля экземпляров клас­ са являются либо примитивными, либо переходными (transient).

Рассмотрите использование агентов сериализации вместо сериализованных экземпляров

Как уже говорилось в статье 74 и обсуждалось на протяжении всей главы, применение Serializable увеличивает вероятность ошибок и проблем с безопасностью, так как он приводит к созданию экземпля­ ров, использующих механизмы, за пределами языка вместо обычных конструкторов. Есть тем не менее прием, который существенно снижает подобный риск. Этот прием известен как шаблон агента сериализации.

Шаблон агента сериализации довольно прямолинеен. Во-пер­ вых, создайте закрытый статический вложенный класс сериализуе­ мого класса, который точно представляет собой логическое состояние экземпляра окружающего класса. Этот вложенный класс, известный как агент сериализации, должен иметь один конструктор, типом па­ раметров которого является окружающий класс. Этот конструктор просто копирует данные из его аргумента: ему не требуется провер­ ка целостности или резервное копирование. С точки зрения дизайна сериализованная форма агента сериализации по умолчанию является

430

С татья 78

совершенной сериализованной формой окружающего класса. И окру­ жающий класс, и его агент сериализации должны быть декларирова­ ны так, чтобы реализовывать Serializable.

Например, рассмотрим неизменяемый класс Period, написанный в статье 39 и сериализованный в статье 76. Вот агент сериализации для этого класса. Period настолько прост, что его агент сериализации содержит в точности те же самые поля, что и класс:

// Агент сериализации класса Period

private static class SerializationProxy implements Serializable { private final Date start;

private final Date end; SerializationProxy(Period p) {

this.start = p.start; this.end = p.end;

}

private static final long serialVersionlllD = 234098243823485285L; // Any number will do (Item 75)

}

Затем добавьте следующий метод writeReplace к окружающе­ му классу. Этот метод можно дословно скопировать в любой класс

сагентом сериализации:

//writeReplace method for the serialization proxy pattern private Object writeReplace() {

return new SerializationProxy(this);

}

Присутствие этого метода заставляет систему сериализации выдать экземпляр SerializzationProxy вместо экземпляра окру­ жающего класса. Другими словами, метод writeReplace переводит экземпляр окружающего класса в его агент сериализации до самой сериализации.

При использовании метода writeReplace система сериализации никогда не выдаст сериализованный экземпляр окружающего клас­ са, но его можно сфабриковать при попытке злонамеренно разрушить

431

Глава 11 Сериализация

инварианты класса. Для того чтобы гарантировать, что такая атака не удастся, просто добавьте метод readObject к окружающему классу:

// Метод readObject для шаблона агента сериализации private void readObject(ObjectInputStream stream) throws InvalidObjectException {

throw new InvalidObjectException(“Proxy required”);

}

Наконец, предоставьте метод readResolve классу SerializationProxy, который возвратит логически эквивалентный экземпляр окру­ жающего класса. Присутствие этого метода приводит к тому, что система сериализации переводит агента сериализации обратно в эк­ земпляр окружающего класса при десериализации.

Этот метод readResolve создает экземпляр окружающего класса, используя только открытый API, и в этом и заключается вся красота шаблона. Он в большей степени избегает неязыковой сути сериали­ зации, потому что создается десериализованный экземпляр с исполь­ зованием тех же самых конструкторов, методов статической генера­ ции, как при создании любого другого экземпляра. Это освобождает вас от необходимости отдельно проверять, чтобы десериализованные экземпляры подчинялись инвариантам класса. Если методы стати­ ческой генерации класса или конструкторы устанавливают эти ин­ варианты и методы его экземпляра поддерживают их, то у вас есть гарантия, что сериализация будет также их поддерживать.

Вот пример метода readResolve для вышеупомянутого Period.

SerializationProxy

// Метод readResolve для Period.SerializationProxy private Object readResolve() {

return new Period(start, end); // Uses public constructor

}

Как и подход с использованием резервного копирования (ста­ тья 76), подход с использованием агента сериализации препятствует тяжелым бит-потоковым атакам (статья 76) и атакам кражи вну­

432

С татья 78

треннего поля (статья 76). В отличие от двух предыдущих подходов этот позволяет полю, принадлежащему к Period, быть завершенным, что требуется для того, чтобы класс Period был на самом деле не­ изменяемым (статья 15). И в отличие от двух предыдущих подхо­ дов он не требует длительного размышления. Вам не нужно думать о том, какие поля могут быть дискредитированы при атаках сериали­ зации, вам также не нужно явно выполнять проверку действительно­ сти в качестве части десериализации.

Рассмотрим случай с EnumSet (статья 32). У этого класса нет от­ крытого конструктора, только методы статической генерации. С точ­ ки зрения клиента, она возвращает экземпляры EnumSet, но на самом деле она возвращают один или два подкласса, в зависимости от раз­ мера основного перечислимого типа (статья 1). Если у основного пе­ речислимого типа 64 или менее элементов, то методы статической генерации выдают Regula гEnumSet; в противном случае они возвра­ щают JumboEnumSet. Теперь посмотрим, что происходит, если вы се­ риализуете набор перечислимых типов, в котором перечислимый тип содержит 60 элементов, затем добавите к нему еще пять элемен­ тов и десериализуете набор. При сериализации это был экземпляр RegularEnumSet, но лучше бы ему быть JumboEnumSet при десериали­ зации. На самом деле это точно то, что и происходит, потому что EnumSet использует шаблон агента сериализации. Если вам интерес­ но, вот как выглядит агент сериализации EnumSet. Он действительно настолько прост:

// Агент сериализации EnumSet

private static class SerializationProxy <E extends Enum<E>> implements Serializable {

//Тип элементов данного набора перечислимых типов private final Class<E> elementType;

//Элементы, содержащиеся в данном наборе перечислимых типов private final Enum[] elements;

SerializationProxy(EnumSet<E> set) { elementType = set.elementType;

elements = set.toArray(EMPTY_ENUM_ARRAY); // (Item 43)

433

Глава 11 Сериализация

}

private Object readResolve() {

EnumSet<E> result = EnumSet.noneOf(elementType); for (Enum e : elements)

result.add((E)e); return result;

}

private static final long serialVersionUID = 362491234563181265L;

}

У шаблона агента сериализации есть два ограничения. Он несо­ вместим с классами, расширяемыми своими клиентами (статья 17). Он также несовместим с некоторыми классами, диаграммы объек­ тов которых содержат цикличности: если вы попытаетесь запустить метод на объекте в рамках метода readResolve агента сериализации, то получите ошибку ClassCastException, так как у вас еще нет объек­ та, а только его агент сериализации.

Наконец, дополнительные возможности и безопасность шаблона агента сериализации не свободны. Но моей машине на 14% более затратно сериализовывать и десериализовывать экземпляры Period с помощью агента сериализации, чем с помощью резервного копиро-

ВЭ.НИЯ.

Подведем итоги. Рассмотрите шаблон агента сериализации каж­ дый раз, когда вам приходится писать методы readObject или writeObject на классе, который нерасширяем для своих клиентов. Этот ша­ блон, возможно, является простейшим путем сериализации объектов с нетривиальными инвариантами.

434

Список литературы

[ A m o ld 0 5 ]

A rn o ld ,

K e n ,

Ja m e s

G o slin g ,

an d

D a v id H o lm e s. The Java™

 

Programming

Language,

Fourth

Edition. A d d iso n - W e sle y ,

 

B o sto n ,

 

2 0 0 5 .

I S B N :

0 3 2 1 3 4 9 8 0 6 .

 

 

 

 

[A sse r ts]

Programming

with

Assertions.

S u n

M icro sy ste m s.

 

2 0 0 2 .

 

< h t t p : / / ja v a .s u n .c o m / ja v a s e / 6 / d o c s / te c h n o te s / g u id e s /

 

la n g u a g e /a sse rt.h tm l>

 

 

 

 

 

 

 

 

 

[ B e c k 9 9 ]

B e ck ,

K en t.

Extreme

Programming

Explained: Embrace

 

Change.

A d d iso n -W e sle y ,

 

R e a d in g ,

M A ,

1 9 9 9 .

I S B N :

 

0 2 0 1 6 1 6 4 1 6 .

 

 

 

 

 

 

 

 

 

 

 

 

[B e c k 0 4 ]

B e ck ,

K e n t.

JUnit

Pocket

Guide. O ’ R eilly

M e d ia ,

In c.,

 

S e b a sto p o l,

C A ,

2 0 0 4 . I S B N :

0 5 9 6 0 0 7 4 3 4 .

 

 

 

[B lo c h O l]

B lo ch , Jo sh u a . Effective Java™ Programming Language Guide.

 

A d d iso n -W e sle y ,

B o sto n ,

2 0 0 1 . I S B N :

0 2 0 1 3 1 0 0 5 8 .

 

 

[B lo c h 0 5 ]

B lo ch , Jo sh u a, an d N e a l G after. Java™ Puzzlers: Traps, Pitfalls,

 

and Corner

Cases. A d d iso n -W e sle y ,

B o sto n ,

2 0 0 5 .

I S B N :

 

0 3 2 1 3 3 6 7 8 X .

 

 

 

 

 

 

 

 

 

 

 

 

[B lo c h 0 6 ]

B lo ch ,

Jo sh u a .

C ollection s.

In

The Java™ Tutorial: A

 

Short

 

Course on the Basics, Fourth Edition. S h aro n

Z a k h o u r

et al.

 

A d d iso n -W e sle y ,

B o sto n , 2 0 0 6 .

I S B N : 0 3 2 1 3 3 4 2 0 5 .

 

P a g e s

 

2 9 3 —3 6 8 .

A lso

available

 

as

< h t t p :/ / ja v a .s u n .c o m / d o c s /

b oo k s / tutorial / collections / in dex .h tm l> .

Список литературы

[Bracha04]

Bracha, Gilad. Generics in theJava Programming Language. 2004.

 

<http: / /java.sun.com/j2se/1 .3/pdf/generics-tutorial.pdf>

[BurnOl]

Burn, Oliver. Checkstyle. 2001—2007.

 

<http: / / checkstyle.sourceforge.net>

[Collections]

The Collections Framework. Sun Microsystems. March 2006.

 

<http: / /java.sun.com / javase/ 6 / docs / technotes / guides /

 

collections/ index.html>

[Gafter07]

Gafter, Neal. A Limitation of Super Type Tokens. 2007.

 

<http: / / gafter.blogspot.com / 2007/ 0 5 /limitation-of-super-

 

type-tokens.html>

[Gamma95]

Gamma, Erich, Richard Helm, Ralph Johnson, and John

 

Vlissides. Design Patterns: Elements of Reusable Object-

 

Oriented Software. Addison-Wesley, Reading, MA, 1995.

 

ISBN: 0201633612.

[Goetz06]

Goetz, Brian, with Tim Peierls et al. Java Concurrency in

 

Practice. Addison-Wesley, Boston, 2006. ISBN: 0321349601.

[Gong03]

Gong, Li, Gary Ellison, and Mary Dageforde. Inside Java™

 

2 Platform Security, Second Edition. Addison-Wesley, Boston,

 

2003. ISBN: 0201787911.

[H TM L401]

HTML 4.01 Specification. World Wide Web Consortium.

 

December 1999.

 

<http:/ / www.w3.org/TR/1999/REC-html401-19991224/>

[Jackson75]

Jackson, M. A. Principles of Program Design. Academic Press,

 

London, 1975. ISBN: 0123790506.

[Java5-feat]

New Features and Enhancements J2SE 5.0. Sun Microsystems.

 

2004.

 

<http: / / java.sun.com / j2se/1 .5 .0 /docs / relnotes / features.

 

html>

436

Список литературы

[Java6-feat]

Java™ SE 6 Release Notes: Features and Enhancements. Sun

 

Microsystems. 2008.

 

<http: / / java.sun.com / javase/ 6 / webnotes/ features.html>

[JavaBeans]

J avaBeans™ Spec. Sun Microsystems. March 2001.

 

<http: / /java.sun.com/products/javabeans/docs/spec.html>

[Javadoc-5.0]

What's New in Javadoc 5.0. Sun Microsystems. 2004.

 

< http: / /java.sun .com /j2se /1 .5 .0 /d o cs / guide/javadoc/

 

whatsnew-1.5.0.html>

[Javadoc-guide]

How to Write Doc Comments for the Javadoc Tool. Sun

 

Microsystems. 2000—2004.

 

<http: / /java.sun.com/j2se/javadoc/writingdoccomments/

 

index.html>

[Javadoc-ref] Javadoc Reference Guide. Sun Microsystems. 2002—2006.

<http:/ /java.sun.com /javase / 6 / docs / technotes/tools / solaris/javadoc.html>

<http: / /java.su n .com /javase/6 / d ocs/tech n otes/tools/ windows/ javadoc.html>

[JavaSE6]

Java™ Platform, Standard Edition 6 A PI Specification. Sun

 

Microsystems. March 2006.

 

 

<http: / / java.sun.com/ javase/ 6 / docs/api / >

[J^]

Gosling, James, Bill Joy, and Guy Steele, and Gilad Bracha.

 

The Java™ Language Specification, Third Edition. Addison-

 

Wesley, Boston, 2005. ISBN: 0321246780.

[Kahan91]

Kahan, William, andJ. W. Thomas.Augmenting a Programming

 

Language with Complex Arithmetic.

U C B /C SD -91 -667,

 

University of California, Berkeley, 1991.

 

[Knuth74]

Knuth, Donald. Structured Programming with go to Statements.

 

In Computing Surveys 6 (1974): 261—301.

[Langer08]

Langer, Angelika. Java Generics FAQs

Frequently Asked

 

Questions. 2008.

 

437

Список литературы

 

<http: / / www.angelikalanger.com/ GenericsFAQ/JavaGenerics

 

FAQ.html>

 

[LeaOO]

Lea, Doug. Concurrent Programming in Java™: Design

 

Principles and Patterns, Second Edition, Addison-Wesley,

 

Boston, 2000. ISBN : 0201310090.

 

[Lieberman86]

Lieberman, Henry. Using Prototypical Objects to Implement

 

Shared Behavior in Object-Oriented Systems. In Proceedings of

 

the First ACM Conference on Object-Oriented Programming

 

Systems, Languages, and Applications, pages 214—223,

 

Portland, September 1986. ACM Press.

 

[Liskov87]

Liskov, B. Data Abstraction and Hierarchy. In Addendum to

 

the Proceedings of OOPSLA ‘87 and SICPLAN Notices, Vol.

 

23, No. 3 :1 7 -3 4 , May 1988.

 

[Meyers98]

Meyers, Scott. Effective C + + , Second Edition: 50 Specific

 

Ways to Improve Your Programs and Designs. Addison-Wesley,

 

Reading, MA, 1998. ISBN: 0201924889.

 

[Naftalin07]

Naftalin, Maurice, and Philip Wadler. Java Generics and

 

Collections. O ’Reilly Media, Inc., Sebastopol, CA, 2007.

 

ISBN: 0596527756.

 

[Parnas72]

Parnas, D. L. On the Criteria to Be Used in Decomposing

 

Systems into Modules. In Communications

of the ACM 15

 

(1972): 1053-1058.

 

[Posix]

9945-1:1996 (ISO /IE C ) [IE E E /A N SI

Std. 1003.1 1995

 

Edition] Information Technology— Portable Operating System

 

Interface (P O S IX )— Part 1: System Application: Program

 

Interface (A PI) C Language] (A N SI), IE E E Standards Press,

 

ISBN: 1559375736.

 

[PughOl]

The "Double-Checked Locking is Broken” Declaration. Ed.

 

William Pugh. University of Maryland. March 2001.

<http: / / www.cs.umd.edu / ~pugh / java/m em ory Model / DoubleCheckedLocking.html>

438

Список литературы

[Serialization]

Java™ Object Serialization Specification. Sun Microsystems.

 

March 2003.

 

<http: / /java, sun.com/iavase/ 6 /docs/platform/serialization/

 

spec/serialTOC.html>

[Sestoft05]

Sestoft, Peter. Java Precisely, Second Edition. The M IT Press,

 

Cambridge, MA, 2003. ISBN: 0262693259.

[Smith62]

Smith, Robert. Algorithm 116 Complex Division. In

 

Communications of the ACM, 5.8 (August 1962): 435.

[Snyder86]

Snyder, Alan. Encapsulation and Inheritance in Object-Oriented

 

Programming Languages. In Object-Oriented Programming

 

Systems, Languages, and Applications Conference Proceedings,

 

3 8 -4 5 , 1986. ACM Press.

[Thomas94]

Thomas, Jim, and Jerome T . Coonen. Issues Regarding

 

Imaginary Types for C and C + + . In The Journal of C Language

 

Translation, 5.3 (March 1994): 134—138.

[ThreadStop]

Why Are Thread, stop, Thread, suspend, Thread, re­

 

sume and Runtime. runFinalizersOnExit Deprecated? Sun

 

Microsystems. 1999.

 

< http: / /java.sun .com / j2 s e /1 .4 .2 / d o c s / guide / m i s c /

 

threadPrimitiveDeprecation.html>

[ViegaOl]

Viega, John, and Gary McGraw. Building Secure Software:

 

How to Avoid Security Problems the Right Way. Addison-

 

Wesley, Boston, 2001. ISBN: 020172152X.

[W3C -validator] W3C Markup Validation Service. World Wide Web Consortium.

 

2007.

 

<http: / / validator.w3.org/>

[Wulf72]

Wulf, W. A Case Against the G O TO . In Proceedings of the

 

25th ACM National Conference 2 (1972): 791—797.

439

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]