<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Блог о Java технологиях &#187; JPA</title>
	<atom:link href="http://java.in.ua/category/java/jpa/feed/" rel="self" type="application/rss+xml" />
	<link>http://java.in.ua</link>
	<description></description>
	<lastBuildDate>Tue, 19 Jul 2011 12:39:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Алгоритм сериализации объектов в Java</title>
		<link>http://java.in.ua/2009/06/11/java_serialization_algorithm/</link>
		<comments>http://java.in.ua/2009/06/11/java_serialization_algorithm/#comments</comments>
		<pubDate>Thu, 11 Jun 2009 11:26:35 +0000</pubDate>
		<dc:creator>Evgenij Nerush</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JPA]]></category>
		<category><![CDATA[Serialization]]></category>

		<guid isPermaLink="false">http://java.in.ua/?p=733</guid>
		<description><![CDATA[Сериализацией (Serialization) называют процесс сохранения состояния объекта в последовательность байт, в то время как десериализацией называют обратный процесс, формирующий объект из последовательности байт. Java Serialization API предоставляет разработчикам механизм, позволяющий производить сериализацию/десериализацию объектов. В этой статье вы узнаете, как сериализовать объект, и когда сериализация является необходимой. Вы так же узнаете, как работает алгоритм сериализации в [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-medium wp-image-370" title="java_starting" src="http://java.in.ua/wp-content/uploads/2008/12/java_starting-300x300.jpg" alt="" width="144" height="144" />Сериализацией (<a title="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf" href="http://en.wikipedia.org/wiki/Serialization" target="_blank">Serialization</a>) называют процесс сохранения состояния объекта в последовательность байт, в то время как десериализацией называют обратный процесс, формирующий объект из последовательности байт. <a href="http://java.sun.com/developer/technicalArticles/Programming/serialization/" target="_blank">Java Serialization API</a> предоставляет разработчикам механизм, позволяющий производить сериализацию/десериализацию объектов. В этой статье вы узнаете, как сериализовать объект, и когда сериализация является необходимой. Вы так же узнаете, как работает алгоритм сериализации в Java на примере, иллюстрирующем формат сериализации объектов на низком уровне.</p>
<p><strong>Итак, зачем нужна сериализация?</strong></p>
<p>На сегодняшний день, традиционное приложение уровня предприятия состоит из разнообразных компонентов и распределено между различными системами и сетями. В Java всё представлено в качестве объектов (за исключением примитивных типов); для того, чтобы два объекта могли взаимодействовать между собой, должен существовать механизм, позволяющий обмениваться данными. Одним из путей достижения такого взаимодействия может служить разработка протокола обмена объектами. В этом случае получатель объекта должен работать по такому же протоколу, по которому работает отправитель объекта, что в свою очередь может привести к затруднениям при интеграции ваших компонентов со сторонними компонентами. Из этого следует, что протокол должен быть простым и обобщённым, что в свою очередь в Java достигается с помощью сериализации.<span id="more-733"></span></p>
<p>Рисунок 1 иллюстрирует взаимодействие &#8220;клиент/сервер&#8221;, в котором объект передаётся от клиента к серверу через сериализацию.</p>
<p><img class="aligncenter size-full wp-image-806" title="jtip050709-fig1" src="http://java.in.ua/wp-content/uploads/2009/06/jtip050709-fig1.gif" alt="" width="500" height="223" /></p>
<p><strong>Рисунок 1. Сериализация в действии</strong></p>
<p><strong>Как сериализовать объект</strong></p>
<p>Для того, чтобы объект был сериализуемым, класс этого объекта должен реализовывать интерфейс  java.io.Serializable. Листинг 1 демонстрирует пример реализации данного интерфейса.</p>
<p><strong>Листинг 1. Реализация интерфейса java.io.Serializable</strong></p>
<pre class="brush: java; title: ; notranslate">import java.io.Serializable;

class TestSerial implements Serializable {
    public byte version = 100;
    public byte count = 0;
}</pre>
<p>Интерфейс java.io.Serializable не содержит методов и является маркером, который говорит механизму сериализации о том, что объект, реализующий данный интерфейс, может быть сериализован.</p>
<p>Теперь, когда у нас уже есть класс, реализующий интерфейс java.io.Serializable, следующим шагом станет написание алгоритма, ответственного за сериализацию экземпляра класса TestSerial, что приведено в Листинге 2.</p>
<p><strong>Листинг 2. Реализация алгоритма сериализации</strong></p>
<pre class="brush: java; title: ; notranslate">public static void main(String args[]) throws IOException {
    FileOutputStream fos = new FileOutputStream(&quot;temp.out&quot;);
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    TestSerial ts = new TestSerial();
    oos.writeObject(ts);
    oos.flush();
    oos.close();
}</pre>
<p>Код, приведённый в Листинге 2, сериализует состояние экземпляра класса TestSerial в файл temp.out. Для воссоздания объекта, нужно произвести десериализацию, как показано в Листинге 3.</p>
<p><strong>Листинг 3. Воссоздание сериализованного объекта</strong></p>
<pre class="brush: java; title: ; notranslate">public static void main(String args[]) throws IOException {
    FileInputStream fis = new FileInputStream(&quot;temp.out&quot;);
    ObjectInputStream oin = new ObjectInputStream(fis);
    TestSerial ts = (TestSerial) oin.readObject();
    System.out.println(&quot;version=&quot;+ts.version);
}</pre>
<p>В Листинге 3, восстановление объекта осуществляется с помощью вызова oin.readObject() метода. Так как этот метод может считывать любой сериализуемый объект, приведение объекта к определённому классу является обязательным. При выполнении данного кода на экран будет выведено сообщение &#8220;<code>version=100</code>&#8220;.</p>
<p><strong>Формат сериализации объекта</strong></p>
<p>Прежде всего, давайте рассмотрим содержимое файла temp.out в шестнадцатиричном формате, приведённое в Листинге 4.</p>
<p><strong>Листинг 4. Представление сериализуемого объекта в шестнадцатиричном формате<br />
</strong></p>
<pre class="brush: java; title: ; notranslate">AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64</pre>
<p>Обратив внимание на класс TestSerial. Вы увидите, что он содержит только два байтовых поля, как показано в Листинге 5.</p>
<p><strong>Листинг 5. Поля класса TestSerial</strong></p>
<pre class="brush: java; title: ; notranslate">    public byte version = 100;
    public byte count = 0;</pre>
<p>Размер каждого из полей состовляет один байт, таким образом, итоговый размер объекта (без заголовков) состовляет два байта. Но если мы посмотрим на размер сериализованного объекта, приведённого в Листинге 4, мы увидим не 2 байта, а 51 байт. Сюрприз! Откуда появились дополнительные байты и какое их предназначение? Дополнительные байты были добавлены алгоритмом сериализации и являются жизненно важными при десериализации.</p>
<p><strong>Алгоритм сериализации в Java</strong></p>
<p>Теперь, когда мы уже знаем, как сериализовать объект, перед нами возникает другой вопрос, каким образом сериализация работает на низком уровне ? Ответ на данный вопрос дают следующие пункты:</p>
<ul>
<li>прежде всего происходит запись метаданных класса, ассоциированного с конкретным экземпляром данного класса</li>
<li>затем происходит рекурсиваня запись описания суперкласса до тех пор, пока не будет достигнут суперкласс типа java.lang.Object</li>
<li>после того, как метаданные были успешно записаны, начинается процесс записи данных экземпляра класса, причем процесс записи начинается с самого верхнего суперкласса</li>
<li>и наконец после того, как данные самого верхнего суперкласса были записаны, алгоритм сериализации рекурсивно проходит по иерархии наследования вниз к производному классу ( экземпляр которого сериализуется) и одновременно с этим проходом записывает данные, описание которых принадлежит итерируемому классу</li>
</ul>
<p>Рассмотрим сериализацию объектов на другом примере, описывающем более широкую иерархию наследования классов. Смотрите Листинг 6.</p>
<p><strong>Листинг 6. Другой пример сериализации объекта</strong></p>
<pre class="brush: java; title: ; notranslate">class Parent implements Serializable {
    int parentVersion = 10;
}

public class Contain implements Serializable {
    int containVersion = 11;
}

public class TestSerial extends Parent implements Serializable {

	int version = 66;
	Contain con = new Contain();

	public int getVersion() {
		return version;
	}

	public static void main(String args[]) throws IOException {
		FileOutputStream fos = new FileOutputStream(&quot;c:\\temp.out&quot;);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		TestSerial st = new TestSerial();
		oos.writeObject(st);
		oos.flush();
		oos.close();
	}
}</pre>
<p>Этот пример довольно простой. Он сериализует экземпляр класса TestSerial, который расширяет Parent класс и содержит экземпляр класса Contain. Представление сериализованного объекта в шестандцатиричном формате приведено в Листинге 7.</p>
<p><strong>Листинг 7. Представление сериализуемого объекта в шестнадцатиричном формате</strong></p>
<pre class="brush: java; title: ; notranslate">AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07
76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09
4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72
65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00
0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70
00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74
61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00
0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78
70 00 00 00 0B</pre>
<p>На рисунке 2 изображена последовательность выполнения алгоритма сериализации.</p>
<p><img class="aligncenter size-full wp-image-804" title="diagram" src="http://java.in.ua/wp-content/uploads/2009/06/diagram.gif" alt="" width="350" height="711" /></p>
<p style="text-align: center;">
<p><strong>Рисунок 2. Последовательность выполнения алгоритма сериализации</strong></p>
<p>Давайте детально рассмотрим представление сериализуемого объекта, приведённое в Листинге 7. Начнем с информации, которая отвечает за идентификацию протокола сериализации:</p>
<ul>
<li>AC ED: STREAM_MAGIC, определение протокола сериализации</li>
<li>00 05: STREAM_VERSION, версия сериализации</li>
<li>0&#215;73: TC_OBJECT, определение нового объекта</li>
</ul>
<p>Первым шагом алгоритма сериализации является запись метаданных класса сериализуемого экземпляра.</p>
<ul>
<li>0&#215;72: TC_CLASSDESC, определение данного класса как нового класса</li>
<li>00 0A: длинна имени класса.</li>
<li>53 65 72 69 61 6c 54 65 73 74: имя класса TestSerial</li>
<li>05 52 81 5A AC 66 02 F6: serialVersionUID класса</li>
<li>0&#215;02: этот флаг говорит о том, что объект поддерживает сериализацию</li>
<li>00 02: количество полей сериализуемого класса</li>
</ul>
<p>Далее, алгоритм записывает поле int version = 66;</p>
<ul>
<li>0&#215;49: код типа поля. 49 представляет &#8220;I&#8221;, т.е. Int</li>
<li>00 07: длинна имени поля</li>
<li>76 65 72 73 69 6F 6E: имя поля version</li>
</ul>
<p>После чего, алгоритм записывает следующее поле: Contain con = new Contain();.</p>
<ul>
<li>0&#215;74: TC_STRING: представляет новую строку</li>
<li>00 09: длинна строки</li>
<li>4C 63 6F 6E 74 61 69 6E 3B: contain;, каноническая  JVM синатура</li>
<li>0&#215;78: TC_ENDBLOCKDATA, конец опционального блока данных для объекта</li>
</ul>
<p>Следующим этапом алгоритма является запись определения Parent класса, который является суперклассом класса TestSerial.</p>
<ul>
<li>0&#215;72: TC_CLASSDESC, определяет новый класс</li>
<li>00 06: длинна имени класса</li>
<li>70 61 72 65 6E 74: имя класса TestSerial</li>
<li>0E DB D2 BD 85 EE 63 7A: serialVersionUID класса</li>
<li>0&#215;02: этот флаг говорит о том, что объект поддерживает сериализацию</li>
<li>00 01: количество полей в классе</li>
</ul>
<p>После того, как алгоритм записал информацию о Parent классе, выполнение переходит к записи информации, описывающей поля класса и их содержимое. В нашем случае класс содержит одно предварительно проинициализированное поле int parentVersion = 100;.</p>
<ul>
<li>0&#215;49: код типа поля, 49 представляет &#8220;I&#8221;, т.е. Int</li>
<li>00 0D: длинна имени поля</li>
<li>70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion, имя поля</li>
<li>0&#215;78: TC_ENDBLOCKDATA, конец опционального блока данных для объекта</li>
<li>0&#215;70: TC_NULL, этот байт говорит нам о том, что даный класс не имеет суперклассов и является корневым в иерархии наследования</li>
</ul>
<p>Итак, на данном этапе алгоритм сериализации записал метаданные класса, ассоциируемого с экземпляром, а так же метаданные суперкласса класса сериализуемого экземпляра. Далее алгоритм записывает данные, ассоциируемые с экземпляром. Прежде всего это значиния суперклассов (в нашем случае значение поля parentVersion класса Parent), после чего данные класса сериализуемого экземпляра (в нашем случае данные полей класса TestSerial):</p>
<ul>
<li>00 00 00 0A: 10, значение поля parentVersion</li>
<li>00 00 00 42: 66, значение поля version</li>
</ul>
<p>Следующие байты вызывают особый интерес. Алгоритму необходимо записать информацию об экземпляре класса Contain, приведённом в Листинге 8.</p>
<p><strong>Листинг 8. Экземпляр класса Contain</strong></p>
<pre>Contain con = new Contain();</pre>
<p>Далее, алгоритм сериализации записывает метаданные класса Contain:</p>
<ul>
<li>0&#215;73: TC_OBJECT, назначение нового объекта</li>
<li>0&#215;72: TC_CLASSDESC, определяет новый класс</li>
<li>00 07: длинна имени класса</li>
<li>63 6F 6E 74 61 69 6E: contain, имя поля класса</li>
<li>FC BB E6 0E FB CB 60 C7: serialVersionUID класса</li>
<li>0&#215;02: этот флаг говорит о том, что объект поддерживает сериализацию</li>
<li>00 01: количество полей в классе</li>
</ul>
<p>После чего очередь переходит к записи данных о поле containVersion:</p>
<ul>
<li>0&#215;49: код типа поля, 49 представляет &#8220;I&#8221;, т.е. Int</li>
<li>00 0E: длинна имени поля</li>
<li>63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: имя поля containVersion</li>
<li>0&#215;78: TC_ENDBLOCKDATA, конец опционального блока данных для объекта</li>
</ul>
<p>После записи вышеперечисленных байт, алгоритм проверят класс Contain на наличие суперкласса. Если таков существует в иерархии наследования, алгоритм переходит к записи метаданных суперкласса. В нашем случае у класса Contain нет родителя, следовательно, алгоритм записывает TC_NULL:</p>
<ul>
<li>0&#215;70: TC_NULL</li>
</ul>
<p>В конечном итоге, алгоритм записывает данные полей класса Contain:</p>
<ul>
<li>00 00 00 0B: 11, значение поля containVersion</li>
</ul>
<p>Настал момент вздохнуть с облегчением &#8211; все байты рассмотрены.</p>
<p><strong>Заключение</strong></p>
<p>В данной статье мы познакомились с механизмом сериализации объектов в Java, а так же рассмотрели работу алгоритма сериализации в деталях. Надеюсь, полученная информация в достаточной мере помогла Вам развеять все страхи при произнесении такого магического слова, как сериализация <img src='http://java.in.ua/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .</p>
<p><strong>Примечание автора перевода</strong></p>
<p>За возможные ошибки в переводе прошу сильно не пинать. Спасибо за внимание <img src='http://java.in.ua/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p><span style="color: #c0c0c0;">Источник: http://www.javaworld.com/community/node/2915</span></p>
<div><script type="text/javascript" src="http://odnaknopka.ru/wp/ok2.utf8.js"></script><script type="text/javascript">okbm("http://java.in.ua/2009/06/11/java_serialization_algorithm/","Алгоритм сериализации объектов в Java")</script></div>]]></content:encoded>
			<wfw:commentRss>http://java.in.ua/2009/06/11/java_serialization_algorithm/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Какими должны быть EntityBean&#8217;ы?</title>
		<link>http://java.in.ua/2008/11/12/entitybean/</link>
		<comments>http://java.in.ua/2008/11/12/entitybean/#comments</comments>
		<pubDate>Wed, 12 Nov 2008 10:36:25 +0000</pubDate>
		<dc:creator>Evgenij Nerush</dc:creator>
				<category><![CDATA[JPA]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[OpenJPA]]></category>

		<guid isPermaLink="false">http://java.in.ua/?p=241</guid>
		<description><![CDATA[Вот уже в который раз мне пришлось исправлять ранее написанные сущностные бины (в моем случае это OpenJPA) таким образом, что бы они соответствовали следующим требованиям: Каждый класс должен быть объявлен с модификатором public Каждый класс должен реализовывать интерфейс Serializable Каждый класс должен иметь публичный конструктор без аргументов Если класс является внутренним, он должен быть статическим [...]]]></description>
			<content:encoded><![CDATA[<p>Вот уже в который раз мне пришлось исправлять ранее написанные сущностные бины (в моем случае это OpenJPA) таким образом, что бы они соответствовали следующим требованиям:</p>
<ol>
<li>Каждый класс должен быть объявлен с модификатором public</li>
<li>Каждый класс должен реализовывать интерфейс Serializable</li>
<li>Каждый класс должен иметь публичный конструктор без аргументов</li>
<li>Если класс является внутренним, он должен быть статическим</li>
<li>Метод equals должен быть реализован таким образом, чтобы он обеспечивал уникальность сущности в соответствии с теми полями, которые непосредственно обеспечивают уникальность в таблице.<span id="more-241"></span></li>
</ol>
<p>Рассмотрим следущую сущность в качестве шаблона</p>
<pre class="brush: java; title: ; notranslate">@Entity
@Table(name = &quot;BOOKS&quot;)
public class Book implements Serializable {

    private static final long serialVersionUID = -6222821312345685779L;

    @Id
    @Column(name = &quot;ID&quot;)
    private Integer id;

    @Column(name = &quot;NAME&quot;)
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode(){
        int hash = 3;
        hash = 29 * hash + (this.id != null ? this.id.hashCode() : 0);
        hash = 29 * hash + (this.name != null ? this.name.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof Book))
            return false;
        final Book other = (Book) obj;
        return (this.id == other.id || (this.id != null &amp;amp;&amp;amp; this.id.equals(other.id)));
    }

}</pre>
<p>Прошу обратить Ваше внимание на то, как реализован метод equals <img src='http://java.in.ua/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> , о <a href="http://java.in.ua/2008/11/03/orm-%d0%b8-%d0%bf%d0%be%d0%b4%d0%b2%d0%be%d0%b4%d0%bd%d1%8b%d0%b5-%d0%ba%d0%b0%d0%bc%d0%bd%d0%b8-%d1%80%d0%b5%d0%b0%d0%bb%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d0%b8-equals-%d0%b8-hashcode">хитростях реализации которого я недавно писал в одном из моих предыдущих постов</a> <img src='http://java.in.ua/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<div><script type="text/javascript" src="http://odnaknopka.ru/wp/ok2.utf8.js"></script><script type="text/javascript">okbm("http://java.in.ua/2008/11/12/entitybean/","Какими должны быть EntityBean&amp;#8217;ы?")</script></div>]]></content:encoded>
			<wfw:commentRss>http://java.in.ua/2008/11/12/entitybean/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ORM и подводные камни реализации equals и hashCode.</title>
		<link>http://java.in.ua/2008/11/03/orm-%d0%b8-%d0%bf%d0%be%d0%b4%d0%b2%d0%be%d0%b4%d0%bd%d1%8b%d0%b5-%d0%ba%d0%b0%d0%bc%d0%bd%d0%b8-%d1%80%d0%b5%d0%b0%d0%bb%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d0%b8-equals-%d0%b8-hashcode/</link>
		<comments>http://java.in.ua/2008/11/03/orm-%d0%b8-%d0%bf%d0%be%d0%b4%d0%b2%d0%be%d0%b4%d0%bd%d1%8b%d0%b5-%d0%ba%d0%b0%d0%bc%d0%bd%d0%b8-%d1%80%d0%b5%d0%b0%d0%bb%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d0%b8-equals-%d0%b8-hashcode/#comments</comments>
		<pubDate>Mon, 03 Nov 2008 16:59:03 +0000</pubDate>
		<dc:creator>Evgenij Nerush</dc:creator>
				<category><![CDATA[JPA]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://java.in.ua/?p=201</guid>
		<description><![CDATA[Думаю каждому, кому приходилось работать в плотную с ORM (аля Hibernate, TopLink, OpenJPA, &#8230;), приходилось сталкиваться с подводными камнями при реализации классов. Тоже самое случилось и со мной, когда мне поручили искать бажину в одном из наших приложений &#8230;. окна дебага поглотили меня не на один час&#8230; Проблема заключалась в том, что при вызове утильного [...]]]></description>
			<content:encoded><![CDATA[<p>Думаю каждому, кому приходилось работать в плотную с ORM (аля <a href="http://hibernate.org">Hibernate</a>, <a href="http://www.oracle.com/technology/products/ias/toplink/index.html">TopLink</a>, <a href="http://openjpa.apache.org/">OpenJPA</a>, &#8230;), приходилось сталкиваться с подводными камнями при реализации классов. Тоже самое случилось и со мной, когда мне поручили искать бажину в одном из наших приложений &#8230;. окна дебага поглотили меня не на один час&#8230; Проблема заключалась в том, что при вызове утильного метода <strong>ListUtils.subtract(list1, list2)</strong> (данный метод исключает list2 из list1) на выходе получалось совсем не то что ожидалось, а получалось так потому, что лажа скрывалась в реализации метода equals. Просто не нужно в equals обрабатыать ВСЕ поля класса, ну не нужно, я Вас умоляю. В моём случае в equals обрабатывалось поле lastUpdated &#8211; о чём это говорит, думаю Вы догадываетесь. Именно по этой причине некоторые классы входящие в список list2 не исключались из списка классов list1, которые были детачены ранее. Плюс ко всему, <strong>старайтесь реализовывать метод equals таким образом, что бы он обеспечивал УНИКАЛЬНОСТЬ сущности в соответствии с теми полями, которые непосредственно обеспечивают уникальность в таблице</strong>! <span id="more-201"></span></p>
<p>Есть вопросы? &#8211; пишем комменты )) Идём дальше. Если мы используем lazy loading, мы должны знать, что во многих случаях мы работаем с объектами через динамический прокси во избежание их предварительной загрузки. Это говорит нам о том, что эти самые прокси реализованы как подклассы класса, экземпляр которого загружается, и выражение this.getClass().equals(o.getClass()) вернёт false. Рассмотрим на примере:</p>
<pre class="brush: java; title: ; notranslate">User saved = new User(&quot;Irina Alkaeva&quot;);
Long key = dao.save(saved);
dao.flush();
User retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass());
// Will return false if User is loaded lazy</pre>
<p><strong>В этом случае вместо equals() спасёт instanceof User, так как именно он обеспечит правильное поведение.</strong></p>
<p>Есть вопросы? &#8211; пишем комменты )) Работаем дальше с lazy loading. ORM обычно используют геттеры для лейзи лоадинга объектов, таким образом значение поля user.username будет равно null, если мы предварительно не обратимся к методу объекта user.getUsername(), поэтому <strong>принудительно советую в реализации метода equals и hashCode обращаться к полям через геттеры.</strong></p>
<p>Есть вопросы? Пишем комменты )) Идём дальше. <strong>При сохранении новго объекта будет изменено его состояние</strong>. Допустим для обеспечения уникальности сущность мы используем целочисленные айдишники в качестве ключа. Когда мы создаем новый объект и затем персистим его, соответственно будет автоматически сгенерирован уникальный ключ для нашего объекта. И здесь <strong>мы должны помнить о том, что если в реализации метода hashCode задействован ключ, то значение hashCode до персистенса и после будет координально отличаться</strong>, поэтому практика не советует пихать ключи в hashCode, потому что может получиться так, что вы никогда не найдете обект, положенный ранее например в HashSet &#8211; а это лажа.</p>
<div><script type="text/javascript" src="http://odnaknopka.ru/wp/ok2.utf8.js"></script><script type="text/javascript">okbm("http://java.in.ua/2008/11/03/orm-%d0%b8-%d0%bf%d0%be%d0%b4%d0%b2%d0%be%d0%b4%d0%bd%d1%8b%d0%b5-%d0%ba%d0%b0%d0%bc%d0%bd%d0%b8-%d1%80%d0%b5%d0%b0%d0%bb%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d0%b8-equals-%d0%b8-hashcode/","ORM и подводные камни реализации equals и hashCode.")</script></div>]]></content:encoded>
			<wfw:commentRss>http://java.in.ua/2008/11/03/orm-%d0%b8-%d0%bf%d0%be%d0%b4%d0%b2%d0%be%d0%b4%d0%bd%d1%8b%d0%b5-%d0%ba%d0%b0%d0%bc%d0%bd%d0%b8-%d1%80%d0%b5%d0%b0%d0%bb%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d0%b8-equals-%d0%b8-hashcode/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

