Hibernate SVN: r11168 - branches/HAN_SPLIT/HibernateExt.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 19:13:03 -0500 (Wed, 07 Feb 2007)
New Revision: 11168
Added:
branches/HAN_SPLIT/HibernateExt/entitymanager/
Removed:
branches/HAN_SPLIT/HibernateExt/ejb/
Log:
rename ejb => entitymanager
Copied: branches/HAN_SPLIT/HibernateExt/entitymanager (from rev 11167, branches/HAN_SPLIT/HibernateExt/ejb)
17 years, 2 months
Hibernate SVN: r11167 - in branches/HAN_SPLIT/HibernateExt: ejb/lib and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 19:08:26 -0500 (Wed, 07 Feb 2007)
New Revision: 11167
Removed:
branches/HAN_SPLIT/HibernateExt/ejb/lib/ejb3-persistence.jar
branches/HAN_SPLIT/HibernateExt/ejb/lib/hibernate-annotations.jar
branches/HAN_SPLIT/HibernateExt/ejb/lib/javassist.jar
branches/HAN_SPLIT/HibernateExt/metadata/lib/ejb3-persistence.jar
branches/HAN_SPLIT/HibernateExt/metadata/lib/jms.jar
branches/HAN_SPLIT/HibernateExt/metadata/lib/jta.jar
branches/HAN_SPLIT/HibernateExt/metadata/lib/jta.licence.txt
branches/HAN_SPLIT/HibernateExt/metadata/lib/lucene-core-2.0.0.jar
Modified:
branches/HAN_SPLIT/HibernateExt/ejb/build.properties.dist
branches/HAN_SPLIT/HibernateExt/ejb/build.xml
branches/HAN_SPLIT/HibernateExt/ejb/lib/README.txt
branches/HAN_SPLIT/HibernateExt/validator/build.properties.dist
Log:
Java Persistence build system
Modified: branches/HAN_SPLIT/HibernateExt/ejb/build.properties.dist
===================================================================
--- branches/HAN_SPLIT/HibernateExt/ejb/build.properties.dist 2007-02-07 23:07:10 UTC (rev 11166)
+++ branches/HAN_SPLIT/HibernateExt/ejb/build.properties.dist 2007-02-08 00:08:26 UTC (rev 11167)
@@ -3,4 +3,11 @@
test.dir=test
resources.dir=resources
testresources.dir=test-resources
-hibernate-core.home=../hibernate-3.2
\ No newline at end of file
+hibernate-core.home=../hibernate-3.2
+
+
+#locally present jars
+jpa-api.jar=./lib/ejb3-persistence.jar
+validator.jar=./lib/hibernate-validator.jar
+commons-annotations.jar=./lib/hibernate-commons-annotations.jar
+annotations.jar=./lib/hibernate-annotations.jar
\ No newline at end of file
Modified: branches/HAN_SPLIT/HibernateExt/ejb/build.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/ejb/build.xml 2007-02-07 23:07:10 UTC (rev 11166)
+++ branches/HAN_SPLIT/HibernateExt/ejb/build.xml 2007-02-08 00:08:26 UTC (rev 11167)
@@ -16,13 +16,23 @@
<!-- Name of project and version, used to create filenames -->
<property name="Name" value="Hibernate EntityManager"/>
<property name="name" value="hibernate-entitymanager"/>
- <property name="version" value="3.2.1.GA"/>
+ <property name="version" value="3.2.2.GA"/>
<property name="javadoc.packagenames" value="org.hibernate.ejb.*"/>
<property name="jdbc.dir" value="jdbc"/>
<property name="copy.test" value="true"/>
+ <property name="javac.source" value="1.5"/>
+ <property name="javac.target" value="1.5"/>
<property name="common.dir" value="../common"/>
<available property="jpa-present" file="${basedir}/../ejb-api" type="dir"/>
+ <property name="jpa-api.jar" value="${basedir}/../ejb-api/build/ejb3-persistence.jar"/>
+ <property name="annotations.jar"
+ value="${basedir}/../metadata/target/hibernate-annotations/hibernate-annotations.jar"/>
+ <property name="validator.jar"
+ value="${basedir}/../validator/target/hibernate-validator/hibernate-validator.jar"/>
+ <property name="commons-annotations.jar"
+ value="${basedir}/../commons-annotations/target/hibernate-commons-annotations/hibernate-commons-annotations.jar"/>
+
<import file="${common.dir}/common-build.xml"/>
<property name="jpa-javadoc.dir" value="${dist.doc.dir}/ejb-api"/>
@@ -32,20 +42,70 @@
<property name="build.testresources.dir" value="${build.dir}/testresources"/>
<property name="build.temp.dir" value="${build.dir}/temp"/>
- <target name="compile" depends="init" description="Compile the Java source code">
+ <path id="lib.moduleclass.path">
+ <pathelement location="${jpa-api.jar}"/>
+ <pathelement location="${commons-annotations.jar}"/>
+ <pathelement location="${annotations.jar}"/>
+ <pathelement location="${validator.jar}"/>
+ </path>
+ <path id="junit.moduleclasspath">
+ <pathelement location="${src.dir}"/>
+ <pathelement location="${test.dir}"/>
+ <fileset dir="${jdbc.dir}">
+ <include name="*.jar"/>
+ <include name="*.zip"/>
+ </fileset>
+ <fileset dir="${lib.dir}/test">
+ <include name="*.jar"/>
+ <include name="*.zip"/>
+ </fileset>
+ </path>
+
+ <target name="init">
+ <antcall target="common-build.init"/>
+ <!-- check for dependency artefacts -->
+ <available file="${jpa-api.jar}" type="file" property="jpa-api.jar.available"/>
+ <available file="${commons-annotations.jar}" type="file" property="commons-annotations.jar.available"/>
+ <available file="${annotations.jar}" type="file" property="annotations.jar.available"/>
+ <available file="${validator.jar}" type="file" property="validator.jar.available"/>
+ <mkdir dir="${lib.dir}/test"/>
+ </target>
+
+ <target name="get.jpa-api" depends="init" unless="jpa-api.jar.available">
+ <ant inheritall="false" dir="${basedir}/../ejb-api" target="clean"/>
+ <ant inheritall="false" dir="${basedir}/../ejb-api" target="jar"/>
+ </target>
+
+ <target name="get.commons-annotations" depends="init" unless="commons-annotations.jar.available">
+ <ant inheritall="false" dir="${basedir}/../commons-annotations" target="clean"/>
+ <ant inheritall="false" dir="${basedir}/../commons-annotations" target="jar"/>
+ </target>
+
+ <target name="get.annotations" depends="init" unless="annotations.jar.available">
+ <ant inheritall="false" dir="${basedir}/../metadata" target="clean"/>
+ <ant inheritall="false" dir="${basedir}/../metadata" target="jar"/>
+ </target>
+
+ <target name="get.validator" depends="init" unless="validator.jar.available">
+ <ant inheritall="false" dir="${basedir}/../validator" target="clean"/>
+ <ant inheritall="false" dir="${basedir}/../validator" target="jar"/>
+ </target>
+
+ <target name="compile" depends="init,get.jpa-api,get.commons-annotations,get.annotations,get.validator" description="Compile the Java source code">
<available
classname="org.eclipse.core.launcher.Main"
property="build.compiler"
value="org.eclipse.jdt.core.JDTCompilerAdapter"
classpath="${java.class.path}"/>
<javac
- source="1.5"
srcdir="${src.dir}"
destdir="${classes.dir}"
classpathref="lib.class.path"
debug="${javac.debug}"
optimize="${javac.optimize}"
nowarn="on"
+ source="${javac.source}"
+ target="${javac.target}"
>
</javac>
</target>
@@ -127,12 +187,13 @@
value="org.eclipse.jdt.core.JDTCompilerAdapter"
classpath="${java.class.path}"/>
<javac
- source="1.5"
srcdir="${test.dir}"
destdir="${classes.dir}"
debug="${javac.debug}"
optimize="${javac.optimize}"
- nowarn="on">
+ nowarn="on"
+ source="${javac.source}"
+ target="${javac.target}">
<classpath>
<path refid="lib.class.path"/>
</classpath>
@@ -261,6 +322,16 @@
<include name="common-build.xml"/>
</fileset>
</copy>
+
+ <!-- copy dependencies -->
+ <copy todir="${dist.lib.dir}" failonerror="false">
+ <fileset file="${jpa-api.jar}"/>
+ <fileset file="${commons-annotations.jar}"/>
+ <fileset file="${annotations.jar}"/>
+ <fileset file="${validator.jar}"/>
+ </copy>
+ <mkdir dir="${dist.lib.dir}/test"/>
+
<copy file="${basedir}/build.properties.dist" tofile="${dist.dir}/build.properties" failonerror="false">
</copy>
<antcall target="common-build.dist"/>
Modified: branches/HAN_SPLIT/HibernateExt/ejb/lib/README.txt
===================================================================
--- branches/HAN_SPLIT/HibernateExt/ejb/lib/README.txt 2007-02-07 23:07:10 UTC (rev 11166)
+++ branches/HAN_SPLIT/HibernateExt/ejb/lib/README.txt 2007-02-08 00:08:26 UTC (rev 11167)
@@ -1,7 +1,19 @@
-Hibernate Metadata dependencies
-===============================
+Hibernate Entity Manager dependencies
+=====================================
-ejb3-persistence (final release): required
+
+Core
+====
+hibernate-commons-annotations.jar: required
+ejb3-persistence.jar: required
hibernate-annotations: required
-javassist (3.3): required
+hibernate-validator: required
+hibernate3.jar: required
+hibernate core dependencies: required (see Hibernate Core for more information)
+javassist.jar: required (part of Hibernate Core dependencies)
jboss-archive-browsing (5.0.0alpha build: CVSTag=HEAD date=200607201 119): required
+
+
+Test
+====
+(no extra dependency)
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/ejb/lib/ejb3-persistence.jar
===================================================================
(Binary files differ)
Deleted: branches/HAN_SPLIT/HibernateExt/ejb/lib/hibernate-annotations.jar
===================================================================
(Binary files differ)
Deleted: branches/HAN_SPLIT/HibernateExt/ejb/lib/javassist.jar
===================================================================
(Binary files differ)
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/lib/ejb3-persistence.jar
===================================================================
(Binary files differ)
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/lib/jms.jar
===================================================================
(Binary files differ)
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/lib/jta.jar
===================================================================
(Binary files differ)
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/lib/jta.licence.txt
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/lib/jta.licence.txt 2007-02-07 23:07:10 UTC (rev 11166)
+++ branches/HAN_SPLIT/HibernateExt/metadata/lib/jta.licence.txt 2007-02-08 00:08:26 UTC (rev 11167)
@@ -1,49 +0,0 @@
-
-Sun Microsystems, Inc.
-Binary Code License Agreement
-
-READ THE TERMS OF THIS AGREEMENT AND ANY PROVIDED SUPPLEMENTAL LICENSE TERMS (COLLECTIVELY "AGREEMENT") CAREFULLY BEFORE OPENING THE SOFTWARE MEDIA PACKAGE. BY OPENING THE SOFTWARE MEDIA PACKAGE, YOU AGREE TO THE TERMS OF THIS AGREEMENT. IF YOU ARE ACCESSING THE SOFTWARE ELECTRONICALLY, INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE "ACCEPT" BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL THESE TERMS, PROMPTLY RETURN THE UNUSED SOFTWARE TO YOUR PLACE OF PURCHASE FOR A REFUND OR, IF THE SOFTWARE IS ACCESSED ELECTRONICALLY, SELECT THE "DECLINE" BUTTON AT THE END OF THIS AGREEMENT.
-
-1. LICENSE TO USE. Sun grants you a non-exclusive and non-transferable license for the internal use only of the accompanying software and documentation and any error corrections provided by Sun (collectively "Software"), by the number of users and the class of computer hardware for which the corresponding fee has been paid.
-
-2. RESTRICTIONS. Software is confidential and copyrighted. Title to Software and all associated intellectual property rights is retained by Sun and/or its licensors. Except as specifically authorized in any Supplemental License Terms, you may not make copies of Software, other than a single copy of Software for archival purposes. Unless enforcement is prohibited by applicable law, you may not modify, decompile, or reverse engineer Software. Licensee acknowledges that Licensed Software is not designed or intended for use in the design, construction, operation or maintenance of any nuclear facility. Sun Microsystems, Inc. disclaims any express or implied warranty of fitness for such uses. No right, title or interest in or to any trademark, service mark, logo or trade name of Sun or its licensors is granted under this Agreement.
-
-3. LIMITED WARRANTY. Sun warrants to you that for a period of ninety (90) days from the date of purchase, as evidenced by a copy of the receipt, the media on which Software is furnished (if any) will be free of defects in materials and workmanship under normal use. Except for the foregoing, Software is provided "AS IS". Your exclusive remedy and Sun's entire liability under this limited warranty will be at Sun's option to replace Software media or refund the fee paid for Software.
-
-4. DISCLAIMER OF WARRANTY. UNLESS SPECIFIED IN THIS AGREEMENT, ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
-
-5. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. In no event will Sun's liability to you, whether in contract, tort (including negligence), or otherwise, exceed the amount paid by you for Software under this Agreement. The foregoing limitations will apply even if the above stated warranty fails of its essential purpose.
-
-6. Termination. This Agreement is effective until terminated. You may terminate this Agreement at any time by destroying all copies of Software. This Agreement will terminate immediately without notice from Sun if you fail to comply with any provision of this Agreement. Upon Termination, you must destroy all copies of Software.
-
-7. Export Regulations. All Software and technical data delivered under this Agreement are subject to US export control laws and may be subject to export or import regulations in other countries. You agree to comply strictly with all such laws and regulations and acknowledge that you have the responsibility to obtain such licenses to export, re-export, or import as may be required after delivery to you.
-
-8. U.S. Government Restricted Rights. If Software is being acquired by or on behalf of the U.S. Government or by a U.S. Government prime contractor or subcontractor (at any tier), then the Government's rights in Software and accompanying documentation will be only as set forth in this Agreement; this is in accordance with 48 CFR 227.7201 through 227.7202-4 (for Department of Defense (DOD) acquisitions) and with 48 CFR 2.101 and 12.212 (for non-DOD acquisitions).
-
-9. Governing Law. Any action related to this Agreement will be governed by California law and controlling U.S. federal law. No choice of law rules of any jurisdiction will apply.
-
-10. Severability. If any provision of this Agreement is held to be unenforceable, this Agreement will remain in effect with the provision omitted, unless omission would frustrate the intent of the parties, in which case this Agreement will immediately terminate.
-
-11. Integration. This Agreement is the entire agreement between you and Sun relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, representations and warranties and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification of this Agreement will be binding, unless in writing and signed by an authorized representative of each party.
-
-JAVATM INTERFACE CLASSES
-JAVA TRANSACTION API (JTA), VERSION 1.0.1B, MAINTENANCE RELEASE
-SUPPLEMENTAL LICENSE TERMS
-
-These supplemental license terms ("Supplemental Terms") add to or modify the terms of the Binary Code License Agreement (collectively, the "Agreement"). Capitalized terms not defined in these Supplemental Terms shall have the same meanings ascribed to them in the Agreement. These Supplemental Terms shall supersede any inconsistent or conflicting terms in the Agreement, or in any license contained within the Software.
-
-1. Software Internal Use and Development License Grant. Subject to the terms and conditions of this Agreement, including, but not limited to Section 3 (Java Technology Restrictions) of these Supplemental Terms, Sun grants you a non-exclusive, non-transferable, limited license to reproduce internally and use internally the binary form of the Software, complete and unmodified, for the sole purpose of designing, developing and testing your Java applets and applications ("Programs").
-
-2. License to Distribute Software. In addition to the license granted in Section 1 (Software Internal Use and Development License Grant) of these Supplemental Terms, subject to the terms and conditions of this Agreement, including but not limited to Section 3 (Java Technology Restrictions), Sun grants you a non-exclusive, non-transferable, limited license to reproduce and distribute the Software in binary form only, provided that you (i) distribute the Software complete and unmodified and only bundled as part of your Programs, (ii) do not distribute additional software intended to replace any component(s) of the Software, (iii) do not remove or alter any proprietary legends or notices contained in the Software, (iv) only distribute the Software subject to a license agreement that protects Sun's interests consistent with the terms contained in this Agreement, and (v) agree to defend and indemnify Sun and its licensors from and against any damages, costs, liabilities, settle!
ment amounts and/or expenses (including attorneys' fees) incurred in connection with any claim, lawsuit or action by any third party that arises or results from the use or distribution of any and all Programs and/or Software.
-
-3. Java Technology Restrictions. You may not modify the Java Platform Interface ("JPI", identified as classes contained within the "java" package or any subpackages of the "java" package), by creating additional classes within the JPI or otherwise causing the addition to or modification of the classes in the JPI. In the event that you create an additional class and associated API(s) which (i) extends the functionality of the Java Platform, and (ii) is exposed to third party software developers for the purpose of developing additional software which invokes such additional API, you must promptly publish broadly an accurate specification for such API for free use by all developers. You may not create, or authorize your licensees to create additional classes, interfaces, or subpackages that are in any way identified as "java", "javax", "sun" or similar convention as specified by Sun in any naming convention designation.
-
-4. Trademarks and Logos. You acknowledge and agree as between you and Sun that Sun owns the SUN, SOLARIS, JAVA, JINI, FORTE, and iPLANET trademarks and all SUN, SOLARIS, JAVA, JINI, FORTE, and iPLANET-related trademarks, service marks, logos and other brand designations ("Sun Marks"), and you agree to comply with the Sun Trademark and Logo Usage Requirements currently located at http://www.sun.com/policies/trademarks. Any use you make of the Sun Marks inures to Sun's benefit.
-
-5. Source Code. Software may contain source code that is provided solely for reference purposes pursuant to the terms of this Agreement. Source code may not be redistributed unless expressly provided for in this Agreement.
-
-6. Termination for Infringement. Either party may terminate this Agreement immediately should any Software become, or in either party's opinion be likely to become, the subject of a claim of infringement of any intellectual property right.
-
-For inquiries please contact: Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, California 95054.
-
-
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/lib/lucene-core-2.0.0.jar
===================================================================
(Binary files differ)
Modified: branches/HAN_SPLIT/HibernateExt/validator/build.properties.dist
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/build.properties.dist 2007-02-07 23:07:10 UTC (rev 11166)
+++ branches/HAN_SPLIT/HibernateExt/validator/build.properties.dist 2007-02-08 00:08:26 UTC (rev 11167)
@@ -6,6 +6,6 @@
#locally present jars
jpa-api.jar=./lib/ejb3-persistence.jar
jpa.jar=./lib/test/hibernate-entitymanager.jar
-archive-browsing.jar=./lib/test/hibernate-entitymanager.jar
+archive-browsing.jar=./lib/test/jboss-archive-browsing.jar
commons-annotations.jar=./lib/hibernate-commons-annotations.jar
annotations.jar=./lib/test/hibernate-annotations.jar
\ No newline at end of file
17 years, 2 months
Hibernate SVN: r11166 - branches/HAN_SPLIT/HibernateExt/metadata/lib.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 18:07:10 -0500 (Wed, 07 Feb 2007)
New Revision: 11166
Modified:
branches/HAN_SPLIT/HibernateExt/metadata/lib/README.txt
Log:
depdendecy descriptions
Modified: branches/HAN_SPLIT/HibernateExt/metadata/lib/README.txt
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/lib/README.txt 2007-02-07 23:01:44 UTC (rev 11165)
+++ branches/HAN_SPLIT/HibernateExt/metadata/lib/README.txt 2007-02-07 23:07:10 UTC (rev 11166)
@@ -1,5 +1,15 @@
Hibernate Metadata dependencies
===============================
-ejb3-persistence.jar (final release version): required
-lucene-2.0.0.jar (2.0.0): optional, useful when lucene integration is used
\ No newline at end of file
+
+Core
+====
+hibernate-commons-annotations.jar: required
+hibernate3.jar: required
+hibernate core dependencies: required (see Hibernate Core for more information)
+hibernate-validator.jar: required
+ejb3-persistence.jar: optional (needed for Java Persistence integration)
+
+Test
+====
+(no additinal dependency)
\ No newline at end of file
17 years, 2 months
Hibernate SVN: r11165 - branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 18:01:44 -0500 (Wed, 07 Feb 2007)
New Revision: 11165
Added:
branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/additionalmodules.xml
Log:
oups missing module doc
Added: branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/additionalmodules.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/additionalmodules.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/additionalmodules.xml 2007-02-07 23:01:44 UTC (rev 11165)
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="additionalmodules">
+ <title>Additional modules</title>
+
+ <para>Hibernate Annotations mainly focus on persistence metadata. The
+ project also have a nice integration with two Hibernate modules.</para>
+
+ <section>
+ <title>Hibernate Validator</title>
+
+ <section>
+ <title>Description</title>
+
+ <para>Annotations are a very convenient and elegant way to specify
+ invariant constraints for a domain model. You can, for example, express
+ that a property should never be null, that the account balance should be
+ strictly positive, etc. These domain model constraints are declared in
+ the bean itself by annotating its properties. A validator can then read
+ them and check for constraint violations. The validation mechanism can
+ be executed in different layers in your application without having to
+ duplicate any of these rules (presentation layer, data access layer).
+ Following the DRY principle, Hibernate Validator has been designed for
+ that purpose.</para>
+
+ <para>Hibernate Validator works at two levels. First, it is able to
+ check in-memory instances of a class for constraint violations. Second,
+ it can apply the constraints to the Hibernate metamodel and incorporate
+ them into the generated database schema.</para>
+
+ <para>Each constraint annotation is associated to a validator
+ implementation responsible for checking the constraint on the entity
+ instance. A validator can also (optionally) apply the constraint to the
+ Hibernate metamodel, allowing Hibernate to generate DDL that expresses
+ the constraint. With the appropriate event listener, you can execute the
+ checking operation on inserts and updates done by Hibernate. Hibernate
+ Validator is not limited to use with Hibernate. You can easily use it
+ anywhere in your application.</para>
+
+ <para>When checking instances at runtime, Hibernate Validator returns
+ information about constraint violations in an array of
+ <classname>InvalidValue</classname> s. Among other information, the
+ <classname>InvalidValue</classname> contains an error description
+ message that can embed the parameter values bundle with the annotation
+ (eg. length limit), and message strings that may be externalized to a
+ <classname>ResourceBundle</classname> .</para>
+ </section>
+
+ <section>
+ <title>Integration with Hibernate Annotations</title>
+
+ <para>If Hibernate Validator
+ (<filename>hibernate-validator.jar</filename>) is available in the
+ classpath, Hibernate Annotations will integrates in two ways: </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Constraints will be applied to the Data Definition Language.
+ In other words, the database schema will reflect the constraints
+ (provided that you use the hbm2ddl tool).</para>
+ </listitem>
+
+ <listitem>
+ <para>Before an entity change is applied to the database (insert or
+ update), the entity is validated. Validation errors, if any, will be
+ carried over through an
+ <classname>InvalidStateException</classname>.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>For entities free of validation rules, the runtime performance
+ cost is null.</para>
+
+ <para>To disable constraint propagation to DDL, set up
+ <literal>hibernate.validator.apply_to_ddl</literal> to false in the
+ configuration file. Such a need is very uncommon and not
+ recommanded.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Hibernate Search</title>
+
+ <section>
+ <title>Decription</title>
+
+ <para>Full text search engines like <productname>Apache
+ Lucene</productname> are a very powerful technology to bring free
+ text/efficient queries to applications. If suffers several mismatches
+ when dealing with a object domain model (keeping the index up to date,
+ mismatch between the index structure and the domain model, querying
+ mismatch...) Hibernate Search indexes your domain model thanks to a few
+ annotations, takes care of the database / index synchronization and
+ brings you back regular managed objects from free text queries.
+ Hibernate Search is using <ulink url="http://lucene.apache.org">Apache
+ Lucene</ulink> under the cover.</para>
+ </section>
+
+ <section>
+ <title>Integration with Hibernate Annotations</title>
+
+ <para>Hibernate Search integrates with Hibernate Annotations through
+ Hibernate event listeners definitions, please check the Hibernate Search
+ reference documentation for more information.</para>
+ </section>
+ </section>
+</chapter>
\ No newline at end of file
17 years, 2 months
Hibernate SVN: r11164 - in branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test: jpa and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 18:00:53 -0500 (Wed, 07 Feb 2007)
New Revision: 11164
Added:
branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/
branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Commander.java
branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPATestCase.java
branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPAValidateListenerTest.java
branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Submarine.java
Log:
Java persistence integration test
Added: branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Commander.java
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Commander.java (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Commander.java 2007-02-07 23:00:53 UTC (rev 11164)
@@ -0,0 +1,25 @@
+//$Id: $
+package org.hibernate.validator.test.jpa;
+
+import javax.persistence.Embeddable;
+import javax.persistence.Column;
+
+import org.hibernate.validator.NotEmpty;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Embeddable
+public class Commander {
+ @NotEmpty
+ @Column(name="commander_name")
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
Added: branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPATestCase.java
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPATestCase.java (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPATestCase.java 2007-02-07 23:00:53 UTC (rev 11164)
@@ -0,0 +1,103 @@
+//$Id: $
+package org.hibernate.validator.test.jpa;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.ArrayList;
+import java.io.InputStream;
+import java.io.IOException;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.hibernate.cfg.Environment;
+import org.hibernate.ejb.HibernatePersistence;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class JPATestCase extends junit.framework.TestCase {
+ protected EntityManagerFactory factory;
+
+ public JPATestCase() {
+ super();
+ }
+
+ public JPATestCase(String name) {
+ super( name );
+ }
+
+ public void setUp() {
+ factory = new HibernatePersistence().createEntityManagerFactory( getConfig() );
+ }
+
+ public void tearDown() {
+ factory.close();
+ }
+
+ public abstract Class[] getAnnotatedClasses();
+
+ public String[] getEjb3DD() {
+ return new String[]{};
+ }
+
+ public Map<Class, String> getCachedClasses() {
+ return new HashMap<Class, String>();
+ }
+
+ public Map<String, String> getCachedCollections() {
+ return new HashMap<String, String>();
+ }
+
+ public static Properties loadProperties() {
+ Properties props = new Properties();
+ InputStream stream = Persistence.class.getResourceAsStream( "/hibernate.properties" );
+ if ( stream != null ) {
+ try {
+ props.load( stream );
+ }
+ catch (Exception e) {
+ throw new RuntimeException( "could not load hibernate.properties" );
+ }
+ finally {
+ try {
+ stream.close();
+ }
+ catch (IOException ioe) {
+ }
+ }
+ }
+ props.setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+ return props;
+ }
+
+ public Map getConfig() {
+ Map config = loadProperties();
+ ArrayList<Class> classes = new ArrayList<Class>();
+
+ for ( Class clazz : getAnnotatedClasses() ) {
+ classes.add( clazz );
+ }
+ config.put( HibernatePersistence.LOADED_CLASSES, classes );
+ for ( Map.Entry<Class, String> entry : getCachedClasses().entrySet() ) {
+ config.put(
+ HibernatePersistence.CLASS_CACHE_PREFIX + "." + entry.getKey().getName(),
+ entry.getValue()
+ );
+ }
+ for ( Map.Entry<String, String> entry : getCachedCollections().entrySet() ) {
+ config.put(
+ HibernatePersistence.COLLECTION_CACHE_PREFIX + "." + entry.getKey(),
+ entry.getValue()
+ );
+ }
+ if ( getEjb3DD().length > 0 ) {
+ ArrayList<String> dds = new ArrayList<String>();
+ for ( String dd : getEjb3DD() ) {
+ dds.add( dd );
+ }
+ config.put( HibernatePersistence.XML_FILE_NAMES, dds );
+ }
+ return config;
+ }
+}
Added: branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPAValidateListenerTest.java
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPAValidateListenerTest.java (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/JPAValidateListenerTest.java 2007-02-07 23:00:53 UTC (rev 11164)
@@ -0,0 +1,84 @@
+//$Id: $
+package org.hibernate.validator.test.jpa;
+
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+
+import org.hibernate.ejb.HibernatePersistence;
+import org.hibernate.validator.Environment;
+import org.hibernate.validator.InvalidStateException;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class JPAValidateListenerTest extends JPATestCase {
+
+ public void testEventTrigger() {
+ EntityManager em = factory.createEntityManager();
+ em.getTransaction().begin();
+ Commander beetles = new Commander();
+ beetles.setName( "" );
+ Submarine yellowSubmarine = new Submarine();
+ yellowSubmarine.setCommander( beetles );
+ yellowSubmarine.setName( "" );
+ yellowSubmarine.setSize( 3 );
+ try {
+ em.persist( yellowSubmarine );
+ em.flush();
+ fail("Event not wired");
+ }
+ catch(InvalidStateException e) {
+ assertEquals( 3, e.getInvalidValues().length );
+ }
+ finally {
+ em.getTransaction().rollback();
+ em.close();
+ }
+
+ //update trigger
+ em = factory.createEntityManager();
+ em.getTransaction().begin();
+ beetles = new Commander();
+ beetles.setName( "Beetles" );
+ yellowSubmarine = new Submarine();
+ yellowSubmarine.setCommander( beetles );
+ yellowSubmarine.setName( "Yellow" );
+ yellowSubmarine.setSize( 13 );
+ em.persist( yellowSubmarine );
+ em.flush();
+ em.clear();
+ yellowSubmarine = em.find( Submarine.class, yellowSubmarine.getId() );
+ yellowSubmarine.setSize( 3 );
+ try {
+ em.flush();
+ fail("Event not wired");
+ }
+ catch(InvalidStateException e) {
+ assertEquals( 1, e.getInvalidValues().length );
+ }
+ finally {
+ em.getTransaction().rollback();
+ em.close();
+ }
+
+ }
+
+ public Class[] getAnnotatedClasses() {
+ return new Class[]{
+ Commander.class,
+ Submarine.class
+ };
+ }
+
+
+ public Map getConfig() {
+ Map map = super.getConfig();
+ //Remove regular Validator wiring
+ map.put( HibernatePersistence.EVENT_LISTENER_PREFIX + "." + "pre-insert",
+ "" );
+ map.put( HibernatePersistence.EVENT_LISTENER_PREFIX + "." + "pre-update",
+ "" );
+ return map;
+ }
+}
Added: branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Submarine.java
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Submarine.java (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/validator/src/test/org/hibernate/validator/test/jpa/Submarine.java 2007-02-07 23:00:53 UTC (rev 11164)
@@ -0,0 +1,65 @@
+//$Id: $
+package org.hibernate.validator.test.jpa;
+
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+import org.hibernate.validator.Min;
+import org.hibernate.validator.NotEmpty;
+import org.hibernate.validator.Valid;
+import org.hibernate.validator.event.JPAValidateListener;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Entity
+@EntityListeners( JPAValidateListener.class )
+public class Submarine {
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ @NotEmpty
+ private String name;
+
+ @Valid
+ private Commander commander;
+
+ @Min( 10 )
+ private long size;
+
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ public Commander getCommander() {
+ return commander;
+ }
+
+ public void setCommander(Commander commander) {
+ this.commander = commander;
+ }
+}
17 years, 2 months
Hibernate SVN: r11163 - branches/HAN_SPLIT/HibernateExt/metadata.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 17:47:49 -0500 (Wed, 07 Feb 2007)
New Revision: 11163
Modified:
branches/HAN_SPLIT/HibernateExt/metadata/build.properties.dist
branches/HAN_SPLIT/HibernateExt/metadata/build.xml
Log:
annotations dist structure
Modified: branches/HAN_SPLIT/HibernateExt/metadata/build.properties.dist
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/build.properties.dist 2007-02-07 22:08:01 UTC (rev 11162)
+++ branches/HAN_SPLIT/HibernateExt/metadata/build.properties.dist 2007-02-07 22:47:49 UTC (rev 11163)
@@ -1,4 +1,9 @@
common.dir=.
src.dir=src
test.dir=test
-hibernate-core.home=../hibernate-3.2
\ No newline at end of file
+hibernate-core.home=../hibernate-3.2
+
+#locally present jars
+jpa-api.jar=./lib/ejb3-persistence.jar
+commons-annotations.jar=./lib/hibernate-commons-annotations.jar
+validator.jar=./lib/test/hibernate-validator.jar
\ No newline at end of file
Modified: branches/HAN_SPLIT/HibernateExt/metadata/build.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/build.xml 2007-02-07 22:08:01 UTC (rev 11162)
+++ branches/HAN_SPLIT/HibernateExt/metadata/build.xml 2007-02-07 22:47:49 UTC (rev 11163)
@@ -20,7 +20,9 @@
<property name="javadoc.packagenames" value="org.hibernate.*"/>
<property name="jdbc.dir" value="jdbc"/>
<property name="copy.test" value="true"/>
- <property name="common.dir" value="../common"/>
+ <property name="javac.source" value="1.5"/>
+ <property name="javac.target" value="1.5"/>
+ <property name="common.dir" value="../common"/>
<property name="jpa-api.jar" value="${basedir}/../ejb-api/build/ejb3-persistence.jar"/>
<property name="validator.jar"
@@ -54,7 +56,8 @@
<available file="${jpa-api.jar}" type="file" property="jpa-api.jar.available"/>
<available file="${commons-annotations.jar}" type="file" property="commons-annotations.jar.available"/>
<available file="${validator.jar}" type="file" property="validator.jar.available"/>
- </target>
+ <mkdir dir="${lib.dir}/test"/>
+ </target>
<target name="get.jpa-api" depends="init" unless="jpa-api.jar.available">
<ant inheritall="false" dir="${basedir}/../ejb-api" target="clean"/>
@@ -85,7 +88,8 @@
debug="${javac.debug}"
optimize="${javac.optimize}"
nowarn="on"
- source="1.5">
+ source="${javac.source}"
+ target="${javac.target}">
<src path="${src.dir}"/>
</javac>
<copy todir="${classes.dir}">
@@ -108,8 +112,8 @@
debug="${javac.debug}"
optimize="${javac.optimize}"
nowarn="on"
- source="1.5"
- target="1.5">
+ source="${javac.source}"
+ target="${javac.target}">
<src refid="testsrc.path"/>
</javac>
</target>
@@ -211,7 +215,18 @@
<include name="common-build.xml"/>
</fileset>
</copy>
- <copy file="${basedir}/build.properties.dist" tofile="${dist.dir}/build.properties" failonerror="false">
+
+ <!-- copy dependencies -->
+ <copy todir="${dist.lib.dir}" failonerror="false">
+ <fileset file="${jpa-api.jar}"/>
+ <fileset file="${commons-annotations.jar}"/>
+ </copy>
+ <mkdir dir="${dist.lib.dir}/test"/>
+ <copy todir="${dist.lib.dir}/test" failonerror="false">
+ <fileset file="${validator.jar}"/>
+ </copy>
+
+ <copy file="${basedir}/build.properties.dist" tofile="${dist.dir}/build.properties" failonerror="false">
</copy>
<antcall target="common-build.dist"/>
</target>
17 years, 2 months
Hibernate SVN: r11162 - in branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en: modules and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 17:08:01 -0500 (Wed, 07 Feb 2007)
New Revision: 11162
Removed:
branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/lucene.xml
branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/validator.xml
Modified:
branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/master.xml
branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/entity.xml
branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/setup.xml
Log:
new Annotations documentation
Modified: branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/master.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/master.xml 2007-02-07 07:43:17 UTC (rev 11161)
+++ branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/master.xml 2007-02-07 22:08:01 UTC (rev 11162)
@@ -4,8 +4,7 @@
<!ENTITY setup SYSTEM "modules/setup.xml">
<!ENTITY entity SYSTEM "modules/entity.xml">
<!ENTITY xml-overriding SYSTEM "modules/xml-overriding.xml">
-<!ENTITY validator SYSTEM "modules/validator.xml">
-<!ENTITY lucene SYSTEM "modules/lucene.xml">
+<!ENTITY additionalmodules SYSTEM "modules/additionalmodules.xml">
]>
<book lang="en">
<bookinfo>
@@ -13,7 +12,7 @@
<subtitle>Reference Guide</subtitle>
- <releaseinfo>3.2.1.GA</releaseinfo>
+ <releaseinfo>3.2.2.GA</releaseinfo>
<mediaobject>
<imageobject>
@@ -63,8 +62,8 @@
informations.</para>
<para>If you are moving from previous Hibernate Annotations versions,
- please have a look at <uri>http://www.hibernate.org/371.html</uri> for a
- migration guide.</para>
+ please have a look at <ulink url="http://www.hibernate.org/398.html">Java
+ Persistence migration guide</ulink>.</para>
</preface>
&setup;
@@ -73,7 +72,6 @@
&xml-overriding;
- &validator;
+ &additionalmodules;
- &lucene;
</book>
\ No newline at end of file
Modified: branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/entity.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/entity.xml 2007-02-07 07:43:17 UTC (rev 11161)
+++ branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/entity.xml 2007-02-07 22:08:01 UTC (rev 11162)
@@ -1,12 +1,12 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<chapter id="entity">
<title>Entity Beans</title>
- <sect1 id="entity-overview" revision="1">
+ <sect1 id="entity-overview" revision="2">
<title>Intro</title>
- <para>This section covers EJB 3.0 (aka JPA) entity annotations and
- Hibernate-specific extensions.</para>
+ <para>This section covers EJB 3.0 (aka Java Persistence) entity
+ annotations and Hibernate-specific extensions.</para>
</sect1>
<sect1 id="entity-mapping" revision="2">
@@ -1203,11 +1203,11 @@
annotation takes into parameter a list of comma separated (target
entity) properties to order the collection by (eg <code>firstname
asc, age desc</code>), if the string is empty, the collection will
- be ordered by id. For true indexed
- collections, please refer to the <xref linkend="entity-hibspec" />.
- EJB3 allows you to map Maps using as a key one of the target entity
- property using <literal>@MapKey(name="myProperty")</literal>
- (myProperty is a property name in the target entity). When using
+ be ordered by id. For true indexed collections, please refer to the
+ <xref linkend="entity-hibspec" />. EJB3 allows you to map Maps using
+ as a key one of the target entity property using
+ <literal>@MapKey(name="myProperty")</literal> (myProperty is a
+ property name in the target entity). When using
<literal>@MapKey</literal> (without property name), the target
entity primary key is used. The map key uses the same column as the
property pointed out: there is no additional column defined to hold
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/lucene.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/lucene.xml 2007-02-07 07:43:17 UTC (rev 11161)
+++ branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/lucene.xml 2007-02-07 22:08:01 UTC (rev 11162)
@@ -1,670 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="lucene" revision="2">
- <title>Hibernate Search: Apache <trademark>Lucene</trademark>
- Integration</title>
-
- <para><ulink url="http://lucene.apache.org">Apache Lucene</ulink> is a
- high-performance Java search engine library available at the Apache Software
- Foundation. Hibernate Annotations includes a package of annotations that
- allows you to mark any domain model object as indexable and have Hibernate
- maintain a Lucene index of any instances persisted via Hibernate. Apache
- Lucene is also integrated with the Hibernate query facility.</para>
-
- <para>Hibernate Search is a work in progress and new features are cooking in
- this area. So expect some compatibility changes in subsequent
- versions.</para>
-
- <section id="lucene-architecture">
- <title>Architecture</title>
-
- <para>Hibernate Search is made of an indexing engine and an index search
- engine. Both are backed by Apache Lucene.</para>
-
- <para>When an entity is inserted, updated or removed to/from the database,
- <productname>Hibernate Search</productname> will keep track of this event
- (through the Hibernate event system) and schedule an index update. When
- out of transaction, the update is executed right after the actual database
- operation. It is however recommended, for both your database and Hibernate
- Search, to execute your operation in a transaction (whether JDBC or JTA).
- When in a transaction, the index update is schedule for the transaction
- commit (and discarded in case of transaction rollback). You can think of
- this as the regular (infamous) autocommit vs transactional behavior. From
- a performance perspective, the <emphasis>in transaction</emphasis> mode is
- recommended. All the index updates are handled for you without you having
- to use the Apache Lucene APIs.</para>
-
- <para>To interact with Apache Lucene indexes, Hibernate Search has the
- notion of <classname>DirectoryProvider</classname>. A directory provider
- will manage a given Lucene <classname>Directory</classname> type. You can
- configure directory providers to adjust the directory target.</para>
-
- <para><productname>Hibernate Search</productname> can also use a Lucene
- index to search an entity and return a (list of) managed entity saving you
- from the tedious Object / Lucene Document mapping and low level Lucene
- APIs. The application code use the unified
- <classname>org.hibernate.Query</classname> API exactly the way a HQL or
- native query would be done.</para>
- </section>
-
- <section id="lucene-configuration">
- <title>Configuration</title>
-
- <section id="lucene-configuration-directory" revision="1">
- <title>Directory configuration</title>
-
- <para>Apache Lucene has a notion of Directory where the index is stored.
- The Directory implementation can be customized but Lucene comes bundled
- with a file system and a full memory implementation.
- <productname>Hibernate Search</productname> has the notion of
- <literal>DirectoryProvider</literal> that handle the configuration and
- the initialization of the Lucene Directory.</para>
-
- <table>
- <title>List of built-in Directory Providers</title>
-
- <tgroup cols="3">
- <thead>
- <row>
- <entry align="center">Class</entry>
-
- <entry align="center">description</entry>
-
- <entry align="center">Properties</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>org.hibernate.search.store.FSDirectoryProvider</entry>
-
- <entry>File system based directory. The directory used will be
- <indexBase>/<<literal>@Indexed.name</literal>></entry>
-
- <entry><literal>indexBase</literal>: Base directory</entry>
- </row>
-
- <row>
- <entry>org.hibernate.search.store.RAMDirectoryProvider</entry>
-
- <entry>Memory based directory, the directory will be uniquely
- indentified by the <literal>@Indexed.name</literal>
- element</entry>
-
- <entry>none</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>If the built-in directory providers does not fit your needs, you
- can write your own directory provider by implementing the
- <classname>org.hibernate.store.DirectoryProvider</classname>
- interface</para>
-
- <para>Each indexed entity is associated to a Lucene index (an index can
- be shared by several entities but this is not usually the case). You can
- configure the index through properties prefixed by
- <constant>hibernate.search.</constant><replaceable>indexname</replaceable>.
- Default properties inherited to all indexes can be defined using the
- prefix <constant>hibernate.search.default.</constant></para>
-
- <para>To define the directory provider of a given index, you use the
- <constant>hibernate.search.<replaceable>indexname</replaceable>.directory_provider</constant></para>
-
- <programlisting>hibernate.search.default.directory_provider org.hibernate.search.store.FSDirectoryProvider
-hibernate.search.default.indexBase=/usr/lucene/indexes
-
-hibernate.search.Rules.directory_provider org.hibernate.search.store.RAMDirectoryProvider
-</programlisting>
-
- <para>applied on</para>
-
- <programlisting>@Indexed(name="Status")
-public class Status { ... }
-
-@Indexed(name="Rules")
-public class Rule { ... }</programlisting>
-
- <para>will create a file system directory in
- <filename>/usr/lucene/indexes/Status</filename> where the Status
- entities will be indexed, and use an in memory directory named
- <literal>Rules</literal> where Rule entities will be indexed.</para>
-
- <para>So you can easily defined common rules like the directory provider
- and base directory, and overide those default later on on a per index
- basis.</para>
-
- <para>Writing your own <classname>DirectoryProvider</classname>, you can
- benefit this configuration mechanism too.</para>
- </section>
-
- <section id="lucene-configuration-event" revision="1">
- <title>Enabling automatic indexing</title>
-
- <para>Finally, we enable the <literal>SearchEventListener</literal> for
- the three Hibernate events that occur after changes are executed to the
- database.</para>
-
- <programlisting><hibernate-configuration>
- ...
- <event type="post-update"
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-insert"
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-delete"
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
-</hibernate-configuration></programlisting>
- </section>
- </section>
-
- <section id="lucene-mapping" revision="2">
- <title>Mapping entities to the index structure</title>
-
- <para>All the metadata information related to indexed entities is
- described through some Java annotations. There is no need for xml mapping
- files nor a list of indexed entities. The list is discovered at startup
- time scanning the Hibernate mapped entities.</para>
-
- <para>First, we must declare a persistent class as indexable. This is done
- by annotating the class with <literal>@Indexed</literal> (all entities not
- annotated with <literal>@Indexed</literal> will be ignored by the indexing
- process):</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@Indexed(index="indexes/essays")</emphasis>
-public class Essay {
- ...
-}</programlisting>
-
- <para>The <literal>index</literal> attribute tells Hibernate what the
- Lucene directory name is (usually a directory on your file system). If you
- wish to define a base directory for all Lucene indexes, you can use the
- <literal>hibernate.search.default.indexBase</literal> property in your
- configuration file. Each entity instance will be represented by a Lucene
- <classname>Document</classname> inside the given index (aka
- Directory).</para>
-
- <para>For each property (or attribute) of your entity, you have the
- ability to describe how it will be indexed. The default (ie no annotation)
- means that the property is completly ignored by the indexing process.
- <literal>@Field</literal> does declare a property as indexed. When
- indexing an element to a Lucene document you can specify how it is
- indexed:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>name</literal>: describe under which name, the property
- should be stored in the Lucene Document. The default value is the
- property name (following the JavaBeans convention)</para>
- </listitem>
-
- <listitem>
- <para><literal>store</literal>: describe whether or not the property
- is stored in the Lucene index. You can store the value
- <literal>Store.YES</literal> (comsuming more space in the index),
- store it in a compressed way <literal>Store.COMPRESS</literal> (this
- does consume more CPU), or avoid any storage
- <literal>Store.NO</literal> (this is the default value). When a
- property is stored, you can retrieve it from the Lucene Document (note
- that this is not related to whether the element is indexed or
- not).</para>
- </listitem>
-
- <listitem>
- <para>index: describe how the element is indexed (ie the process used
- to index the property and the type of information store). The
- different values are <literal>Index.NO</literal> (no indexing, ie
- cannot be found by a query), <literal>Index.TOKENIZED</literal> (use
- an analyzer to process the property),
- <literal>Index.UN_TOKENISED</literal> (no analyzer pre processing),
- <literal>Index.NO_NORM</literal> (do not store the normalization
- data).</para>
- </listitem>
- </itemizedlist>
-
- <para>These attributes are part of the <literal>@Field</literal>
- annotation.</para>
-
- <para>Whether or not you want to store the data depends on how you wish to
- use the index query result. As of today, for a pure <productname>Hibernate
- Search</productname> usage, storing is not necessary. Whether or not you
- want to tokenize a property or not depends on whether you wish to search
- the element as is, or only normalized part of it. It make sense to
- tokenize a text field, but it does not to do it for a date field (or an id
- field).</para>
-
- <para>Finally, the id property of an entity is a special property used by
- <productname>Hibernate Search</productname> to ensure index unicity of a
- given entity. By design, an id has to be stored and must not be tokenized.
- To mark a property as index id, use the <literal>@DocumentId</literal>
- annotation.</para>
-
- <programlisting>@Entity
-@Indexed(index="indexes/essays")
-public class Essay {
- ...
-
- @Id
- <emphasis role="bold">@DocumentId</emphasis>
- public Long getId() { return id; }
-
- <emphasis role="bold">@Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)</emphasis>
- public String getSummary() { return summary; }
-
- @Lob
- <emphasis role="bold">@Field(index=Index.TOKENIZED)</emphasis>
- public String getText() { return text; }
-
-}</programlisting>
-
- <para>These annotations define an index with three fields:
- <literal>id</literal>, <literal>Abstract</literal> and
- <literal>text</literal>. Note that by default the field name is
- decapitalized, following the JavaBean specification.</para>
-
- <para>Note: you <emphasis>must</emphasis> specify
- <literal>@DocumentId</literal> on the identifier property of your entity
- class.</para>
-
- <para>Lucene has the notion of <emphasis>boost factor</emphasis>. It's a
- way to give more weigth to a field or to an indexed element over an other
- during the indexation process. You can use <literal>@Boost</literal> at
- the field or the class level.</para>
-
- <programlisting>@Entity
-@Indexed(index="indexes/essays")
-<emphasis role="bold">@Boost(2)</emphasis>
-public class Essay {
- ...
-
- @Id
- @DocumentId
- public Long getId() { return id; }
-
- @Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)
- <emphasis role="bold">@Boost(2.5f)</emphasis>
- public String getSummary() { return summary; }
-
- @Lob
- @Field(index=Index.TOKENIZED)
- public String getText() { return text; }
-
-}</programlisting>
-
- <para>In our example, Essay's probability to reach the top of the search
- list will be multiplied by 2 and the summary field will be 2.5 more
- important than the test field. Note that this explaination is actually
- wrong, but it is simple and close enought to the reality. Please check the
- Lucene documentation or the excellent <citetitle>Lucene In
- Action</citetitle> from Otis Gospodnetic and Erik Hatcher.</para>
-
- <para>The analyzer class used to index the elements is configurable
- through the <literal>hibernate.search.analyzer</literal> property. If none
- defined,
- <classname>org.apache.lucene.analysis.standard.StandardAnalyzer</classname>
- is used as the default.</para>
- </section>
-
- <section id="lucene-bridge">
- <title>Property/Field Bridge</title>
-
- <para>All field of a full text index in Lucene have to be represented as
- Strings. Ones Java properties have to be indexed in a String form. For
- most of your properties, <productname>Hibernate Search</productname> does
- the translation job for you thanks to a built-in set of bridges. In some
- cases, though you need a fine grain control over the translation
- process.</para>
-
- <section>
- <title>Built-in bridges</title>
-
- <para><literal>Hibernate Search</literal> comes bundled with a set of
- built-in bridges between a Java property type and its full text
- representation.</para>
-
- <para><literal>Null</literal> elements are not indexed (Lucene does not
- support null elements and it does not make much sense either)</para>
-
- <variablelist>
- <varlistentry>
- <term>null</term>
-
- <listitem>
- <para>null elements are not indexed. Lucene does not support null
- elements and this does not make much sense either.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>java.lang.String</term>
-
- <listitem>
- <para>String are indexed as is</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>short, Short, integer, Integer, long, Long, float, Float,
- double, Double, BigInteger, BigDecimal</term>
-
- <listitem>
- <para>Numbers are converted in their String representation. Note
- that numbers cannot be compared by Lucene (ie used in ranged
- queries) out of the box: they have to be padded <footnote>
- <para>Using a Range query is debattable and has drawbacks, an
- alternative approach is to use a Filter query which will
- filter the result query to the appropriate range.</para>
-
- <para><productname>Hibernate Search</productname> will support
- a padding mechanism</para>
- </footnote></para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>java.util.Date</term>
-
- <listitem>
- <para>Dates are stored as yyyyMMddHHmmssSSS in GMT time
- (200611072203012 for Nov 7th of 2006 4:03PM and 12ms EST). You
- shouldn't really bother with the internal format. What is
- important is that when using a DateRange Query, you should know
- that the dates have to be expressed in GMT time.</para>
-
- <para>Usually, storing the date up to the milisecond is not
- necessary. <literal>@DateBridge</literal> defines the appropriate
- resolution you are willing to store in the index
- (<literal><literal>@DateBridge(resolution=Resolution.DAY)</literal></literal>).
- The date pattern will then be truncated accordingly.</para>
-
- <programlisting>@Entity @Indexed
-public class Meeting {
- @Field(index=Index.UN_TOKENIZED)
- <emphasis role="bold">@DateBridge(resolution=Resolution.MINUTE)</emphasis>
- private Date date;
- ...
-}</programlisting>
-
- <warning>
- <para>A Date whose resolution is lower than
- <literal>MILLISECOND</literal> cannot be a
- <literal>@DocumentId</literal></para>
- </warning>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para></para>
- </section>
-
- <section>
- <title>Custom Bridge</title>
-
- <para>It can happen that the built-in bridges of Hibernate Search does
- not cover some of your property types, or that the String representation
- used is not what you expect.</para>
-
- <section>
- <title>StringBridge</title>
-
- <para>The simpliest custom solution is to give <productname>Hibernate
- Search</productname> an implementation of your expected
- <emphasis>object to String</emphasis> bridge. To do so you need to
- implements the
- <literal>org.hibernate.search.bridge.StringBridge</literal>
- interface</para>
-
- <programlisting>/**
- * Padding Integer bridge.
- * All numbers will be padded with 0 to match 5 digits
- *
- * @author Emmanuel Bernard
- */
-public class PaddedIntegerBridge implements <emphasis role="bold">StringBridge</emphasis> {
-
- private int PADDING = 5;
-
- <emphasis role="bold">public String objectToString(Object object)</emphasis> {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > PADDING) throw new IllegalArgumentException( "Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < PADDING ; padIndex++ ) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-}</programlisting>
-
- <para>Then any property or field can use this bridge thanks to the
- <literal>@FieldBridge</literal> annotation</para>
-
- <programlisting><emphasis role="bold">@FieldBridge(impl = PaddedIntegerBridge.class)</emphasis>
-private Integer length;</programlisting>
-
- <para>Parameters can be passed to the Bridge implementation making it
- more flexible. The Bridge implementation implements a
- <classname>ParameterizedBridge</classname> interface, and the
- parameters are passed through the <literal>@FieldBridge</literal>
- annotation.</para>
-
- <programlisting>public class PaddedIntegerBridge implements StringBridge, <emphasis
- role="bold">ParameterizedBridge</emphasis> {
-
- public static String PADDING_PROPERTY = "padding";
- private int padding = 5; //default
-
- <emphasis role="bold">public void setParameterValues(Map parameters)</emphasis> {
- Object padding = parameters.get( PADDING_PROPERTY );
- if (padding != null) this.padding = (Integer) padding;
- }
-
- public String objectToString(Object object) {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > padding) throw new IllegalArgumentException( "Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-}
-
-
-//property
-@FieldBridge(impl = PaddedIntegerBridge.class,
- <emphasis role="bold">params = @Parameter(name="padding", value="10")</emphasis> )
-private Integer length;</programlisting>
-
- <para>The <classname>ParameterizedBridge</classname> interface can be
- implemented by <classname>StringBridge</classname>,
- <classname>TwoWayStringBridge</classname>,
- <classname>FieldBridge</classname> implementations (see
- bellow).</para>
-
- <para>If you expect to use your bridge implementation on for an id
- property (ie annotated with <literal>@DocumentId</literal>), you need
- to use a slightly extended version of <literal>StringBridge</literal>
- named <classname>TwoWayStringBridge</classname>. <literal>Hibernate
- Search</literal> needs to read the string representation of the
- identifier and generate the object out of it. There is not difference
- in the way the <literal>@FieldBridge</literal> annotation is
- used.</para>
-
- <programlisting>public class PaddedIntegerBridge implements TwoWayStringBridge, ParameterizedBridge {
-
- public static String PADDING_PROPERTY = "padding";
- private int padding = 5; //default
-
- public void setParameterValues(Map parameters) {
- Object padding = parameters.get( PADDING_PROPERTY );
- if (padding != null) this.padding = (Integer) padding;
- }
-
- public String objectToString(Object object) {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > padding) throw new IllegalArgumentException( "Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-
- <emphasis role="bold">public Object stringToObject(String stringValue)</emphasis> {
- return new Integer(stringValue);
- }
-}
-
-
-//id property
-@DocumentId
-@FieldBridge(impl = PaddedIntegerBridge.class,
- params = @Parameter(name="padding", value="10") )
-private Integer id;</programlisting>
-
- <para>It is critically important for the two-way process to be
- idempotent (ie object = stringToObject( objectToString( object ) )
- ).</para>
- </section>
-
- <section>
- <title>FieldBridge</title>
-
- <para>Some usecase requires more than a simple object to string
- translation when mapping a property to a Lucene index. To give you
- most of the flexibility you can also implement a bridge as a
- <classname>FieldBridge</classname>. This interface give you a property
- value and let you map it the way you want in your Lucene
- <classname>Document</classname>.This interface is very similar in its
- concept to the <productname>Hibernate</productname>
- <classname>UserType</classname>.</para>
-
- <para>You can for example store a given property in two different
- document fields</para>
-
- <programlisting>/**
- * Store the date in 3 different field year, month, day
- * to ease Range Query per year, month or day
- * (eg get all the elements of december for the last 5 years)
- *
- * @author Emmanuel Bernard
- */
-public class DateSplitBridge implements FieldBridge {
- private final static TimeZone GMT = TimeZone.getTimeZone("GMT");
-
- <emphasis role="bold">public void set(String name, Object value, Document document, Field.Store store, Field.Index index, Float boost) {</emphasis>
- Date date = (Date) value;
- Calendar cal = GregorianCalendar.getInstance( GMT );
- cal.setTime( date );
- int year = cal.get( Calendar.YEAR );
- int month = cal.get( Calendar.MONTH ) + 1;
- int day = cal.get( Calendar.DAY_OF_MONTH );
- //set year
- Field field = new Field( name + ".year", String.valueOf(year), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- //set month and pad it if needed
- field = new Field( name + ".month", month < 10 ? "0" : "" + String.valueOf(month), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- //set day and pad it if needed
- field = new Field( name + ".day", day < 10 ? "0" : "" + String.valueOf(day), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- }
-}
-
-
-//property
-<emphasis role="bold">@FieldBridge(impl = DateSplitBridge.class)</emphasis>
-private Integer length;</programlisting>
-
- <para></para>
- </section>
- </section>
- </section>
-
- <section id="lucene-query">
- <title>Querying</title>
-
- <para>The second most important capability of <productname>Hibernate
- Search</productname> is the ability to execute a Lucene query and retrieve
- entities managed by an Hibernate session, providing the power of Lucene
- without living the Hibernate paradygm, and giving another dimension to the
- Hibernate classic search mechanisms (HQL, Criteria query, native SQL
- query).</para>
-
- <para>To access the <productname>Hibernate Search</productname> querying
- facilities, you have to use an Hibernate
- <classname>FullTextSession</classname>. A SearchSession wrap an regular
- <classname>org.hibernate.Session</classname> to provide query and indexing
- capabilities.</para>
-
- <programlisting>Session session = sessionFactory.openSession();
-...
-FullTextSession fullTextSession = Search.createFullTextSession(session);</programlisting>
-
- <para>The search facility is built on native Lucene queries.</para>
-
- <programlisting>org.apache.lucene.QueryParser parser = new QueryParser("title", new StopAnalyzer() );
-
-org.hibernate.lucene.search.Query luceneQuery = parser.parse( "summary:Festina Or brand:Seiko" );
-<emphasis role="bold">org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );</emphasis>
-
-List result = fullTextQuery.list(); //return a list of managed objects</programlisting>
-
- <para>The Hibernate query built on top of the Lucene query is a regular
- <literal>org.hibernate.Query</literal>, you are is the same paradygm as
- the other Hibernate query facilities (HQL, Native or Criteria). The
- regular <literal>list()</literal>, <literal>uniqueResult()</literal>,
- <literal>iterate()</literal> and <literal>scroll()</literal> can be
- used.</para>
-
- <para>If you expect a reasonnable result number and expect to work on all
- of them, <methodname>list()</methodname> or
- <methodname>uniqueResult()</methodname> are recommanded.
- <methodname>list()</methodname> work best if the entity
- <literal>batch-size</literal> is set up properly. Note that Hibernate
- Seach has to process all Lucene Hits elements when using
- <methodname>list()</methodname>, <methodname>uniqueResult()</methodname>
- and <methodname>iterate()</methodname>. If you wish to minimize Lucene
- document loading, <methodname>scroll()</methodname> is more appropriate,
- Don't forget to close the <classname>ScrollableResults</classname> object
- when you're done, since it keeps Lucene resources.</para>
-
- <para>An efficient way to work with queries is to use pagination. The
- pagination API is exactly the one available in
- <classname>org.hibernate.Query</classname>:</para>
-
- <programlisting><emphasis role="bold">org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );</emphasis>
-fullTextQuery.setFirstResult(30);
-fullTextQuery.setMaxResult(20);
-fullTextQuery.list(); //will return a list of 20 elements starting from the 30th</programlisting>
-
- <para>Only the relevant Lucene Documents are accessed.</para>
- </section>
-
- <section id="lucene-index">
- <title>Indexing</title>
-
- <para>It is sometimes useful to index an object event if this object is
- not inserted nor updated to the database. This is especially true when you
- want to build your index the first time. You can achieve that goal using
- the <classname>FullTextSession</classname>.</para>
-
- <programlisting>FullTextSession fullTextSession = Search.createFullTextSession(session);
-Transaction tx = fullTextSession.beginTransaction();
-for (Customer customer : customers) {
- <emphasis role="bold">fullTextSession.index(customer);</emphasis>
-}
-tx.commit(); //index are written at commit time</programlisting>
-
- <para>For maximum efficiency, Hibernate Search batch index operations
- which and execute them at commit time (Note: you don't need to use
- <classname>org.hibernate.Transaction</classname> in a JTA
- environment).</para>
- </section>
-</chapter>
\ No newline at end of file
Modified: branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/setup.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/setup.xml 2007-02-07 07:43:17 UTC (rev 11161)
+++ branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/setup.xml 2007-02-07 22:08:01 UTC (rev 11162)
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<chapter>
<title id="setup" revision="1">Setting up an annotations project</title>
- <section id="setup-requirements">
+ <section id="setup-requirements" revision="1">
<title>Requirements</title>
<itemizedlist>
@@ -12,27 +12,27 @@
</listitem>
<listitem>
- <para><emphasis>This release requires Hibernate 3.2.0.GA and above.
- Do not use this release of Hibernate Annotations with an older version
- of Hibernate 3.x!</emphasis></para>
+ <para><emphasis>This release requires Hibernate 3.2.0.GA and above. Do
+ not use this release of Hibernate Annotations with an older version of
+ Hibernate 3.x!</emphasis></para>
</listitem>
<listitem>
- <para>This release is known to work on Hibernate core 3.2.0.CR5, 3.2.0.GA
- and 3.2.1.GA</para>
+ <para>This release is known to work on Hibernate core 3.2.0.CR5 and
+ 3.2.x.GA</para>
</listitem>
<listitem>
- <para>Make sure you have JDK 5.0 installed. You can of course continue
- using XDoclet and get some of the benefits of annotation-based
- metadata with older JDK versions. Note that this document only
- describes JDK 5.0 annotations and you have to refer to the XDoclet
- documentation for more information.</para>
+ <para>Make sure you have JDK 5.0 installed or above. You can of course
+ continue using XDoclet and get some of the benefits of
+ annotation-based metadata with older JDK versions. Note that this
+ document only describes JDK 5.0 annotations and you have to refer to
+ the XDoclet documentation for more information.</para>
</listitem>
</itemizedlist>
</section>
- <section id="setup-configuration">
+ <section id="setup-configuration" revision="1">
<title>Configuration</title>
<para>First, set up your classpath (after you have created a new project
@@ -43,17 +43,23 @@
</listitem>
<listitem>
- <para>Copy <filename>hibernate-annotations.jar</filename> and
+ <para>Copy <filename>hibernate-annotations.jar</filename>,
+ <filename>lib/hibernate-comons-annotations.jar</filename> and
<filename>lib/ejb3-persistence.jar</filename> from the Hibernate
Annotations distribution to your classpath as well.</para>
</listitem>
- <listitem>
- <para>To use the <xref linkend="lucene" />, add the lucene jar
- file.</para>
- </listitem>
</itemizedlist></para>
+ <para>If you wish to use Hibernate Validator (TODO make a link to HV doc),
+ download it from the Hibernate website and add
+ <filename>hibernate-validator.jar</filename> in your classpath.</para>
+
+ <para>If you wish to use Hibernate Search (TODO make a link to HSearch
+ doc), download it from the Hibernate website and add
+ <filename>hibernate-search.jar</filename> and
+ <filename>lucene-core-x.y.z.jar</filename> in your classpath.</para>
+
<para>We also recommend a small wrapper class to startup Hibernate in a
static initializer block, known as <classname>HibernateUtil</classname>.
You might have seen this class in various forms in other areas of the
Deleted: branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/validator.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/validator.xml 2007-02-07 07:43:17 UTC (rev 11161)
+++ branches/HAN_SPLIT/HibernateExt/metadata/doc/reference/en/modules/validator.xml 2007-02-07 22:08:01 UTC (rev 11162)
@@ -1,560 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="validator">
- <title>Hibernate Validator</title>
-
- <para>Annotations are a very convenient and elegant way to specify invariant
- constraints for a domain model. You can, for example, express that a
- property should never be null, that the account balance should be strictly
- positive, etc. These domain model constraints are declared in the bean
- itself by annotating its properties. A validator can then read them and
- check for constraint violations. The validation mechanism can be executed in
- different layers in your application without having to duplicate any of
- these rules (presentation layer, data access layer). Hibernate Validator has
- been designed for that purpose.</para>
-
- <para>Hibernate Validator works at two levels. First, it is able to check
- in-memory instances of a class for constraint violations. Second, it can
- apply the constraints to the Hibernate metamodel and incorporate them into
- the generated database schema.</para>
-
- <para>Each constraint annotation is associated to a validator implementation
- responsible for checking the constraint on the entity instance. A validator
- can also (optionally) apply the constraint to the Hibernate metamodel,
- allowing Hibernate to generate DDL that expresses the constraint. With the
- appropriate event listener, you can execute the checking operation on
- inserts and updates done by Hibernate. Hibernate Validator is not limited to
- use with Hibernate. You can easily use it anywhere in your
- application.</para>
-
- <para>When checking instances at runtime, Hibernate Validator returns
- information about constraint violations in an array of
- <classname>InvalidValue</classname>s. Among other information, the
- <classname>InvalidValue</classname> contains an error description message
- that can embed the parameter values bundle with the annotation (eg. length
- limit), and message strings that may be externalized to a
- <classname>ResourceBundle</classname>.</para>
-
- <sect1 id="validator-constraints">
- <title>Constraints</title>
-
- <sect2>
- <title>What is a constraint?</title>
-
- <para>A constraint is represented by an annotation. A constraint usually
- has some attributes used to parameterize the constraints limits. The
- constraint apply to the annotated element.</para>
- </sect2>
-
- <sect2 id="validator-constraints-built-in" revision="1">
- <title>Built in constraints</title>
-
- <para>Hibernate Validator comes with some built-in constraints, which
- covers most basic data checks. As we'll see later, you're not limited to
- them, you can in a minute write your own constraints.</para>
-
- <table>
- <title>Built-in constraints</title>
-
- <tgroup cols="4">
- <colspec align="center" />
-
- <thead>
- <row>
- <entry>Annotation</entry>
-
- <entry>Apply on</entry>
-
- <entry>Runtime checking</entry>
-
- <entry>Hibernate Metadata impact</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>@Length(min=, max=)</entry>
-
- <entry>property (String)</entry>
-
- <entry>check if the string length match the range</entry>
-
- <entry>Column length will be set to max</entry>
- </row>
-
- <row>
- <entry>@Max(value=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is less than or equals to max</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Min(value=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is more than or equals to min</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@NotNull</entry>
-
- <entry>property</entry>
-
- <entry>check if the value is not null</entry>
-
- <entry>Column(s) are not null</entry>
- </row>
-
- <row>
- <entry>@NotEmpty</entry>
-
- <entry>property</entry>
-
- <entry>check if the string is not null nor empty. Check if the
- connection is not null nor empty</entry>
-
- <entry>Column(s) are not null (for String)</entry>
- </row>
-
- <row>
- <entry>@Past</entry>
-
- <entry>property (date or calendar)</entry>
-
- <entry>check if the date is in the past</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Future</entry>
-
- <entry>property (date or calendar)</entry>
-
- <entry>check if the date is in the future</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Pattern(regex="regexp", flag=)</entry>
-
- <entry>property (string)</entry>
-
- <entry>check if the property match the regular expression given
- a match flag (see <classname> java.util.regex.Pattern
- </classname> )</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Range(min=, max=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is between min and max
- (included)</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Size(min=, max=)</entry>
-
- <entry>property (array, collection, map)</entry>
-
- <entry>check if the element size is between min and max
- (included)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@AssertFalse</entry>
-
- <entry>property</entry>
-
- <entry>check that the method evaluates to false (useful for
- constraints expressed in code rather than annotations)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@AssertTrue</entry>
-
- <entry>property</entry>
-
- <entry>check that the method evaluates to true (useful for
- constraints expressed in code rather than annotations)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Valid</entry>
-
- <entry>property (object)</entry>
-
- <entry>perform validation recursively on the associated object.
- If the object is a Collection or an array, the elements are
- validated recursively. If the object is a Map, the value
- elements are validated recursively.</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Email</entry>
-
- <entry>property (String)</entry>
-
- <entry>check whether the string is conform to the email address
- specification</entry>
-
- <entry>none</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
-
- <sect2 id="validator-constraints-error" xreflabel="Error messages">
- <title>Error messages</title>
-
- <para>Hibernate Validator comes with a default set of error messages
- translated in about ten languages (if yours is not part of it, please
- sent us a patch). You can override those messages by creating a
- <filename>ValidatorMessages.properties</filename> or
- (<filename>ValidatorMessages_loc.properties</filename>) and override the
- needed keys. You can even add your own additional set of messages while
- writing your validator annotations. If Hibernate Validator cannot
- resolve a key from your resourceBundle nor from ValidatorMessage, it
- falls back to the default built-in values.</para>
-
- <para>Alternatively you can provide a
- <classname>ResourceBundle</classname> while checking programmatically
- the validation rules on a bean or if you want a completly different
- interpolation mechanism, you can provide an implementation of
- <literal>org.hibernate.validator.MessageInterpolator</literal> (check
- the JavaDoc for more informations).</para>
- </sect2>
-
- <sect2>
- <title>Writing your own constraints</title>
-
- <para>Extending the set of built-in constraints is extremely easy. Any
- constraint consists of two pieces: the constraint
- <emphasis>descriptor</emphasis> (the annotation) and the constraint
- <emphasis>validator</emphasis> (the implementation class). Here is a
- simple user-defined descriptor:</para>
-
- <programlisting>@ValidatorClass(CapitalizedValidator.class)
-@Target(METHOD)
-@Retention(RUNTIME)
-@Documented
-public @interface Capitalized {
- CapitalizeType type() default Capitalize.FIRST;
- String message() default "has incorrect capitalization";
-}</programlisting>
-
- <para><literal>type</literal> is a parameter describing how the property
- should to be capitalized. This is a user parameter fully dependant on
- the annotation business.</para>
-
- <para><literal>message</literal> is the default string used to describe
- the constraint violation and is mandatory. You can hard code the string
- or you can externalize part/all of it through the Java ResourceBundle
- mechanism. Parameters values are going to be injected inside the message
- when the <literal>{parameter}</literal> string is found (in our example
- <literal>Capitalization is not {type}</literal> would generate
- <literal>Capitalization is not FIRST</literal>), externalizing the whole
- string in <filename>ValidatorMessages.properties</filename> is
- considered good practice. See <xref
- linkend="validator-constraints-error" />.</para>
-
- <programlisting>@ValidatorClass(CapitalizedValidator.class)
-@Target(METHOD)
-@Retention(RUNTIME)
-@Documented
-public @interface Capitalized {
- CapitalizeType type() default Capitalize.FIRST;
- String message() default "{validator.capitalized}";
-}
-
-...
-#in ValidatorMessages.properties
-validator.capitalized=<literal>Capitalization is not {type}</literal></programlisting>
-
- <para>As you can see the {} notation is recursive.</para>
-
- <para>To link a descriptor to its validator implementation, we use the
- <literal>@ValidatorClass</literal> meta-annotation. The validator class
- parameter must name a class which implements
- <literal>Validator<ConstraintAnnotation></literal>.</para>
-
- <para>We now have to implement the validator (ie. the rule checking
- implementation). A validation implementation can check the value of the
- a property (by implementing <literal>PropertyConstraint</literal>)
- and/or can modify the hibernate mapping metadata to express the
- constraint at the database level (by implementing
- <literal>PersistentClassConstraint</literal>).</para>
-
- <programlisting>public class CapitalizedValidator
- implements Validator<Capitalized>, PropertyConstraint {
- private CapitalizeType type;
-
- //part of the Validator<Annotation> contract,
- //allows to get and use the annotation values
- public void initialize(Capitalized parameters) {
- type = parameters.type();
- }
-
- //part of the property constraint contract
- public boolean isValid(Object value) {
- if (value==null) return true;
- if ( !(value instanceof String) ) return false;
- String string = (String) value;
- if (type == CapitalizeType.ALL) {
- return string.equals( string.toUpperCase() );
- }
- else {
- String first = string.substring(0,1);
- return first.equals( first.toUpperCase();
- }
- }
-}</programlisting>
-
- <para>The <literal>isValid()</literal> method should return false if the
- constraint has been violated. For more examples, refer to the built-in
- validator implementations.</para>
-
- <para>We only have seen property level validation, but you can write a
- Bean level validation annotation. Instead of receiving the return
- instance of a property, the bean itself will be passed to the validator.
- To activate the validation checking, just annotated the bean itself
- instead. A small sample can be found in the unit test suite.</para>
- </sect2>
-
- <sect2>
- <title>Annotating your domain model</title>
-
- <para>Since you are already familiar with annotations now, the syntax
- should be very familiar.</para>
-
- <programlisting>public class Address {
- private String line1;
- private String line2;
- private String zip;
- private String state;
- private String country;
- private long id;
-
- // a not null string of 20 characters maximum
- @Length(max=20)
- @NotNull
- public String getCountry() {
- return country;
- }
-
- // a non null string
- @NotNull
- public String getLine1() {
- return line1;
- }
-
- //no constraint
- public String getLine2() {
- return line2;
- }
-
- // a not null string of 3 characters maximum
- @Length(max=3) @NotNull
- public String getState() {
- return state;
- }
-
- // a not null numeric string of 5 characters maximum
- // if the string is longer, the message will
- //be searched in the resource bundle at key 'long'
- @Length(max=5, message="{long}")
- @Pattern(regex="[0-9]+")
- @NotNull
- public String getZip() {
- return zip;
- }
-
- // should always be true
- @AssertTrue
- public boolean isValid() {
- return true;
- }
-
- // a numeric between 1 and 2000
- @Id @Min(1)
- @Range(max=2000)
- public long getId() {
- return id;
- }
-}</programlisting>
-
- <para>While the example only shows public property validation, you can
- also annotate fields of any kind of visibility.</para>
-
- <programlisting>@MyBeanConstraint(max=45)
-public class Dog {
- @AssertTrue private boolean isMale;
- @NotNull protected String getName() { ... };
- ...
-}</programlisting>
-
- <para>You can also annotate interfaces. Hibernate Validator will check
- all superclasses and interfaces extended or implemented by a given bean
- to read the appropriate validator annotations.</para>
-
- <programlisting>public interface Named {
- @NotNull String getName();
- ...
-}
-
-public class Dog implements Named {
-
- @AssertTrue private boolean isMale;
-
- public String getName() { ... };
-
-}</programlisting>
-
- <para>The name property will be checked for nullity when the Dog bean is
- validated.</para>
- </sect2>
- </sect1>
-
- <sect1>
- <title>Using the Validator framework</title>
-
- <para>Hibernate Validator is intended to be used to implement
- multi-layered data validation, where we express constraints in one place
- (the annotated domain model) and apply them at various different layers of
- the application.</para>
-
- <sect2>
- <title>Database schema-level validation</title>
-
- <para>Out of the box, Hibernate Annotations will translate the
- constraints you have defined for your entities into mapping metadata.
- For example, if a property of your entity is annotated
- <literal>@NotNull</literal>, its columns will be declared as
- <literal>not null</literal> in the DDL schema generated by
- Hibernate.</para>
- </sect2>
-
- <sect2>
- <title>Hibernate event-based validation</title>
-
- <para>Hibernate Validator has two built-in Hibernate event listeners.
- Whenever a <literal>PreInsertEvent</literal> or
- <literal>PreUpdateEvent</literal> occurs, the listeners will verify all
- constraints of the entity instance and throw an exception if any
- constraint is violated. Basically, objects will be checked before any
- inserts and before any updates made by Hibernate. This is the most
- convenient and the easiest way to activate the validation process. On
- constraint violation, the event will raise a runtime
- <classname>InvalidStateException</classname> which contains an array of
- <literal>InvalidValue</literal>s describing each failure.</para>
-
- <programlisting><hibernate-configuration>
- ...
- <event type="pre-update">
- <listener
- class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
- </event>
- <event type="pre-insert">
- <listener
- class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
- </event>
-</hibernate-configuration></programlisting>
-
- <para><note>
- <para>When using Hibernate Entity Manager, the Validation framework
- is activated out of the box. If the beans are not annotated with
- validation annotations, there is no performance cost.</para>
- </note></para>
- </sect2>
-
- <sect2>
- <title>Application-level validation</title>
-
- <para>Hibernate Validator can be applied anywhere in your application
- code.</para>
-
- <programlisting>ClassValidator personValidator = new ClassValidator( Person.class );
-ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
-
-InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);</programlisting>
-
- <para>The first two lines prepare the Hibernate Validator for class
- checking. The first one relies upon the error messages embedded in
- Hibernate Validator (see <xref
- linkend="validator-constraints-error" />), the second one uses a
- resource bundle for these messages. It is considered a good practice to
- execute these lines once and cache the validator instances.</para>
-
- <para>The third line actually validates the <literal>Address</literal>
- instance and returns an array of <literal>InvalidValue</literal>s. Your
- application logic will then be able to react to the failure.</para>
-
- <para>You can also check a particular property instead of the whole
- bean. This might be useful for property per property user
- interaction</para>
-
- <programlisting>ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
-
-//only get city property invalid values
-InvalidValue[] validationMessages = addressValidator.getInvalidValues(address, "city");
-
-//only get potential city property invalid values
-InvalidValue[] validationMessages = addressValidator.getPotentialInvalidValues("city", "Paris")</programlisting>
- </sect2>
-
- <sect2>
- <title>Validation informations</title>
-
- <para>As a validation information carrier, hibernate provide an array of
- <classname>InvalidValue</classname>. Each
- <literal>InvalidValue</literal> has a buch of methods describing the
- individual issues.</para>
-
- <para><methodname>getBeanClass()</methodname> retrieves the failing bean
- type</para>
-
- <para><methodname>getBean()</methodname>retrieves the failing instance
- (if any ie not when using
- <methodname>getPotentianInvalidValues()</methodname>)</para>
-
- <para><methodname>getValue()</methodname> retrieves the failing
- value</para>
-
- <para><methodname>getMessage()</methodname> retrieves the proper
- internationalized error message</para>
-
- <para><methodname>getRootBean()</methodname> retrieves the root bean
- instance generating the issue (useful in conjunction with
- <literal>@Valid</literal>), is null if getPotentianInvalidValues() is
- used.</para>
-
- <para><literal>getPropertyPath()</literal> retrieves the dotted path of
- the failing property starting from the root bean</para>
- </sect2>
- </sect1>
-</chapter>
\ No newline at end of file
17 years, 2 months
Hibernate SVN: r11161 - branches/HAN_SPLIT/HibernateExt/search.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 02:43:17 -0500 (Wed, 07 Feb 2007)
New Revision: 11161
Modified:
branches/HAN_SPLIT/HibernateExt/search/build.properties.dist
branches/HAN_SPLIT/HibernateExt/search/build.xml
branches/HAN_SPLIT/HibernateExt/search/readme.txt
Log:
Search distro build
Modified: branches/HAN_SPLIT/HibernateExt/search/build.properties.dist
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/build.properties.dist 2007-02-07 06:23:00 UTC (rev 11160)
+++ branches/HAN_SPLIT/HibernateExt/search/build.properties.dist 2007-02-07 07:43:17 UTC (rev 11161)
@@ -1,4 +1,10 @@
common.dir=.
src.dir=src
test.dir=test
-hibernate-core.home=../hibernate-3.2
\ No newline at end of file
+hibernate-core.home=../hibernate-3.2
+
+#locally present jars
+jpa-api.jar=./lib/ejb3-persistence.jar
+commons-annotations.jar=./lib/hibernate-commons-annotations.jar
+annotations.jar=./lib/test/hibernate-annotations.jar
+validator.jar=./lib/test/hibernate-validator.jar
\ No newline at end of file
Modified: branches/HAN_SPLIT/HibernateExt/search/build.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/build.xml 2007-02-07 06:23:00 UTC (rev 11160)
+++ branches/HAN_SPLIT/HibernateExt/search/build.xml 2007-02-07 07:43:17 UTC (rev 11161)
@@ -19,9 +19,12 @@
<property name="version" value="3.2.2.beta1"/>
<property name="javadoc.packagenames" value="org.hibernate.search.*"/>
<property name="copy.test" value="true"/>
- <property name="jdbc.dir" value="jdbc"/>
+ <property name="javac.source" value="1.5"/>
+ <property name="javac.target" value="1.5"/>
+ <property name="jdbc.dir" value="jdbc"/>
<property name="common.dir" value="${basedir}/../common"/>
- <property name="jpa-api.jar" value="${basedir}/../ejb-api/build/ejb3-persistence.jar"/>
+
+ <property name="jpa-api.jar" value="${basedir}/../ejb-api/build/ejb3-persistence.jar"/>
<property name="annotations.jar"
value="${basedir}/../metadata/target/hibernate-annotations/hibernate-annotations.jar"/>
<property name="commons-annotations.jar"
@@ -45,20 +48,21 @@
<include name="*.jar"/>
<include name="*.zip"/>
</fileset>
- <!-- TODO yuk, will go away the minute archive browsing is out -->
- <fileset dir="${basedir}/../ejb/lib">
- <include name="jboss-archive-browsing.jar"/>
+ <fileset dir="${lib.dir}/test">
+ <include name="*.jar"/>
+ <include name="*.zip"/>
</fileset>
</path>
- <target name="init">
+ <target name="init">
<antcall target="common-build.init"/>
<!-- check for dependency artefacts -->
<available file="${jpa-api.jar}" type="file" property="jpa-api.jar.available"/>
<available file="${commons-annotations.jar}" type="file" property="commons-annotations.jar.available"/>
<available file="${validator.jar}" type="file" property="validator.jar.available"/>
<available file="${annotations.jar}" type="file" property="annotations.jar.available"/>
- </target>
+ <mkdir dir="${lib.dir}/test"/>
+ </target>
<target name="get.jpa-api" depends="init" unless="jpa-api.jar.available">
<ant inheritall="false" dir="${basedir}/../ejb-api" target="clean"/>
@@ -93,7 +97,8 @@
debug="${javac.debug}"
optimize="${javac.optimize}"
nowarn="on"
- source="1.5">
+ source="${javac.source}"
+ target="${javac.target}">
<src path="${src.dir}"/>
</javac>
<copy todir="${classes.dir}">
@@ -116,8 +121,8 @@
debug="${javac.debug}"
optimize="${javac.optimize}"
nowarn="on"
- source="1.5"
- target="1.5">
+ source="${javac.source}"
+ target="${javac.target}">
<src refid="testsrc.path"/>
</javac>
</target>
@@ -210,12 +215,24 @@
<include name="common-build.xml"/>
</fileset>
</copy>
- <copy file="${basedir}/build.properties.dist" tofile="${dist.dir}/build.properties" failonerror="false">
+
+ <!-- copy dependencies -->
+ <copy todir="${dist.lib.dir}" failonerror="false">
+ <fileset file="${jpa-api.jar}"/>
+ <fileset file="${commons-annotations.jar}"/>
+ </copy>
+ <mkdir dir="${dist.lib.dir}/test"/>
+ <copy todir="${dist.lib.dir}/test" failonerror="false">
+ <fileset file="${annotations.jar}"/>
+ <fileset file="${validator.jar}"/>
+ </copy>
+
+ <copy file="${basedir}/build.properties.dist" tofile="${dist.dir}/build.properties" failonerror="false">
</copy>
<antcall target="common-build.dist"/>
</target>
- <target name="zip-dist" description="zip the dist">
+ <target name="zip-dist" description="zip the dist">
<zip zipfile="${dist.dir}-${version}.zip">
<zipfileset prefix="${name}-${version}" dir="${dist.dir}"/>
</zip>
Modified: branches/HAN_SPLIT/HibernateExt/search/readme.txt
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/readme.txt 2007-02-07 06:23:00 UTC (rev 11160)
+++ branches/HAN_SPLIT/HibernateExt/search/readme.txt 2007-02-07 07:43:17 UTC (rev 11161)
@@ -10,7 +10,7 @@
when dealing with a object domain model (keeping the index up to date, mismatch
between the index structure and the domain model, ...)
Hibernate Search indexes your domain model thanks to a few annotations, takes
-care of the index synchronization, bringa you back managed objects from free text
+care of the index synchronization, brings you back managed objects from free text
queries.
Hibernate Search is using Apache Lucene(tm) under the cover.
17 years, 2 months
Hibernate SVN: r11160 - in branches/HAN_SPLIT/HibernateExt/search/doc/reference: en and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-07 01:23:00 -0500 (Wed, 07 Feb 2007)
New Revision: 11160
Added:
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/mapping.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/query.xml
Removed:
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/setup.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/validator.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/xml-overriding.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/fr/
branches/HAN_SPLIT/HibernateExt/search/doc/reference/zh_cn/
Modified:
branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml
branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml
Log:
Search documentation
Modified: branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/build.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -9,17 +9,9 @@
<!-- TRANSLATOR: Duplicate this call for your language -->
<antcall target="lang.all">
- <param name="docname" value="hibernate_annotations"/>
+ <param name="docname" value="hibernate_search"/>
<param name="lang" value="en"/>
</antcall>
- <antcall target="lang.all">
- <param name="docname" value="hibernate_annotations"/>
- <param name="lang" value="zh_cn"/>
- </antcall>
- <antcall target="lang.all">
- <param name="docname" value="hibernate_annotations"/>
- <param name="lang" value="fr"/>
- </antcall>
</target>
</project>
Modified: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/master.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,79 +1,57 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
-"../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
-<!ENTITY setup SYSTEM "modules/setup.xml">
-<!ENTITY entity SYSTEM "modules/entity.xml">
-<!ENTITY xml-overriding SYSTEM "modules/xml-overriding.xml">
-<!ENTITY validator SYSTEM "modules/validator.xml">
-<!ENTITY lucene SYSTEM "modules/lucene.xml">
-]>
+ "../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
+ <!ENTITY architecture SYSTEM "modules/architecture.xml">
+ <!ENTITY configuration SYSTEM "modules/configuration.xml">
+ <!ENTITY mapping SYSTEM "modules/mapping.xml">
+ <!ENTITY query SYSTEM "modules/query.xml">
+ <!ENTITY batchindex SYSTEM "modules/batchindex.xml">
+ ]>
<book lang="en">
<bookinfo>
- <title>Hibernate Annotations</title>
+ <title>Hibernate Search</title>
+ <subtitle>Apache <trademark>Lucene</trademark>
+ Integration</subtitle>
<subtitle>Reference Guide</subtitle>
- <releaseinfo>3.2.1.GA</releaseinfo>
+ <releaseinfo>3.2.2.beta1</releaseinfo>
<mediaobject>
<imageobject>
- <imagedata fileref="images/hibernate_logo_a.png" format="png" />
+ <imagedata fileref="images/hibernate_logo_a.png" format="png"/>
</imageobject>
</mediaobject>
</bookinfo>
<toc></toc>
- <preface id="preface" revision="1">
+ <preface id="preface" revision="2">
<title>Preface</title>
- <para>Hibernate, like all other object/relational mapping tools, requires
- metadata that governs the transformation of data from one representation
- to the other (and vice versa). In Hibernate 2.x, mapping metadata is most
- of the time declared in XML text files. Another option is XDoclet,
- utilizing Javadoc source code annotations and a preprocessor at compile
- time. The same kind of annotation support is now available in the standard
- JDK, although more powerful and better supported by tools. IntelliJ IDEA,
- and Eclipse for example, support auto-completion and syntax highlighting
- of JDK 5.0 annotations. Annotations are compiled into the bytecode and
- read at runtime (in Hibernate's case on startup) using reflection, so no
- external XML files are needed.</para>
+ <para>Full text search engines like <productname>Apache Lucene</productname>
+ are a very powerful technology to
+bring free text/efficient queries to applications. If suffers several mismatches
+when dealing with a object domain model (keeping the index up to date, mismatch
+between the index structure and the domain model, querying mismatch...)
+Hibernate Search indexes your domain model thanks to a few annotations, takes
+care of the database / index synchronization and brings you back regular managed
+objects from free text queries.
+Hibernate Search is using <ulink url="http://lucene.apache.org">Apache Lucene</ulink>
+under the cover.</para>
- <para>The EJB3 specification recognizes the interest and the success of
- the transparent object/relational mapping paradigm. The EJB3 specification
- standardizes the basic APIs and the metadata needed for any
- object/relational persistence mechanism. <emphasis>Hibernate
- EntityManager</emphasis> implements the programming interfaces and
- lifecycle rules as defined by the EJB3 persistence specification. Together
- with <emphasis>Hibernate Annotations</emphasis>, this wrapper implements a
- complete (and standalone) EJB3 persistence solution on top of the mature
- Hibernate core. You may use a combination of all three together,
- annotations without EJB3 programming interfaces and lifecycle, or even
- pure native Hibernate, depending on the business and technical needs of
- your project. You can at all times fall back to Hibernate native APIs, or
- if required, even to native JDBC and SQL.</para>
-
- <para>This release is based on the final release of the EJB 3.0 / JPA
- specification (aka JSP-220) and support all the specification features
- (including the optional ones). Most of the Hibernate features and
- extensions are also available through Hibernate specific annotations
- compared to the specification are also available. While the Hibernate
- feature coverage is now very high, some are still missing. The eventual
- goal is to cover all of them. See the JIRA road map section for more
- informations.</para>
-
- <para>If you are moving from previous Hibernate Annotations versions,
- please have a look at <uri>http://www.hibernate.org/371.html</uri> for a
- migration guide.</para>
+ <para>Hibernate Search is a work in progress and new features are cooking in
+ this area. So expect some compatibility changes in subsequent
+ versions.</para>
</preface>
- &setup;
+ &architecture;
- &entity;
+ &configuration;
- &xml-overriding;
+ &mapping;
- &validator;
+ &query;
- &lucene;
+ &batchindex;
</book>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<chapter id="search-architecture">
+ <title>Architecture</title>
+
+ <para>Hibernate Search is made of an indexing engine and an index search
+ engine. Both are backed by Apache Lucene.
+ </para>
+
+ <para>When an entity is inserted, updated or removed to/from the database,
+ <productname>Hibernate Search</productname>
+ will keep track of this event
+ (through the Hibernate event system) and schedule an index update. When
+ out of transaction, the update is executed right after the actual database
+ operation. It is however recommended, for both your database and Hibernate
+ Search, to execute your operation in a transaction (whether JDBC or JTA).
+ When in a transaction, the index update is schedule for the transaction
+ commit (and discarded in case of transaction rollback). You can think of
+ this as the regular (infamous) autocommit vs transactional behavior. From
+ a performance perspective, the
+ <emphasis>in transaction</emphasis>
+ mode is
+ recommended. All the index updates are handled for you without you having
+ to use the Apache Lucene APIs.
+ </para>
+
+ <para>To interact with Apache Lucene indexes, Hibernate Search has the
+ notion of
+ <classname>DirectoryProvider</classname>
+ . A directory provider
+ will manage a given Lucene
+ <classname>Directory</classname>
+ type. You can
+ configure directory providers to adjust the directory target.
+ </para>
+
+ <para>
+ <productname>Hibernate Search</productname>
+ can also use a Lucene
+ index to search an entity and return a (list of) managed entity saving you
+ from the tedious Object / Lucene Document mapping and low level Lucene
+ APIs. The application code use the unified
+ <classname>org.hibernate.Query</classname>
+ API exactly the way a HQL or
+ native query would be done.
+ </para>
+</chapter>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/batchindex.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="search-batchindex">
+ <title>Indexing</title>
+
+ <para>It is sometimes useful to index an object event if this object is not
+ inserted nor updated to the database. This is especially true when you want
+ to build your index the first time. You can achieve that goal using the
+ <classname>FullTextSession</classname> .</para>
+
+ <programlisting>FullTextSession fullTextSession = Search.createFullTextSession(session);
+Transaction tx = fullTextSession.beginTransaction();
+for (Customer customer : customers) {
+ <emphasis role="bold">fullTextSession.index(customer);</emphasis>
+}
+tx.commit(); //index are written at commit time </programlisting>
+
+ <para>For maximum efficiency, Hibernate Search batch index operations which
+ and execute them at commit time (Note: you don't need to use
+ <classname>org.hibernate.Transaction</classname> in a JTA
+ environment).</para>
+</chapter>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="search-configuration">
+ <title>Configuration</title>
+
+ <section id="search-configuration-directory" revision="1">
+ <title>Directory configuration</title>
+
+ <para>Apache Lucene has a notion of Directory where the index is stored.
+ The Directory implementation can be customized but Lucene comes bundled
+ with a file system and a full memory implementation.
+ <productname>Hibernate Search</productname> has the notion of
+ <literal>DirectoryProvider</literal> that handle the configuration and the
+ initialization of the Lucene Directory.</para>
+
+ <table>
+ <title>List of built-in Directory Providers</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry align="center">Class</entry>
+
+ <entry align="center">description</entry>
+
+ <entry align="center">Properties</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>org.hibernate.search.store.FSDirectoryProvider</entry>
+
+ <entry>File system based directory. The directory used will be
+ <indexBase>/< <literal>@Indexed.name</literal>
+ ></entry>
+
+ <entry><literal>indexBase</literal> : Base directory</entry>
+ </row>
+
+ <row>
+ <entry>org.hibernate.search.store.RAMDirectoryProvider</entry>
+
+ <entry>Memory based directory, the directory will be uniquely
+ indentified by the <literal>@Indexed.name</literal>
+ element</entry>
+
+ <entry>none</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>If the built-in directory providers does not fit your needs, you can
+ write your own directory provider by implementing the
+ <classname>org.hibernate.store.DirectoryProvider</classname>
+ interface</para>
+
+ <para>Each indexed entity is associated to a Lucene index (an index can be
+ shared by several entities but this is not usually the case). You can
+ configure the index through properties prefixed by
+ <constant>hibernate.search.</constant>
+ <replaceable>indexname</replaceable> . Default properties inherited to all
+ indexes can be defined using the prefix
+ <constant>hibernate.search.default.</constant></para>
+
+ <para>To define the directory provider of a given index, you use the
+ <constant>hibernate.search. <replaceable>indexname</replaceable>
+ .directory_provider </constant></para>
+
+ <programlisting>hibernate.search.default.directory_provider org.hibernate.search.store.FSDirectoryProvider
+hibernate.search.default.indexBase=/usr/lucene/indexes
+
+hibernate.search.Rules.directory_provider org.hibernate.search.store.RAMDirectoryProvider </programlisting>
+
+ <para>applied on</para>
+
+ <programlisting>@Indexed(name="Status")
+public class Status { ... }
+
+@Indexed(name="Rules")
+public class Rule { ... }
+ </programlisting>
+
+ <para>will create a file system directory in
+ <filename>/usr/lucene/indexes/Status</filename> where the Status entities
+ will be indexed, and use an in memory directory named
+ <literal>Rules</literal> where Rule entities will be indexed.</para>
+
+ <para>So you can easily defined common rules like the directory provider
+ and base directory, and overide those default later on on a per index
+ basis.</para>
+
+ <para>Writing your own <classname>DirectoryProvider</classname> , you can
+ benefit this configuration mechanism too.</para>
+ </section>
+
+ <section id="search-configuration-event" revision="1">
+ <title>Enabling automatic indexing</title>
+
+ <para>Finally, we enable the <literal>SearchEventListener</literal> for
+ the three Hibernate events that occur after changes are executed to the
+ database.</para>
+
+ <programlisting><hibernate-configuration>
+ ...
+ <event type="post-update"
+ <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ <event type="post-insert"
+ <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ <event type="post-delete"
+ <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+</hibernate-configuration></programlisting>
+ </section>
+</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/entity.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,3432 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="entity">
- <title>Entity Beans</title>
-
- <sect1 id="entity-overview" revision="1">
- <title>Intro</title>
-
- <para>This section covers EJB 3.0 (aka JPA) entity annotations and
- Hibernate-specific extensions.</para>
- </sect1>
-
- <sect1 id="entity-mapping" revision="2">
- <title>Mapping with EJB3/JPA Annotations</title>
-
- <para>EJB3 entities are plain POJOs. Actually they represent the exact
- same concept as the Hibernate persistent entities. Their mappings are
- defined through JDK 5.0 annotations (an XML descriptor syntax for
- overriding is defined in the EJB3 specification). Annotations can be split
- in two categories, the logical mapping annotations (allowing you to
- describe the object model, the class associations, etc.) and the physical
- mapping annotations (describing the physical schema, tables, columns,
- indexes, etc). We will mix annotations from both categories in the
- following code examples.</para>
-
- <para>EJB3 annotations are in the <literal>javax.persistence.*</literal>
- package. Most JDK 5 compliant IDE (like Eclipse, IntelliJ IDEA and
- Netbeans) can autocomplete annotation interfaces and attributes for you
- (even without a specific "EJB3" module, since EJB3 annotations are plain
- JDK 5 annotations).</para>
-
- <para>For more and runnable concrete examples read the JBoss EJB 3.0
- tutorial or review the Hibernate Annotations test suite. Most of the unit
- tests have been designed to represent a concrete example and be a
- inspiration source.</para>
-
- <sect2>
- <title>Declaring an entity bean</title>
-
- <para>Every bound persistent POJO class is an entity bean and is
- declared using the <literal>@Entity</literal> annotation (at the class
- level):</para>
-
- <programlisting>
-@Entity
-public class Flight implements Serializable {
- Long id;
-
- @Id
- public Long getId() { return id; }
-
- public void setId(Long id) { this.id = id; }
-}
- </programlisting>
-
- <para><literal>@Entity</literal> declares the class as an entity bean
- (i.e. a persistent POJO class), <literal>@Id</literal> declares the
- identifier property of this entity bean. The other mapping declarations
- are implicit. This configuration by exception concept is central to the
- new EJB3 specification and a major improvement. The class Flight is
- mapped to the Flight table, using the column id as its primary key
- column.</para>
-
- <para>Depending on whether you annotate fields or methods, the access
- type used by Hibernate will be <literal>field</literal> or
- <literal>property</literal>. The EJB3 spec requires that you declare
- annotations on the element type that will be accessed, i.e. the getter
- method if you use <literal>property</literal> access, the field if you
- use <literal>field</literal> access. Mixing EJB3 annotations in both
- fields and methods should be avoided. Hibernate will guess the access
- type from the position of <literal>@Id</literal> or
- <literal>@EmbeddedId</literal>.</para>
-
- <sect3>
- <title>Defining the table</title>
-
- <para><literal>@Table</literal> is set at the class level; it allows
- you to define the table, catalog, and schema names for your entity
- bean mapping. If no <literal>@Table</literal> is defined the default
- values are used: the unqualified class name of the entity.</para>
-
- <programlisting>
-@Entity
-@Table(name="tbl_sky")
-public class Sky implements Serializable {
-...
- </programlisting>
-
- <para>The <literal>@Table</literal> element also contains a
- <literal>schema</literal> and a <literal>catalog</literal> attributes,
- if they need to be defined. You can also define unique constraints to
- the table using the <literal>@UniqueConstraint</literal> annotation in
- conjunction with <literal>@Table</literal> (for a unique constraint
- bound to a single column, refer to <literal>@Column</literal>).</para>
-
- <programlisting>@Table(name="tbl_sky",
- <emphasis role="bold">uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}</emphasis>
-)</programlisting>
-
- <para>A unique constraint is applied to the tuple month, day. Note
- that the <literal>columnNames</literal> array refers to the logical
- column names.</para>
-
- <remark>The logical column name is defined by the Hibernate
- NamingStrategy implementation. The default EJB3 naming strategy use
- the physical column name as the logical column name. Note that this
- may be different than the property name (if the column name is
- explicit). Unless you override the NamingStrategy, you shouldn't worry
- about that.</remark>
- </sect3>
-
- <sect3>
- <title>Versioning for optimistic locking</title>
-
- <para>You can add optimistic locking capability to an entity bean
- using the <literal>@Version</literal> annotation:</para>
-
- <programlisting>
-@Entity
-public class Flight implements Serializable {
-...
- @Version
- @Column(name="OPTLOCK")
- public Integer getVersion() { ... }
-} </programlisting>
-
- <para>The version property will be mapped to the
- <literal>OPTLOCK</literal> column, and the entity manager will use it
- to detect conflicting updates (preventing lost updates you might
- otherwise see with the last-commit-wins strategy).</para>
-
- <para>The version column may be a numeric (the recommended solution)
- or a timestamp as per the EJB3 spec. Hibernate support any kind of
- type provided that you define and implement the appropriate
- <classname>UserVersionType</classname>.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Mapping simple properties</title>
-
- <sect3>
- <title>Declaring basic property mappings</title>
-
- <para>Every non static non transient property (field or method) of an
- entity bean is considered persistent, unless you annotate it as
- <literal>@Transient</literal>. Not having an annotation for your
- property is equivalent to the appropriate <literal>@Basic</literal>
- annotation. The <literal>@Basic</literal> annotation allows you to
- declare the fetching strategy for a property:</para>
-
- <programlisting>public transient int counter; //transient property
-
-private String firstname; //persistent property
-
-@Transient
-String getLengthInMeter() { ... } //transient property
-
-String getName() {... } // persistent property
-
-@Basic
-int getLength() { ... } // persistent property
-
-@Basic(fetch = FetchType.LAZY)
-String getDetailedComment() { ... } // persistent property
-
-(a)Temporal(TemporalType.TIME)
-java.util.Date getDepartureTime() { ... } // persistent property
-
-@Enumerated(STRING)
-Starred getNote() { ... } //enum persisted as String in database</programlisting>
-
- <para><literal>counter</literal>, a transient field, and
- <literal>lengthInMeter</literal>, a method annotated as
- <literal>@Transient</literal>, and will be ignored by the entity
- manager. <literal>name</literal>, <literal>length</literal>, and
- <literal>firstname</literal> properties are mapped persistent and
- eagerly fetched (the default for simple properties). The
- <literal>detailedComment</literal> property value will be lazily
- fetched from the database once a lazy property of the entity is
- accessed for the first time. Usually you don't need to lazy simple
- properties (not to be confused with lazy association fetching).</para>
-
- <note>
- <para>To enable property level lazy fetching, your classes have to
- be instrumented: bytecode is added to the original one to enable
- such feature, please refer to the Hibernate reference documentation.
- If your classes are not instrumented, property level lazy loading is
- silently ignored.</para>
- </note>
-
- <para>The recommended alternative is to use the projection capability
- of EJB-QL or Criteria queries.</para>
-
- <para>EJB3 support property mapping of all basic types supported by
- Hibernate (all basic Java types , their respective wrappers and
- serializable classes). Hibernate Annotations support out of the box
- Enum type mapping either into a ordinal column (saving the enum
- ordinal) or a string based column (saving the enum string
- representation): the persistence representation, defaulted to ordinal,
- can be overriden through the <literal>@Enumerated</literal> annotation
- as shown in the <literal>note</literal> property example.</para>
-
- <para>In core Java APIs, the temporal precision is not defined. When
- dealing with temporal data you might want to describe the expected
- precision in database. Temporal data can have <literal>DATE</literal>,
- <literal>TIME</literal>, or <literal>TIMESTAMP</literal> precision (ie
- the actual date, only the time, or both). Use the
- <literal>@Temporal</literal> annotation to fine tune that.</para>
-
- <para><literal>@Lob</literal> indicates that the property should be
- persisted in a Blob or a Clob depending on the property type:
- <classname>java.sql.Clob</classname>,
- <classname>Character[]</classname>, <classname>char[]</classname> and
- java.lang.<classname>String</classname> will be persisted in a Clob.
- <classname>java.sql.Blob</classname>, <classname>Byte[]</classname>,
- <classname>byte[] </classname>and serializable type will be persisted
- in a Blob.</para>
-
- <programlisting>
-@Lob
-public String getFullText() {
- return fullText;
-}
-
-@Lob
-public byte[] getFullCode() {
- return fullCode;
-}
- </programlisting>
-
- <para>If the property type implements
- <classname>java.io.Serializable</classname> and is not a basic type,
- and if the property is not annotated with <literal>@Lob</literal>,
- then the Hibernate <literal>serializable</literal> type is
- used.</para>
- </sect3>
-
- <sect3>
- <title>Declaring column attributes</title>
-
- <para>The column(s) used for a property mapping can be defined using
- the <literal>@Column</literal> annotation. Use it to override default
- values (see the EJB3 specification for more information on the
- defaults). You can use this annotation at the property level for
- properties that are:</para>
-
- <itemizedlist>
- <listitem>
- <para>not annotated at all</para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Basic</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Version</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Lob</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with <literal>@Temporal</literal></para>
- </listitem>
-
- <listitem>
- <para>annotated with
- <literal>@org.hibernate.annotations.CollectionOfElements</literal>
- (for Hibernate only)</para>
- </listitem>
- </itemizedlist>
-
- <programlisting>
-@Entity
-public class Flight implements Serializable {
-...
-@Column(updatable = false, name = "flight_name", nullable = false, length=50)
-public String getName() { ... }
- </programlisting>
-
- <para>The <literal>name</literal> property is mapped to the
- <literal>flight_name</literal> column, which is not nullable, has a
- length of 50 and is not updatable (making the property
- immutable).</para>
-
- <para>This annotation can be applied to regular properties as well as
- <literal>@Id</literal> or <literal>@Version</literal>
- properties.</para>
-
- <programlistingco>
- <areaspec>
- <area coords="2 55" id="hm1" />
-
- <area coords="3 55" id="hm2" />
-
- <area coords="4 55" id="hm3" />
-
- <area coords="5 55" id="hm4" />
-
- <area coords="6 55" id="hm5" />
-
- <area coords="7 55" id="hm6" />
-
- <area coords="8 55" id="hm7" />
-
- <area coords="9 55" id="hm8" />
-
- <area coords="10 55" id="hm9" />
-
- <area coords="11 55" id="hm10" />
- </areaspec>
-
- <programlisting>@Column(
- name="columnName";
- boolean unique() default false;
- boolean nullable() default true;
- boolean insertable() default true;
- boolean updatable() default true;
- String columnDefinition() default "";
- String table() default "";
- int length() default 255;
- int precision() default 0; // decimal precision
- int scale() default 0; // decimal scale</programlisting>
-
- <calloutlist>
- <callout arearefs="hm1">
- <para><literal>name</literal> (optional): the column name
- (default to the property name)</para>
- </callout>
-
- <callout arearefs="hm2">
- <para><literal>unique</literal> (optional): set a unique
- constraint on this column or not (default false)</para>
- </callout>
-
- <callout arearefs="hm3">
- <para><literal>nullable</literal> (optional): set the column as
- nullable (default false).</para>
- </callout>
-
- <callout arearefs="hm4">
- <para><literal>insertable</literal> (optional): whether or not
- the column will be part of the insert statement (default
- true)</para>
- </callout>
-
- <callout arearefs="hm5">
- <para><literal>updatable</literal> (optional): whether or not
- the column will be part of the update statement (default
- true)</para>
- </callout>
-
- <callout arearefs="hm6">
- <para><literal>columnDefinition</literal> (optional): override
- the sql DDL fragment for this particular column (non
- portable)</para>
- </callout>
-
- <callout arearefs="hm7">
- <para><literal>table</literal> (optional): define the targeted
- table (default primary table)</para>
- </callout>
-
- <callout arearefs="hm8">
- <para><literal><literal>length</literal></literal> (optional):
- column length (default 255)</para>
- </callout>
-
- <callout arearefs="hm8">
- <para><literal><literal>precision</literal></literal>
- (optional): column decimal precision (default 0)</para>
- </callout>
-
- <callout arearefs="hm10">
- <para><literal><literal>scale</literal></literal> (optional):
- column decimal scale if useful (default 0)</para>
- </callout>
- </calloutlist>
- </programlistingco>
- </sect3>
-
- <sect3>
- <title>Embedded objects (aka components)</title>
-
- <para>It is possible to declare an embedded component inside an entity
- and even override its column mapping. Component classes have to be
- annotated at the class level with the <literal>@Embeddable</literal>
- annotation. It is possible to override the column mapping of an
- embedded object for a particular entity using the
- <literal>@Embedded</literal> and <literal>@AttributeOverride</literal>
- annotation in the associated property:</para>
-
- <programlisting>
-@Entity
-public class Person implements Serializable {
-
- // Persistent component using defaults
- Address homeAddress;
-
- @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
- @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
- } )
- Country bornIn;
- ...
-}
- </programlisting>
-
- <programlisting>
-@Embeddable
-public class Address implements Serializable {
- String city;
- Country nationality; //no overriding here
-}
- </programlisting>
-
- <programlisting>
-@Embeddable
-public class Country implements Serializable {
- private String iso2;
- @Column(name="countryName") private String name;
-
- public String getIso2() { return iso2; }
- public void setIso2(String iso2) { this.iso2 = iso2; }
-
-
- public String getName() { return name; }
- public void setName(String name) { this.name = name; }
- ...
-}
- </programlisting>
-
- <para>A embeddable object inherit the access type of its owning entity
- (note that you can override that using the Hibernate specific
- <literal>@AccessType</literal> annotations (see <xref
- linkend="entity-hibspec" />).</para>
-
- <para>The <literal>Person</literal> entity bean has two component
- properties, <literal>homeAddress</literal> and
- <literal>bornIn</literal>. <literal>homeAddress</literal> property has
- not been annotated, but Hibernate will guess that it is a persistent
- component by looking for the <literal>@Embeddable</literal> annotation
- in the Address class. We also override the mapping of a column name
- (to <literal>bornCountryName</literal>) with the
- <literal>@Embedded</literal> and <literal>@AttributeOverride
- </literal>annotations for each mapped attribute of
- <literal>Country</literal>. As you can see, <literal>Country
- </literal>is also a nested component of <literal>Address</literal>,
- again using auto-detection by Hibernate and EJB3 defaults. Overriding
- columns of embedded objects of embedded objects is currently not
- supported in the EJB3 spec, however, Hibernate Annotations supports it
- through dotted expressions.</para>
-
- <para><programlisting> @Embedded
- @AttributeOverrides( {
- @AttributeOverride(name="city", column = @Column(name="fld_city") )
- @AttributeOverride(name="<emphasis role="bold">nationality.iso2</emphasis>", column = @Column(name="nat_Iso2") ),
- @AttributeOverride(name="<emphasis role="bold">nationality.name</emphasis>", column = @Column(name="nat_CountryName") )
- //nationality columns in homeAddress are overridden
- } )
- Address homeAddress;</programlisting>Hibernate Annotations supports one
- more feature that is not explicitly supported by the EJB3
- specification. You can annotate a embedded object with the
- <literal>@MappedSuperclass</literal> annotation to make the superclass
- properties persistent (see <literal>@MappedSuperclass</literal> for
- more informations).</para>
-
- <para>While not supported by the EJB3 specification, Hibernate
- Annotations allows you to use association annotations in an embeddable
- object (ie <literal>@*ToOne</literal> nor
- <literal>@*ToMany</literal>). To override the association columns you
- can use <literal>@AssociationOverride</literal>.</para>
-
- <para>If you want to have the same embeddable object type twice in the
- same entity, the column name defaulting will not work: at least one of
- the columns will have to be explicit. Hibernate goes beyond the EJB3
- spec and allows you to enhance the defaulting mechanism through the
- <classname>NamingStrategy</classname>.
- <classname>DefaultComponentSafeNamingStrategy</classname> is a small
- improvement over the default EJB3NamingStrategy that allows embedded
- objects to be defaulted even if used twice in the same entity.</para>
- </sect3>
-
- <sect3>
- <title>Non-annotated property defaults</title>
-
- <para>If a property is not annotated, the following rules
- apply:</para>
-
- <itemizedlist>
- <listitem>
- If the property is of a single type, it is mapped as @Basic
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is annotated as @Embeddable, it is mapped as @Embedded
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is Serializable, it is mapped as @Basic in a column holding the object in its serialized version
- </listitem>
-
- <listitem>
- Otherwise, if the type of the property is java.sql.Clob or java.sql.Blob, it is mapped as @Lob with the appropriate LobType
- </listitem>
- </itemizedlist>
- </sect3>
- </sect2>
-
- <sect2 id="entity-mapping-identifier" label=""
- xreflabel="Mapping identifier properties">
- <title>Mapping identifier properties</title>
-
- <para>The <literal>@Id</literal> annotation lets you define which
- property is the identifier of your entity bean. This property can be set
- by the application itself or be generated by Hibernate (preferred). You
- can define the identifier generation strategy thanks to the
- <literal>@GeneratedValue</literal> annotation:</para>
-
- <itemizedlist>
- <listitem>
- AUTO - either identity column, sequence or table depending on the underlying DB
- </listitem>
-
- <listitem>
- TABLE - table holding the id
- </listitem>
-
- <listitem>
- IDENTITY - identity column
- </listitem>
-
- <listitem>
- SEQUENCE - sequence
- </listitem>
- </itemizedlist>
-
- <para>Hibernate provides more id generators than the basic EJB3 ones.
- Check <xref linkend="entity-hibspec" /> for more informations.</para>
-
- <para>The following example shows a sequence generator using the
- SEQ_STORE configuration (see below)</para>
-
- <programlisting>
-@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
-public Integer getId() { ... }
- </programlisting>
-
- <para>The next example uses the identity generator:</para>
-
- <programlisting>
-@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
-public Long getId() { ... }
- </programlisting>
-
- <para>The <literal>AUTO</literal> generator is the preferred type for
- portable applications (across several DB vendors). The identifier
- generation configuration can be shared for several
- <literal>@Id</literal> mappings with the generator attribute. There are
- several configurations available through
- <literal>@SequenceGenerator</literal> and
- <literal>@TableGenerator</literal>. The scope of a generator can be the
- application or the class. Class-defined generators are not visible
- outside the class and can override application level generators.
- Application level generators are defined at XML level (see <xref
- linkend="xml-overriding" />):</para>
-
- <programlisting><table-generator name="EMP_GEN"
- table="GENERATOR_TABLE"
- pk-column-name="key"
- value-column-name="hi"
- pk-column-value="EMP"
- allocation-size="20"/>
-
-//and the annotation equivalent
-
-(a)javax.persistence.TableGenerator(
- name="EMP_GEN",
- table="GENERATOR_TABLE",
- pkColumnName = "key",
- valueColumnName = "hi"
- pkColumnValue="EMP",
- allocationSize=20
-)
-
-<sequence-generator name="SEQ_GEN"
- sequence-name="my_sequence"
- allocation-size="20"/>
-
-//and the annotation equivalent
-
-(a)javax.persistence.SequenceGenerator(
- name="SEQ_GEN",
- sequenceName="my_sequence",
- allocationSize=20
-)
- </programlisting>
-
- <para>If JPA XML (like <filename>META-INF/orm.xml</filename>) is used to
- define thegenerators, <literal>EMP_GEN</literal> and
- <literal>SEQ_GEN</literal> are application level generators.
- <literal>EMP_GEN</literal> defines a table based id generator using the
- hilo algorithm with a <literal>max_lo</literal> of 20. The hi value is
- kept in a <literal>table</literal> "<literal>GENERATOR_TABLE</literal>".
- The information is kept in a row where <literal>pkColumnName</literal>
- "key" is equals to <literal>pkColumnValue</literal>
- "<literal>EMP</literal>" and column <literal>valueColumnName</literal>
- "<literal>hi</literal>" contains the the next high value used.</para>
-
- <para><literal>SEQ_GEN</literal> defines a sequence generator using a
- sequence named <literal>my_sequence</literal>. The allocation size used
- for this sequence based hilo algorithm is 20. Note that this version of
- Hibernate Annotations does not handle <literal>initialValue</literal> in
- the sequence generator. The default allocation size is 50, so if you
- want to use a sequence and pickup the value each time, you must set the
- allocation size to 1.</para>
-
- <note>
- <para>Package level definition is no longer supported by the EJB 3.0
- specification. However, you can use the
- <literal>@GenericGenerator</literal> at the package level (see <xref
- linkend="entity-hibspec-identifier" />).</para>
- </note>
-
- <para>The next example shows the definition of a sequence generator in a
- class scope:</para>
-
- <programlisting>
-@Entity
-(a)javax.persistence.SequenceGenerator(
- name="SEQ_STORE",
- sequenceName="my_sequence"
-)
-public class Store implements Serializable {
- private Long id;
-
- @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
- public Long getId() { return id; }
-}
- </programlisting>
-
- <para>This class will use a sequence named my_sequence and the SEQ_STORE
- generator is not visible in other classes. Note that you can check the
- Hibernate Annotations tests in the org.hibernate.test.metadata.id
- package for more examples.</para>
-
- <para>You can define a composite primary key through several
- syntaxes:</para>
-
- <itemizedlist>
- <listitem>
- annotate the component property as @Id and make the component class @Embeddable
- </listitem>
-
- <listitem>
- annotate the component property as @EmbeddedId
- </listitem>
-
- <listitem>
- annotate the class as @IdClass and annotate each property of the entity involved in the primary key with @Id
- </listitem>
- </itemizedlist>
-
- <para>While quite common to the EJB2 developer,
- <literal>@IdClass</literal> is likely new for Hibernate users. The
- composite primary key class corresponds to multiple fields or properties
- of the entity class, and the names of primary key fields or properties
- in the primary key class and those of the entity class must match and
- their types must be the same. Let's look at an example:</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@IdClass(FootballerPk.class)</emphasis>
-public class Footballer {
- //part of the id key
- <emphasis role="bold">@Id</emphasis> public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- //part of the id key
- <emphasis role="bold">@Id</emphasis> public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-
- public String getClub() {
- return club;
- }
-
- public void setClub(String club) {
- this.club = club;
- }
-
- //appropriate equals() and hashCode() implementation
-}
-
-@Embeddable
-public class FootballerPk implements Serializable {
- //same name and type as in Footballer
- public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- //same name and type as in Footballer
- public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-
- //appropriate equals() and hashCode() implementation
-}
-</programlisting>
-
- <para>As you may have seen, <literal>@IdClass</literal> points to the
- corresponding primary key class.</para>
-
- <para>While not supported by the EJB3 specification, Hibernate allows
- you to define associations inside a composite identifier. Simply use the
- regular annotations for that</para>
-
- <programlisting>@Entity
-@AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") )
-public class TvMagazin {
- @EmbeddedId public TvMagazinPk id;
- @Temporal(TemporalType.TIME) Date time;
-}
-
-@Embeddable
-public class TvMagazinPk implements Serializable {
- @ManyToOne
- public Channel channel;
- public String name;
- @ManyToOne
- public Presenter presenter;
-}
-</programlisting>
- </sect2>
-
- <sect2>
- <title>Mapping inheritance</title>
-
- <para>EJB3 supports the three types of inheritance:</para>
-
- <itemizedlist>
- <listitem>
- Table per Class Strategy: the <union-class> element in Hibernate
- </listitem>
-
- <listitem>
- Single Table per Class Hierarchy Strategy: the <subclass> element in Hibernate
- </listitem>
-
- <listitem>
- Joined Subclass Strategy: the <joined-subclass> element in Hibernate
- </listitem>
- </itemizedlist>
-
- <para>The chosen strategy is declared at the class level of the top
- level entity in the hierarchy using the <literal>@Inheritance</literal>
- annotation.</para>
-
- <note>
- <para>Annotating interfaces is currently not supported.</para>
- </note>
-
- <sect3>
- <title>Table per class</title>
-
- <para>This strategy has many drawbacks (esp. with polymorphic queries
- and associations) explained in the EJB3 spec, the Hibernate reference
- documentation, Hibernate in Action, and many other places. Hibernate
- work around most of them implementing this strategy using <literal>SQL
- UNION</literal> queries. It is commonly used for the top level of an
- inheritance hierarchy:</para>
-
- <programlisting>
-@Entity
-@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
-public class Flight implements Serializable {
- </programlisting>
-
- <para>This strategy support one to many associations provided that
- they are bidirectional. This strategy does not support the
- <literal>IDENTITY</literal> generator strategy: the id has to be
- shared across several tables. Consequently, when using this strategy,
- you should not use <literal>AUTO </literal>nor
- <literal>IDENTITY</literal>.</para>
- </sect3>
-
- <sect3>
- <title>Single table per class hierarchy</title>
-
- <para>All properties of all super- and subclasses are mapped into the
- same table, instances are distinguished by a special discriminator
- column:</para>
-
- <programlisting>
-@Entity
-(a)Inheritance(strategy=InheritanceType.SINGLE_TABLE)
-@DiscriminatorColumn(
- name="planetype",
- discriminatorType=DiscriminatorType.STRING
-)
-@DiscriminatorValue("Plane")
-public class Plane { ... }
-
-@Entity
-@DiscriminatorValue("A320")
-public class A320 extends Plane { ... }
- </programlisting>
-
- <para><classname>Plane</classname> is the superclass, it defines the
- inheritance strategy <literal>InheritanceType.SINGLE_TABLE</literal>.
- It also defines the discriminator column through the
- <literal>@DiscriminatorColumn</literal> annotation, a discriminator
- column can also define the discriminator type. Finally, the
- <literal>@DiscriminatorValue</literal> annotation defines the value
- used to differentiate a class in the hierarchy. All of these
- attributes have sensible default values. The default name of the
- discriminator column is <literal>DTYPE</literal>. The default
- discriminator value is the entity name (as defined in
- <literal>@Entity.name</literal>) for DiscriminatorType.STRING.
- <classname>A320</classname> is a subclass; you only have to define
- discriminator value if you don't want to use the default value. The
- strategy and the discriminator type are implicit.</para>
-
- <para><literal>@Inheritance</literal> and
- <literal>@DiscriminatorColumn</literal> should only be defined at the
- top of the entity hierarchy.</para>
- </sect3>
-
- <sect3>
- <title>Joined subclasses</title>
-
- <para>The<literal> @PrimaryKeyJoinColumn</literal> and
- <literal>@PrimaryKeyJoinColumns</literal> annotations define the
- primary key(s) of the joined subclass table:</para>
-
- <programlisting>
-@Entity
-(a)Inheritance(strategy=InheritanceType.JOINED)
-public class Boat implements Serializable { ... }
-
-@Entity
-public class Ferry extends Boat { ... }
-
-@Entity
-@PrimaryKeyJoinColumn(name="BOAT_ID")
-public class AmericaCupClass extends Boat { ... }
- </programlisting>
-
- <para>All of the above entities use the <literal>JOINED</literal>
- strategy, the <literal>Ferry</literal> table is joined with the
- <literal>Boat</literal> table using the same primary key names. The
- <literal>AmericaCupClass</literal> table is joined with
- <literal>Boat</literal> using the join condition <code>Boat.id =
- AmericaCupClass.BOAT_ID</code>.</para>
- </sect3>
-
- <sect3>
- <title>Inherit properties from superclasses</title>
-
- <para>This is sometimes useful to share common properties through a
- technical or a business superclass without including it as a regular
- mapped entity (ie no specific table for this entity). For that purpose
- you can map them as <literal>@MappedSuperclass</literal>.</para>
-
- <programlisting>@MappedSuperclass
-public class BaseEntity {
- @Basic
- @Temporal(TemporalType.TIMESTAMP)
- public Date getLastUpdate() { ... }
- public String getLastUpdater() { ... }
- ...
-}
-
-@Entity class Order extends BaseEntity {
- @Id public Integer getId() { ... }
- ...
-}</programlisting>
-
- <para>In database, this hierarchy will be represented as an
- <literal>Order</literal> table having the <literal>id</literal>,
- <literal>lastUpdate</literal> and <literal>lastUpdater</literal>
- columns. The embedded superclass property mappings are copied into
- their entity subclasses. Remember that the embeddable superclass is
- not the root of the hierarchy though.</para>
-
- <note>
- <para>Properties from superclasses not mapped as
- <literal>@MappedSuperclass</literal> are ignored.</para>
- </note>
-
- <note>
- <para>The access type (field or methods), is inherited from the root
- entity, unless you use the Hibernate annotation
- <literal>@AccessType</literal></para>
- </note>
-
- <note>
- <para>The same notion can be applied to
- <literal>@Embeddable</literal> objects to persist properties from
- their superclasses. You also need to use
- <literal>@MappedSuperclass</literal> to do that (this should not be
- considered as a standard EJB3 feature though)</para>
- </note>
-
- <note>
- <para>It is allowed to mark a class as
- <literal>@MappedSuperclass</literal> in the middle of the mapped
- inheritance hierarchy.</para>
- </note>
-
- <note>
- <para>Any class in the hierarchy non annotated with
- <literal>@MappedSuperclass</literal> nor <literal>@Entity</literal>
- will be ignored.</para>
- </note>
-
- <para>You can override columns defined in entity superclasses at the
- root entity level using the <literal>@AttributeOverride</literal>
- annotation.</para>
-
- <programlisting>@MappedSuperclass
-public class FlyingObject implements Serializable {
-
- public int getAltitude() {
- return altitude;
- }
-
- @Transient
- public int getMetricAltitude() {
- return metricAltitude;
- }
-
- @ManyToOne
- public PropulsionType getPropulsion() {
- return metricAltitude;
- }
- ...
-}
-
-@Entity
-@AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
-@AssociationOverride( name="propulsion", joinColumns = @JoinColumn(name="fld_propulsion_fk") )
-public class Plane extends FlyingObject {
- ...
-}</programlisting>
-
- <para>The <literal>altitude</literal> property will be persisted in an
- <literal>fld_altitude</literal> column of table
- <literal>Plane</literal> and the propulsion association will be
- materialized in a <literal>fld_propulsion_fk</literal> foreign key
- column.</para>
-
- <para>You can define <literal>@AttributeOverride</literal>(s) and
- <literal>@AssociationOverride</literal>(s) on
- <literal>@Entity</literal> classes,
- <literal>@MappedSuperclass</literal> classes and properties pointing
- to an <literal>@Embeddable</literal> object.</para>
- </sect3>
- </sect2>
-
- <sect2 id="entity-mapping-association">
- <title>Mapping entity bean associations/relationships</title>
-
- <sect3>
- <title>One-to-one</title>
-
- <para>You can associate entity beans through a one-to-one relationship
- using <literal>@OneToOne</literal>. There are three cases for
- one-to-one associations: either the associated entities share the same
- primary keys values, a foreign key is held by one of the entities
- (note that this FK column in the database should be constrained unique
- to simulate one-to-one multiplicity), or a association table is used
- to store the link between the 2 entities (a unique constraint has to
- be defined on each fk to ensure the one to one multiplicity)</para>
-
- <para>First, we map a real one-to-one association using shared primary
- keys:</para>
-
- <programlisting>
-@Entity
-public class Body {
- @Id
- public Long getId() { return id; }
-
- @OneToOne(cascade = CascadeType.ALL)
- @PrimaryKeyJoinColumn
- public Heart getHeart() {
- return heart;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Heart {
- @Id
- public Long getId() { ...}
-}
- </programlisting>
-
- <para>The one to one is marked as true by using the
- <literal>@PrimaryKeyJoinColumn</literal> annotation.</para>
-
- <para>In the following example, the associated entities are linked
- through a foreign key column:</para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToOne(cascade = CascadeType.ALL)
- <emphasis role="bold">@JoinColumn(name="passport_fk")</emphasis>
- public Passport getPassport() {
- ...
- }
-
-@Entity
-public class Passport implements Serializable {
- @OneToOne(<emphasis role="bold">mappedBy = "passport"</emphasis>)
- public Customer getOwner() {
- ...
-}
- </programlisting>
-
- <para>A <classname>Customer</classname> is linked to a
- <classname>Passport</classname>, with a foreign key column named
- <literal>passport_fk</literal> in the <literal>Customer</literal>
- table. The join column is declared with the
- <literal>@JoinColumn</literal> annotation which looks like the
- <literal>@Column</literal> annotation. It has one more parameters
- named <literal>referencedColumnName</literal>. This parameter declares
- the column in the targeted entity that will be used to the join. Note
- that when using
- <literal><literal>referencedColumnName</literal></literal> to a non
- primary key column, the associated class has to be
- <classname>Serializable</classname>. Also note that the
- <literal><literal>referencedColumnName</literal></literal> to a non
- primary key column has to be mapped to a property having a single
- column (other cases might not work).</para>
-
- <para>The association may be bidirectional. In a bidirectional
- relationship, one of the sides (and only one) has to be the owner: the
- owner is responsible for the association column(s) update. To declare
- a side as <emphasis>not</emphasis> responsible for the relationship,
- the attribute <literal>mappedBy</literal> is used.
- <literal>mappedBy</literal> refers to the property name of the
- association on the owner side. In our case, this is
- <literal>passport</literal>. As you can see, you don't have to (must
- not) declare the join column since it has already been declared on the
- owners side.</para>
-
- <para>If no <literal>@JoinColumn</literal> is declared on the owner
- side, the defaults apply. A join column(s) will be created in the
- owner table and its name will be the concatenation of the name of the
- relationship in the owner side, <keycap>_</keycap> (underscore), and
- the name of the primary key column(s) in the owned side. In this
- example <literal>passport_id</literal> because the property name is
- <literal>passport</literal> and the column id of <literal>Passport
- </literal>is <literal>id</literal>.</para>
-
- <para>The third possibility (using an association table) is very
- exotic.</para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToOne(cascade = CascadeType.ALL)
- <emphasis role="bold">@JoinTable(name = "CustomerPassports"
- joinColumns = @JoinColumn(name="customer_fk"),
- inverseJoinColumns = @JoinColumns(name="passport_fk")</emphasis>
- )
- public Passport getPassport() {
- ...
- }
-
-@Entity
-public class Passport implements Serializable {
- @OneToOne(<emphasis role="bold">mappedBy = "passport"</emphasis>)
- public Customer getOwner() {
- ...
-}
- </programlisting>
-
- <para>A <classname>Customer</classname> is linked to a
- <classname>Passport</classname> through a association table named
- <literal>CustomerPassports</literal> ; this association table has a
- foreign key column named <literal>passport_fk</literal> pointing to
- the <literal>Passport</literal> table (materialized by the
- <literal>inverseJoinColumn</literal>, and a foreign key column named
- <literal>customer_fk</literal> pointing to the
- <literal>Customer</literal> table materialized by the
- <literal>joinColumns</literal> attribute.</para>
-
- <para>You must declare the join table name and the join columns
- explicitly in such a mapping.</para>
- </sect3>
-
- <sect3>
- <title>Many-to-one</title>
-
- <para>Many-to-one associations are declared at the property level with
- the annotation <literal>@ManyToOne</literal>:</para>
-
- <programlisting>
-@Entity()
-public class Flight implements Serializable {
- <emphasis role="bold">@ManyToOne</emphasis>( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
- @JoinColumn(name="COMP_ID")
- public Company getCompany() {
- return company;
- }
- ...
-}
- </programlisting>
-
- <para>The <literal>@JoinColumn</literal> attribute is optional, the
- default value(s) is like in one to one, the concatenation of the name
- of the relationship in the owner side, <keycap>_</keycap>
- (underscore), and the name of the primary key column in the owned
- side. In this example <literal>company_id</literal> because the
- property name is <literal>company</literal> and the column id of
- Company is <literal>id</literal>.</para>
-
- <para><literal>@ManyToOne</literal> has a parameter named
- <literal>targetEntity</literal> which describes the target entity
- name. You usually don't need this parameter since the default value
- (the type of the property that stores the association) is good in
- almost all cases. However this is useful when you want to use
- interfaces as the return type instead of the regular entity.</para>
-
- <programlisting>
-@Entity()
-public class Flight implements Serializable {
- @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, <emphasis
- role="bold">targetEntity=CompanyImpl.class</emphasis> )
- @JoinColumn(name="COMP_ID")
- public Company getCompany() {
- return company;
- }
- ...
-}
-
-public interface Company {
- ...
- </programlisting>
-
- <para>You can alse map a many to one association through an
- association table. This association table described by the
- <literal>@JoinTable</literal> annotation will contains a foreign key
- referencing back the entity table (through
- <literal>@JoinTable.joinColumns</literal>) and a a foreign key
- referencing the target entity table (through
- <literal>@JoinTable.inverseJoinColumns</literal>).</para>
-
- <programlisting>
-@Entity()
-public class Flight implements Serializable {
- @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
- <emphasis role="bold">@JoinTable(name="Flight_Company",
- joinColumns = @JoinColumn(name="FLIGHT_ID"),
- inverseJoinColumns = @JoinColumns(name="COMP_ID")
- )</emphasis>
- public Company getCompany() {
- return company;
- }
- ...
-}
- </programlisting>
- </sect3>
-
- <sect3 id="entity-mapping-association-collections" revision="1">
- <title>Collections</title>
-
- <sect4 id="entity-mapping-association-collections-overview"
- revision="1">
- <title>Overview</title>
-
- <para>You can map <classname>Collection</classname>,
- <literal>List</literal> (ie ordered lists, not indexed lists),
- <literal>Map</literal> and <classname>Set</classname>. The EJB3
- specification describes how to map an ordered list (ie a list
- ordered at load time) using
- <literal>@javax.persistence.OrderBy</literal> annotation: this
- annotation takes into parameter a list of comma separated (target
- entity) properties to order the collection by (eg <code>firstname
- asc, age desc</code>), if the string is empty, the collection will
- be ordered by id. For true indexed
- collections, please refer to the <xref linkend="entity-hibspec" />.
- EJB3 allows you to map Maps using as a key one of the target entity
- property using <literal>@MapKey(name="myProperty")</literal>
- (myProperty is a property name in the target entity). When using
- <literal>@MapKey</literal> (without property name), the target
- entity primary key is used. The map key uses the same column as the
- property pointed out: there is no additional column defined to hold
- the map key, and it does make sense since the map key actually
- represent a target property. Be aware that once loaded, the key is
- no longer kept in sync with the property, in other words, if you
- change the property value, the key will not change automatically in
- your Java model (for true map support please refers to <xref
- linkend="entity-hibspec" />). Many people confuse
- <literal><map></literal> capabilities and
- <literal>@MapKey</literal> ones. These are two different features.
- <literal>@MapKey</literal> still has some limitations, please check
- the forum or the JIRA tracking system for more informations.</para>
-
- <para>Hibernate has several notions of collections.</para>
-
- <para></para>
-
- <table>
- <title>Collections semantics</title>
-
- <tgroup cols="3">
- <colspec colname="c1" />
-
- <colspec colname="c2" />
-
- <colspec colname="c3" colnum="2" />
-
- <thead>
- <row>
- <entry>Semantic</entry>
-
- <entry>java representation</entry>
-
- <entry>annotations</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>Bag semantic</entry>
-
- <entry>java.util.List, java.util.Collection</entry>
-
- <entry>@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany</entry>
- </row>
-
- <row>
- <entry>Bag semantic with primary key (withtout the
- limitations of Bag semantic)</entry>
-
- <entry>java.util.List, java.util.Collection</entry>
-
- <entry>(@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and @CollectionId</entry>
- </row>
-
- <row>
- <entry>List semantic</entry>
-
- <entry>java.util.List</entry>
-
- <entry>(@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and
- @org.hibernate.annotations.IndexColumn</entry>
- </row>
-
- <row>
- <entry>Set semantic</entry>
-
- <entry>java.util.Set</entry>
-
- <entry>@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany</entry>
- </row>
-
- <row>
- <entry>Map semantic</entry>
-
- <entry>java.util.Map</entry>
-
- <entry>(@org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany) and (nothing or
- @org.hibernate.annotations.MapKey/MapKeyManyToMany for true
- map support, OR @javax.persistence.MapKey</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <remark>So specifically, java.util.List collections without
- @org.hibernate.annotations.IndexColumn are going to be considered as
- bags.</remark>
-
- <para>Collection of primitive, core type or embedded objects is not
- supported by the EJB3 specification. Hibernate Annotations allows
- them however (see <xref linkend="entity-hibspec" />).</para>
-
- <programlisting>@Entity public class City {
- @OneToMany(mappedBy="city")
- <emphasis role="bold">@OrderBy("streetName")</emphasis>
- public List<Street> getStreets() {
- return streets;
- }
-...
-}
-
-@Entity public class Street {
- <emphasis role="bold">public String getStreetName()</emphasis> {
- return streetName;
- }
-
- @ManyToOne
- public City getCity() {
- return city;
- }
- ...
-}
-
-
-@Entity
-public class Software {
- @OneToMany(mappedBy="software")
- <emphasis role="bold">@MapKey(name="codeName")</emphasis>
- public Map<String, Version> getVersions() {
- return versions;
- }
-...
-}
-
-@Entity
-@Table(name="tbl_version")
-public class Version {
- <emphasis role="bold">public String getCodeName()</emphasis> {...}
-
- @ManyToOne
- public Software getSoftware() { ... }
-...
-}</programlisting>
-
- <para>So <literal>City</literal> has a collection of
- <literal>Street</literal>s that are ordered by
- <literal>streetName</literal> (of <literal>Street</literal>) when
- the collection is loaded. <literal>Software</literal> has a map of
- <literal>Version</literal>s which key is the
- <literal>Version</literal> <literal>codeName</literal>.</para>
-
- <para>Unless the collection is a generic, you will have to define
- <literal>targetEntity</literal>. This is a annotation attribute that
- take the target entity class as a value.</para>
- </sect4>
-
- <sect4 id="entity-mapping-association-collection-onetomany"
- revision="2">
- <title>One-to-many</title>
-
- <para>One-to-many associations are declared at the property level
- with the annotation <literal>@OneToMany</literal>. One to many
- associations may be bidirectional.</para>
-
- <sect5>
- <title>Bidirectional</title>
-
- <para>Since many to one are (almost) always the owner side of a
- bidirectional relationship in the EJB3 spec, the one to many
- association is annotated by <literal>@OneToMany( mappedBy=...
- )</literal></para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany(mappedBy="troop")
- public Set<Soldier> getSoldiers() {
- ...
-}
-
-@Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk")
- public Troop getTroop() {
- ...
-} </programlisting>
-
- <para><classname>Troop</classname> has a bidirectional one to many
- relationship with <literal>Soldier</literal> through the
- <literal>troop</literal> property. You don't have to (must not)
- define any physical mapping in the <literal>mappedBy</literal>
- side.</para>
-
- <para>To map a bidirectional one to many, with the one-to-many
- side as the owning side, you have to remove the
- <literal>mappedBy</literal> element and set the many to one
- <literal>@JoinColumn</literal> as insertable and updatable to
- false. This solution is obviously not optimized and will produce
- some additional UPDATE statements.</para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany
- @JoinColumn(name="troop_fk") //we need to duplicate the physical information
- public Set<Soldier> getSoldiers() {
- ...
-}
-
-@Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk", insertable=false, updatable=false)
- public Troop getTroop() {
- ...
-}</programlisting>
- </sect5>
-
- <sect5>
- <title>Unidirectional</title>
-
- <para>A unidirectional one to many using a foreign key column in
- the owned entity is not that common and not really recommended. We
- strongly advise you to use a join table for this kind of
- association (as explained in the next section). This kind of
- association is described through a
- <literal>@JoinColumn</literal></para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- public Set<Ticket> getTickets() {
- ...
-}
-
-@Entity
-public class Ticket implements Serializable {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Customer</literal> describes a unidirectional
- relationship with <literal>Ticket</literal> using the join column
- <literal>CUST_ID</literal>.</para>
- </sect5>
-
- <sect5>
- <title>Unidirectional with join table</title>
-
- <para>A unidirectional one to many with join table is much
- preferred. This association is described through an
- <literal>@JoinTable</literal>.</para>
-
- <programlisting>
-@Entity
-public class Trainer {
- @OneToMany
- @JoinTable(
- name="TrainedMonkeys",
- joinColumns = { @JoinColumn( name="trainer_id") },
- inverseJoinColumns = @JoinColumn( name="monkey_id")
- )
- public Set<Monkey> getTrainedMonkeys() {
- ...
-}
-
-@Entity
-public class Monkey {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Trainer</literal> describes a unidirectional
- relationship with <classname>Monkey</classname> using the join
- table <classname>TrainedMonkeys</classname>, with a foreign key
- <literal>trainer_id</literal> to <literal>Trainer</literal>
- (<literal>joinColumns</literal>) and a foreign key
- <literal>monkey_id</literal> to <literal>Monkey</literal>
- (<literal>inversejoinColumns</literal>).</para>
- </sect5>
-
- <sect5 id="entity-mapping-association-collection-manytomany-default"
- revision="1">
- <title>Defaults</title>
-
- <para>Without describing any physical mapping, a unidirectional
- one to many with join table is used. The table name is the
- concatenation of the owner table name, <keycap>_</keycap>, and the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the owner table,
- <keycap>_</keycap>, and the owner primary key column(s) name. The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>, and
- the other side primary key column(s) name. A unique constraint is
- added to the foreign key referencing the other side table to
- reflect the one to many.</para>
-
- <programlisting>
-@Entity
-public class Trainer {
- @OneToMany
- public Set<Tiger> getTrainedTigers() {
- ...
-}
-
-@Entity
-public class Tiger {
- ... //no bidir
-}
- </programlisting>
-
- <para><classname>Trainer</classname> describes a unidirectional
- relationship with <classname>Tiger</classname> using the join
- table <literal>Trainer_Tiger</literal>, with a foreign key
- <literal>trainer_id</literal> to <literal>Trainer</literal> (table
- name, <keycap>_</keycap>, trainer id) and a foreign key
- <literal>trainedTigers_id</literal> to <literal>Monkey</literal>
- (property name, <keycap>_</keycap>, Tiger primary column).</para>
- </sect5>
- </sect4>
-
- <sect4 id="eentity-mapping-association-collection-manytomany"
- revision="">
- <title>Many-to-many</title>
-
- <sect5>
- <title>Definition</title>
-
- <para>A many-to-many association is defined logically using the
- <literal>@ManyToMany</literal> annotation. You also have to
- describe the association table and the join conditions using the
- <literal>@JoinTable</literal> annotation. If the association is
- bidirectional, one side has to be the owner and one side has to be
- the inverse end (ie. it will be ignored when updating the
- relationship values in the association table):</para>
-
- <programlisting>
-@Entity
-public class Employer implements Serializable {
- @ManyToMany(
- targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
- cascade={CascadeType.PERSIST, CascadeType.MERGE}
- )
- @JoinTable(
- name="EMPLOYER_EMPLOYEE",
- joinColumns={@JoinColumn(name="EMPER_ID")},
- inverseJoinColumns={@JoinColumn(name="EMPEE_ID")}
- )
- public Collection getEmployees() {
- return employees;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Employee implements Serializable {
- @ManyToMany(
- cascade={CascadeType.PERSIST, CascadeType.MERGE},
- mappedBy="employees"
- targetEntity=Employer.class
- )
- public Collection getEmployers() {
- return employers;
- }
-}
- </programlisting>
-
- <para>We've already shown the many declarations and the detailed
- attributes for associations. We'll go deeper in the
- <literal>@JoinTable</literal> description, it defines a
- <literal>name</literal>, an array of join columns (an array in
- annotation is defined using { A, B, C }), and an array of inverse
- join columns. The latter ones are the columns of the association
- table which refer to the <classname>Employee</classname> primary
- key (the "other side").</para>
-
- <para>As seen previously, the other side don't have to (must not)
- describe the physical mapping: a simple
- <literal>mappedBy</literal> argument containing the owner side
- property name bind the two.</para>
- </sect5>
-
- <sect5>
- <title>Default values</title>
-
- <para>As any other annotations, most values are guessed in a many
- to many relationship. Without describing any physical mapping in a
- unidirectional many to many the following rules applied. The table
- name is the concatenation of the owner table name,
- <keycap>_</keycap> and the other side table name. The foreign key
- name(s) referencing the owner table is the concatenation of the
- owner table name, <keycap>_</keycap> and the owner primary key
- column(s). The foreign key name(s) referencing the other side is
- the concatenation of the owner property name, <keycap>_</keycap>,
- and the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
-@Entity
-public class Store {
- @ManyToMany(cascade = CascadeType.PERSIST)
- public Set<City> getImplantedIn() {
- ...
- }
-}
-
-@Entity
-public class City {
- ... //no bidirectional relationship
-}
- </programlisting>
-
- <para>A <literal>Store_City</literal> is used as the join table.
- The <literal>Store_id</literal> column is a foreign key to the
- <literal>Store</literal> table. The
- <literal>implantedIn_id</literal> column is a foreign key to the
- <literal>City</literal> table.</para>
-
- <para>Without describing any physical mapping in a bidirectional
- many to many the following rules applied. The table name is the
- concatenation of the owner table name, <keycap>_</keycap> and the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the other side property name,
- <keycap>_</keycap>, and the owner primary key column(s). The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>, and
- the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
-@Entity
-public class Store {
- @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
- public Set<Customer> getCustomers() {
- ...
- }
-}
-
-@Entity
-public class Customer {
- @ManyToMany(mappedBy="customers")
- public Set<Store> getStores() {
- ...
- }
-}
- </programlisting>
-
- <para>A <literal>Store_Customer</literal> is used as the join
- table. The <literal>stores_id</literal> column is a foreign key to
- the <literal>Store</literal> table. The
- <literal>customers_id</literal> column is a foreign key to the
- <literal>Customer</literal> table.</para>
- </sect5>
- </sect4>
- </sect3>
-
- <sect3>
- <title>Transitive persistence with cascading</title>
-
- <para>You probably have noticed the <literal>cascade</literal>
- attribute taking an array of <classname>CascadeType</classname> as a
- value. The cascade concept in EJB3 is very is similar to the
- transitive persistence and cascading of operations in Hibernate, but
- with slightly different semantics and cascading types:</para>
-
- <itemizedlist>
- <listitem>
- CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed
- </listitem>
-
- <listitem>
- CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed
- </listitem>
-
- <listitem>
- CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called
- </listitem>
-
- <listitem>
- CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called
- </listitem>
-
- <listitem>
- CascadeType.ALL: all of the above
- </listitem>
- </itemizedlist>
-
- <para>Please refer to the chapter 6.3 of the EJB3 specification for
- more information on cascading and create/merge semantics.</para>
- </sect3>
-
- <sect3 id="entity-mapping-association-fetching" revision="1">
- <title>Association fetching</title>
-
- <para>You have the ability to either eagerly or lazily fetch
- associated entities. The <literal>fetch</literal> parameter can be set
- to <literal>FetchType.LAZY</literal> or
- <literal>FetchType.EAGER</literal>. <literal>EAGER</literal> will try
- to use an outer join select to retrieve the associated object, while
- <literal>LAZY</literal> will only trigger a select when the associated
- object is accessed for the first time. <literal>@OneToMany</literal>
- and <literal>@ManyToMany</literal> associations are defaulted to
- <literal>LAZY</literal> and <literal>@OneToOne</literal> and
- <literal>@ManyToOne</literal> are defaulted to
- <literal>EAGER</literal>. For more information about static fetching,
- check <xref linkend="entity-hibspec-singleassoc-fetching" />.</para>
-
- <para>The recommanded approach is to use <literal>LAZY</literal> onn
- all static fetching definitions and override this choice dynamically
- through JPA-QL. JPA-QL has a <literal>fetch</literal> keyword that
- allows you to override laziness when doing a particular query. This is
- very useful to improve performance and is decided on a use case to use
- case basis.</para>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Mapping composite primary and foreign keys</title>
-
- <para>Composite primary keys use a embedded class as the primary key
- representation, so you'd use the <literal>@Id</literal> and
- <literal>@Embeddable</literal> annotations. Alternatively, you can use
- the <literal>@EmbeddedId</literal> annotation. Note that the dependent
- class has to be serializable and implements
- <methodname>equals()</methodname>/<methodname>hashCode()</methodname>.
- You can also use <literal>@IdClass</literal> as described in <xref
- linkend="entity-mapping-identifier" />.</para>
-
- <programlisting>
-@Entity
-public class RegionalArticle implements Serializable {
-
- @Id
- public RegionalArticlePk getPk() { ... }
-}
-
-@Embeddable
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
-
- <para>or alternatively</para>
-
- <programlisting>
-@Entity
-public class RegionalArticle implements Serializable {
-
- @EmbeddedId
- public RegionalArticlePk getPk() { ... }
-}
-
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
-
- <para><literal>@Embeddable</literal> inherit the access type of its
- owning entity unless the Hibernate specific annotation
- <literal>@AccessType</literal> is used. Composite foreign keys (if not
- using the default sensitive values) are defined on associations using
- the <literal>@JoinColumns</literal> element, which is basically an array
- of <literal>@JoinColumn</literal>. It is considered a good practice to
- express <literal>referencedColumnNames</literal> explicitly. Otherwise,
- Hibernate will suppose that you use the same order of columns as in the
- primary key declaration.</para>
-
- <programlisting>
-@Entity
-public class Parent implements Serializable {
- @Id
- public ParentPk id;
- public int age;
-
- @OneToMany(cascade=CascadeType.ALL)
- @JoinColumns ({
- @JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
- @JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
- @JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
- })
- public Set<Child> children; //unidirectional
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Child implements Serializable {
- @Id @GeneratedValue
- public Integer id;
-
- @ManyToOne
- @JoinColumns ({
- @JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
- @JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
- @JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
- })
- public Parent parent; //unidirectional
-}
- </programlisting>
-
- <programlisting>
-@Embeddable
-public class ParentPk implements Serializable {
- String firstName;
- String lastName;
- ...
-}
- </programlisting>
-
- <para>Note the explicit usage of the
- <literal>referencedColumnName</literal>.</para>
- </sect2>
-
- <sect2>
- <title>Mapping secondary tables</title>
-
- <para>You can map a single entity bean to several tables using the
- <literal>@SecondaryTable</literal> or
- <literal>@SecondaryTables</literal> class level annotations. To express
- that a column is in a particular table, use the <literal>table</literal>
- parameter of <literal>@Column</literal> or
- <literal>@JoinColumn</literal>.</para>
-
- <programlisting>
-@Entity
-@Table(name="MainCat")
-<emphasis role="bold">@SecondaryTables({
- @SecondaryTable(name="Cat1", pkJoinColumns={
- @PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
- ),
- @SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
-})</emphasis>
-public class Cat implements Serializable {
-
- private Integer id;
- private String name;
- private String storyPart1;
- private String storyPart2;
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- <emphasis role="bold">@Column(table="Cat1")</emphasis>
- public String getStoryPart1() {
- return storyPart1;
- }
-
- <emphasis role="bold">@Column(table="Cat2")</emphasis>
- public String getStoryPart2() {
- return storyPart2;
- }
-</programlisting>
-
- <para>In this example, <literal>name</literal> will be in
- <literal>MainCat</literal>. <literal>storyPart1</literal> will be in
- <literal>Cat1</literal> and <literal>storyPart2</literal> will be in
- <literal>Cat2</literal>. <literal>Cat1</literal> will be joined to
- <literal>MainCat</literal> using the <literal>cat_id</literal> as a
- foreign key, and <literal>Cat2</literal> using <literal>id</literal> (ie
- the same column name, the <literal>MainCat</literal> id column has).
- Plus a unique constraint on <literal>storyPart2</literal> has been
- set.</para>
-
- <para>Check out the JBoss EJB 3 tutorial or the Hibernate Annotations
- unit test suite for more examples.</para>
- </sect2>
- </sect1>
-
- <sect1 id="entity-mapping-query">
- <title>Mapping Queries</title>
-
- <sect2 id="entity-mapping-query-hql" label="Mapping JPAQL/HQL queries"
- revision="1">
- <title>Mapping JPAQL/HQL queries</title>
-
- <para>You can map EJBQL/HQL queries using annotations.
- <literal>@NamedQuery</literal> and <literal>@NamedQueries</literal> can
- be defined at the class level or in a JPA XML file. However their
- definitions are global to the session factory/entity manager factory
- scope. A named query is defined by its name and the actual query
- string.</para>
-
- <programlisting><entity-mappings>
- <named-query name="plane.getAll">
- <query>select p from Plane p</query>
- </named-query>
- ...
-</entity-mappings>
-...
-
-@Entity
-@NamedQuery(name="night.moreRecentThan", query="select n from Night n where n.date >= :date")
-public class Night {
- ...
-}
-
-public class MyDao {
- doStuff() {
- Query q = s.getNamedQuery("night.moreRecentThan");
- q.setDate( "date", aMonthAgo );
- List results = q.list();
- ...
- }
- ...
-}
- </programlisting>
-
- <para>You can also provide some hints to a query through an array of
- <literal>QueryHint</literal> through a <literal>hints</literal>
- attribute.</para>
-
- <para>The availabe Hibernate hints are</para>
-
- <para></para>
-
- <table>
- <title>Query hints</title>
-
- <tgroup cols="2">
- <thead>
- <colspec colname="c1" />
-
- <colspec colname="c2" colnum="2" />
-
- <row>
- <entry>hint</entry>
-
- <entry colname="c2">description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>org.hibernate.cacheable</entry>
-
- <entry>Whether the query should interact with the second level
- cache (defualt to false)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.cacheRegion</entry>
-
- <entry>Cache region name (default used otherwise)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.timeout</entry>
-
- <entry>Query timeout</entry>
- </row>
-
- <row>
- <entry>org.hibernate.fetchSize</entry>
-
- <entry>resultset fetch size</entry>
- </row>
-
- <row>
- <entry>org.hibernate.flushMode</entry>
-
- <entry>Flush mode used for this query</entry>
- </row>
-
- <row>
- <entry>org.hibernate.cacheMode</entry>
-
- <entry>Cache mode used for this query</entry>
- </row>
-
- <row>
- <entry>org.hibernate.readOnly</entry>
-
- <entry>Entities loaded by this query should be in read only mode
- or not (default to false)</entry>
- </row>
-
- <row>
- <entry>org.hibernate.comment</entry>
-
- <entry>Query comment added to the generated SQL</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
-
- <sect2 id="entity-mapping-query-native" revision="2">
- <title>Mapping native queries</title>
-
- <para>You can also map a native query (ie a plain SQL query). To achieve
- that, you need to describe the SQL resultset structure using
- <literal>@SqlResultSetMapping</literal> (or
- <literal>@SqlResultSetMappings</literal> if you plan to define several
- resulset mappings). Like <literal>@NamedQuery</literal>, a
- <literal>@SqlResultSetMapping</literal> can be defined at class level or
- in a JPA XML file. However its scope is global to the
- application.</para>
-
- <para>As we will see, a <literal>resultSetMapping</literal> parameter is
- defined in <literal>@NamedNativeQuery</literal>, it represents the name
- of a defined <literal>@SqlResultSetMapping</literal>. The resultset
- mapping declares the entities retrieved by this native query. Each field
- of the entity is bound to an SQL alias (or column name). All fields of
- the entity including the ones of subclasses and the foreign key columns
- of related entities have to be present in the SQL query. Field
- definitions are optional provided that they map to the same column name
- as the one declared on the class property.</para>
-
- <para><programlisting>@NamedNativeQuery(name="night&area", query="select night.id nid, night.night_duration, "
- + " night.night_date, area.id aid, night.area_id, area.name "
- + "from Night night, Area area where night.area_id = area.id", <emphasis
- role="bold">resultSetMapping="joinMapping"</emphasis>)
-@SqlResultSetMapping(name="joinMapping", entities={
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields = {
- @FieldResult(name="id", column="nid"),
- @FieldResult(name="duration", column="night_duration"),
- @FieldResult(name="date", column="night_date"),
- @FieldResult(name="area", column="area_id"),
- discriminatorColumn="disc"
- }),
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields = {
- @FieldResult(name="id", column="aid"),
- @FieldResult(name="name", column="name")
- })
- }
-)</programlisting></para>
-
- <para>In the above example, the <literal>night&area</literal> named
- query use the <literal>joinMapping</literal> result set mapping. This
- mapping returns 2 entities, <literal>Night</literal> and
- <literal>Area</literal>, each property is declared and associated to a
- column name, actually the column name retrieved by the query. Let's now
- see an implicit declaration of the property / column.</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@SqlResultSetMapping(name="implicit", entities=(a)EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class))
-@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultSetMapping="implicit")</emphasis>
-public class SpaceShip {
- private String name;
- private String model;
- private double speed;
-
- @Id
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Column(name="model_txt")
- public String getModel() {
- return model;
- }
-
- public void setModel(String model) {
- this.model = model;
- }
-
- public double getSpeed() {
- return speed;
- }
-
- public void setSpeed(double speed) {
- this.speed = speed;
- }
-}</programlisting>
-
- <para>In this example, we only describe the entity member of the result
- set mapping. The property / column mappings is done using the entity
- mapping values. In this case the <literal>model</literal> property is
- bound to the <literal>model_txt </literal>column. If the association to
- a related entity involve a composite primary key, a
- <literal>@FieldResult</literal> element should be used for each foreign
- key column. The <literal>@FieldResult</literal> name is composed of the
- property name for the relationship, followed by a dot ("."), followed by
- the name or the field or property of the primary key.</para>
-
- <programlisting>@Entity
-@SqlResultSetMapping(name="compositekey",
- entities=(a)EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class,
- fields = {
- @FieldResult(name="name", column = "name"),
- @FieldResult(name="model", column = "model"),
- @FieldResult(name="speed", column = "speed"),
-<emphasis role="bold"> @FieldResult(name="captain.firstname", column = "firstn"),
- @FieldResult(name="captain.lastname", column = "lastn"),</emphasis>
- @FieldResult(name="dimensions.length", column = "length"),
- @FieldResult(name="dimensions.width", column = "width")
- }),
- columns = { @ColumnResult(name = "surface"),
- @ColumnResult(name = "volume") } )
-
-@NamedNativeQuery(name="compositekey",
- query="select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as surface from SpaceShip",
- resultSetMapping="compositekey")
-} )
-public class SpaceShip {
- private String name;
- private String model;
- private double speed;
- private Captain captain;
- private Dimensions dimensions;
-
- @Id
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @ManyToOne(fetch= FetchType.LAZY)
- @JoinColumns( {
- @JoinColumn(name="fname", referencedColumnName = "firstname"),
- @JoinColumn(name="lname", referencedColumnName = "lastname")
- } )
- public Captain getCaptain() {
- return captain;
- }
-
- public void setCaptain(Captain captain) {
- this.captain = captain;
- }
-
- public String getModel() {
- return model;
- }
-
- public void setModel(String model) {
- this.model = model;
- }
-
- public double getSpeed() {
- return speed;
- }
-
- public void setSpeed(double speed) {
- this.speed = speed;
- }
-
- public Dimensions getDimensions() {
- return dimensions;
- }
-
- public void setDimensions(Dimensions dimensions) {
- this.dimensions = dimensions;
- }
-}
-
-@Entity
-(a)IdClass(Identity.class)
-public class Captain implements Serializable {
- private String firstname;
- private String lastname;
-
- @Id
- public String getFirstname() {
- return firstname;
- }
-
- public void setFirstname(String firstname) {
- this.firstname = firstname;
- }
-
- @Id
- public String getLastname() {
- return lastname;
- }
-
- public void setLastname(String lastname) {
- this.lastname = lastname;
- }
-}
-</programlisting>
-
- <note>
- <para>If you look at the dimension property, you'll see that Hibernate
- supports the dotted notation for embedded objects (you can even have
- nested embedded objects). EJB3 implementations do not have to support
- this feature, we do :-)</para>
- </note>
-
- <para>If you retrieve a single entity and if you use the default
- mapping, you can use the <literal>resultClass</literal> attribute
- instead of <literal>resultSetMapping</literal>:</para>
-
- <programlisting><emphasis role="bold">@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip",
- resultClass=SpaceShip.class)</emphasis>
-public class SpaceShip {</programlisting>
-
- <para>In some of your native queries, you'll have to return scalar
- values, for example when building report queries. You can map them in
- the <literal>@SqlResultsetMapping</literal> through
- <literal>@ColumnResult</literal>. You actually can even mix, entities
- and scalar returns in the same native query (this is probably not that
- common though).</para>
-
- <programlisting><emphasis role="bold">@SqlResultSetMapping(name="scalar", columns=@ColumnResult(name="dimension"))
-@NamedNativeQuery(name="scalar", query="select length*width as dimension from SpaceShip", resultSetMapping="scalar")</emphasis></programlisting>
-
- <para>An other query hint specific to native queries has been
- introduced: <literal>org.hibernate.callable</literal> which can be true
- or false depending on whether the query is a stored procedure or
- not.</para>
- </sect2>
- </sect1>
-
- <sect1 id="entity-hibspec" xreflabel="Hibernate Annotation Extensions">
- <title>Hibernate Annotation Extensions</title>
-
- <para>Hibernate 3.1 offers a variety of additional annotations that you
- can mix/match with your EJB 3 entities. They have been designed as a
- natural extension of EJB3 annotations.</para>
-
- <para>To empower the EJB3 capabilities, hibernate provides specific
- annotations that match hibernate features. The
- <classname>org.hibernate.annotations</classname> package contains all
- these annotations extensions.</para>
-
- <sect2 id="entity-hibspec-entity" revision="2">
- <title>Entity</title>
-
- <para>You can fine tune some of the actions done by Hibernate on
- entities beyond what the EJB3 spec offers.</para>
-
- <para><classname>@org.hibernate.annotations.Entity</classname> adds
- additional metadata that may be needed beyond what is defined in the
- standard <literal>@Entity</literal> <itemizedlist>
- <listitem>
- mutable: whether this entity is mutable or not
- </listitem>
-
- <listitem>
- dynamicInsert: allow dynamic SQL for inserts
- </listitem>
-
- <listitem>
- dynamicUpdate: allow dynamic SQL for updates
- </listitem>
-
- <listitem>
- selectBeforeUpdate: Specifies that Hibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified.
- </listitem>
-
- <listitem>
- polymorphism: whether the entity polymorphism is of PolymorphismType.IMPLICIT (default) or PolymorphismType.EXPLICIT
- </listitem>
-
- <listitem>
- persister: allow the overriding of the default persister implementation
- </listitem>
-
- <listitem>
- optimisticLock: optimistic locking strategy (OptimisticLockType.VERSION, OptimisticLockType.NONE, OptimisticLockType.DIRTY or OptimisticLockType.ALL)
- </listitem>
- </itemizedlist></para>
-
- <para><note>
- <para>@javax.persistence.Entity is still mandatory,
- @org.hibernate.annotations.Entity is not a replacement.</para>
- </note></para>
-
- <para>Here are some additional Hibernate annotation extensions</para>
-
- <para><literal>@org.hibernate.annotations.BatchSize</literal> allows you
- to define the batch size when fetching instances of this entity ( eg.
- <literal>@BatchSize(size=4)</literal> ). When loading a given entity,
- Hibernate will then load all the uninitialized entities of the same type
- in the persistence context up to the batch size.</para>
-
- <para><literal>@org.hibernate.annotations.Proxy</literal> defines the
- laziness attributes of the entity. lazy (default to true) define whether
- the class is lazy or not. proxyClassName is the interface used to
- generate the proxy (default is the class itself).</para>
-
- <para><literal>@org.hibernate.annotations.Where</literal> defines an
- optional SQL WHERE clause used when instances of this class is
- retrieved.</para>
-
- <para><literal>@org.hibernate.annotations.Check</literal> defines an
- optional check constraints defined in the DDL statetement.</para>
-
- <para><literal>@OnDelete(action=OnDeleteAction.CASCADE)</literal> on
- joined subclasses: use a SQL cascade delete on deletion instead of the
- regular Hibernate mechanism.</para>
-
- <para><literal>@Table(appliesTo="tableName", indexes = {
- @Index(name="index1", columnNames={"column1", "column2"} ) } )</literal>
- creates the defined indexes on the columns of table
- <literal>tableName</literal>. This can be applied on the primary table
- or any secondary table. The <literal>@Tables</literal> annotation allows
- your to apply indexes on different tables. This annotation is expected
- where <literal>@javax.persistence.Table</literal> or
- <literal>@javax.persistence.SecondaryTable</literal>(s) occurs.</para>
-
- <note>
- <para><literal>@org.hibernate.annotations.Table</literal> is a
- complement, not a replacement to
- <literal>@javax.persistence.Table</literal>. Especially, if you want
- to change the default name of a table, you must use
- <literal>@javax.persistence.Table</literal>, not
- <literal>@org.hibernate.annotations.Table</literal>.</para>
- </note>
-
- <para><programlisting>@Entity
-@BatchSize(size=5)
-(a)org.hibernate.annotations.Entity(
- selectBeforeUpdate = true,
- dynamicInsert = true, dynamicUpdate = true,
- optimisticLock = OptimisticLockType.ALL,
- polymorphism = PolymorphismType.EXPLICIT)
-@Where(clause="1=1")
-(a)org.hibernate.annotations.Table(name="Forest", indexes = { @Index(name="idx", columnNames = { "name", "length" } ) } )
-public class Forest { ... }</programlisting><programlisting>@Entity
-@Inheritance(
- strategy=InheritanceType.JOINED
-)
-public class Vegetable { ... }
-
-@Entity
-(a)OnDelete(action=OnDeleteAction.CASCADE)
-public class Carrot extends Vegetable { ... }</programlisting></para>
- </sect2>
-
- <sect2 id="entity-hibspec-identifier" label="Identifier" revision="1">
- <title>Identifier</title>
-
- <para><literal><literal>@org.hibernate.annotations.GenericGenerator</literal>
- allows you to define an Hibernate specific id
- generator.</literal></para>
-
- <para><programlisting>@Id @GeneratedValue(generator="system-uuid")
-@GenericGenerator(name="system-uuid", strategy = "uuid")
-public String getId() {
-
-@Id @GeneratedValue(generator="hibseq")
-@GenericGenerator(name="hibseq", strategy = "seqhilo",
- parameters = {
- @Parameter(name="max_lo", value = "5"),
- @Parameter(name="sequence", value="heybabyhey")
- }
-)
-public Integer getId() {</programlisting></para>
-
- <para><literal>strategy</literal> is the short name of an Hibernate3
- generator strategy or the fully qualified class name of an
- <classname>IdentifierGenerator</classname> implementation. You can add
- some parameters through the <literal>parameters</literal>
- attribute.</para>
-
- <para>Contrary to its standard counterpart,
- <literal>@GenericGenerator</literal> can be used in package level
- annotations, making it an application level generator (just like if it
- were in a JPA XML file).</para>
-
- <programlisting>@GenericGenerator(name="hibseq", strategy = "seqhilo",
- parameters = {
- @Parameter(name="max_lo", value = "5"),
- @Parameter(name="sequence", value="heybabyhey")
- }
-)
-package org.hibernate.test.model</programlisting>
- </sect2>
-
- <sect2 id="entity-hibspec-property" revision="2">
- <title>Property</title>
-
- <sect3>
- <title>Access type</title>
-
- <para>The access type is guessed from the position of
- <literal>@Id</literal> or <literal>@EmbeddedId</literal> in the entity
- hierarchy. Sub-entities, embedded objects and mapped superclass
- inherit the access type from the root entity.</para>
-
- <para>In Hibernate, you can override the access type to:</para>
-
- <itemizedlist>
- <listitem>
- <para>use a custom access type strategy</para>
- </listitem>
-
- <listitem>
- <para>fine tune the access type at the class level or at the
- property level</para>
- </listitem>
- </itemizedlist>
-
- <para>An @AccessType annotation has been introduced to support this
- behavior. You can define the access type on</para>
-
- <itemizedlist>
- <listitem>
- <para>an entity</para>
- </listitem>
-
- <listitem>
- <para>a superclass</para>
- </listitem>
-
- <listitem>
- <para>an embeddable object</para>
- </listitem>
-
- <listitem>
- <para>a property</para>
- </listitem>
- </itemizedlist>
-
- <para>The access type is overriden for the annotated element, if
- overriden on a class, all the properties of the given class inherit
- the access type. For root entities, the access type is considered to
- be the default one for the whole hierarchy (overridable at class or
- property level).</para>
-
- <para>If the access type is marked as "property", the getters are
- scanned for annotations, if the access type is marked as "field", the
- fields are scanned for annotations. Otherwise the elements marked with
- @Id or @embeddedId are scanned.</para>
-
- <para>You can override an access type for a property, but the element
- to annotate will not be influenced: for example an entity having
- access type <literal>field</literal>, can annotate a field with
- <literal>@AccessType("property")</literal>, the access type will then
- be property for this attribute, the the annotations still have to be
- carried on the field.</para>
-
- <para>If a superclass or an embeddable object is not annotated, the
- root entity access type is used (even if an access type has been
- define on an intermediate superclass or embeddable object). The
- russian doll principle does not apply.</para>
-
- <programlisting>@Entity
-public class Person implements Serializable {
- @Id @GeneratedValue //access type field
- Integer id;
-
- @Embedded
- @AttributeOverrides({
- @AttributeOverride(name = "iso2", column = @Column(name = "bornIso2")),
- @AttributeOverride(name = "name", column = @Column(name = "bornCountryName"))
- })
- Country bornIn;
-}
-
-@Embeddable
-<emphasis role="bold">@AccessType("property")</emphasis> //override access type for all properties in Country
-public class Country implements Serializable {
- private String iso2;
- private String name;
-
- public String getIso2() {
- return iso2;
- }
-
- public void setIso2(String iso2) {
- this.iso2 = iso2;
- }
-
- @Column(name = "countryName")
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-}
-</programlisting>
- </sect3>
-
- <sect3>
- <title>Formula</title>
-
- <para>Sometimes, you want the Database to do some computation for you
- rather than in the JVM, you might also create some kind of virtual
- column. You can use a SQL fragment (aka formula) instead of mapping a
- property into a column. This kind of property is read only (its value
- is calculated by your formula fragment).</para>
-
- <programlisting>@Formula("obj_length * obj_height * obj_width")
-public long getObjectVolume()</programlisting>
-
- <para>The SQL fragment can be as complex as you want avec even include
- subselects.</para>
- </sect3>
-
- <sect3>
- <title>Type</title>
-
- <para><literal>@org.hibernate.annotations.Type</literal> overrides the
- default hibernate type used: this is generally not necessary since the
- type is correctly inferred by Hibernate. Please refer to the Hibernate
- reference guide for more informations on the Hibernate types.</para>
-
- <para><literal>@org.hibernate.annotations.TypeDef</literal> and
- <literal>@org.hibernate.annotations.TypeDefs</literal> allows you to
- declare type definitions. These annotations are placed at the class or
- package level. Note that these definitions will be global for the
- session factory (even at the class level) and that type definition has
- to be defined before any usage.</para>
-
- <programlisting>@TypeDefs(
- {
- @TypeDef(
- name="caster",
- typeClass = CasterStringType.class,
- parameters = {
- @Parameter(name="cast", value="lower")
- }
- )
- }
-)
-package org.hibernate.test.annotations.entity;
-
-...
-public class Forest {
- @Type(type="caster")
- public String getSmallText() {
- ...
-}
- </programlisting>
-
- <para>When using composite user type, you will have to express column
- definitions. The <literal>@Columns</literal> has been introduced for
- that purpose.</para>
-
- <programlisting>@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")
-@Columns(columns = {
- @Column(name="r_amount"),
- @Column(name="r_currency")
-})
-public MonetaryAmount getAmount() {
- return amount;
-}
-
-
-public class MonetaryAmount implements Serializable {
- private BigDecimal amount;
- private Currency currency;
- ...
-}</programlisting>
- </sect3>
-
- <sect3>
- <title>Index</title>
-
- <para>You can define an index on a particular column using the
- <literal>@Index</literal> annotation on a one column property, the
- columnNames attribute will then be ignored</para>
-
- <programlisting>@Column(secondaryTable="Cat1")
-@Index(name="story1index")
-public String getStoryPart1() {
- return storyPart1;
-}</programlisting>
- </sect3>
-
- <sect3>
- <title>@Parent</title>
-
- <para>When inside an embeddable object, you can define one of the
- properties as a pointer back to the owner element.</para>
-
- <programlisting>@Entity
-public class Person {
- @Embeddable public Address address;
- ...
-}
-
-@Embeddable
-public class Address {
- @Parent public Person owner;
- ...
-}
-
-
-person == person.address.owner</programlisting>
- </sect3>
-
- <sect3>
- <title>Generated properties</title>
-
- <para>Some properties are generated at insert or update time by your
- database. Hibernate can deal with such properties and triggers a
- subsequent select to read these properties.</para>
-
- <programlisting>@Entity
-public class Antenna {
- @Id public Integer id;
- @Generated(GenerationTime.ALWAYS) @Column(insertable = false, updatable = false)
- public String longitude;
-
- @Generated(GenerationTime.INSERT) @Column(insertable = false)
- public String latitude;
-}</programlisting>
-
- <para>Annotate your property as <literal>@Generated</literal> You have
- to make sure your insertability or updatability does not conflict with
- the generation strategy you have chosen. When GenerationTime.INSERT is
- chosen, the property must not contains insertable columns, when
- GenerationTime.ALWAYS is chosen, the property must not contains
- insertable nor updatable columns.</para>
-
- <para><literal>@Version</literal> properties cannot be
- <literal>@Generated(INSERT)</literal> by design, it has to be either
- <literal>NEVER</literal> or <literal>ALWAYS</literal>.</para>
- </sect3>
-
- <sect3>
- <title>@Target</title>
-
- <para>Sometimes, the type guessed by reflection is not the one you
- want Hibernate to use. This is especially true on components when an
- interface is used. You can use <literal>@Target</literal> to by pass
- the reflection guessing mechanism (very much like the
- <literal>targetEntity</literal> attribute available on
- associations.</para>
-
- <programlisting> @Embedded
- <emphasis role="bold">@Target(OwnerImpl.class)</emphasis>
- public Owner getOwner() {
- return owner;
- }</programlisting>
-
- <para></para>
- </sect3>
- </sect2>
-
- <sect2 id="entity-hibspec-inheritance" revision="1">
- <title>Inheritance</title>
-
- <para>SINGLE_TABLE is a very powerful strategy but sometimes, and
- especially for legacy systems, you cannot add an additional
- discriminator column. For that purpose Hibernate has introduced the
- notion of discriminator formula:
- <literal>@DiscriminatorFormula</literal> is a replacement of
- <literal>@DiscriminatorColumn</literal> and use a SQL fragment as a
- formula for discriminator resolution (no need to have a dedicated
- column).</para>
-
- <programlisting>@Entity
-@DiscriminatorForumla("case when forest_type is null then 0 else forest_type end")
-public class Forest { ... }</programlisting>
-
- <para>By default, when querying the top entities, Hibernate does not put
- a restriction clause on the discriminator column. This can be
- inconvenient if this column contains values not mapped in your hierarchy
- (through <literal>@DiscriminatorValue</literal>). To work around that
- you can use <literal>@ForceDiscriminator</literal> (at the class level,
- next to <literal>@DiscriminatorColumn</literal>). Hibernate will then
- list the available values when loading the entities.</para>
- </sect2>
-
- <sect2 id="entity-hibspec-singleassoc">
- <title>Single Association related annotations</title>
-
- <para>By default, when Hibernate cannot resolve the association because
- the expected associated element is not in database (wrong id on the
- association column), an exception is raised by Hibernate. This might be
- inconvenient for lecacy and badly maintained schemas. You can ask
- Hibernate to ignore such elements instead of raising an exception using
- the <literal>@NotFound</literal> annotation. This annotation can be used
- on a <literal>@OneToOne</literal> (with FK),
- <literal>@ManyToOne</literal>, <literal>@OneToMany</literal> or
- <literal>@ManyToMany</literal> association.</para>
-
- <programlisting>@Entity
-public class Child {
- ...
- @ManyToOne
- @NotFound(action=NotFoundAction.IGNORE)
- public Parent getParent() { ... }
- ...
-}</programlisting>
-
- <para>Sometimes you want to delegate to your database the deletion of
- cascade when a given entity is deleted.</para>
-
- <programlisting>@Entity
-public class Child {
- ...
- @ManyToOne
- @OnDelete(action=OnDeleteAction.CASCADE)
- public Parent getParent() { ... }
- ...
-}</programlisting>
-
- <para>In this case Hibernate generates a cascade delete constraint at
- the database level.</para>
-
- <para>Foreign key constraints, while generated by Hibernate, have a
- fairly unreadable name. You can override the constraint name by use
- <literal>@ForeignKey</literal>.</para>
-
- <programlisting>@Entity
-public class Child {
- ...
- @ManyToOne
- <emphasis role="bold">@ForeignKey(name="FK_PARENT")</emphasis>
- public Parent getParent() { ... }
- ...
-}
-
-alter table Child add constraint FK_PARENT foreign key (parent_id) references Parent</programlisting>
-
- <sect3 id="entity-hibspec-singleassoc-fetching"
- label="Lazy options and fetching modes">
- <title>Lazy options and fetching modes</title>
-
- <para>EJB3 comes with the <literal>fetch</literal> option to define
- lazy loading and fetching modes, however Hibernate has a much more
- option set in this area. To fine tune the lazy loading and fetching
- strategies, some additional annotations have been introduced:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>@LazyToOne</literal>: defines the lazyness option
- on <literal>@ManyToOne</literal> and <literal>@OneToOne</literal>
- associations. <literal>LazyToOneOption</literal> can be
- <literal>PROXY</literal> (ie use a proxy based lazy loading),
- <literal>NO_PROXY</literal> (use a bytecode enhancement based lazy
- loading - note that build time bytecode processing is necessary)
- and <literal>FALSE</literal> (association not lazy)</para>
- </listitem>
-
- <listitem>
- <para><literal>@LazyCollection</literal>: defines the lazyness
- option on <literal>@ManyTo</literal>Many and
- <literal>@OneToMany</literal> associations. LazyCollectionOption
- can be <literal>TRUE</literal> (the collection is lazy and will be
- loaded when its state is accessed), <literal>EXTRA</literal> (the
- collection is lazy and all operations will try to avoid the
- collection loading, this is especially useful for huge collections
- when loading all the elements is not necessary) and FALSE
- (association not lazy)</para>
- </listitem>
-
- <listitem>
- <para><literal>@Fetch</literal>: defines the fetching strategy
- used to load the association. <literal>FetchMode</literal> can be
- <literal>SELECT</literal> (a select is triggered when the
- association needs to be loaded), <literal>SUBSELECT</literal>
- (only available for collections, use a subselect strategy - please
- refers to the Hibernate Reference Documentation for more
- information) or <literal>JOIN</literal> (use a SQL JOIN to load
- the association while loading the owner entity).
- <literal>JOIN</literal> overrides any lazy attribute (an
- association loaded through a <literal>JOIN</literal> strategy
- cannot be lazy).</para>
- </listitem>
- </itemizedlist>
-
- <para>The Hibernate annotations overrides the EJB3 fetching
- options.</para>
-
- <table>
- <title>Lazy and fetch options equivalent</title>
-
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Annotations</entry>
-
- <entry>Lazy</entry>
-
- <entry>Fetch</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>@[One|Many]ToOne](fetch=FetchType.LAZY)</entry>
-
- <entry>@LazyToOne(PROXY)</entry>
-
- <entry>@Fetch(SELECT)</entry>
- </row>
-
- <row>
- <entry>@[One|Many]ToOne](fetch=FetchType.EAGER)</entry>
-
- <entry>@LazyToOne(FALSE)</entry>
-
- <entry>@Fetch(JOIN)</entry>
- </row>
-
- <row>
- <entry>@ManyTo[One|Many](fetch=FetchType.LAZY)</entry>
-
- <entry>@LazyCollection(TRUE)</entry>
-
- <entry>@Fetch(SELECT)</entry>
- </row>
-
- <row>
- <entry>@ManyTo[One|Many](fetch=FetchType.EAGER)</entry>
-
- <entry>@LazyCollection(FALSE)</entry>
-
- <entry>@Fetch(JOIN)</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect3>
- </sect2>
-
- <sect2 id="entity-hibspec-collection" revision="2">
- <title>Collection related annotations</title>
-
- <sect3 id="entity-hibspec-collection-enhance" revision="2">
- <title>Enhance collection settings</title>
-
- <para>It is possible to set <itemizedlist>
- <listitem>
- the batch size for collections using @BatchSize
- </listitem>
-
- <listitem>
- the where clause, using @Where (applied on the target entity) or @WhereJoinTable (applied on the association table)
- </listitem>
-
- <listitem>
- the check clause, using @Check
- </listitem>
-
- <listitem>
- the SQL order by clause, using @OrderBy
- </listitem>
-
- <listitem>
- the delete cascade strategy through @OnDelete(action=OnDeleteAction.CASCADE)
- </listitem>
- </itemizedlist></para>
-
- <para>You can also declare a sort comparator. Use the
- <literal>@Sort</literal> annotation. Expressing the comparator type
- you want between unsorted, natural or custom comparator. If you want
- to use your own comparator implementation, you'll also have to express
- the implementation class using the <literal>comparator</literal>
- attribute. Note that you need to use either a
- <classname>SortedSet</classname> or a <classname>SortedMap</classname>
- interface.</para>
-
- <programlisting> @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- @Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class)
- @Where(clause="1=1")
- @OnDelete(action=OnDeleteAction.CASCADE)
- public SortedSet<Ticket> getTickets() {
- return tickets;
- }</programlisting>
-
- <para>Please refer to the previous descriptions of these annotations
- for more informations.</para>
-
- <para>Foreign key constraints, while generated by Hibernate, have a
- fairly unreadable name. You can override the constraint name by use
- <literal>@ForeignKey</literal>. Note that this annotation has to be
- placed on the owning side of the relationship,
- <literal>inverseName</literal> referencing to the other side
- constraint.</para>
-
- <programlisting>@Entity
-public class Woman {
- ...
- @ManyToMany(cascade = {CascadeType.ALL})
- <emphasis role="bold">@ForeignKey(name = "TO_WOMAN_FK", inverseName = "TO_MAN_FK")</emphasis>
- public Set<Man> getMens() {
- return mens;
- }
-}
-
-alter table Man_Woman add constraint TO_WOMAN_FK foreign key (woman_id) references Woman
-alter table Man_Woman add constraint TO_MAN_FK foreign key (man_id) references Man</programlisting>
- </sect3>
-
- <sect3 id="entity-hibspec-collection-extratype" revision="1">
- <title>Extra collection types</title>
-
- <sect4>
- <title>List</title>
-
- <para>Beyond EJB3, Hibernate Annotations supports true
- <classname>List</classname> and <classname>Array</classname>. Map
- your collection the same way as usual and add the
- @<literal>IndexColumn</literal>. This annotation allows you to
- describe the column that will hold the index. You can also declare
- the index value in DB that represent the first element (aka as base
- index). The usual value is <literal>0</literal> or
- <literal>1</literal>.</para>
-
- <programlisting>@OneToMany(cascade = CascadeType.ALL)
-@IndexColumn(name = "drawer_position", base=1)
-public List<Drawer> getDrawers() {
- return drawers;
-}</programlisting>
-
- <note>
- <para>If you forgot to set <literal>@IndexColumn</literal>, the
- bag semantic is applied. If you want the bag semantic without the
- limitations of it, consider using
- <literal>@CollectionId</literal>.</para>
- </note>
- </sect4>
-
- <sect4 id="entity-hibspec-collection-extratype-map" revision="1">
- <title>Map</title>
-
- <para>Hibernate Annotations also supports true Map mappings, if
- <literal>@javax.persistence.MapKey</literal> is not set, hibernate
- will map the key element or embeddable object in its/their own
- columns. To overrides the default columns, you can use
- <literal>@org.hibernate.annotations.MapKey</literal> if your key is
- a basic type (defaulted to <literal>mapkey</literal>) or an
- embeddable object, or you can use
- <literal>@org.hibernate.annotations.MapKeyManyToMany</literal> if
- your key is an entity.</para>
-
- <para>Both <literal>@org.hibernate.annotations.MapKey</literal> and
- <literal>@org.hibernate.annotations.MapKeyManyToMany</literal>
- allows you to override the target element to be used. This is
- especially useful if your collection does not use generics (or if
- you use interfaces).</para>
-
- <programlisting> @CollectionOfElements(targetElement = SizeImpl.class)
- @MapKeyManyToMany(<emphasis role="bold">targetEntity = LuggageImpl.class</emphasis>)
- private Map<Luggage, Size> sizePerLuggage = new HashMap<Luggage, Size>();</programlisting>
-
- <para></para>
- </sect4>
-
- <sect4 id="entity-hibspec-collection-extratype-indexbidir">
- <title>Bidirectional association with indexed collections</title>
-
- <para>A bidirectional association where one end is represented as a
- <literal>@IndexColumn</literal> or
- <literal>@org.hibernate.annotations.MapKey[ManyToMany]</literal>
- requires special consideration. If there is a property of the child
- class which maps to the index column, no problem, we can continue
- using <literal>mappedBy</literal> on the collection mapping:</para>
-
- <programlisting>@Entity
-public class Parent {
- @OneToMany(mappedBy="parent")
- @org.hibernate.annotations.MapKey(columns=@Column(name="name"))
- private Map<String, Child> children;
- ...
-}
-
-@Entity
-public class Parent {
- ...
- @Basic
- private String name;
-
- @ManyToOne
- @JoinColumn(name="parent_id", nullable=false)
- private Parent parent;
- ...
-}</programlisting>
-
- <para>But, if there is no such property on the child class, we can't
- think of the association as truly bidirectional (there is
- information available at one end of the association that is not
- available at the other end). In this case, we can't map the
- collection <literal>mappedBy</literal>. Instead, we could use the
- following mapping:</para>
-
- <programlisting>@Entity
-public class Parent {
- @OneToMany
- @org.hibernate.annotations.MapKey(columns=@Column(name="name"))
- @JoinColumn(name="parent_id", nullable=false)
- private Map<String, Child> children;
- ...
-}
-
-@Entity
-public class Parent {
- ...
- @ManyToOne
- @JoinColumn(name="parent_id", insertable=false, updatable=false, nullable=false)
- private Parent parent;
- ...
-}</programlisting>
-
- <para>Note that in this mapping, the collection-valued end of the
- association is responsible for updates to the foreign key.</para>
- </sect4>
-
- <sect4>
- <title>Bag with primary key</title>
-
- <para>Another interesting feature is the ability to define a
- surrogate primary key to a bag collection. This remove pretty much
- all of the drawbacks of bags: update and removal are efficient, more
- than one <literal>EAGER</literal> bag per query or per entity. This
- primary key will be contained in a additional column of your
- collection table but will not be visible to the Java application.
- @CollectionId is used to mark a collection as id bag, it also allow
- to override the primary key column(s), the primary key type and the
- generator strategy. The strategy can be <literal>identity</literal>,
- or any defined generator name of your application.</para>
-
- <programlisting>@Entity
-@TableGenerator(name="ids_generator", table="IDS")
-public class Passport {
- ...
-
- @ManyToMany(cascade = CascadeType.ALL)
- @JoinTable(name="PASSPORT_VISASTAMP")
- <emphasis role="bold">@CollectionId(
- columns = @Column(name="COLLECTION_ID"),
- type=@Type(type="long"),
- generator = "ids_generator"
- )</emphasis>
- private Collection<Stamp> visaStamp = new ArrayList();
- ...
-}</programlisting>
- </sect4>
-
- <sect4>
- <title>Collection of element or composite elements</title>
-
- <para>Hibernate Annotations also supports collections of core types
- (Integer, String, Enums, ...), collections of embeddable objects and
- even arrays of primitive types. This is known as collection of
- elements.</para>
-
- <para>A collection of elements has to be annotated as
- <literal>@CollectionOfElements</literal> (as a replacement of
- <literal>@OneToMany</literal>) To define the collection table, the
- <literal>@JoinTable</literal> annotation is used on the association
- property, <literal>joinColumns</literal> defines the join columns
- between the entity primary table and the collection table
- (inverseJoincolumn is useless and should be left empty). For
- collection of core types or array of primitive types, you can
- override the element column definition using a
- <literal>@Column</literal> on the association property. You can also
- override the columns of a collection of embeddable object using
- <literal>@AttributeOverride</literal>. To reach the collection
- element, you need to append "element" to the attribute override name
- (eg "element" for core types, or "element.serial" for the serial
- property of an embeddable element). To reach the index/key of a
- collection, append "key" instead.</para>
-
- <programlisting>@Entity
-public class Boy {
- private Integer id;
- private Set<String> nickNames = new HashSet<String>();
- private int[] favoriteNumbers;
- private Set<Toy> favoriteToys = new HashSet<Toy>();
- private Set<Character> characters = new HashSet<Character>();
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- <emphasis role="bold">@CollectionOfElements
- public Set<String></emphasis> getNickNames() {
- return nickNames;
- }
-
- <emphasis role="bold">@CollectionOfElements
- @JoinTable(
- table=@Table(name="BoyFavoriteNumbers"),
- joinColumns = @JoinColumn(name="BoyId")
- )
- @Column(name="favoriteNumber", nullable=false)</emphasis>
- @IndexColumn(name="nbr_index")
- public int[] getFavoriteNumbers() {
- return favoriteNumbers;
- }
-
- <emphasis role="bold">@CollectionOfElements
- @AttributeOverride( name="element.serial", column=@Column(name="serial_nbr") )</emphasis>
- public Set<Toy> getFavoriteToys() {
- return favoriteToys;
- }
-
- <emphasis role="bold">@CollectionOfElements
- public Set<Character></emphasis> getCharacters() {
- return characters;
- }
- ...
-}
-
-public enum Character {
- GENTLE,
- NORMAL,
- AGGRESSIVE,
- ATTENTIVE,
- VIOLENT,
- CRAFTY
-}
-
-@Embeddable
-public class Toy {
- public String name;
- public String serial;
- public Boy owner;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getSerial() {
- return serial;
- }
-
- public void setSerial(String serial) {
- this.serial = serial;
- }
-
- <emphasis role="bold">@Parent</emphasis>
- public Boy getOwner() {
- return owner;
- }
-
- public void setOwner(Boy owner) {
- this.owner = owner;
- }
-
- public boolean equals(Object o) {
- if ( this == o ) return true;
- if ( o == null || getClass() != o.getClass() ) return false;
-
- final Toy toy = (Toy) o;
-
- if ( !name.equals( toy.name ) ) return false;
- if ( !serial.equals( toy.serial ) ) return false;
-
- return true;
- }
-
- public int hashCode() {
- int result;
- result = name.hashCode();
- result = 29 * result + serial.hashCode();
- return result;
- }
-}</programlisting>
-
- <para>On a collection of embeddable objects, the embeddable object
- can have a property annotated with <literal>@Parent</literal>. This
- property will then point back to the entity containing the
- collection.</para>
-
- <note>
- <para>Previous versions of Hibernate Annotations used the
- <literal>@OneToMany</literal> to mark a collection of elements.
- Due to semantic inconsistencies, we've introduced the annotation
- <literal>@CollectionOfElements</literal>. Marking collections of
- elements the old way still work but is considered deprecated and
- is going to be unsupported in future releases</para>
- </note>
- </sect4>
- </sect3>
- </sect2>
-
- <sect2>
- <title>Cache</title>
-
- <para>In order to optimize your database accesses, you can activave the
- so called second level cache of Hibernate. This cache is configurable on
- a per entity and per collection basis.</para>
-
- <para><literal>@org.hibernate.annotations.Cache</literal> defines the
- caching strategy and region of a given second level cache. This
- annotation can be applied on the root entity (not the sub entities), and
- on the collections.</para>
-
- <programlisting>@Entity
-@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
-public class Forest { ... }</programlisting>
-
- <programlisting> @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
- public SortedSet<Ticket> getTickets() {
- return tickets;
- }</programlisting>
-
- <para></para>
-
- <programlistingco>
- <areaspec>
- <area coords="2 55" id="hm1" />
-
- <area coords="3 55" id="hm2" />
-
- <area coords="4 55" id="hm3" />
- </areaspec>
-
- <programlisting>@Cache(
- CacheConcurrencyStrategy usage();
- String region() default "";
- String include() default "all";
-)</programlisting>
-
- <calloutlist>
- <callout arearefs="hm1">
- <para>usage: the given cache concurrency strategy (NONE,
- READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)</para>
- </callout>
-
- <callout arearefs="hm2">
- <para>region (optional): the cache region (default to the fqcn of
- the class or the fq role name of the collection)</para>
- </callout>
-
- <callout arearefs="hm3">
- <para><literal>include</literal> (optional): all to include all
- properties, non-lazy to only include non lazy properties (default
- all).</para>
- </callout>
- </calloutlist>
- </programlistingco>
- </sect2>
-
- <sect2 id="entity-hibspec-filters">
- <title>Filters</title>
-
- <para>Hibernate has the ability to apply arbitrary filters on top of
- your data. Those filters are applied at runtime on a given session.
- First, you need to define them.</para>
-
- <para><literal>@org.hibernate.annotations.FilterDef</literal> or
- <literal>@FilterDefs</literal> define filter definition(s) used by
- filter(s) using the same name. A filter definition has a name() and an
- array of parameters(). A parameter will allow you to adjust the behavior
- of the filter at runtime. Each parameter is defined by a
- <literal>@ParamDef</literal> which has a name and a type. You can also
- define a defaultCondition() parameter for a given
- <literal>@FilterDef</literal> to set the default condition to use when
- none are defined in each individual <literal>@Filter</literal>. A
- <literal>@FilterDef</literal>(s) can be defined at the class or package
- level.</para>
-
- <para>We now need to define the SQL filter clause applied to either the
- entity load or the collection load. <literal>@Filter</literal> is used
- and placed either on the entity or the collection element</para>
-
- <para><programlisting>@Entity
-@FilterDef(name="minLength", parameters={ @ParamDef( name="minLength", type="integer" ) } )
-@Filters( {
- @Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
- @Filter(name="minLength", condition=":minLength <= length")
-} )
-public class Forest { ... }</programlisting></para>
-
- <para>When the collection use an association table as a relational
- representation, you might want to apply the filter condition to the
- association table itself or to the target entity table. To apply the
- constraint on the target entity, use the regular
- <literal>@Filter</literal> annotation. However, if you wan to target the
- association table, use the <literal>@FilterJoinTable</literal>
- annotation.</para>
-
- <programlisting> @OneToMany
- @JoinTable
- //filter on the target entity table
- @Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length")
- //filter on the association table
- @FilterJoinTable(name="security", condition=":userlevel >= requredLevel")
- public Set<Forest> getForests() { ... }</programlisting>
- </sect2>
-
- <sect2 id="entity-hibspec-query">
- <title>Queries</title>
-
- <para>Since Hibernate has more features on named queries than the one
- defined in the EJB3 specification,
- <literal>@org.hibernate.annotations.NamedQuery</literal>,
- <literal>@org.hibernate.annotations.NamedQueries</literal>,
- <literal>@org.hibernate.annotations.NamedNativeQuery</literal> and
- <literal>@org.hibernate.annotations.NamedNativeQueries</literal> have
- been introduced. They add some attributes to the standard version and
- can be used as a replacement:</para>
-
- <itemizedlist>
- <listitem>
- <para>flushMode: define the query flush mode (Always, Auto, Commit
- or Never)</para>
- </listitem>
-
- <listitem>
- <para>cacheable: whether the query should be cached or not</para>
- </listitem>
-
- <listitem>
- <para>cacheRegion: cache region used if the query is cached</para>
- </listitem>
-
- <listitem>
- <para>fetchSize: JDBC statement fetch size for this query</para>
- </listitem>
-
- <listitem>
- <para>timeout: query time out</para>
- </listitem>
-
- <listitem>
- <para>callable: for native queries only, to be set to true for
- stored procedures</para>
- </listitem>
-
- <listitem>
- <para>comment: if comments are activated, the comment seen when the
- query is sent to the database.</para>
- </listitem>
-
- <listitem>
- <para>cacheMode: Cache interaction mode (get, ignore, normal, put or
- refresh)</para>
- </listitem>
-
- <listitem>
- <para>readOnly: whether or not the elements retrievent from the
- query are in read only mode.</para>
- </listitem>
- </itemizedlist>
-
- <para>Those hints can be set in a standard
- <literal>@javax.persistence.NamedQuery</literal> annotations through the
- detyped <literal>@QueryHint</literal>. Another key advantage is the
- ability to set those annotations at a package level.</para>
- </sect2>
-
- <sect2 id="entity-hibspec-customsql">
- <title>Custom SQL for CRUD operations</title>
-
- <para>Hibernate gives you the avility to override every single SQL
- statement generated. We have seen native SQL query usage already, but
- you can also override the SQL statement used to load or change the state
- of entities.</para>
-
- <programlisting>@Entity
-@Table(name="CHAOS")
-<emphasis role="bold">@SQLInsert( sql="INSERT INTO CHAOS(size, name, nickname, id) VALUES(?,upper(?),?,?)")
-@SQLUpdate( sql="UPDATE CHAOS SET size = ?, name = upper(?), nickname = ? WHERE id = ?")
-@SQLDelete( sql="DELETE CHAOS WHERE id = ?")
-@SQLDeleteAll( sql="DELETE CHAOS")
-</emphasis><emphasis role="bold">@Loader(namedQuery = "chaos")</emphasis>
-@NamedNativeQuery(name="chaos", query="select id, size, name, lower( nickname ) as nickname from CHAOS where id= ?", resultClass = Chaos.class)
-public class Chaos {
- @Id
- private Long id;
- private Long size;
- private String name;
- private String nickname;</programlisting>
-
- <para><literal>@SQLInsert</literal>, <literal>@SQLUpdate</literal>,
- <literal>@SQLDelete</literal>, <literal>@SQLDeleteAll</literal>
- respectively override the INSERT statement, UPDATE statement, DELETE
- statement, DELETE statement to remove all entities.</para>
-
- <para>If you expect to call a store procedure, be sure to set the
- <literal>callable</literal> attribute to true
- (<literal>@SQLInsert(callable=true, ...)</literal>).</para>
-
- <para>To check that the execution happens correctly, Hibernate allows
- you to define one of those three strategies:</para>
-
- <itemizedlist>
- <listitem>
- <para>NONE: no check is performed: the store procedure is expected
- to fail upon issues</para>
- </listitem>
-
- <listitem>
- <para>COUNT: use of rowcount to check that the update is
- successful</para>
- </listitem>
-
- <listitem>
- <para>PARAM: like COUNT but using an output parameter rather that
- the standard mechanism</para>
- </listitem>
- </itemizedlist>
-
- <para>To define the result check style, use the <literal>check</literal>
- parameter (<literal>@SQLUpdate(check=ResultCheckStyle.COUNT,
- ...)</literal>).</para>
-
- <para>You can also override the SQL load statement by a native SQL query
- or a HQL query. You just have to refer to a named query with the
- <literal><literal>@Loader</literal></literal> annotation.</para>
-
- <para>You can use the exact same set of annotations to override the
- collection related statements.</para>
-
- <programlisting>@OneToMany
-@JoinColumn(name="chaos_fk")
-<emphasis role="bold">@SQLInsert( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = ? where id = ?")
-@SQLDelete( sql="UPDATE CASIMIR_PARTICULE SET chaos_fk = null where id = ?")</emphasis>
-private Set<CasimirParticle> particles = new HashSet<CasimirParticle>();</programlisting>
-
- <para>The parameters order is important and is defined by the order
- Hibernate handle properties. You can see the expected order by enabling
- debug logging for the <literal>org.hibernate.persister.entity</literal>
- level. With this level enabled Hibernate will print out the static SQL
- that is used to create, update, delete etc. entities. (To see the
- expected sequence, remember to not include your custom SQL through
- annotations as that will override the Hibernate generated static
- sql.)</para>
- </sect2>
- </sect1>
-</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,670 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="lucene" revision="2">
- <title>Hibernate Search: Apache <trademark>Lucene</trademark>
- Integration</title>
-
- <para><ulink url="http://lucene.apache.org">Apache Lucene</ulink> is a
- high-performance Java search engine library available at the Apache Software
- Foundation. Hibernate Annotations includes a package of annotations that
- allows you to mark any domain model object as indexable and have Hibernate
- maintain a Lucene index of any instances persisted via Hibernate. Apache
- Lucene is also integrated with the Hibernate query facility.</para>
-
- <para>Hibernate Search is a work in progress and new features are cooking in
- this area. So expect some compatibility changes in subsequent
- versions.</para>
-
- <section id="lucene-architecture">
- <title>Architecture</title>
-
- <para>Hibernate Search is made of an indexing engine and an index search
- engine. Both are backed by Apache Lucene.</para>
-
- <para>When an entity is inserted, updated or removed to/from the database,
- <productname>Hibernate Search</productname> will keep track of this event
- (through the Hibernate event system) and schedule an index update. When
- out of transaction, the update is executed right after the actual database
- operation. It is however recommended, for both your database and Hibernate
- Search, to execute your operation in a transaction (whether JDBC or JTA).
- When in a transaction, the index update is schedule for the transaction
- commit (and discarded in case of transaction rollback). You can think of
- this as the regular (infamous) autocommit vs transactional behavior. From
- a performance perspective, the <emphasis>in transaction</emphasis> mode is
- recommended. All the index updates are handled for you without you having
- to use the Apache Lucene APIs.</para>
-
- <para>To interact with Apache Lucene indexes, Hibernate Search has the
- notion of <classname>DirectoryProvider</classname>. A directory provider
- will manage a given Lucene <classname>Directory</classname> type. You can
- configure directory providers to adjust the directory target.</para>
-
- <para><productname>Hibernate Search</productname> can also use a Lucene
- index to search an entity and return a (list of) managed entity saving you
- from the tedious Object / Lucene Document mapping and low level Lucene
- APIs. The application code use the unified
- <classname>org.hibernate.Query</classname> API exactly the way a HQL or
- native query would be done.</para>
- </section>
-
- <section id="lucene-configuration">
- <title>Configuration</title>
-
- <section id="lucene-configuration-directory" revision="1">
- <title>Directory configuration</title>
-
- <para>Apache Lucene has a notion of Directory where the index is stored.
- The Directory implementation can be customized but Lucene comes bundled
- with a file system and a full memory implementation.
- <productname>Hibernate Search</productname> has the notion of
- <literal>DirectoryProvider</literal> that handle the configuration and
- the initialization of the Lucene Directory.</para>
-
- <table>
- <title>List of built-in Directory Providers</title>
-
- <tgroup cols="3">
- <thead>
- <row>
- <entry align="center">Class</entry>
-
- <entry align="center">description</entry>
-
- <entry align="center">Properties</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>org.hibernate.search.store.FSDirectoryProvider</entry>
-
- <entry>File system based directory. The directory used will be
- <indexBase>/<<literal>@Indexed.name</literal>></entry>
-
- <entry><literal>indexBase</literal>: Base directory</entry>
- </row>
-
- <row>
- <entry>org.hibernate.search.store.RAMDirectoryProvider</entry>
-
- <entry>Memory based directory, the directory will be uniquely
- indentified by the <literal>@Indexed.name</literal>
- element</entry>
-
- <entry>none</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>If the built-in directory providers does not fit your needs, you
- can write your own directory provider by implementing the
- <classname>org.hibernate.store.DirectoryProvider</classname>
- interface</para>
-
- <para>Each indexed entity is associated to a Lucene index (an index can
- be shared by several entities but this is not usually the case). You can
- configure the index through properties prefixed by
- <constant>hibernate.search.</constant><replaceable>indexname</replaceable>.
- Default properties inherited to all indexes can be defined using the
- prefix <constant>hibernate.search.default.</constant></para>
-
- <para>To define the directory provider of a given index, you use the
- <constant>hibernate.search.<replaceable>indexname</replaceable>.directory_provider</constant></para>
-
- <programlisting>hibernate.search.default.directory_provider org.hibernate.search.store.FSDirectoryProvider
-hibernate.search.default.indexBase=/usr/lucene/indexes
-
-hibernate.search.Rules.directory_provider org.hibernate.search.store.RAMDirectoryProvider
-</programlisting>
-
- <para>applied on</para>
-
- <programlisting>@Indexed(name="Status")
-public class Status { ... }
-
-@Indexed(name="Rules")
-public class Rule { ... }</programlisting>
-
- <para>will create a file system directory in
- <filename>/usr/lucene/indexes/Status</filename> where the Status
- entities will be indexed, and use an in memory directory named
- <literal>Rules</literal> where Rule entities will be indexed.</para>
-
- <para>So you can easily defined common rules like the directory provider
- and base directory, and overide those default later on on a per index
- basis.</para>
-
- <para>Writing your own <classname>DirectoryProvider</classname>, you can
- benefit this configuration mechanism too.</para>
- </section>
-
- <section id="lucene-configuration-event" revision="1">
- <title>Enabling automatic indexing</title>
-
- <para>Finally, we enable the <literal>SearchEventListener</literal> for
- the three Hibernate events that occur after changes are executed to the
- database.</para>
-
- <programlisting><hibernate-configuration>
- ...
- <event type="post-update"
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-insert"
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-delete"
- <listener class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
-</hibernate-configuration></programlisting>
- </section>
- </section>
-
- <section id="lucene-mapping" revision="2">
- <title>Mapping entities to the index structure</title>
-
- <para>All the metadata information related to indexed entities is
- described through some Java annotations. There is no need for xml mapping
- files nor a list of indexed entities. The list is discovered at startup
- time scanning the Hibernate mapped entities.</para>
-
- <para>First, we must declare a persistent class as indexable. This is done
- by annotating the class with <literal>@Indexed</literal> (all entities not
- annotated with <literal>@Indexed</literal> will be ignored by the indexing
- process):</para>
-
- <programlisting>@Entity
-<emphasis role="bold">@Indexed(index="indexes/essays")</emphasis>
-public class Essay {
- ...
-}</programlisting>
-
- <para>The <literal>index</literal> attribute tells Hibernate what the
- Lucene directory name is (usually a directory on your file system). If you
- wish to define a base directory for all Lucene indexes, you can use the
- <literal>hibernate.search.default.indexBase</literal> property in your
- configuration file. Each entity instance will be represented by a Lucene
- <classname>Document</classname> inside the given index (aka
- Directory).</para>
-
- <para>For each property (or attribute) of your entity, you have the
- ability to describe how it will be indexed. The default (ie no annotation)
- means that the property is completly ignored by the indexing process.
- <literal>@Field</literal> does declare a property as indexed. When
- indexing an element to a Lucene document you can specify how it is
- indexed:</para>
-
- <itemizedlist>
- <listitem>
- <para><literal>name</literal>: describe under which name, the property
- should be stored in the Lucene Document. The default value is the
- property name (following the JavaBeans convention)</para>
- </listitem>
-
- <listitem>
- <para><literal>store</literal>: describe whether or not the property
- is stored in the Lucene index. You can store the value
- <literal>Store.YES</literal> (comsuming more space in the index),
- store it in a compressed way <literal>Store.COMPRESS</literal> (this
- does consume more CPU), or avoid any storage
- <literal>Store.NO</literal> (this is the default value). When a
- property is stored, you can retrieve it from the Lucene Document (note
- that this is not related to whether the element is indexed or
- not).</para>
- </listitem>
-
- <listitem>
- <para>index: describe how the element is indexed (ie the process used
- to index the property and the type of information store). The
- different values are <literal>Index.NO</literal> (no indexing, ie
- cannot be found by a query), <literal>Index.TOKENIZED</literal> (use
- an analyzer to process the property),
- <literal>Index.UN_TOKENISED</literal> (no analyzer pre processing),
- <literal>Index.NO_NORM</literal> (do not store the normalization
- data).</para>
- </listitem>
- </itemizedlist>
-
- <para>These attributes are part of the <literal>@Field</literal>
- annotation.</para>
-
- <para>Whether or not you want to store the data depends on how you wish to
- use the index query result. As of today, for a pure <productname>Hibernate
- Search</productname> usage, storing is not necessary. Whether or not you
- want to tokenize a property or not depends on whether you wish to search
- the element as is, or only normalized part of it. It make sense to
- tokenize a text field, but it does not to do it for a date field (or an id
- field).</para>
-
- <para>Finally, the id property of an entity is a special property used by
- <productname>Hibernate Search</productname> to ensure index unicity of a
- given entity. By design, an id has to be stored and must not be tokenized.
- To mark a property as index id, use the <literal>@DocumentId</literal>
- annotation.</para>
-
- <programlisting>@Entity
-@Indexed(index="indexes/essays")
-public class Essay {
- ...
-
- @Id
- <emphasis role="bold">@DocumentId</emphasis>
- public Long getId() { return id; }
-
- <emphasis role="bold">@Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)</emphasis>
- public String getSummary() { return summary; }
-
- @Lob
- <emphasis role="bold">@Field(index=Index.TOKENIZED)</emphasis>
- public String getText() { return text; }
-
-}</programlisting>
-
- <para>These annotations define an index with three fields:
- <literal>id</literal>, <literal>Abstract</literal> and
- <literal>text</literal>. Note that by default the field name is
- decapitalized, following the JavaBean specification.</para>
-
- <para>Note: you <emphasis>must</emphasis> specify
- <literal>@DocumentId</literal> on the identifier property of your entity
- class.</para>
-
- <para>Lucene has the notion of <emphasis>boost factor</emphasis>. It's a
- way to give more weigth to a field or to an indexed element over an other
- during the indexation process. You can use <literal>@Boost</literal> at
- the field or the class level.</para>
-
- <programlisting>@Entity
-@Indexed(index="indexes/essays")
-<emphasis role="bold">@Boost(2)</emphasis>
-public class Essay {
- ...
-
- @Id
- @DocumentId
- public Long getId() { return id; }
-
- @Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)
- <emphasis role="bold">@Boost(2.5f)</emphasis>
- public String getSummary() { return summary; }
-
- @Lob
- @Field(index=Index.TOKENIZED)
- public String getText() { return text; }
-
-}</programlisting>
-
- <para>In our example, Essay's probability to reach the top of the search
- list will be multiplied by 2 and the summary field will be 2.5 more
- important than the test field. Note that this explaination is actually
- wrong, but it is simple and close enought to the reality. Please check the
- Lucene documentation or the excellent <citetitle>Lucene In
- Action</citetitle> from Otis Gospodnetic and Erik Hatcher.</para>
-
- <para>The analyzer class used to index the elements is configurable
- through the <literal>hibernate.search.analyzer</literal> property. If none
- defined,
- <classname>org.apache.lucene.analysis.standard.StandardAnalyzer</classname>
- is used as the default.</para>
- </section>
-
- <section id="lucene-bridge">
- <title>Property/Field Bridge</title>
-
- <para>All field of a full text index in Lucene have to be represented as
- Strings. Ones Java properties have to be indexed in a String form. For
- most of your properties, <productname>Hibernate Search</productname> does
- the translation job for you thanks to a built-in set of bridges. In some
- cases, though you need a fine grain control over the translation
- process.</para>
-
- <section>
- <title>Built-in bridges</title>
-
- <para><literal>Hibernate Search</literal> comes bundled with a set of
- built-in bridges between a Java property type and its full text
- representation.</para>
-
- <para><literal>Null</literal> elements are not indexed (Lucene does not
- support null elements and it does not make much sense either)</para>
-
- <variablelist>
- <varlistentry>
- <term>null</term>
-
- <listitem>
- <para>null elements are not indexed. Lucene does not support null
- elements and this does not make much sense either.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>java.lang.String</term>
-
- <listitem>
- <para>String are indexed as is</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>short, Short, integer, Integer, long, Long, float, Float,
- double, Double, BigInteger, BigDecimal</term>
-
- <listitem>
- <para>Numbers are converted in their String representation. Note
- that numbers cannot be compared by Lucene (ie used in ranged
- queries) out of the box: they have to be padded <footnote>
- <para>Using a Range query is debattable and has drawbacks, an
- alternative approach is to use a Filter query which will
- filter the result query to the appropriate range.</para>
-
- <para><productname>Hibernate Search</productname> will support
- a padding mechanism</para>
- </footnote></para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>java.util.Date</term>
-
- <listitem>
- <para>Dates are stored as yyyyMMddHHmmssSSS in GMT time
- (200611072203012 for Nov 7th of 2006 4:03PM and 12ms EST). You
- shouldn't really bother with the internal format. What is
- important is that when using a DateRange Query, you should know
- that the dates have to be expressed in GMT time.</para>
-
- <para>Usually, storing the date up to the milisecond is not
- necessary. <literal>@DateBridge</literal> defines the appropriate
- resolution you are willing to store in the index
- (<literal><literal>@DateBridge(resolution=Resolution.DAY)</literal></literal>).
- The date pattern will then be truncated accordingly.</para>
-
- <programlisting>@Entity @Indexed
-public class Meeting {
- @Field(index=Index.UN_TOKENIZED)
- <emphasis role="bold">@DateBridge(resolution=Resolution.MINUTE)</emphasis>
- private Date date;
- ...
-}</programlisting>
-
- <warning>
- <para>A Date whose resolution is lower than
- <literal>MILLISECOND</literal> cannot be a
- <literal>@DocumentId</literal></para>
- </warning>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para></para>
- </section>
-
- <section>
- <title>Custom Bridge</title>
-
- <para>It can happen that the built-in bridges of Hibernate Search does
- not cover some of your property types, or that the String representation
- used is not what you expect.</para>
-
- <section>
- <title>StringBridge</title>
-
- <para>The simpliest custom solution is to give <productname>Hibernate
- Search</productname> an implementation of your expected
- <emphasis>object to String</emphasis> bridge. To do so you need to
- implements the
- <literal>org.hibernate.search.bridge.StringBridge</literal>
- interface</para>
-
- <programlisting>/**
- * Padding Integer bridge.
- * All numbers will be padded with 0 to match 5 digits
- *
- * @author Emmanuel Bernard
- */
-public class PaddedIntegerBridge implements <emphasis role="bold">StringBridge</emphasis> {
-
- private int PADDING = 5;
-
- <emphasis role="bold">public String objectToString(Object object)</emphasis> {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > PADDING) throw new IllegalArgumentException( "Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < PADDING ; padIndex++ ) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-}</programlisting>
-
- <para>Then any property or field can use this bridge thanks to the
- <literal>@FieldBridge</literal> annotation</para>
-
- <programlisting><emphasis role="bold">@FieldBridge(impl = PaddedIntegerBridge.class)</emphasis>
-private Integer length;</programlisting>
-
- <para>Parameters can be passed to the Bridge implementation making it
- more flexible. The Bridge implementation implements a
- <classname>ParameterizedBridge</classname> interface, and the
- parameters are passed through the <literal>@FieldBridge</literal>
- annotation.</para>
-
- <programlisting>public class PaddedIntegerBridge implements StringBridge, <emphasis
- role="bold">ParameterizedBridge</emphasis> {
-
- public static String PADDING_PROPERTY = "padding";
- private int padding = 5; //default
-
- <emphasis role="bold">public void setParameterValues(Map parameters)</emphasis> {
- Object padding = parameters.get( PADDING_PROPERTY );
- if (padding != null) this.padding = (Integer) padding;
- }
-
- public String objectToString(Object object) {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > padding) throw new IllegalArgumentException( "Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-}
-
-
-//property
-@FieldBridge(impl = PaddedIntegerBridge.class,
- <emphasis role="bold">params = @Parameter(name="padding", value="10")</emphasis> )
-private Integer length;</programlisting>
-
- <para>The <classname>ParameterizedBridge</classname> interface can be
- implemented by <classname>StringBridge</classname>,
- <classname>TwoWayStringBridge</classname>,
- <classname>FieldBridge</classname> implementations (see
- bellow).</para>
-
- <para>If you expect to use your bridge implementation on for an id
- property (ie annotated with <literal>@DocumentId</literal>), you need
- to use a slightly extended version of <literal>StringBridge</literal>
- named <classname>TwoWayStringBridge</classname>. <literal>Hibernate
- Search</literal> needs to read the string representation of the
- identifier and generate the object out of it. There is not difference
- in the way the <literal>@FieldBridge</literal> annotation is
- used.</para>
-
- <programlisting>public class PaddedIntegerBridge implements TwoWayStringBridge, ParameterizedBridge {
-
- public static String PADDING_PROPERTY = "padding";
- private int padding = 5; //default
-
- public void setParameterValues(Map parameters) {
- Object padding = parameters.get( PADDING_PROPERTY );
- if (padding != null) this.padding = (Integer) padding;
- }
-
- public String objectToString(Object object) {
- String rawInteger = ( (Integer) object ).toString();
- if (rawInteger.length() > padding) throw new IllegalArgumentException( "Try to pad on a number too big" );
- StringBuilder paddedInteger = new StringBuilder( );
- for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
- paddedInteger.append('0');
- }
- return paddedInteger.append( rawInteger ).toString();
- }
-
- <emphasis role="bold">public Object stringToObject(String stringValue)</emphasis> {
- return new Integer(stringValue);
- }
-}
-
-
-//id property
-@DocumentId
-@FieldBridge(impl = PaddedIntegerBridge.class,
- params = @Parameter(name="padding", value="10") )
-private Integer id;</programlisting>
-
- <para>It is critically important for the two-way process to be
- idempotent (ie object = stringToObject( objectToString( object ) )
- ).</para>
- </section>
-
- <section>
- <title>FieldBridge</title>
-
- <para>Some usecase requires more than a simple object to string
- translation when mapping a property to a Lucene index. To give you
- most of the flexibility you can also implement a bridge as a
- <classname>FieldBridge</classname>. This interface give you a property
- value and let you map it the way you want in your Lucene
- <classname>Document</classname>.This interface is very similar in its
- concept to the <productname>Hibernate</productname>
- <classname>UserType</classname>.</para>
-
- <para>You can for example store a given property in two different
- document fields</para>
-
- <programlisting>/**
- * Store the date in 3 different field year, month, day
- * to ease Range Query per year, month or day
- * (eg get all the elements of december for the last 5 years)
- *
- * @author Emmanuel Bernard
- */
-public class DateSplitBridge implements FieldBridge {
- private final static TimeZone GMT = TimeZone.getTimeZone("GMT");
-
- <emphasis role="bold">public void set(String name, Object value, Document document, Field.Store store, Field.Index index, Float boost) {</emphasis>
- Date date = (Date) value;
- Calendar cal = GregorianCalendar.getInstance( GMT );
- cal.setTime( date );
- int year = cal.get( Calendar.YEAR );
- int month = cal.get( Calendar.MONTH ) + 1;
- int day = cal.get( Calendar.DAY_OF_MONTH );
- //set year
- Field field = new Field( name + ".year", String.valueOf(year), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- //set month and pad it if needed
- field = new Field( name + ".month", month < 10 ? "0" : "" + String.valueOf(month), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- //set day and pad it if needed
- field = new Field( name + ".day", day < 10 ? "0" : "" + String.valueOf(day), store, index );
- if ( boost != null ) field.setBoost( boost );
- document.add( field );
- }
-}
-
-
-//property
-<emphasis role="bold">@FieldBridge(impl = DateSplitBridge.class)</emphasis>
-private Integer length;</programlisting>
-
- <para></para>
- </section>
- </section>
- </section>
-
- <section id="lucene-query">
- <title>Querying</title>
-
- <para>The second most important capability of <productname>Hibernate
- Search</productname> is the ability to execute a Lucene query and retrieve
- entities managed by an Hibernate session, providing the power of Lucene
- without living the Hibernate paradygm, and giving another dimension to the
- Hibernate classic search mechanisms (HQL, Criteria query, native SQL
- query).</para>
-
- <para>To access the <productname>Hibernate Search</productname> querying
- facilities, you have to use an Hibernate
- <classname>FullTextSession</classname>. A SearchSession wrap an regular
- <classname>org.hibernate.Session</classname> to provide query and indexing
- capabilities.</para>
-
- <programlisting>Session session = sessionFactory.openSession();
-...
-FullTextSession fullTextSession = Search.createFullTextSession(session);</programlisting>
-
- <para>The search facility is built on native Lucene queries.</para>
-
- <programlisting>org.apache.lucene.QueryParser parser = new QueryParser("title", new StopAnalyzer() );
-
-org.hibernate.lucene.search.Query luceneQuery = parser.parse( "summary:Festina Or brand:Seiko" );
-<emphasis role="bold">org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );</emphasis>
-
-List result = fullTextQuery.list(); //return a list of managed objects</programlisting>
-
- <para>The Hibernate query built on top of the Lucene query is a regular
- <literal>org.hibernate.Query</literal>, you are is the same paradygm as
- the other Hibernate query facilities (HQL, Native or Criteria). The
- regular <literal>list()</literal>, <literal>uniqueResult()</literal>,
- <literal>iterate()</literal> and <literal>scroll()</literal> can be
- used.</para>
-
- <para>If you expect a reasonnable result number and expect to work on all
- of them, <methodname>list()</methodname> or
- <methodname>uniqueResult()</methodname> are recommanded.
- <methodname>list()</methodname> work best if the entity
- <literal>batch-size</literal> is set up properly. Note that Hibernate
- Seach has to process all Lucene Hits elements when using
- <methodname>list()</methodname>, <methodname>uniqueResult()</methodname>
- and <methodname>iterate()</methodname>. If you wish to minimize Lucene
- document loading, <methodname>scroll()</methodname> is more appropriate,
- Don't forget to close the <classname>ScrollableResults</classname> object
- when you're done, since it keeps Lucene resources.</para>
-
- <para>An efficient way to work with queries is to use pagination. The
- pagination API is exactly the one available in
- <classname>org.hibernate.Query</classname>:</para>
-
- <programlisting><emphasis role="bold">org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );</emphasis>
-fullTextQuery.setFirstResult(30);
-fullTextQuery.setMaxResult(20);
-fullTextQuery.list(); //will return a list of 20 elements starting from the 30th</programlisting>
-
- <para>Only the relevant Lucene Documents are accessed.</para>
- </section>
-
- <section id="lucene-index">
- <title>Indexing</title>
-
- <para>It is sometimes useful to index an object event if this object is
- not inserted nor updated to the database. This is especially true when you
- want to build your index the first time. You can achieve that goal using
- the <classname>FullTextSession</classname>.</para>
-
- <programlisting>FullTextSession fullTextSession = Search.createFullTextSession(session);
-Transaction tx = fullTextSession.beginTransaction();
-for (Customer customer : customers) {
- <emphasis role="bold">fullTextSession.index(customer);</emphasis>
-}
-tx.commit(); //index are written at commit time</programlisting>
-
- <para>For maximum efficiency, Hibernate Search batch index operations
- which and execute them at commit time (Note: you don't need to use
- <classname>org.hibernate.Transaction</classname> in a JTA
- environment).</para>
- </section>
-</chapter>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/mapping.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/mapping.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/mapping.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,438 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="search-mapping" revision="3">
+ <title>Mapping entities to the index structure</title>
+
+ <para>All the metadata information related to indexed entities is described
+ through some Java annotations. There is no need for xml mapping files nor a
+ list of indexed entities. The list is discovered at startup time scanning
+ the Hibernate mapped entities.</para>
+
+ <section id="search-mapping-entity" revision="3">
+ <title>Mapping an entity</title>
+
+ <para>First, we must declare a persistent class as indexable. This is done
+ by annotating the class with <literal>@Indexed</literal> (all entities not
+ annotated with <literal>@Indexed</literal> will be ignored by the indexing
+ process):</para>
+
+ <programlisting>@Entity
+<emphasis role="bold">@Indexed(index="indexes/essays")</emphasis>
+public class Essay {
+ ...
+}
+ </programlisting>
+
+ <para>The <literal>index</literal> attribute tells Hibernate what the
+ Lucene directory name is (usually a directory on your file system). If you
+ wish to define a base directory for all Lucene indexes, you can use the
+ <literal>hibernate.search.default.indexBase</literal> property in your
+ configuration file. Each entity instance will be represented by a Lucene
+ <classname>Document</classname> inside the given index (aka
+ Directory).</para>
+
+ <para>For each property (or attribute) of your entity, you have the
+ ability to describe how it will be indexed. The default (ie no annotation)
+ means that the property is completly ignored by the indexing process.
+ <literal>@Field</literal> does declare a property as indexed. When
+ indexing an element to a Lucene document you can specify how it is
+ indexed:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><literal>name</literal> : describe under which name, the
+ property should be stored in the Lucene Document. The default value is
+ the property name (following the JavaBeans convention)</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>store</literal> : describe whether or not the property
+ is stored in the Lucene index. You can store the value
+ <literal>Store.YES</literal> (comsuming more space in the index),
+ store it in a compressed way <literal>Store.COMPRESS</literal> (this
+ does consume more CPU), or avoid any storage
+ <literal>Store.NO</literal> (this is the default value). When a
+ property is stored, you can retrieve it from the Lucene Document (note
+ that this is not related to whether the element is indexed or
+ not).</para>
+ </listitem>
+
+ <listitem>
+ <para>index: describe how the element is indexed (ie the process used
+ to index the property and the type of information store). The
+ different values are <literal>Index.NO</literal> (no indexing, ie
+ cannot be found by a query), <literal>Index.TOKENIZED</literal> (use
+ an analyzer to process the property),
+ <literal>Index.UN_TOKENISED</literal> (no analyzer pre processing),
+ <literal>Index.NO_NORM</literal> (do not store the normalization
+ data).</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>These attributes are part of the <literal>@Field</literal>
+ annotation.</para>
+
+ <para>Whether or not you want to store the data depends on how you wish to
+ use the index query result. As of today, for a pure <productname>Hibernate
+ Search </productname> usage, storing is not necessary. Whether or not you
+ want to tokenize a property or not depends on whether you wish to search
+ the element as is, or only normalized part of it. It make sense to
+ tokenize a text field, but it does not to do it for a date field (or an id
+ field).</para>
+
+ <para>Finally, the id property of an entity is a special property used by
+ <productname>Hibernate Search</productname> to ensure index unicity of a
+ given entity. By design, an id has to be stored and must not be tokenized.
+ To mark a property as index id, use the <literal>@DocumentId</literal>
+ annotation.</para>
+
+ <programlisting>@Entity
+@Indexed(index="indexes/essays")
+public class Essay {
+ ...
+
+ @Id
+ <emphasis role="bold">@DocumentId</emphasis>
+ public Long getId() { return id; }
+
+ <emphasis role="bold">@Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)</emphasis>
+ public String getSummary() { return summary; }
+
+ @Lob
+ <emphasis role="bold">@Field(index=Index.TOKENIZED)</emphasis>
+ public String getText() { return text; }
+}</programlisting>
+
+ <para>These annotations define an index with three fields:
+ <literal>id</literal> , <literal>Abstract</literal> and
+ <literal>text</literal> . Note that by default the field name is
+ decapitalized, following the JavaBean specification.</para>
+
+ <para>Note: you <emphasis>must</emphasis> specify
+ <literal>@DocumentId</literal> on the identifier property of your entity
+ class.</para>
+
+ <para>Lucene has the notion of <emphasis>boost factor</emphasis> . It's a
+ way to give more weigth to a field or to an indexed element over an other
+ during the indexation process. You can use <literal>@Boost</literal> at
+ the field or the class level.</para>
+
+ <programlisting>@Entity
+@Indexed(index="indexes/essays")
+<emphasis role="bold">@Boost(2)</emphasis>
+public class Essay {
+ ...
+
+ @Id
+ @DocumentId
+ public Long getId() { return id; }
+
+ @Field(name="Abstract", index=Index.TOKENIZED, store=Store.YES)
+ <emphasis role="bold">@Boost(2.5f)</emphasis>
+ public String getSummary() { return summary; }
+
+ @Lob
+ @Field(index=Index.TOKENIZED)
+ public String getText() { return text; }
+} </programlisting>
+
+ <para>In our example, Essay's probability to reach the top of the search
+ list will be multiplied by 2 and the summary field will be 2.5 more
+ important than the test field. Note that this explaination is actually
+ wrong, but it is simple and close enought to the reality. Please check the
+ Lucene documentation or the excellent <citetitle>Lucene In Action
+ </citetitle> from Otis Gospodnetic and Erik Hatcher.</para>
+
+ <para>The analyzer class used to index the elements is configurable
+ through the <literal>hibernate.search.analyzer</literal> property. If none
+ defined,
+ <classname>org.apache.lucene.analysis.standard.StandardAnalyzer</classname>
+ is used as the default.</para>
+ </section>
+
+ <section id="search-mapping-bridge">
+ <title>Property/Field Bridge</title>
+
+ <para>All field of a full text index in Lucene have to be represented as
+ Strings. Ones Java properties have to be indexed in a String form. For
+ most of your properties, <productname>Hibernate Search</productname> does
+ the translation job for you thanks to a built-in set of bridges. In some
+ cases, though you need a fine grain control over the translation
+ process.</para>
+
+ <section>
+ <title>Built-in bridges</title>
+
+ <para><literal>Hibernate Search</literal> comes bundled with a set of
+ built-in bridges between a Java property type and its full text
+ representation.</para>
+
+ <para><literal>Null</literal> elements are not indexed (Lucene does not
+ support null elements and it does not make much sense either)</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>null</term>
+
+ <listitem>
+ <para>null elements are not indexed. Lucene does not support null
+ elements and this does not make much sense either.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>java.lang.String</term>
+
+ <listitem>
+ <para>String are indexed as is</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>short, Short, integer, Integer, long, Long, float, Float,
+ double, Double, BigInteger, BigDecimal</term>
+
+ <listitem>
+ <para>Numbers are converted in their String representation. Note
+ that numbers cannot be compared by Lucene (ie used in ranged
+ queries) out of the box: they have to be padded <footnote>
+ <para>Using a Range query is debattable and has drawbacks, an
+ alternative approach is to use a Filter query which will
+ filter the result query to the appropriate range.</para>
+
+ <para><productname>Hibernate Search</productname> will support
+ a padding mechanism</para>
+ </footnote></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>java.util.Date</term>
+
+ <listitem>
+ <para>Dates are stored as yyyyMMddHHmmssSSS in GMT time
+ (200611072203012 for Nov 7th of 2006 4:03PM and 12ms EST). You
+ shouldn't really bother with the internal format. What is
+ important is that when using a DateRange Query, you should know
+ that the dates have to be expressed in GMT time.</para>
+
+ <para>Usually, storing the date up to the milisecond is not
+ necessary. <literal>@DateBridge</literal> defines the appropriate
+ resolution you are willing to store in the index ( <literal>
+ <literal>@DateBridge(resolution=Resolution.DAY)</literal>
+ </literal> ). The date pattern will then be truncated
+ accordingly.</para>
+
+ <programlisting>@Entity
+@Indexed
+public class Meeting {
+ @Field(index=Index.UN_TOKENIZED)
+ <emphasis role="bold">@DateBridge(resolution=Resolution.MINUTE)</emphasis>
+ private Date date;
+ ... </programlisting>
+
+ <warning>
+ <para>A Date whose resolution is lower than
+ <literal>MILLISECOND</literal> cannot be a
+ <literal>@DocumentId</literal></para>
+ </warning>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para></para>
+ </section>
+
+ <section>
+ <title>Custom Bridge</title>
+
+ <para>It can happen that the built-in bridges of Hibernate Search does
+ not cover some of your property types, or that the String representation
+ used is not what you expect.</para>
+
+ <section>
+ <title>StringBridge</title>
+
+ <para>The simpliest custom solution is to give <productname>Hibernate
+ Search </productname> an implementation of your expected
+ <emphasis>object to String</emphasis> bridge. To do so you need to
+ implements the
+ <literal>org.hibernate.search.bridge.StringBridge</literal>
+ interface</para>
+
+ <programlisting>/**
+ * Padding Integer bridge.
+ * All numbers will be padded with 0 to match 5 digits
+ *
+ * @author Emmanuel Bernard
+ */
+public class PaddedIntegerBridge implements <emphasis role="bold">StringBridge</emphasis> {
+
+ private int PADDING = 5;
+
+ <emphasis role="bold">public String objectToString(Object object)</emphasis> {
+ String rawInteger = ( (Integer) object ).toString();
+ if (rawInteger.length() > PADDING)
+ throw new IllegalArgumentException( "Try to pad on a number too big" );
+ StringBuilder paddedInteger = new StringBuilder( );
+ for ( int padIndex = rawInteger.length() ; padIndex < PADDING ; padIndex++ ) {
+ paddedInteger.append('0');
+ }
+ return paddedInteger.append( rawInteger ).toString();
+ }
+} </programlisting>
+
+ <para>Then any property or field can use this bridge thanks to the
+ <literal>@FieldBridge</literal> annotation</para>
+
+ <programlisting><emphasis role="bold">@FieldBridge(impl = PaddedIntegerBridge.class)</emphasis>
+private Integer length; </programlisting>
+
+ <para>Parameters can be passed to the Bridge implementation making it
+ more flexible. The Bridge implementation implements a
+ <classname>ParameterizedBridge</classname> interface, and the
+ parameters are passed through the <literal>@FieldBridge</literal>
+ annotation.</para>
+
+ <programlisting>public class PaddedIntegerBridge implements StringBridge, <emphasis
+ role="bold">ParameterizedBridge</emphasis> {
+
+ public static String PADDING_PROPERTY = "padding";
+ private int padding = 5; //default
+
+ <emphasis role="bold">public void setParameterValues(Map parameters)</emphasis> {
+ Object padding = parameters.get( PADDING_PROPERTY );
+ if (padding != null) this.padding = (Integer) padding;
+ }
+
+ public String objectToString(Object object) {
+ String rawInteger = ( (Integer) object ).toString();
+ if (rawInteger.length() > padding)
+ throw new IllegalArgumentException( "Try to pad on a number too big" );
+ StringBuilder paddedInteger = new StringBuilder( );
+ for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
+ paddedInteger.append('0');
+ }
+ return paddedInteger.append( rawInteger ).toString();
+ }
+}
+
+
+//property
+@FieldBridge(impl = PaddedIntegerBridge.class,
+ <emphasis role="bold">params = @Parameter(name="padding", value="10")</emphasis>
+ )
+private Integer length; </programlisting>
+
+ <para>The <classname>ParameterizedBridge</classname> interface can be
+ implemented by <classname>StringBridge</classname> ,
+ <classname>TwoWayStringBridge</classname> ,
+ <classname>FieldBridge</classname> implementations (see
+ bellow).</para>
+
+ <para>If you expect to use your bridge implementation on for an id
+ property (ie annotated with <literal>@DocumentId</literal> ), you need
+ to use a slightly extended version of <literal>StringBridge</literal>
+ named <classname>TwoWayStringBridge</classname> . <literal>Hibernate
+ Search </literal> needs to read the string representation of the
+ identifier and generate the object out of it. There is not difference
+ in the way the <literal>@FieldBridge</literal> annotation is
+ used.</para>
+
+ <programlisting>public class PaddedIntegerBridge implements TwoWayStringBridge, ParameterizedBridge {
+
+ public static String PADDING_PROPERTY = "padding";
+ private int padding = 5; //default
+
+ public void setParameterValues(Map parameters) {
+ Object padding = parameters.get( PADDING_PROPERTY );
+ if (padding != null) this.padding = (Integer) padding;
+ }
+
+ public String objectToString(Object object) {
+ String rawInteger = ( (Integer) object ).toString();
+ if (rawInteger.length() > padding)
+ throw new IllegalArgumentException( "Try to pad on a number too big" );
+ StringBuilder paddedInteger = new StringBuilder( );
+ for ( int padIndex = rawInteger.length() ; padIndex < padding ; padIndex++ ) {
+ paddedInteger.append('0');
+ }
+ return paddedInteger.append( rawInteger ).toString();
+ }
+
+ <emphasis role="bold">public Object stringToObject(String stringValue)</emphasis> {
+ return new Integer(stringValue);
+ }
+}
+
+
+//id property
+@DocumentId
+@FieldBridge(impl = PaddedIntegerBridge.class,
+ params = @Parameter(name="padding", value="10")
+private Integer id;
+ </programlisting>
+
+ <para>It is critically important for the two-way process to be
+ idempotent (ie object = stringToObject( objectToString( object ) )
+ ).</para>
+ </section>
+
+ <section>
+ <title>FieldBridge</title>
+
+ <para>Some usecase requires more than a simple object to string
+ translation when mapping a property to a Lucene index. To give you
+ most of the flexibility you can also implement a bridge as a
+ <classname>FieldBridge</classname> . This interface give you a
+ property value and let you map it the way you want in your Lucene
+ <classname>Document</classname> .This interface is very similar in its
+ concept to the <productname>Hibernate</productname>
+ <classname>UserType</classname> .</para>
+
+ <para>You can for example store a given property in two different
+ document fields</para>
+
+ <programlisting>/**
+ * Store the date in 3 different field year, month, day
+ * to ease Range Query per year, month or day
+ * (eg get all the elements of december for the last 5 years)
+ *
+ * @author Emmanuel Bernard
+ */
+public class DateSplitBridge implements FieldBridge {
+ private final static TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+ <emphasis role="bold">public void set(String name, Object value, Document document, Field.Store
+ store, Field.Index index, Float boost) {
+ </emphasis>
+ Date date = (Date) value;
+ Calendar cal = GregorianCalendar.getInstance( GMT );
+ cal.setTime( date );
+ int year = cal.get( Calendar.YEAR );
+ int month = cal.get( Calendar.MONTH ) + 1;
+ int day = cal.get( Calendar.DAY_OF_MONTH );
+ //set year
+ Field field = new Field( name + ".year", String.valueOf(year), store, index );
+ if ( boost != null ) field.setBoost( boost );
+ document.add( field );
+ //set month and pad it if needed
+ field = new Field( name + ".month", month < 10 ? "0" : "" + String.valueOf(month), store, index);
+ if ( boost != null ) field.setBoost( boost );
+ document.add( field );
+ //set day and pad it if needed
+ field = new Field( name + ".day", day < 10 ? "0" : "" + String.valueOf(day), store, index );
+ if ( boost != null ) field.setBoost( boost );
+ document.add( field );
+ }
+}
+
+
+//property
+<emphasis role="bold">@FieldBridge(impl = DateSplitBridge.class)</emphasis>
+private Integer length; </programlisting>
+
+ <para></para>
+ </section>
+ </section>
+ </section>
+</chapter>
\ No newline at end of file
Copied: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/query.xml (from rev 11154, branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/lucene.xml)
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/query.xml (rev 0)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/query.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<chapter id="search-query">
+ <title>Querying</title>
+
+ <para>The second most important capability of <productname>Hibernate Search
+ </productname> is the ability to execute a Lucene query and retrieve
+ entities managed by an Hibernate session, providing the power of Lucene
+ without living the Hibernate paradygm, and giving another dimension to the
+ Hibernate classic search mechanisms (HQL, Criteria query, native SQL
+ query).</para>
+
+ <para>To access the <productname>Hibernate Search</productname> querying
+ facilities, you have to use an Hibernate
+ <classname>FullTextSession</classname> . A SearchSession wrap an regular
+ <classname>org.hibernate.Session</classname> to provide query and indexing
+ capabilities.</para>
+
+ <programlisting>Session session = sessionFactory.openSession();
+...
+FullTextSession fullTextSession = Search.createFullTextSession(session); </programlisting>
+
+ <para>The search facility is built on native Lucene queries.</para>
+
+ <programlisting>org.apache.lucene.QueryParser parser = new QueryParser("title", new StopAnalyzer() );
+
+org.hibernate.lucene.search.Query luceneQuery = parser.parse( "summary:Festina Or brand:Seiko" );
+<emphasis role="bold">org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
+ </emphasis>
+
+List result = fullTextQuery.list(); //return a list of managed objects </programlisting>
+
+ <para>The Hibernate query built on top of the Lucene query is a regular
+ <literal>org.hibernate.Query</literal> , you are is the same paradygm as the
+ other Hibernate query facilities (HQL, Native or Criteria). The regular
+ <literal>list()</literal> , <literal>uniqueResult()</literal> ,
+ <literal>iterate()</literal> and <literal>scroll()</literal> can be
+ used.</para>
+
+ <para>If you expect a reasonnable result number and expect to work on all of
+ them, <methodname>list()</methodname> or
+ <methodname>uniqueResult()</methodname> are recommanded.
+ <methodname>list()</methodname> work best if the entity
+ <literal>batch-size</literal> is set up properly. Note that Hibernate Seach
+ has to process all Lucene Hits elements when using
+ <methodname>list()</methodname> , <methodname>uniqueResult()</methodname>
+ and <methodname>iterate()</methodname> . If you wish to minimize Lucene
+ document loading, <methodname>scroll()</methodname> is more appropriate,
+ Don't forget to close the <classname>ScrollableResults</classname> object
+ when you're done, since it keeps Lucene resources.</para>
+
+ <para>An efficient way to work with queries is to use pagination. The
+ pagination API is exactly the one available in
+ <classname>org.hibernate.Query</classname> :</para>
+
+ <programlisting><emphasis role="bold">org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
+ </emphasis>
+fullTextQuery.setFirstResult(30);
+fullTextQuery.setMaxResult(20);
+fullTextQuery.list(); //will return a list of 20 elements starting from the 30th </programlisting>
+
+ <para>Only the relevant Lucene Documents are accessed.</para>
+</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/setup.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/setup.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/setup.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,153 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter>
- <title id="setup" revision="1">Setting up an annotations project</title>
-
- <section id="setup-requirements">
- <title>Requirements</title>
-
- <itemizedlist>
- <listitem>
- <para>Download and unpack the Hibernate Annotations distribution from
- the Hibernate website.</para>
- </listitem>
-
- <listitem>
- <para><emphasis>This release requires Hibernate 3.2.0.GA and above.
- Do not use this release of Hibernate Annotations with an older version
- of Hibernate 3.x!</emphasis></para>
- </listitem>
-
- <listitem>
- <para>This release is known to work on Hibernate core 3.2.0.CR5, 3.2.0.GA
- and 3.2.1.GA</para>
- </listitem>
-
- <listitem>
- <para>Make sure you have JDK 5.0 installed. You can of course continue
- using XDoclet and get some of the benefits of annotation-based
- metadata with older JDK versions. Note that this document only
- describes JDK 5.0 annotations and you have to refer to the XDoclet
- documentation for more information.</para>
- </listitem>
- </itemizedlist>
- </section>
-
- <section id="setup-configuration">
- <title>Configuration</title>
-
- <para>First, set up your classpath (after you have created a new project
- in your favorite IDE): <itemizedlist>
- <listitem>
- <para>Copy all Hibernate3 core and required 3rd party library files
- (see lib/README.txt in Hibernate).</para>
- </listitem>
-
- <listitem>
- <para>Copy <filename>hibernate-annotations.jar</filename> and
- <filename>lib/ejb3-persistence.jar</filename> from the Hibernate
- Annotations distribution to your classpath as well.</para>
- </listitem>
-
- <listitem>
- <para>To use the <xref linkend="lucene" />, add the lucene jar
- file.</para>
- </listitem>
- </itemizedlist></para>
-
- <para>We also recommend a small wrapper class to startup Hibernate in a
- static initializer block, known as <classname>HibernateUtil</classname>.
- You might have seen this class in various forms in other areas of the
- Hibernate documentation. For Annotation support you have to enhance this
- helper class as follows: <programlisting>package hello;
-
-import org.hibernate.*;
-import org.hibernate.cfg.*;
-import test.*;
-import test.animals.Dog;
-
-public class HibernateUtil {
-
-private static final SessionFactory sessionFactory;
-
- static {
- try {
-
- sessionFactory = new <emphasis role="bold">AnnotationConfiguration()</emphasis>.buildSessionFactory();
- } catch (Throwable ex) {
- // Log exception!
- throw new ExceptionInInitializerError(ex);
- }
- }
-
- public static Session getSession()
- throws HibernateException {
- return sessionFactory.openSession();
- }
-}
- </programlisting></para>
-
- <para>Interesting here is the use of
- <classname>AnnotationConfiguration</classname>. The packages and annotated
- classes are declared in your regular XML configuration file (usually
- <filename>hibernate.cfg.xml</filename>). Here is the equivalent of the
- above declaration:</para>
-
- <programlisting><!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
-
- <hibernate-configuration>
- <session-factory>
- <emphasis role="bold"><mapping package="test.animals"/>
- <mapping class="test.Flight"/>
- <mapping class="test.Sky"/>
- <mapping class="test.Person"/>
- <mapping class="test.animals.Dog"/></emphasis>
-<emphasis role="bold"> <mapping resource="test/animals/orm.xml"/></emphasis>
- </session-factory>
- </hibernate-configuration>
- </programlisting>
-
- <para>Note that you can mix the hbm.xml use and the new annotation one.
- The resource element can be either an hbm file or an EJB3 XML deployment
- descriptor. The distinction is transparent for your configuration
- process.</para>
-
- <para>Alternatively, you can define the annotated classes and packages
- using the programmatic API</para>
-
- <programlisting> sessionFactory = new <emphasis role="bold">AnnotationConfiguration()
- .addPackage("test.animals") //the fully qualified package name
- .addAnnotatedClass(Flight.class)
- .addAnnotatedClass(Sky.class)
- .addAnnotatedClass(Person.class)
- .addAnnotatedClass(Dog.class)</emphasis>
-<emphasis role="bold"> .addResource("test/animals/orm.xml")</emphasis>
- .buildSessionFactory();</programlisting>
-
- <para>You can also use the Hibernate EntityManager which has its own
- configuration mechanism. Please refer to this project documentation for
- more details.</para>
-
- <para>There is no other difference in the way you use Hibernate APIs with
- annotations, except for this startup routine change or in the
- configuration file. You can use your favorite configuration method for
- other properties ( <filename>hibernate.properties</filename>,
- <filename>hibernate.cfg.xml</filename>, programmatic APIs, etc). You can
- even mix annotated persistent classes and classic
- <filename>hbm.cfg.xml</filename> declarations with the same
- <classname>SessionFactory</classname>. You can however not declare a class
- several times (whether annotated or through hbm.xml). You cannot mix
- configuration strategies (hbm vs annotations) in a mapped entity hierarchy
- either.</para>
-
- <para>To ease the migration process from hbm files to annotations, the
- configuration mechanism detects the mapping duplication between
- annotations and hbm files. HBM files are then prioritized over annotated
- metadata on a class to class basis. You can change the priority using
- <literal>hibernate.mapping.precedence</literal> property. The default is
- <literal>hbm, class</literal>, changing it to <literal>class,
- hbm</literal> will prioritize the annotated classes over hbm files when a
- conflict occurs.</para>
- </section>
-</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/validator.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/validator.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/validator.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,560 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="validator">
- <title>Hibernate Validator</title>
-
- <para>Annotations are a very convenient and elegant way to specify invariant
- constraints for a domain model. You can, for example, express that a
- property should never be null, that the account balance should be strictly
- positive, etc. These domain model constraints are declared in the bean
- itself by annotating its properties. A validator can then read them and
- check for constraint violations. The validation mechanism can be executed in
- different layers in your application without having to duplicate any of
- these rules (presentation layer, data access layer). Hibernate Validator has
- been designed for that purpose.</para>
-
- <para>Hibernate Validator works at two levels. First, it is able to check
- in-memory instances of a class for constraint violations. Second, it can
- apply the constraints to the Hibernate metamodel and incorporate them into
- the generated database schema.</para>
-
- <para>Each constraint annotation is associated to a validator implementation
- responsible for checking the constraint on the entity instance. A validator
- can also (optionally) apply the constraint to the Hibernate metamodel,
- allowing Hibernate to generate DDL that expresses the constraint. With the
- appropriate event listener, you can execute the checking operation on
- inserts and updates done by Hibernate. Hibernate Validator is not limited to
- use with Hibernate. You can easily use it anywhere in your
- application.</para>
-
- <para>When checking instances at runtime, Hibernate Validator returns
- information about constraint violations in an array of
- <classname>InvalidValue</classname>s. Among other information, the
- <classname>InvalidValue</classname> contains an error description message
- that can embed the parameter values bundle with the annotation (eg. length
- limit), and message strings that may be externalized to a
- <classname>ResourceBundle</classname>.</para>
-
- <sect1 id="validator-constraints">
- <title>Constraints</title>
-
- <sect2>
- <title>What is a constraint?</title>
-
- <para>A constraint is represented by an annotation. A constraint usually
- has some attributes used to parameterize the constraints limits. The
- constraint apply to the annotated element.</para>
- </sect2>
-
- <sect2 id="validator-constraints-built-in" revision="1">
- <title>Built in constraints</title>
-
- <para>Hibernate Validator comes with some built-in constraints, which
- covers most basic data checks. As we'll see later, you're not limited to
- them, you can in a minute write your own constraints.</para>
-
- <table>
- <title>Built-in constraints</title>
-
- <tgroup cols="4">
- <colspec align="center" />
-
- <thead>
- <row>
- <entry>Annotation</entry>
-
- <entry>Apply on</entry>
-
- <entry>Runtime checking</entry>
-
- <entry>Hibernate Metadata impact</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry>@Length(min=, max=)</entry>
-
- <entry>property (String)</entry>
-
- <entry>check if the string length match the range</entry>
-
- <entry>Column length will be set to max</entry>
- </row>
-
- <row>
- <entry>@Max(value=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is less than or equals to max</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Min(value=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is more than or equals to min</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@NotNull</entry>
-
- <entry>property</entry>
-
- <entry>check if the value is not null</entry>
-
- <entry>Column(s) are not null</entry>
- </row>
-
- <row>
- <entry>@NotEmpty</entry>
-
- <entry>property</entry>
-
- <entry>check if the string is not null nor empty. Check if the
- connection is not null nor empty</entry>
-
- <entry>Column(s) are not null (for String)</entry>
- </row>
-
- <row>
- <entry>@Past</entry>
-
- <entry>property (date or calendar)</entry>
-
- <entry>check if the date is in the past</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Future</entry>
-
- <entry>property (date or calendar)</entry>
-
- <entry>check if the date is in the future</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Pattern(regex="regexp", flag=)</entry>
-
- <entry>property (string)</entry>
-
- <entry>check if the property match the regular expression given
- a match flag (see <classname> java.util.regex.Pattern
- </classname> )</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Range(min=, max=)</entry>
-
- <entry>property (numeric or string representation of a
- numeric)</entry>
-
- <entry>check if the value is between min and max
- (included)</entry>
-
- <entry>Add a check constraint on the column</entry>
- </row>
-
- <row>
- <entry>@Size(min=, max=)</entry>
-
- <entry>property (array, collection, map)</entry>
-
- <entry>check if the element size is between min and max
- (included)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@AssertFalse</entry>
-
- <entry>property</entry>
-
- <entry>check that the method evaluates to false (useful for
- constraints expressed in code rather than annotations)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@AssertTrue</entry>
-
- <entry>property</entry>
-
- <entry>check that the method evaluates to true (useful for
- constraints expressed in code rather than annotations)</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Valid</entry>
-
- <entry>property (object)</entry>
-
- <entry>perform validation recursively on the associated object.
- If the object is a Collection or an array, the elements are
- validated recursively. If the object is a Map, the value
- elements are validated recursively.</entry>
-
- <entry>none</entry>
- </row>
-
- <row>
- <entry>@Email</entry>
-
- <entry>property (String)</entry>
-
- <entry>check whether the string is conform to the email address
- specification</entry>
-
- <entry>none</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </sect2>
-
- <sect2 id="validator-constraints-error" xreflabel="Error messages">
- <title>Error messages</title>
-
- <para>Hibernate Validator comes with a default set of error messages
- translated in about ten languages (if yours is not part of it, please
- sent us a patch). You can override those messages by creating a
- <filename>ValidatorMessages.properties</filename> or
- (<filename>ValidatorMessages_loc.properties</filename>) and override the
- needed keys. You can even add your own additional set of messages while
- writing your validator annotations. If Hibernate Validator cannot
- resolve a key from your resourceBundle nor from ValidatorMessage, it
- falls back to the default built-in values.</para>
-
- <para>Alternatively you can provide a
- <classname>ResourceBundle</classname> while checking programmatically
- the validation rules on a bean or if you want a completly different
- interpolation mechanism, you can provide an implementation of
- <literal>org.hibernate.validator.MessageInterpolator</literal> (check
- the JavaDoc for more informations).</para>
- </sect2>
-
- <sect2>
- <title>Writing your own constraints</title>
-
- <para>Extending the set of built-in constraints is extremely easy. Any
- constraint consists of two pieces: the constraint
- <emphasis>descriptor</emphasis> (the annotation) and the constraint
- <emphasis>validator</emphasis> (the implementation class). Here is a
- simple user-defined descriptor:</para>
-
- <programlisting>@ValidatorClass(CapitalizedValidator.class)
-@Target(METHOD)
-@Retention(RUNTIME)
-@Documented
-public @interface Capitalized {
- CapitalizeType type() default Capitalize.FIRST;
- String message() default "has incorrect capitalization";
-}</programlisting>
-
- <para><literal>type</literal> is a parameter describing how the property
- should to be capitalized. This is a user parameter fully dependant on
- the annotation business.</para>
-
- <para><literal>message</literal> is the default string used to describe
- the constraint violation and is mandatory. You can hard code the string
- or you can externalize part/all of it through the Java ResourceBundle
- mechanism. Parameters values are going to be injected inside the message
- when the <literal>{parameter}</literal> string is found (in our example
- <literal>Capitalization is not {type}</literal> would generate
- <literal>Capitalization is not FIRST</literal>), externalizing the whole
- string in <filename>ValidatorMessages.properties</filename> is
- considered good practice. See <xref
- linkend="validator-constraints-error" />.</para>
-
- <programlisting>@ValidatorClass(CapitalizedValidator.class)
-@Target(METHOD)
-@Retention(RUNTIME)
-@Documented
-public @interface Capitalized {
- CapitalizeType type() default Capitalize.FIRST;
- String message() default "{validator.capitalized}";
-}
-
-...
-#in ValidatorMessages.properties
-validator.capitalized=<literal>Capitalization is not {type}</literal></programlisting>
-
- <para>As you can see the {} notation is recursive.</para>
-
- <para>To link a descriptor to its validator implementation, we use the
- <literal>@ValidatorClass</literal> meta-annotation. The validator class
- parameter must name a class which implements
- <literal>Validator<ConstraintAnnotation></literal>.</para>
-
- <para>We now have to implement the validator (ie. the rule checking
- implementation). A validation implementation can check the value of the
- a property (by implementing <literal>PropertyConstraint</literal>)
- and/or can modify the hibernate mapping metadata to express the
- constraint at the database level (by implementing
- <literal>PersistentClassConstraint</literal>).</para>
-
- <programlisting>public class CapitalizedValidator
- implements Validator<Capitalized>, PropertyConstraint {
- private CapitalizeType type;
-
- //part of the Validator<Annotation> contract,
- //allows to get and use the annotation values
- public void initialize(Capitalized parameters) {
- type = parameters.type();
- }
-
- //part of the property constraint contract
- public boolean isValid(Object value) {
- if (value==null) return true;
- if ( !(value instanceof String) ) return false;
- String string = (String) value;
- if (type == CapitalizeType.ALL) {
- return string.equals( string.toUpperCase() );
- }
- else {
- String first = string.substring(0,1);
- return first.equals( first.toUpperCase();
- }
- }
-}</programlisting>
-
- <para>The <literal>isValid()</literal> method should return false if the
- constraint has been violated. For more examples, refer to the built-in
- validator implementations.</para>
-
- <para>We only have seen property level validation, but you can write a
- Bean level validation annotation. Instead of receiving the return
- instance of a property, the bean itself will be passed to the validator.
- To activate the validation checking, just annotated the bean itself
- instead. A small sample can be found in the unit test suite.</para>
- </sect2>
-
- <sect2>
- <title>Annotating your domain model</title>
-
- <para>Since you are already familiar with annotations now, the syntax
- should be very familiar.</para>
-
- <programlisting>public class Address {
- private String line1;
- private String line2;
- private String zip;
- private String state;
- private String country;
- private long id;
-
- // a not null string of 20 characters maximum
- @Length(max=20)
- @NotNull
- public String getCountry() {
- return country;
- }
-
- // a non null string
- @NotNull
- public String getLine1() {
- return line1;
- }
-
- //no constraint
- public String getLine2() {
- return line2;
- }
-
- // a not null string of 3 characters maximum
- @Length(max=3) @NotNull
- public String getState() {
- return state;
- }
-
- // a not null numeric string of 5 characters maximum
- // if the string is longer, the message will
- //be searched in the resource bundle at key 'long'
- @Length(max=5, message="{long}")
- @Pattern(regex="[0-9]+")
- @NotNull
- public String getZip() {
- return zip;
- }
-
- // should always be true
- @AssertTrue
- public boolean isValid() {
- return true;
- }
-
- // a numeric between 1 and 2000
- @Id @Min(1)
- @Range(max=2000)
- public long getId() {
- return id;
- }
-}</programlisting>
-
- <para>While the example only shows public property validation, you can
- also annotate fields of any kind of visibility.</para>
-
- <programlisting>@MyBeanConstraint(max=45)
-public class Dog {
- @AssertTrue private boolean isMale;
- @NotNull protected String getName() { ... };
- ...
-}</programlisting>
-
- <para>You can also annotate interfaces. Hibernate Validator will check
- all superclasses and interfaces extended or implemented by a given bean
- to read the appropriate validator annotations.</para>
-
- <programlisting>public interface Named {
- @NotNull String getName();
- ...
-}
-
-public class Dog implements Named {
-
- @AssertTrue private boolean isMale;
-
- public String getName() { ... };
-
-}</programlisting>
-
- <para>The name property will be checked for nullity when the Dog bean is
- validated.</para>
- </sect2>
- </sect1>
-
- <sect1>
- <title>Using the Validator framework</title>
-
- <para>Hibernate Validator is intended to be used to implement
- multi-layered data validation, where we express constraints in one place
- (the annotated domain model) and apply them at various different layers of
- the application.</para>
-
- <sect2>
- <title>Database schema-level validation</title>
-
- <para>Out of the box, Hibernate Annotations will translate the
- constraints you have defined for your entities into mapping metadata.
- For example, if a property of your entity is annotated
- <literal>@NotNull</literal>, its columns will be declared as
- <literal>not null</literal> in the DDL schema generated by
- Hibernate.</para>
- </sect2>
-
- <sect2>
- <title>Hibernate event-based validation</title>
-
- <para>Hibernate Validator has two built-in Hibernate event listeners.
- Whenever a <literal>PreInsertEvent</literal> or
- <literal>PreUpdateEvent</literal> occurs, the listeners will verify all
- constraints of the entity instance and throw an exception if any
- constraint is violated. Basically, objects will be checked before any
- inserts and before any updates made by Hibernate. This is the most
- convenient and the easiest way to activate the validation process. On
- constraint violation, the event will raise a runtime
- <classname>InvalidStateException</classname> which contains an array of
- <literal>InvalidValue</literal>s describing each failure.</para>
-
- <programlisting><hibernate-configuration>
- ...
- <event type="pre-update">
- <listener
- class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
- </event>
- <event type="pre-insert">
- <listener
- class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
- </event>
-</hibernate-configuration></programlisting>
-
- <para><note>
- <para>When using Hibernate Entity Manager, the Validation framework
- is activated out of the box. If the beans are not annotated with
- validation annotations, there is no performance cost.</para>
- </note></para>
- </sect2>
-
- <sect2>
- <title>Application-level validation</title>
-
- <para>Hibernate Validator can be applied anywhere in your application
- code.</para>
-
- <programlisting>ClassValidator personValidator = new ClassValidator( Person.class );
-ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
-
-InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);</programlisting>
-
- <para>The first two lines prepare the Hibernate Validator for class
- checking. The first one relies upon the error messages embedded in
- Hibernate Validator (see <xref
- linkend="validator-constraints-error" />), the second one uses a
- resource bundle for these messages. It is considered a good practice to
- execute these lines once and cache the validator instances.</para>
-
- <para>The third line actually validates the <literal>Address</literal>
- instance and returns an array of <literal>InvalidValue</literal>s. Your
- application logic will then be able to react to the failure.</para>
-
- <para>You can also check a particular property instead of the whole
- bean. This might be useful for property per property user
- interaction</para>
-
- <programlisting>ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );
-
-//only get city property invalid values
-InvalidValue[] validationMessages = addressValidator.getInvalidValues(address, "city");
-
-//only get potential city property invalid values
-InvalidValue[] validationMessages = addressValidator.getPotentialInvalidValues("city", "Paris")</programlisting>
- </sect2>
-
- <sect2>
- <title>Validation informations</title>
-
- <para>As a validation information carrier, hibernate provide an array of
- <classname>InvalidValue</classname>. Each
- <literal>InvalidValue</literal> has a buch of methods describing the
- individual issues.</para>
-
- <para><methodname>getBeanClass()</methodname> retrieves the failing bean
- type</para>
-
- <para><methodname>getBean()</methodname>retrieves the failing instance
- (if any ie not when using
- <methodname>getPotentianInvalidValues()</methodname>)</para>
-
- <para><methodname>getValue()</methodname> retrieves the failing
- value</para>
-
- <para><methodname>getMessage()</methodname> retrieves the proper
- internationalized error message</para>
-
- <para><methodname>getRootBean()</methodname> retrieves the root bean
- instance generating the issue (useful in conjunction with
- <literal>@Valid</literal>), is null if getPotentianInvalidValues() is
- used.</para>
-
- <para><literal>getPropertyPath()</literal> retrieves the dotted path of
- the failing property starting from the root bean</para>
- </sect2>
- </sect1>
-</chapter>
\ No newline at end of file
Deleted: branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/xml-overriding.xml
===================================================================
--- branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/xml-overriding.xml 2007-02-06 23:46:27 UTC (rev 11159)
+++ branches/HAN_SPLIT/HibernateExt/search/doc/reference/en/modules/xml-overriding.xml 2007-02-07 06:23:00 UTC (rev 11160)
@@ -1,402 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<chapter id="xml-overriding" label="Overriding metadata through XML">
- <title>Overriding metadata through XML</title>
-
- <para>The primary target for metadata in EJB3 is annotations, but the EJB3
- specification provides a way to override or replace the annotation defined
- metadata through an XML deployment descriptor. In the current release only
- pure EJB3 annotations overriding are supported. If you wish to use Hibernate
- specific features in some entities, you'll have to either use annotations or
- fallback to hbm files. You can of course mix and match annotated entities
- and entities describes in hbm files.</para>
-
- <para>The unit test suite shows some additional XML file samples.</para>
-
- <section id="xml-overriding-principles">
- <title>Principles</title>
-
- <para>The XML deployment descriptor structure has been designed to reflect
- the annotations one. So if you know the annotations structure, using the
- XML schema will be straightforward for you.</para>
-
- <para>You can define one ot more XML files describing your metadata, these
- files will be merged by the overriding engine.</para>
-
- <section>
- <title>Global level metadata</title>
-
- <para>You can define global level metadata available for all XML files.
- You must not define these metadata more than once per deployment.</para>
-
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
-
-<entity-mappings
- xmlns="http://java.sun.com/xml/ns/persistence/orm"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
- version="1.0">
-
- <persistence-unit-metadata>
- <xml-mapping-metadata-complete/>
- <persistence-unit-defaults>
- <schema>myschema</schema>
- <catalog>mycatalog</catalog>
- <cascade-persist/>
- </persistence-unit-defaults>
- </persistence-unit-metadata></programlisting>
-
- <para><literal>xml-mapping-metadata-complete</literal> means that all
- entity, mapped-superclasses and embeddable metadata should be picked up
- from XML (ie ignore annotations).</para>
-
- <para><literal>schema / catalog</literal> will override all default
- definitions of schema and catalog in the metadata (both XML and
- annotations).</para>
-
- <para><literal>cascade-persist</literal> means that all associations
- have PERSIST as a cascade type. We recommend you to not use this
- feature.</para>
- </section>
-
- <section id="xml-overriding-principles-entity" revision="1">
- <title>Entity level metadata</title>
-
- <para>You can either define or override metadata informations on a given
- entity.</para>
-
- <programlistingco>
- <areaspec>
- <area coords="3 85" id="aa1" />
-
- <area coords="9 85" id="aa2" />
-
- <area coords="10 85" id="aa3" />
-
- <area coords="11 85" id="aa4" />
-
- <area coords="17 85" id="aa5" />
-
- <area coords="23 85" id="aa6" />
-
- <area coords="24 85" id="aa7" />
-
- <area coords="25 85" id="aa8" />
-
- <area coords="26 85" id="aa9" />
-
- <area coords="31 85" id="aa10" />
- </areaspec>
-
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
-
-<entity-mappings
- xmlns="http://java.sun.com/xml/ns/persistence/orm"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
- version="1.0">
-
- <package>org.hibernate.test.annotations.reflection</package>
- <entity class="Administration" access="PROPERTY" metadata-complete="true">
- <table name="tbl_admin">
- <unique-constraint>
- <column-name>firstname</column-name>
- <column-name>lastname</column-name>
- </unique-constraint>
- </table>
- <secondary-table name="admin2">
- <primary-key-join-column name="admin_id" referenced-column-name="id"/>
- <unique-constraint>
- <column-name>address</column-name>
- </unique-constraint>
- </secondary-table>
- <id-class class="SocialSecurityNumber"/>
- <inheritance strategy="JOINED"/>
- <sequence-generator name="seqhilo" sequence-name="seqhilo"/>
- <table-generator name="table" table="tablehilo"/>
- ...
- </entity>
-
- <entity class="PostalAdministration">
- <primary-key-join-column name="id"/>
- ...
- </entity>
-</entity-mappings></programlisting>
-
- <calloutlist>
- <callout arearefs="aa1">
- <para><literal>entity-mappings</literal>: entity-mappings is the
- root element for all XML files. You must declare the xml schema,
- the schema file is included in the hibernate-annotations.jar file,
- no internet access will be processed by Hibernate
- Annotations.</para>
- </callout>
-
- <callout arearefs="aa2">
- <para><literal>package</literal> (optional): default package used
- for all non qualified class names in the given deployment
- descriptor file.</para>
- </callout>
-
- <callout arearefs="aa3">
- <para><literal>entity</literal>: desribes an entity.</para>
-
- <para><literal>metadata-complete</literal> defines whether the
- metadata description for this element is complete or not (in other
- words, if annotations present at the class level should be
- considered or not).</para>
-
- <para>An entity has to have a <literal>class</literal> attribute
- refering the java class the metadata applies on.</para>
-
- <para>You can overrides entity name through the
- <literal>name</literal> attribute, if none is defined and if an
- <literal>@Entity.name</literal> is present, then it is used
- (provided that metadata complete is not set).</para>
-
- <para>For netadata complete (see below) element, you can define an
- <literal>access</literal> (either <literal>FIELD</literal> or
- <literal>PROPERTY</literal> (default)). For non medatada complete
- element, if <literal>access</literal> is not defined, the @Id
- position will lead position, if <literal>access</literal> is
- defined, the value is used.</para>
- </callout>
-
- <callout arearefs="aa4">
- <para><literal>table</literal>: you can declare table properties
- (name, schema, catalog), if none is defined, the java annotation
- is used.</para>
-
- <para>You can define one or several unique constraints as seen in
- the example</para>
- </callout>
-
- <callout arearefs="aa5">
- <para><literal>secondary-table</literal>: defines a secondary
- table very much like a regular table except that you can define
- the primary key / foreign key column(s) through the
- <literal>primary-key-join-column</literal> element. On non
- metadata complete, annotation secondary tables are used only if
- there is no <literal>secondary-table</literal> definition,
- annotations are ignored otherwise.</para>
- </callout>
-
- <callout arearefs="aa6">
- <para><literal>id-class</literal>: defines the id class in a
- similar way <literal>@IdClass</literal> does</para>
- </callout>
-
- <callout arearefs="aa7">
- <para><literal>inheritance</literal>: defines the inheritance
- strategy (<literal>JOINED</literal>,
- <literal>TABLE_PER_CLASS</literal>,
- <literal>SINGLE_TABLE</literal>), Available only at the root
- entity level</para>
- </callout>
-
- <callout arearefs="aa8">
- <para><literal>sequence-generator</literal>: defines a sequence
- generator</para>
- </callout>
-
- <callout arearefs="aa9">
- <para><literal>table-generator</literal>: defines a table
- generator</para>
- </callout>
-
- <callout arearefs="aa10">
- <para><literal><literal>primary-key-join-column</literal></literal>:
- defines the primary key join column for sub entities when JOINED
- inheritance strategy is used</para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <programlistingco>
- <areaspec>
- <area coords="11 85" id="ab1" />
-
- <area coords="18 85" id="ab2" />
-
- <area coords="22 85" id="ab3" />
-
- <area coords="28 85" id="ab4" />
-
- <area coords="34 85" id="ab5" />
- </areaspec>
-
- <programlisting><?xml version="1.0" encoding="UTF-8"?>
-
-<entity-mappings
- xmlns="http://java.sun.com/xml/ns/persistence/orm"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
- version="1.0">
-
- <package>org.hibernate.test.annotations.reflection</package>
- <entity class="Music" access="PROPERTY" metadata-complete="true">
- <discriminator-value>Generic</discriminator-value>
- <discriminator-column length="34"/>
- ...
- </entity>
-
- <entity class="PostalAdministration">
- <primary-key-join-column name="id"/>
- <named-query name="adminById">
- <query>select m from Administration m where m.id = :id</query>
- <hint name="org.hibernate.timeout" value="200"/>
- </named-query>
- <named-native-query name="allAdmin" result-set-mapping="adminrs">
- <query>select *, count(taxpayer_id) as taxPayerNumber
- from Administration, TaxPayer
- where taxpayer_admin_id = admin_id group by ...</query>
- <hint name="org.hibernate.timeout" value="200"/>
- </named-native-query>
- <sql-result-set-mapping name="adminrs">
- <entity-result entity-class="Administration">
- <field-result name="name" column="fld_name"/>
- </entity-result>
- <column-result name="taxPayerNumber"/>
- </sql-result-set-mapping>
- <attribute-override name="ground">
- <column name="fld_ground" unique="true" scale="2"/>
- </attribute-override>
- <association-override name="referer">
- <join-column name="referer_id" referenced-column-name="id"/>
- </association-override>
- ...
- </entity>
-</entity-mappings></programlisting>
-
- <calloutlist>
- <callout arearefs="ab1">
- <para><literal>discriminator-value /
- discriminator-column</literal>: defines the discriminator value
- and the column holding it when the SINGLE_TABLE inheritance
- strategy is chosen</para>
- </callout>
-
- <callout arearefs="ab2">
- <para><literal>named-query</literal>: defines named queries and
- possibly the hints associated to them. Those definitions are
- additive to the one defined in annotations, if two definitions
- have the same name, the XML one has priority.</para>
- </callout>
-
- <callout arearefs="ab3">
- <para><literal>named-native-query</literal>: defines an named
- native query and its sql result set mapping. Alternatively, you
- can define the <literal>result-class</literal>. Those definitions
- are additive to the one defined in annotations, if two definitions
- have the same name, the XML one has priority.</para>
- </callout>
-
- <callout arearefs="ab4">
- <para><literal>sql-result-set-mapping</literal>: describes the
- result set mapping structure. You can define both entity and
- column mappings. Those definitions are additive to the one defined
- in annotations, if two definitions have the same name, the XML one
- has priority</para>
- </callout>
-
- <callout arearefs="ab5">
- <para><literal>attribute-override /
- association-override</literal>: defines a column or join column
- overriding. This overriding is additive to the one defined in
- annotations</para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>Same applies for <literal><embeddable></literal> and
- <literal><mapped-superclass></literal>.</para>
- </section>
-
- <section>
- <title>Property level metadata</title>
-
- <para>You can of course defines XML overriding for properties. If
- metadata complete is defined, then additional properties (ie at the Java
- level) will be ignored. Otherwise, once you start overriding a property,
- all annotations on the given property are ignored. All property level
- metadata behave in <literal>entity/attributes</literal>,
- <literal>mapped-superclass/attributes</literal> or
- <literal>embeddable/attributes</literal>.</para>
-
- <programlisting> <attributes>
- <id name="id">
- <column name="fld_id"/>
- <generated-value generator="generator" strategy="SEQUENCE"/>
- <temporal>DATE</temporal>
- <sequence-generator name="generator" sequence-name="seq"/>
- </id>
- <version name="version"/>
- <embedded name="embeddedObject">
- <attribute-override name"subproperty">
- <column name="my_column"/>
- </attribute-override>
- </embedded>
- <basic name="status" optional="false">
- <enumerated>STRING</enumerated>
- </basic>
- <basic name="serial" optional="true">
- <column name="serialbytes"/>
- <lob/>
- </basic>
- <basic name="terminusTime" fetch="LAZY">
- <temporal>TIMESTAMP</temporal>
- </basic>
- </attributes></programlisting>
-
- <para>You can override a property through <literal>id</literal>,
- <literal>embedded-id</literal>, <literal>version</literal>,
- <literal>embedded</literal> and <literal>basic</literal>. Each of these
- elements can have subelements accordingly: <literal>lob</literal>,
- <literal>temporal</literal>, <literal>enumerated</literal>,
- <literal>column</literal>.</para>
- </section>
-
- <section>
- <title>Association level metadata</title>
-
- <para>You can define XML overriding for associations. All association
- level metadata behave in <literal>entity/attributes</literal>,
- <literal>mapped-superclass/attributes</literal> or
- <literal>embeddable/attributes</literal>.</para>
-
- <programlisting> <attributes>
- <one-to-many name="players" fetch="EAGER">
- <map-key name="name"/>
- <join-column name="driver"/>
- <join-column name="number"/>
- </one-to-many>
- <many-to-many name="roads" target-entity="Administration">
- <order-by>maxSpeed</order-by>
- <join-table name="bus_road">
- <join-column name="driver"/>
- <join-column name="number"/>
- <inverse-join-column name="road_id"/>
- <unique-constraint>
- <column-name>driver</column-name>
- <column-name>number</column-name>
- </unique-constraint>
- </join-table>
- </many-to-many>
- <many-to-many name="allTimeDrivers" mapped-by="drivenBuses">
- </attributes></programlisting>
-
- <para>You can override an association through
- <literal>one-to-many</literal>, <literal>one-to-one</literal>,
- <literal>many-to-one</literal>, and <literal>many-to-many</literal>.
- Each of these elements can have subelements accordingly:
- <literal>join-table</literal> (which can have
- <literal>join-column</literal>s and
- <literal>inverse-join-column</literal>s),
- <literal><literal>join-column</literal>s</literal>,
- <literal>map-key</literal>, and <literal>order-by</literal>.
- <literal>mapped-by</literal> and <literal>target-entity</literal> can be
- defined as attributes when it makes sense. Once again the structure is
- reflects the annotations structure. You can find all semantic
- informations in the chapter describing annotations.</para>
- </section>
- </section>
-</chapter>
\ No newline at end of file
17 years, 2 months
Hibernate SVN: r11159 - branches/HAN_SPLIT/HibernateExt/validator/src/java/org/hibernate/validator/event.
by hibernate-commits@lists.jboss.org
Author: epbernard
Date: 2007-02-06 18:46:27 -0500 (Tue, 06 Feb 2007)
New Revision: 11159
Modified:
branches/HAN_SPLIT/HibernateExt/validator/src/java/org/hibernate/validator/event/JPAValidateListener.java
Log:
more doc
Modified: branches/HAN_SPLIT/HibernateExt/validator/src/java/org/hibernate/validator/event/JPAValidateListener.java
===================================================================
--- branches/HAN_SPLIT/HibernateExt/validator/src/java/org/hibernate/validator/event/JPAValidateListener.java 2007-02-06 22:44:15 UTC (rev 11158)
+++ branches/HAN_SPLIT/HibernateExt/validator/src/java/org/hibernate/validator/event/JPAValidateListener.java 2007-02-06 23:46:27 UTC (rev 11159)
@@ -12,7 +12,18 @@
import org.hibernate.validator.ClassValidator;
/**
- * Java Persistence Entity Listener
+ * Java Persistence Entity Listener that validates entities on inserts or updates
+ * This listener needs ot be placed on each validatable entities
+ *
+ * <code>
+ * @Entity
+ * @EntityListeners(JPAValidateListener.class)
+ * public class Submarine {
+ * @NotEmpty private String name;
+ * ...
+ * }
+ * </code>
+ *
* @author Emmanuel Bernard
*/
public class JPAValidateListener {
17 years, 2 months