Author: stliu
Date: 2009-11-24 16:08:28 -0500 (Tue, 24 Nov 2009)
New Revision: 18050
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/AnnotationException.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AccessType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Any.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDef.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDefs.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/BatchSize.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cache.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheConcurrencyStrategy.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheModeType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cascade.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CascadeType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Check.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionId.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionOfElements.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Columns.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Entity.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Fetch.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FetchMode.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filter.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDef.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDefs.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTable.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTables.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filters.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FlushModeType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForceDiscriminator.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForeignKey.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Formula.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Generated.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenerationTime.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerator.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerators.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Immutable.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Index.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/IndexColumn.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollection.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollectionOption.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOne.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOneOption.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Loader.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ManyToAny.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKey.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MetaValue.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQueries.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQuery.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQueries.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQuery.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NaturalId.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFound.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFoundAction.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDelete.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDeleteAction.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLock.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLockType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OrderBy.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ParamDef.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parameter.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parent.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Persister.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/PolymorphismType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Proxy.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ResultCheckStyle.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDelete.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDeleteAll.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLInsert.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLUpdate.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Sort.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SortType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Table.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tables.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Target.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizer.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizers.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Type.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDef.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDefs.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Where.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/WhereJoinTable.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotatedClassType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/BinderHelper.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CollectionPropertyHolder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ComponentPropertyHolder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/DefaultComponentSafeNamingStrategy.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3NamingStrategy.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3Column.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3DiscriminatorColumn.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ExtendedMappings.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/FkSecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexColumn.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexOrUniqueKeySecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/InheritanceState.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/JoinedSubclassFkSecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/NotYetImplementedException.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyData.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolderBuilder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyInferredData.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/RecoverableException.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/SecondaryTableSecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/WrappedInferredData.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/BagBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ListBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/MapBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Nullability.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SetBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/TableBinder.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Version.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3OverridenAnnotationReader.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3ReflectionManager.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/search/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/search/HibernateSearchEventListenerRegister.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/mapping/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/mapping/IdGenerator.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/AbstractLobType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/ByteArrayBlobType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/CharacterArrayClobType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/EnumType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveByteArrayBlobType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/SerializableToBlobType.java
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/StringClobType.java
Log:
JBPAPP-3150 change the build tool of Hibernate Annotations(eap 5 cp branch)
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/AnnotationException.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/AnnotationException.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/AnnotationException.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,24 @@
+//$Id: AnnotationException.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate;
+
+/**
+ * Annotation related exception.
+ * The EJB3 EG will probably set a generic exception.
+ * I'll then use this one.
+ *
+ * @author Emmanuel Bernard
+ */
+public class AnnotationException extends MappingException {
+
+ public AnnotationException(String msg, Throwable root) {
+ super( msg, root );
+ }
+
+ public AnnotationException(Throwable root) {
+ super( root );
+ }
+
+ public AnnotationException(String s) {
+ super( s );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AccessType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AccessType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AccessType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: AccessType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Property Access type
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface AccessType {
+ String value();
+}
Added: annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Any.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Any.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Any.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,45 @@
+//$Id: Any.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import static javax.persistence.FetchType.EAGER;
+
+/**
+ * Define a ToOne association pointing to several entity types.
+ * Matching the according entity type is doe through a metadata discriminator column
+ * This kind of mapping should be only marginal.
+ *
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Any {
+ /**
+ * Metadata definition used.
+ * If defined, should point to a @AnyMetaDef name
+ * If not defined, the local (ie in the same field or property) @AnyMetaDef is used
+ */
+ String metaDef() default "";
+
+ /**
+ * Metadata discriminator column description, This column will hold the meta value
corresponding to the
+ * targeted entity.
+ */
+ Column metaColumn();
+ /**
+ * Defines whether the value of the field or property should be lazily loaded or must
be
+ * eagerly fetched. The EAGER strategy is a requirement on the persistence provider
runtime
+ * that the value must be eagerly fetched. The LAZY strategy is applied when bytecode
+ * enhancement is used. If not specified, defaults to EAGER.
+ */
+ FetchType fetch() default EAGER;
+ /**
+ * Whether the association is optional. If set to false then a non-null relationship
must always exist.
+ */
+ boolean optional() default true;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDef.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDef.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDef.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,40 @@
+//$Id: AnyMetaDef.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Defines @Any and @manyToAny metadata
+ *
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target( { PACKAGE, TYPE, METHOD, FIELD } )
+@Retention( RUNTIME )
+public @interface AnyMetaDef {
+ /**
+ * If defined, assign a global meta definition name to be used in an @Any or @ManyToAny
annotation
+ * If not defined, the metadata applies to the current property or field
+ */
+ String name() default "";
+
+ /**
+ * meta discriminator Hibernate type
+ */
+ String metaType();
+
+ /**
+ * Hibernate type of the id column
+ * @return
+ */
+ String idType();
+
+ /**
+ * Matching discriminator values with their respective entity
+ */
+ MetaValue[] metaValues();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDefs.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDefs.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/AnyMetaDefs.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,21 @@
+//$Id: AnyMetaDefs.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Defines @Any and @ManyToAny set of metadata.
+ * Can be defined at the entity level or the package level
+ *
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target( { PACKAGE, TYPE } )
+@Retention( RUNTIME )
+public @interface AnyMetaDefs {
+ AnyMetaDef[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/BatchSize.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/BatchSize.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/BatchSize.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: BatchSize.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Batch size for SQL loading
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface BatchSize {
+ /** Strictly positive integer */
+ int size();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cache.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cache.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cache.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,26 @@
+//$Id: Cache.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Add caching strategy to a root entity or a collection
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Cache {
+ /** concurrency strategy chosen */
+ CacheConcurrencyStrategy usage();
+ /** cache region name */
+ String region() default "";
+ /**
+ * whether or not lazy-properties are included in the second level cache
+ * default all, other value: non-lazy
+ */
+ String include() default "all";
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheConcurrencyStrategy.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheConcurrencyStrategy.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheConcurrencyStrategy.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,15 @@
+//$Id: CacheConcurrencyStrategy.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Cache concurrency strategy
+ *
+ * @author Emmanuel Bernard
+ */
+public enum CacheConcurrencyStrategy {
+ NONE,
+ READ_ONLY,
+ NONSTRICT_READ_WRITE,
+ READ_WRITE,
+ TRANSACTIONAL
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheModeType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheModeType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CacheModeType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,17 @@
+package org.hibernate.annotations;
+
+/**
+ * Enumeration for the different interaction modes between the session and
+ * the Level 2 Cache.
+ *
+ * @author Emmanuel Bernard
+ * @author Carlos Gonz�lez-Cadenas
+ */
+
+public enum CacheModeType {
+ GET,
+ IGNORE,
+ NORMAL,
+ PUT,
+ REFRESH
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cascade.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cascade.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Cascade.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,16 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Apply a cascade strategy on an association
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Cascade {
+ CascadeType[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CascadeType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CascadeType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CascadeType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+package org.hibernate.annotations;
+
+/**
+ * Cascade types (can override default EJB3 cascades
+ */
+public enum CascadeType {
+ ALL,
+ PERSIST,
+ MERGE,
+ REMOVE,
+ REFRESH,
+ DELETE,
+ SAVE_UPDATE,
+ REPLICATE,
+ DELETE_ORPHAN,
+ LOCK,
+ EVICT
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Check.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Check.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Check.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: Check.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Arbitrary SQL check constraints which can be defined at the class,
+ * property or collection level
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Check {
+ String constraints();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionId.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionId.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionId.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,26 @@
+//$Id: CollectionId.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import javax.persistence.Column;
+
+/**
+ * Describe an identifier column for a bag (ie an idbag)
+ * EXPERIMENTAL: the structure of this annotation might slightly change (generator() mix
strategy and generator
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface CollectionId {
+ /** Collection id column(s) */
+ Column[] columns();
+ /** id type, type.type() must be set */
+ Type type();
+ /** generator name: 'identity' or a defined generator name */
+ String generator();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionOfElements.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionOfElements.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/CollectionOfElements.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,28 @@
+//$Id: CollectionOfElements.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+import javax.persistence.FetchType;
+import static javax.persistence.FetchType.LAZY;
+
+/**
+ * Annotation used to mark a collection as a collection of elements or
+ * a collection of embedded objects
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface CollectionOfElements {
+ /**
+ * Represent the element class in the collection
+ * Only useful if the collection does not use generics
+ */
+ Class targetElement() default void.class;
+
+ FetchType fetch() default LAZY;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Columns.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Columns.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Columns.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+//$Id: Columns.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+import javax.persistence.Column;
+
+/**
+ * Support an array of columns. Useful for component user types mappings
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Columns {
+ Column[] columns();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/DiscriminatorFormula.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+//$Id: DiscriminatorFormula.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Discriminator formula
+ * To be placed at the root entity.
+ *
+ * @author Emmanuel Bernard
+ * @see Formula
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface DiscriminatorFormula {
+ String value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Entity.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Entity.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Entity.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,31 @@
+//$Id: Entity.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Extends {@link javax.persistence.Entity} with Hibernate features
+ *
+ * @author Emmanuel Bernard
+ */
+@Target(TYPE)
+@Retention(RUNTIME)
+public @interface Entity {
+ /** Is this entity mutable (read only) or not */
+ boolean mutable() default true;
+ /** Needed column only in SQL on insert */
+ boolean dynamicInsert() default false;
+ /** Needed column only in SQL on update */
+ boolean dynamicUpdate() default false;
+ /** Do a select to retrieve the entity before any potential update */
+ boolean selectBeforeUpdate() default false;
+ /** polymorphism strategy for this entity */
+ PolymorphismType polymorphism() default PolymorphismType.IMPLICIT;
+ /** persister of this entity, default is hibernate internal one */
+ String persister() default "";
+ /** optimistic locking strategy */
+ OptimisticLockType optimisticLock() default OptimisticLockType.VERSION;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Fetch.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Fetch.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Fetch.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: Fetch.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Define the fetching strategy used for the given association
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface Fetch {
+ FetchMode value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FetchMode.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FetchMode.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FetchMode.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,22 @@
+//$Id: FetchMode.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Fetch options on associations
+ *
+ * @author Emmanuel Bernard
+ */
+public enum FetchMode {
+ /**
+ * use a select for each individual entity, collection, or join load
+ */
+ SELECT,
+ /**
+ * use an outer join to load the related entities, collections or joins
+ */
+ JOIN,
+ /**
+ * use a subselect query to load the additional collections
+ */
+ SUBSELECT
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filter.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filter.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filter.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,22 @@
+//$Id: Filter.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Add filters to an entity or a target entity of a collection
+ *
+ * @author Emmanuel Bernard
+ * @author Matthew Inger
+ * @author Magnus Sandberg
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Filter {
+ String name();
+
+ String condition() default "";
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDef.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDef.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDef.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,24 @@
+//$Id: FilterDef.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Filter definition
+ *
+ * @author Matthew Inger
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface FilterDef {
+ String name();
+
+ String defaultCondition() default "";
+
+ ParamDef[] parameters() default {};
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDefs.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDefs.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterDefs.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+//$Id: FilterDefs.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Array of filter definitions
+ *
+ * @author Matthew Inger
+ * @author Emmanuel Bernard
+ */
+@Target({PACKAGE, TYPE})
+@Retention(RUNTIME)
+public @interface FilterDefs {
+ FilterDef[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTable.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTable.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTable.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+//$Id: FilterJoinTable.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Add filters to a join table collection
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface FilterJoinTable {
+ String name();
+
+ String condition() default "";
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTables.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTables.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FilterJoinTables.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: FilterJoinTables.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Add multiple @FilterJoinTable to a collection
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface FilterJoinTables {
+ FilterJoinTable[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filters.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filters.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Filters.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+//$Id: Filters.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Add multiple @Filters
+ *
+ * @author Emmanuel Bernard
+ * @author Matthew Inger
+ * @author Magnus Sandberg
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Filters {
+ Filter[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FlushModeType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FlushModeType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/FlushModeType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,36 @@
+package org.hibernate.annotations;
+
+/**
+ * Enumeration extending javax.persistence flush modes.
+ *
+ * @author Carlos Gonz�lez-Cadenas
+ */
+
+public enum FlushModeType {
+ /**
+ * see {@link org.hibernate.FlushMode.ALWAYS}
+ */
+ ALWAYS,
+ /**
+ * see {@link org.hibernate.FlushMode.AUTO}
+ */
+ AUTO,
+ /**
+ * see {@link org.hibernate.FlushMode.COMMIT}
+ */
+ COMMIT,
+ /**
+ * see {@link org.hibernate.FlushMode.NEVER}
+ * @deprecated use MANUAL, will be removed in a subsequent release
+ */
+ NEVER,
+ /**
+ * see {@link org.hibernate.FlushMode.MANUAL}
+ */
+ MANUAL,
+
+ /**
+ * Current flush mode of the persistence context at the time the query is executed
+ */
+ PERSISTENCE_CONTEXT
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForceDiscriminator.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForceDiscriminator.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForceDiscriminator.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,16 @@
+//$Id: ForceDiscriminator.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * ForceDiscriminator flag
+ * To be placed at the root entity near @DiscriminatorColumn or @DiscriminatorFormula
+ *
+ * @author Serg Prasolov
+ */
+(a)Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME)
+public @interface ForceDiscriminator {}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForeignKey.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForeignKey.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ForeignKey.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,29 @@
+//$Id: ForeignKey.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+@Target({FIELD, METHOD, TYPE})
+@Retention(RUNTIME)
+
+/**
+ * Define the foreign key name
+ */
+public @interface ForeignKey {
+ /**
+ * Name of the foreign key. Used in OneToMany, ManyToOne, and OneToOne
+ * relationships. Used for the owning side in ManyToMany relationships
+ */
+ String name();
+
+ /**
+ * Used for the non-owning side of a ManyToMany relationship. Ignored
+ * in other relationships
+ */
+ String inverseName() default "";
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Formula.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Formula.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Formula.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Formula. To be used as a replacement for @Column in most places
+ * The formula has to be a valid SQL fragment
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Formula {
+ String value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Generated.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Generated.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Generated.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: Generated.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The annotated property is generated by the database
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.FIELD, ElementType.METHOD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface Generated {
+ GenerationTime value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenerationTime.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenerationTime.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenerationTime.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,13 @@
+//$Id: GenerationTime.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * When should the generation occurs
+ *
+ * @author Emmanuel Bernard
+ */
+public enum GenerationTime {
+ NEVER,
+ INSERT,
+ ALWAYS
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerator.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerator.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerator.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,31 @@
+//$Id: GenericGenerator.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Generator annotation describing any kind of Hibernate
+ * generator in a detyped manner
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({PACKAGE, TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface GenericGenerator {
+ /**
+ * unique generator name
+ */
+ String name();
+ /**
+ * Generator strategy either a predefined Hibernate
+ * strategy or a fully qualified class name.
+ */
+ String strategy();
+ /**
+ * Optional generator parameters
+ */
+ Parameter[] parameters() default {};
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerators.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerators.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/GenericGenerators.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,21 @@
+//$
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Array of generic generator definitions
+ *
+ * @author Paul Cowan
+ */
+@Target({PACKAGE, TYPE})
+@Retention(RUNTIME)
+public @interface GenericGenerators {
+ GenericGenerator[] value();
+}
+
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Immutable.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Immutable.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Immutable.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,22 @@
+//$Id: Immutable.java 14801 2008-06-24 19:03:32Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * Mark an Entity or a Collection as immutable. No annotation means the element is
mutable.
+ * <p>
+ * An immutable entity may not be updated by the application. Updates to an immutable
+ * entity will be ignored, but no exception is thrown. @Immutable must be used
on root entities only.
+ * </p>
+ * <p>
+ * @Immutable placed on a collection makes the collection immutable, meaning
additions and
+ * deletions to and from the collection are not allowed. A
<i>HibernateException</i> is thrown in this case.
+ * </p>
+ *
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+@Retention( RetentionPolicy.RUNTIME )
+public @interface Immutable {
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Index.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Index.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Index.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Define a DB index
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({FIELD, METHOD})
+@Retention(RUNTIME)
+public @interface Index {
+ String name();
+
+ String[] columnNames() default {};
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/IndexColumn.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/IndexColumn.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/IndexColumn.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,25 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Describe an index column of a List
+ *
+ * @author Matthew Inger
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface IndexColumn {
+ /** column name */
+ String name();
+ /** index in DB start from base */
+ int base() default 0;
+ /** is the index nullable */
+ boolean nullable() default true;
+ /** column definition, default to an appropriate integer */
+ String columnDefinition() default "";
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollection.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollection.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollection.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: LazyCollection.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Define the lazy status of a collection
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface LazyCollection {
+ LazyCollectionOption value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollectionOption.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollectionOption.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyCollectionOption.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,16 @@
+//$Id: LazyCollectionOption.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Lazy options available for a collection
+ *
+ * @author Emmanuel Bernard
+ */
+public enum LazyCollectionOption {
+ /** eagerly load it */
+ FALSE,
+ /** load it when the state is requested */
+ TRUE,
+ /** prefer extra queries over fill collection loading */
+ EXTRA
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOne.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOne.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOne.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: LazyToOne.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Define the lazy status of a ToOne association
+ * (ie OneToOne or ManyToOne)
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface LazyToOne {
+ LazyToOneOption value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOneOption.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOneOption.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/LazyToOneOption.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,23 @@
+//$Id: LazyToOneOption.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Lazy options available for a ToOne association
+ *
+ * @author Emmanuel Bernard
+ */
+public enum LazyToOneOption {
+ /** eagerly load the association */
+ FALSE,
+ /**
+ * Lazy, give back a proxy which will be loaded when the state is requested
+ * This should be the prefered option
+ */
+ PROXY,
+ /** Lazy, give back the real object loaded when a reference is requested
+ * (Bytecode enhancement is mandatory for this option, fall back to PROXY
+ * if the class is not enhanced)
+ * This option should be avoided unless you can't afford the use of proxies
+ */
+ NO_PROXY
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Loader.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Loader.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Loader.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,22 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Loader Annotation for overwriting Hibernate default FIND method
+ *
+ * @author L�szl� Benke
+ */
+@Target( {TYPE, FIELD, METHOD} )
+@Retention( RUNTIME )
+public @interface Loader {
+ /**
+ * namedQuery to use for loading
+ */
+ String namedQuery() default "";
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ManyToAny.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ManyToAny.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ManyToAny.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,41 @@
+//$Id: ManyToAny.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import static javax.persistence.FetchType.EAGER;
+
+/**
+ * Defined a ToMany association pointing to different entity types.
+ * Matching the according entity type is doe through a metadata discriminator column
+ * This kind of mapping should be only marginal.
+ *
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface ManyToAny {
+ /**
+ * Metadata definition used.
+ * If defined, should point to a @AnyMetaDef name
+ * If not defined, the local (ie in the same field or property) @AnyMetaDef is used
+ */
+ String metaDef() default "";
+
+ /**
+ * Metadata dicriminator column description, This column will hold the meta value
corresponding to the
+ * targeted entity.
+ */
+ Column metaColumn();
+ /**
+ * Defines whether the value of the field or property should be lazily loaded or must
be
+ * eagerly fetched. The EAGER strategy is a requirement on the persistence provider
runtime
+ * that the value must be eagerly fetched. The LAZY strategy is applied when bytecode
+ * enhancement is used. If not specified, defaults to EAGER.
+ */
+ FetchType fetch() default EAGER;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKey.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKey.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKey.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,32 @@
+//$Id: MapKey.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.FIELD;
+import javax.persistence.Column;
+
+/**
+ * Define the map key columns as an explicit column holding the map key
+ * This is completly different from {@link javax.persistence.MapKey} which use an
existing column
+ * This annotation and {@link javax.persistence.MapKey} are mutually exclusive
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface MapKey {
+ Column[] columns() default {};
+ /**
+ * Represent the key class in a Map
+ * Only useful if the collection does not use generics
+ */
+ Class targetElement() default void.class;
+
+ /**
+ * The optional map key type. Guessed if default
+ */
+ Type type() default @Type(type = "");
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,26 @@
+//$Id: MapKeyManyToMany.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.persistence.JoinColumn;
+
+/**
+ * Define the map key columns as an explicit column holding the map key
+ * This is completly different from {@link javax.persistence.MapKey} which use an
existing column
+ * This annotation and {@link javax.persistence.MapKey} are mutually exclusive
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface MapKeyManyToMany {
+ JoinColumn[] joinColumns() default {};
+ /**
+ * Represent the key class in a Map
+ * Only useful if the collection does not use generics
+ */
+ Class targetEntity() default void.class;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MetaValue.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MetaValue.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/MetaValue.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: MetaValue.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Represent a discriminator value associated to a given entity type
+ * @author Emmanuel Bernard
+ */
+public @interface MetaValue {
+ /**
+ * entity type
+ */
+ Class targetEntity();
+
+ /**
+ * discriminator value stored in database
+ */
+ String value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQueries.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQueries.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQueries.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Extends {@link javax.persistence.NamedNativeQueries} to hold hibernate
NamedNativeQuery
+ * objects
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface NamedNativeQueries {
+ NamedNativeQuery[] value();
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQuery.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQuery.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedNativeQuery.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,42 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Extends {@link javax.persistence.NamedNativeQuery} with Hibernate features
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface NamedNativeQuery {
+ String name();
+
+ String query();
+
+ Class resultClass() default void.class;
+
+ String resultSetMapping() default ""; // name of SQLResultSetMapping
+ /** the flush mode for the query */
+ FlushModeType flushMode() default FlushModeType.PERSISTENCE_CONTEXT;
+ /** mark the query as cacheable or not */
+ boolean cacheable() default false;
+ /** the cache region to use */
+ String cacheRegion() default "";
+ /** the number of rows fetched by the JDBC Driver per roundtrip */
+ int fetchSize() default -1;
+ /**the query timeout in seconds*/
+ int timeout() default -1;
+
+ boolean callable() default false;
+ /**comment added to the SQL query, useful for the DBA */
+ String comment() default "";
+ /**the cache mode used for this query*/
+ CacheModeType cacheMode() default CacheModeType.NORMAL;
+ /**marks whether the results are fetched in read-only mode or not*/
+ boolean readOnly() default false;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQueries.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQueries.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQueries.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Extends {@link javax.persistence.NamedQueries} to hold hibernate NamedQuery
+ * objects
+ *
+ * @author Emmanuel Bernard
+ * @author Carlos Gonz�lez-Cadenas
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface NamedQueries {
+ NamedQuery[] value();
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQuery.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQuery.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NamedQuery.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,40 @@
+//$Id: NamedQuery.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Extends {@link javax.persistence.NamedQuery} with Hibernate features
+ *
+ * @author Carlos Gonz�lez-Cadenas
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface NamedQuery {
+
+ /** the name of the NamedQuery */
+ String name();
+ /** the Query String for the NamedQuery */
+ String query();
+ /** the flush mode for the query */
+ FlushModeType flushMode() default FlushModeType.PERSISTENCE_CONTEXT;
+ /** mark the query as cacheable or not */
+ boolean cacheable() default false;
+ /** the cache region to use */
+ String cacheRegion() default "";
+ /** the number of rows fetched by the JDBC Driver per roundtrip */
+ int fetchSize() default -1;
+ /**the query timeout in seconds*/
+ int timeout() default -1;
+ /**comment added to the SQL query, useful for the DBA */
+ String comment() default "";
+ /**the cache mode used for this query*/
+ CacheModeType cacheMode() default CacheModeType.NORMAL;
+ /**marks whether the results are fetched in read-only mode or not*/
+ boolean readOnly() default false;
+
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NaturalId.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NaturalId.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NaturalId.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,22 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+
+/**
+ * This specifies that a property is part of the natural id of the entity.
+ *
+ * @author Nicol�s Lichtmaier
+ */
+@Target( { METHOD, FIELD } )
+@Retention( RUNTIME )
+public @interface NaturalId {
+ /**
+ * If this natural id component is mutable or not.
+ */
+ boolean mutable() default false;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFound.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFound.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFound.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Action to do when an element is not found on a association whiel beeing expected
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface NotFound {
+ NotFoundAction action() default NotFoundAction.EXCEPTION;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFoundAction.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFoundAction.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/NotFoundAction.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,17 @@
+package org.hibernate.annotations;
+
+/**
+ * Actoin to use when an element is not found in DB while beeing expected
+ *
+ * @author Emmanuel Bernard
+ */
+public enum NotFoundAction {
+ /**
+ * raise an exception when an element is not found (default and recommended)
+ */
+ EXCEPTION,
+ /**
+ * ignore the element when not found in DB
+ */
+ IGNORE
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDelete.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDelete.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDelete.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+
+/**
+ * Strategy to use on collections, arrays and on joined subclasses delete
+ * OnDelete of secondary tables currently not supported.
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD, TYPE})
+@Retention(RUNTIME)
+public @interface OnDelete {
+ OnDeleteAction action();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDeleteAction.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDeleteAction.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OnDeleteAction.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,17 @@
+package org.hibernate.annotations;
+
+/**
+ * Possible actions on deletes
+ *
+ * @author Emmanuel Bernard
+ */
+public enum OnDeleteAction {
+ /**
+ * the default
+ */
+ NO_ACTION,
+ /**
+ * use cascade delete capabilities of the DD
+ */
+ CASCADE
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLock.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLock.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLock.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,24 @@
+//$Id: OptimisticLock.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Whether or not update entity's version on property's change
+ * If the annotation is not present, the property is involved in the optimistic lock
srategy (default)
+ *
+ * @author Logi Ragnarsson
+ */
+@Target( {ElementType.METHOD, ElementType.FIELD} )
+@Retention( RetentionPolicy.RUNTIME )
+public @interface OptimisticLock {
+
+ /**
+ * If true, the annotated property change will not trigger a version upgrade
+ */
+ boolean excluded();
+
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLockType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLockType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OptimisticLockType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,27 @@
+//$Id: OptimisticLockType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Optimistic locking strategy
+ * VERSION is the default and recommanded one
+ *
+ * @author Emmanuel Bernard
+ */
+public enum OptimisticLockType {
+ /**
+ * no optimistic locking
+ */
+ NONE,
+ /**
+ * use a column version
+ */
+ VERSION,
+ /**
+ * dirty columns are compared
+ */
+ DIRTY,
+ /**
+ * all columns are compared
+ */
+ ALL
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OrderBy.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OrderBy.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/OrderBy.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Order a collection using SQL ordering (not HQL ordering)
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface OrderBy {
+ /** SQL orderby clause */
+ String clause();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ParamDef.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ParamDef.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ParamDef.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: ParamDef.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * A parameter definition
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({})
+@Retention(RUNTIME)
+public @interface ParamDef {
+ String name();
+
+ String type();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parameter.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parameter.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parameter.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: Parameter.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Parameter (basically key/value pattern)
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({})
+@Retention(RUNTIME)
+public @interface Parameter {
+ String name();
+
+ String value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parent.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parent.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Parent.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: Parent.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Reference the property as a pointer back to the owner (generally the owning entity)
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Parent {
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Persister.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Persister.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Persister.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,16 @@
+//$Id: Persister.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.*;
+
+/**
+ * Specify a custom persister.
+ *
+ * @author Shawn Clowater
+ */
+(a)java.lang.annotation.Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+@Retention( RetentionPolicy.RUNTIME )
+public @interface Persister {
+ /** Custom persister */
+ Class impl();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/PolymorphismType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/PolymorphismType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/PolymorphismType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+//$Id: PolymorphismType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Type of avaliable polymorphism for a particular entity
+ *
+ * @author Emmanuel Bernard
+ */
+public enum PolymorphismType {
+ /**
+ * default, this entity is retrieved if any of its super entity is asked
+ */
+ IMPLICIT,
+ /**
+ * this entity is retrived only if explicitly asked
+ */
+ EXPLICIT
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Proxy.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Proxy.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Proxy.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,26 @@
+//$Id: Proxy.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Lazy and proxy configuration of a particular class
+ *
+ * @author Emmanuel Bernard
+ */
+@Target(TYPE)
+@Retention(RUNTIME)
+public @interface Proxy {
+ /**
+ * Whether this class is lazy or not (default to true)
+ */
+ boolean lazy() default true;
+
+ /**
+ * Proxy class or interface used. Default entity class name.
+ */
+ Class proxyClass() default void.class;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ResultCheckStyle.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ResultCheckStyle.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/ResultCheckStyle.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,31 @@
+//$Id:
+package org.hibernate.annotations;
+
+/**
+ * Possible checks on Sql Insert, Delete, Update
+ *
+ * @author L�szl� Benke
+ */
+public enum ResultCheckStyle {
+ /**
+ * Do not perform checking. Either user simply does not want checking, or is
+ * indicating a {@link java.sql.CallableStatement} execution in which the
+ * checks are being performed explicitly and failures are handled through
+ * propogation of {@link java.sql.SQLException}s.
+ */
+ NONE,
+ /**
+ * Perform row-count checking. Row counts are the int values returned by both
+ * {@link java.sql.PreparedStatement#executeUpdate()} and
+ * {@link java.sql.Statement#executeBatch()}. These values are checked
+ * against some expected count.
+ */
+ COUNT,
+ /**
+ * Essentially the same as {@link #COUNT} except that the row count actually
+ * comes from an output parameter registered as part of a
+ * {@link java.sql.CallableStatement}. This style explicitly prohibits
+ * statement batching from being used...
+ */
+ PARAM
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDelete.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDelete.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDelete.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,33 @@
+//$Id: SQLDelete.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * SqlDelete Annotation for overwriting Hibernate default DELETE method
+ *
+ * @author L�szl� Benke
+ */
+@Target( {TYPE, FIELD, METHOD} )
+@Retention( RUNTIME )
+public @interface SQLDelete {
+ /**
+ * Procedure name or DELETE STATEMENT
+ */
+ String sql();
+
+ /**
+ * Is the statement using stored procedure or not
+ */
+ boolean callable() default false;
+
+ /**
+ * For persistence operation what style of determining results (success/failure) is to
be used.
+ */
+ ResultCheckStyle check() default ResultCheckStyle.NONE;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDeleteAll.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDeleteAll.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLDeleteAll.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,34 @@
+//$Id: SQLDeleteAll.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * SqlDelete Annotation for overwriting Hibernate default DELETE ALL method
+ *
+ * @author L�szl� Benke
+ */
+@Target( {TYPE, FIELD, METHOD} )
+@Retention( RetentionPolicy.RUNTIME )
+public @interface SQLDeleteAll {
+ /**
+ * Procedure name or DELETE STATEMENT
+ */
+ String sql();
+
+ /**
+ * Is the statement using stored procedure or not
+ */
+ boolean callable() default false;
+
+ /**
+ * For persistence operation what style of determining results (success/failure) is to
be used.
+ */
+ ResultCheckStyle check() default ResultCheckStyle.NONE;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLInsert.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLInsert.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLInsert.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,33 @@
+//$Id: SQLInsert.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * SqlInsert Annotation for overwriting Hibernate default INSERT INTO method
+ *
+ * @author L�szl� Benke
+ */
+@Target( {TYPE, FIELD, METHOD} )
+@Retention( RUNTIME )
+public @interface SQLInsert {
+ /**
+ * Procedure name or INSERT STATEMENT
+ */
+ String sql();
+
+ /**
+ * Is the statement using stored procedure or not
+ */
+ boolean callable() default false;
+
+ /**
+ * For persistence operation what style of determining results (success/failure) is to
be used.
+ */
+ ResultCheckStyle check() default ResultCheckStyle.NONE;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLUpdate.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLUpdate.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SQLUpdate.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,34 @@
+//$Id: SQLUpdate.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * SqlUpdate Annotation for overwriting Hibernate default UPDATE method
+ *
+ * @author L�szl� Benke
+ */
+@Target( {TYPE, FIELD, METHOD} )
+@Retention( RUNTIME )
+public @interface SQLUpdate {
+
+ /**
+ * Procedure name or UPDATE STATEMENT
+ */
+ String sql();
+
+ /**
+ * Is the statement using stored procedure or not
+ */
+ boolean callable() default false;
+
+ /**
+ * For persistence operation what style of determining results (success/failure) is to
be used.
+ */
+ ResultCheckStyle check() default ResultCheckStyle.NONE;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Sort.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Sort.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Sort.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,29 @@
+//$Id: Sort.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Collection sort
+ * (Java level sorting)
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Sort {
+ /**
+ * sort type
+ */
+ SortType type() default SortType.UNSORTED;
+ /**
+ * Sort comparator implementation
+ */
+ //TODO find a way to use Class<Comparator>
+
+ Class comparator() default void.class;
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SortType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SortType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/SortType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,13 @@
+//$Id: SortType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+/**
+ * Sort strategies
+ *
+ * @author Emmanuel Bernard
+ */
+public enum SortType {
+ UNSORTED,
+ NATURAL,
+ COMPARATOR
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Table.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Table.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Table.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,86 @@
+//$Id: Table.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Complementary information to a table either primary or secondary
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface Table {
+ /**
+ * name of the targeted table
+ */
+ String appliesTo();
+
+ /**
+ * Indexes
+ */
+ Index[] indexes() default {};
+
+ /**
+ * define a table comment
+ */
+ String comment() default "";
+
+ /**
+ * Defines the Foreign Key name of a secondary table
+ * pointing back to the primary table
+ */
+ ForeignKey foreignKey() default @ForeignKey( name="" );
+
+ /**
+ * If set to JOIN, the default, Hibernate will use an inner join to retrieve a
+ * secondary table defined by a class or its superclasses and an outer join for a
+ * secondary table defined by a subclass.
+ * If set to select then Hibernate will use a
+ * sequential select for a secondary table defined on a subclass, which will be issued
only if a row
+ * turns out to represent an instance of the subclass. Inner joins will still be used to
retrieve a
+ * secondary defined by the class and its superclasses.
+ *
+ * <b>Only applies to secondary tables</b>
+ */
+ FetchMode fetch() default FetchMode.JOIN;
+
+ /**
+ * If true, Hibernate will not try to insert or update the properties defined by this
join.
+ *
+ * <b>Only applies to secondary tables</b>
+ */
+ boolean inverse() default false;
+
+ /**
+ * If enabled, Hibernate will insert a row only if the properties defined by this join
are non-null
+ * and will always use an outer join to retrieve the properties.
+ *
+ * <b>Only applies to secondary tables</b>
+ */
+ boolean optional() default true;
+
+ /**
+ * Defines a custom SQL insert statement
+ *
+ * <b>Only applies to secondary tables</b>
+ */
+ SQLInsert sqlInsert() default @SQLInsert(sql="");
+
+ /**
+ * Defines a custom SQL update statement
+ *
+ * <b>Only applies to secondary tables</b>
+ */
+ SQLUpdate sqlUpdate() default @SQLUpdate(sql="");
+
+ /**
+ * Defines a custom SQL delete statement
+ *
+ * <b>Only applies to secondary tables</b>
+ */
+ SQLDelete sqlDelete() default @SQLDelete(sql="");
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tables.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tables.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tables.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Plural of Table
+ *
+ * @author Emmanuel Bernard
+ * @see Table
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface Tables {
+ Table[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Target.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Target.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Target.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,17 @@
+//$Id: Target.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Define an explicit target,a voiding reflection and generics resolving
+ *
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target({ElementType.FIELD, ElementType.METHOD})
+@Retention( RetentionPolicy.RUNTIME )
+public @interface Target {
+ Class value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizer.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizer.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizer.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,21 @@
+//$Id: Tuplizer.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+/**
+ * Define a tuplizer for an entity or a component
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target( {TYPE, FIELD, METHOD} )
+@Retention( RUNTIME )
+public @interface Tuplizer {
+ /** tuplizer implementation */
+ Class impl();
+ /** either pojo, dynamic-map or dom4j� */
+ String entityMode() default "pojo";
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizers.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizers.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Tuplizers.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,16 @@
+//$Id: Tuplizers.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Define a set of tuplizer for an entity or a component
+ * @author Emmanuel Bernard
+ */
+(a)java.lang.annotation.Target( {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}
)
+@Retention( RetentionPolicy.RUNTIME )
+public @interface Tuplizers {
+ Tuplizer[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Type.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Type.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Type.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,21 @@
+//$Id: Type.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * hibernate type
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({FIELD, METHOD})
+@Retention(RUNTIME)
+public @interface Type {
+ String type();
+
+ Parameter[] parameters() default {};
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDef.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDef.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDef.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,23 @@
+//$Id: TypeDef.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Type definition
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface TypeDef {
+ String name();
+
+ Class typeClass();
+
+ Parameter[] parameters() default {};
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDefs.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDefs.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/TypeDefs.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: TypeDefs.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Type definition array
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, PACKAGE})
+@Retention(RUNTIME)
+public @interface TypeDefs {
+ TypeDef[] value();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Where.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Where.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/Where.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,18 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.*;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+
+/**
+ * Where clause to add to the element Entity or target entity of a collection
+ * The clause is written in SQL
+ *
+ * @author Emmanuel Bernard
+ */
+@Target({TYPE, METHOD, FIELD})
+@Retention(RUNTIME)
+public @interface Where {
+ String clause();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/WhereJoinTable.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/WhereJoinTable.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/annotations/WhereJoinTable.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+//$Id: WhereJoinTable.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Where clause to add to the colleciton join table
+ * The clause is written in SQL
+ *
+ * @author Emmanuel Bernard
+ */
+(a)Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+(a)Retention(RetentionPolicy.RUNTIME)
+public @interface WhereJoinTable {
+ String clause();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AbstractPropertyHolder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,188 @@
+//$Id: AbstractPropertyHolder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.persistence.AssociationOverride;
+import javax.persistence.AssociationOverrides;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class AbstractPropertyHolder implements PropertyHolder {
+ protected PropertyHolder parent;
+ private Map<String, Column[]> holderColumnOverride;
+ private Map<String, Column[]> currentPropertyColumnOverride;
+ private Map<String, JoinColumn[]> holderJoinColumnOverride;
+ private Map<String, JoinColumn[]> currentPropertyJoinColumnOverride;
+ private String path;
+ private ExtendedMappings mappings;
+
+ public AbstractPropertyHolder(
+ String path, PropertyHolder parent, XClass clazzToProcess, ExtendedMappings mappings
+ ) {
+ this.path = path;
+ this.parent = parent;
+ this.mappings = mappings;
+ buildHierarchyColumnOverride( clazzToProcess );
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * property can be null
+ */
+ protected void setCurrentProperty(XProperty property) {
+ if ( property == null ) {
+ this.currentPropertyColumnOverride = null;
+ this.currentPropertyJoinColumnOverride = null;
+ }
+ else {
+ this.currentPropertyColumnOverride = buildColumnOverride(
+ property,
+ getPath()
+ );
+ if ( this.currentPropertyColumnOverride.size() == 0 ) {
+ this.currentPropertyColumnOverride = null;
+ }
+ this.currentPropertyJoinColumnOverride = buildJoinColumnOverride(
+ property,
+ getPath()
+ );
+ if ( this.currentPropertyJoinColumnOverride.size() == 0 ) {
+ this.currentPropertyJoinColumnOverride = null;
+ }
+ }
+ }
+
+ /**
+ * Get column overriding, property first, then parent, then holder
+ */
+ public Column[] getOverriddenColumn(String propertyName) {
+ Column[] override = null;
+ if ( parent != null ) {
+ override = parent.getOverriddenColumn( propertyName );
+ }
+ if ( override == null && currentPropertyColumnOverride != null ) {
+ override = currentPropertyColumnOverride.get( propertyName );
+ }
+ if ( override == null && holderColumnOverride != null ) {
+ override = holderColumnOverride.get( propertyName );
+ }
+ return override;
+ }
+
+ /**
+ * Get column overriding, property first, then parent, then holder
+ */
+ public JoinColumn[] getOverriddenJoinColumn(String propertyName) {
+ JoinColumn[] override = null;
+ if ( parent != null ) {
+ override = parent.getOverriddenJoinColumn( propertyName );
+ }
+ if ( override == null && currentPropertyJoinColumnOverride != null ) {
+ override = currentPropertyJoinColumnOverride.get( propertyName );
+ }
+ if ( override == null && holderJoinColumnOverride != null ) {
+ override = holderJoinColumnOverride.get( propertyName );
+ }
+ return override;
+ }
+
+ private void buildHierarchyColumnOverride(XClass element) {
+ XClass current = element;
+ Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
+ Map<String, JoinColumn[]> joinColumnOverride = new HashMap<String,
JoinColumn[]>();
+ while ( current != null && !mappings.getReflectionManager().toXClass(
Object.class ).equals( current ) ) {
+ if ( current.isAnnotationPresent( Entity.class ) || current.isAnnotationPresent(
MappedSuperclass.class )
+ || current.isAnnotationPresent( Embeddable.class ) ) {
+ //FIXME is embeddable override?
+ Map<String, Column[]> currentOverride = buildColumnOverride( current, getPath()
);
+ Map<String, JoinColumn[]> currentJoinOverride = buildJoinColumnOverride(
current, getPath() );
+ currentOverride.putAll( columnOverride ); //subclasses have precedence over
superclasses
+ currentJoinOverride.putAll( joinColumnOverride ); //subclasses have precedence over
superclasses
+ columnOverride = currentOverride;
+ joinColumnOverride = currentJoinOverride;
+ }
+ current = current.getSuperclass();
+ }
+
+ holderColumnOverride = columnOverride.size() > 0 ? columnOverride : null;
+ holderJoinColumnOverride = joinColumnOverride.size() > 0 ? joinColumnOverride :
null;
+ }
+
+ private static Map<String, Column[]> buildColumnOverride(XAnnotatedElement
element, String path) {
+ Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
+ if ( element == null ) return columnOverride;
+ AttributeOverride singleOverride = element.getAnnotation( AttributeOverride.class );
+ AttributeOverrides multipleOverrides = element.getAnnotation( AttributeOverrides.class
);
+ AttributeOverride[] overrides;
+ if ( singleOverride != null ) {
+ overrides = new AttributeOverride[] { singleOverride };
+ }
+ else if ( multipleOverrides != null ) {
+ overrides = multipleOverrides.value();
+ }
+ else {
+ overrides = null;
+ }
+
+ //fill overriden columns
+ if ( overrides != null ) {
+ for (AttributeOverride depAttr : overrides) {
+ columnOverride.put(
+ StringHelper.qualify( path, depAttr.name() ),
+ new Column[] { depAttr.column() }
+ );
+ }
+ }
+ return columnOverride;
+ }
+
+ private static Map<String, JoinColumn[]> buildJoinColumnOverride(XAnnotatedElement
element, String path) {
+ Map<String, JoinColumn[]> columnOverride = new HashMap<String,
JoinColumn[]>();
+ if ( element == null ) return columnOverride;
+ AssociationOverride singleOverride = element.getAnnotation( AssociationOverride.class
);
+ AssociationOverrides multipleOverrides = element.getAnnotation(
AssociationOverrides.class );
+ AssociationOverride[] overrides;
+ if ( singleOverride != null ) {
+ overrides = new AssociationOverride[] { singleOverride };
+ }
+ else if ( multipleOverrides != null ) {
+ overrides = multipleOverrides.value();
+ }
+ else {
+ overrides = null;
+ }
+
+ //fill overriden columns
+ if ( overrides != null ) {
+ for (AssociationOverride depAttr : overrides) {
+ columnOverride.put(
+ StringHelper.qualify( path, depAttr.name() ),
+ depAttr.joinColumns()
+ );
+ }
+ }
+ return columnOverride;
+ }
+
+ public void setParentProperty(String parentProperty) {
+ throw new AssertionFailure( "Setting the parent property to a non component"
);
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotatedClassType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotatedClassType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotatedClassType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,25 @@
+package org.hibernate.cfg;
+
+/**
+ * Type of annotation of a class will give its type
+ *
+ * @author Emmanuel Bernard
+ */
+public enum AnnotatedClassType {
+ /**
+ * has no revelent top level annotation
+ */
+ NONE,
+ /**
+ * has @Entity annotation
+ */
+ ENTITY,
+ /**
+ * has a @Embeddable annotation
+ */
+ EMBEDDABLE,
+ /**
+ * has @EmbeddedSuperclass annotation
+ */
+ EMBEDDABLE_SUPERCLASS
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,2321 @@
+//$Id: AnnotationBinder.java 14786 2008-06-19 14:59:11Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.DiscriminatorType;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Embeddable;
+import javax.persistence.Embedded;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.InheritanceType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKey;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.NamedNativeQueries;
+import javax.persistence.NamedNativeQuery;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.PrimaryKeyJoinColumns;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.SqlResultSetMapping;
+import javax.persistence.SqlResultSetMappings;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.Version;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.AccessType;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.Check;
+import org.hibernate.annotations.CollectionId;
+import org.hibernate.annotations.CollectionOfElements;
+import org.hibernate.annotations.Columns;
+import org.hibernate.annotations.Fetch;
+import org.hibernate.annotations.Filter;
+import org.hibernate.annotations.FilterDef;
+import org.hibernate.annotations.FilterDefs;
+import org.hibernate.annotations.Filters;
+import org.hibernate.annotations.ForeignKey;
+import org.hibernate.annotations.Formula;
+import org.hibernate.annotations.GenericGenerator;
+import org.hibernate.annotations.Index;
+import org.hibernate.annotations.LazyToOne;
+import org.hibernate.annotations.LazyToOneOption;
+import org.hibernate.annotations.ManyToAny;
+import org.hibernate.annotations.MapKeyManyToMany;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.NotFound;
+import org.hibernate.annotations.NotFoundAction;
+import org.hibernate.annotations.OnDelete;
+import org.hibernate.annotations.OnDeleteAction;
+import org.hibernate.annotations.OrderBy;
+import org.hibernate.annotations.ParamDef;
+import org.hibernate.annotations.Parameter;
+import org.hibernate.annotations.Parent;
+import org.hibernate.annotations.Proxy;
+import org.hibernate.annotations.Sort;
+import org.hibernate.annotations.Target;
+import org.hibernate.annotations.Tuplizer;
+import org.hibernate.annotations.Tuplizers;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.TypeDef;
+import org.hibernate.annotations.TypeDefs;
+import org.hibernate.annotations.Where;
+import org.hibernate.annotations.GenericGenerators;
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XPackage;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.annotations.CollectionBinder;
+import org.hibernate.cfg.annotations.EntityBinder;
+import org.hibernate.cfg.annotations.Nullability;
+import org.hibernate.cfg.annotations.PropertyBinder;
+import org.hibernate.cfg.annotations.QueryBinder;
+import org.hibernate.cfg.annotations.SimpleValueBinder;
+import org.hibernate.cfg.annotations.TableBinder;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.Versioning;
+import org.hibernate.id.MultipleHiLoPerTableGenerator;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.id.SequenceHiLoGenerator;
+import org.hibernate.id.TableHiLoGenerator;
+import org.hibernate.mapping.Any;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.IdGenerator;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.JoinedSubclass;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.SingleTableSubclass;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.UnionSubclass;
+import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
+import org.hibernate.persister.entity.SingleTableEntityPersister;
+import org.hibernate.persister.entity.UnionSubclassEntityPersister;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JSR 175 annotation binder
+ * Will read the annotation from classes, apply the
+ * principles of the EJB3 spec and produces the Hibernate
+ * configuration-time metamodel (the classes in the <tt>mapping</tt>
+ * package)
+ *
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings("unchecked")
+public final class AnnotationBinder {
+
+ /*
+ * Some design description
+ * I tried to remove any link to annotation except from the 2 first level of
+ * method call.
+ * It'll enable to:
+ * - facilitate annotation overriding
+ * - mutualize one day xml and annotation binder (probably a dream though)
+ * - split this huge class in smaller mapping oriented classes
+ *
+ * bindSomething usually create the mapping container and is accessed by one of the 2
first level method
+ * makeSomething usually create the mapping container and is accessed by
bindSomething[else]
+ * fillSomething take the container into parameter and fill it.
+ *
+ *
+ */
+ private AnnotationBinder() {
+ }
+
+ private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class );
+
+ public static void bindDefaults(ExtendedMappings mappings) {
+ Map defaults = mappings.getReflectionManager().getDefaults();
+ {
+ List<SequenceGenerator> anns = (List<SequenceGenerator>) defaults.get(
SequenceGenerator.class );
+ if ( anns != null ) {
+ for (SequenceGenerator ann : anns) {
+ IdGenerator idGen = buildIdGenerator( ann, mappings );
+ if ( idGen != null ) mappings.addDefaultGenerator( idGen );
+ }
+ }
+ }
+ {
+ List<TableGenerator> anns = (List<TableGenerator>) defaults.get(
TableGenerator.class );
+ if ( anns != null ) {
+ for (TableGenerator ann : anns) {
+ IdGenerator idGen = buildIdGenerator( ann, mappings );
+ if ( idGen != null ) mappings.addDefaultGenerator( idGen );
+ }
+ }
+ }
+ {
+ List<NamedQuery> anns = (List<NamedQuery>) defaults.get( NamedQuery.class
);
+ if ( anns != null ) {
+ for (NamedQuery ann : anns) {
+ QueryBinder.bindQuery( ann, mappings, true );
+ }
+ }
+ }
+ {
+ List<NamedNativeQuery> anns = (List<NamedNativeQuery>) defaults.get(
NamedNativeQuery.class );
+ if ( anns != null ) {
+ for (NamedNativeQuery ann : anns) {
+ QueryBinder.bindNativeQuery( ann, mappings, true );
+ }
+ }
+ }
+ {
+ List<SqlResultSetMapping> anns = (List<SqlResultSetMapping>) defaults.get(
SqlResultSetMapping.class );
+ if ( anns != null ) {
+ for (SqlResultSetMapping ann : anns) {
+ QueryBinder.bindSqlResultsetMapping( ann, mappings, true );
+ }
+ }
+ }
+ }
+
+ public static void bindPackage(String packageName, ExtendedMappings mappings) {
+ XPackage pckg = null;
+ try {
+ pckg = mappings.getReflectionManager().packageForName( packageName );
+ }
+ catch (ClassNotFoundException cnf) {
+ log.warn( "Package not found or wo package-info.java: {}", packageName );
+ return;
+ }
+ if ( pckg.isAnnotationPresent( SequenceGenerator.class ) ) {
+ SequenceGenerator ann = pckg.getAnnotation( SequenceGenerator.class );
+ IdGenerator idGen = buildIdGenerator( ann, mappings );
+ mappings.addGenerator( idGen );
+ log.debug( "Add sequence generator with name: {}", idGen.getName() );
+ }
+ if ( pckg.isAnnotationPresent( TableGenerator.class ) ) {
+ TableGenerator ann = pckg.getAnnotation( TableGenerator.class );
+ IdGenerator idGen = buildIdGenerator( ann, mappings );
+ mappings.addGenerator( idGen );
+
+ }
+ bindGenericGenerators(pckg, mappings);
+ bindQueries( pckg, mappings );
+ bindFilterDefs( pckg, mappings );
+ bindTypeDefs( pckg, mappings );
+ BinderHelper.bindAnyMetaDefs( pckg, mappings );
+ }
+
+ private static void bindGenericGenerators(XAnnotatedElement annotatedElement,
ExtendedMappings mappings) {
+ GenericGenerator defAnn = annotatedElement.getAnnotation( GenericGenerator.class );
+ GenericGenerators defsAnn = annotatedElement.getAnnotation( GenericGenerators.class );
+ if ( defAnn != null ) {
+ bindGenericGenerator( defAnn, mappings );
+ }
+ if ( defsAnn != null ) {
+ for (GenericGenerator def : defsAnn.value() ) {
+ bindGenericGenerator( def, mappings );
+ }
+ }
+ }
+
+ private static void bindGenericGenerator(GenericGenerator def, ExtendedMappings
mappings) {
+ IdGenerator idGen = buildIdGenerator( def, mappings );
+ mappings.addGenerator( idGen );
+ }
+
+ private static void bindQueries(XAnnotatedElement annotatedElement, ExtendedMappings
mappings) {
+ {
+ SqlResultSetMapping ann = annotatedElement.getAnnotation( SqlResultSetMapping.class
);
+ QueryBinder.bindSqlResultsetMapping( ann, mappings, false );
+ }
+ {
+ SqlResultSetMappings ann = annotatedElement.getAnnotation( SqlResultSetMappings.class
);
+ if ( ann != null ) {
+ for (SqlResultSetMapping current : ann.value()) {
+ QueryBinder.bindSqlResultsetMapping( current, mappings, false );
+ }
+ }
+ }
+ {
+ NamedQuery ann = annotatedElement.getAnnotation( NamedQuery.class );
+ QueryBinder.bindQuery( ann, mappings, false );
+ }
+ {
+ org.hibernate.annotations.NamedQuery ann = annotatedElement.getAnnotation(
+ org.hibernate.annotations.NamedQuery.class
+ );
+ QueryBinder.bindQuery( ann, mappings );
+ }
+ {
+ NamedQueries ann = annotatedElement.getAnnotation( NamedQueries.class );
+ QueryBinder.bindQueries( ann, mappings, false );
+ }
+ {
+ org.hibernate.annotations.NamedQueries ann = annotatedElement.getAnnotation(
+ org.hibernate.annotations.NamedQueries.class
+ );
+ QueryBinder.bindQueries( ann, mappings );
+ }
+ {
+ NamedNativeQuery ann = annotatedElement.getAnnotation( NamedNativeQuery.class );
+ QueryBinder.bindNativeQuery( ann, mappings, false );
+ }
+ {
+ org.hibernate.annotations.NamedNativeQuery ann = annotatedElement.getAnnotation(
+ org.hibernate.annotations.NamedNativeQuery.class
+ );
+ QueryBinder.bindNativeQuery( ann, mappings );
+ }
+ {
+ NamedNativeQueries ann = annotatedElement.getAnnotation( NamedNativeQueries.class );
+ QueryBinder.bindNativeQueries( ann, mappings, false );
+ }
+ {
+ org.hibernate.annotations.NamedNativeQueries ann = annotatedElement.getAnnotation(
+ org.hibernate.annotations.NamedNativeQueries.class
+ );
+ QueryBinder.bindNativeQueries( ann, mappings );
+ }
+ }
+
+ private static IdGenerator buildIdGenerator(java.lang.annotation.Annotation ann,
Mappings mappings) {
+ IdGenerator idGen = new IdGenerator();
+ if ( mappings.getSchemaName() != null ) {
+ idGen.addParam( PersistentIdentifierGenerator.SCHEMA, mappings.getSchemaName() );
+ }
+ if ( mappings.getCatalogName() != null ) {
+ idGen.addParam( PersistentIdentifierGenerator.CATALOG, mappings.getCatalogName() );
+ }
+ if ( ann == null ) {
+ idGen = null;
+ }
+ else if ( ann instanceof TableGenerator ) {
+ TableGenerator tabGen = (TableGenerator) ann;
+ idGen.setName( tabGen.name() );
+ idGen.setIdentifierGeneratorStrategy( MultipleHiLoPerTableGenerator.class.getName()
);
+
+ if ( !BinderHelper.isDefault( tabGen.table() ) ) {
+ idGen.addParam( MultipleHiLoPerTableGenerator.ID_TABLE, tabGen.table() );
+ }
+ if ( !BinderHelper.isDefault( tabGen.catalog() ) ) {
+ idGen.addParam( MultipleHiLoPerTableGenerator.CATALOG, tabGen.catalog() );
+ }
+ if ( !BinderHelper.isDefault( tabGen.schema() ) ) {
+ idGen.addParam( MultipleHiLoPerTableGenerator.SCHEMA, tabGen.schema() );
+ }
+ //FIXME implements uniqueconstrains
+
+ if ( !BinderHelper.isDefault( tabGen.pkColumnName() ) ) {
+ idGen.addParam( MultipleHiLoPerTableGenerator.PK_COLUMN_NAME, tabGen.pkColumnName()
);
+ }
+ if ( !BinderHelper.isDefault( tabGen.valueColumnName() ) ) {
+ idGen.addParam( MultipleHiLoPerTableGenerator.VALUE_COLUMN_NAME,
tabGen.valueColumnName() );
+ }
+ if ( !BinderHelper.isDefault( tabGen.pkColumnValue() ) ) {
+ idGen.addParam( MultipleHiLoPerTableGenerator.PK_VALUE_NAME, tabGen.pkColumnValue()
);
+ }
+ idGen.addParam( TableHiLoGenerator.MAX_LO, String.valueOf( tabGen.allocationSize() - 1
) );
+ log.debug( "Add table generator with name: {}", idGen.getName() );
+ }
+ else if ( ann instanceof SequenceGenerator ) {
+ SequenceGenerator seqGen = (SequenceGenerator) ann;
+ idGen.setName( seqGen.name() );
+ idGen.setIdentifierGeneratorStrategy( "seqhilo" );
+
+ if ( !BinderHelper.isDefault( seqGen.sequenceName() ) ) {
+ idGen.addParam( org.hibernate.id.SequenceGenerator.SEQUENCE, seqGen.sequenceName()
);
+ }
+ //FIXME: work on initialValue() through SequenceGenerator.PARAMETERS
+ if ( seqGen.initialValue() != 1 ) {
+ log.warn(
+ "Hibernate does not support SequenceGenerator.initialValue()"
+ );
+ }
+ idGen.addParam( SequenceHiLoGenerator.MAX_LO, String.valueOf( seqGen.allocationSize()
- 1 ) );
+ log.debug( "Add sequence generator with name: {}", idGen.getName() );
+ }
+ else if ( ann instanceof GenericGenerator ) {
+ GenericGenerator genGen = (GenericGenerator) ann;
+ idGen.setName( genGen.name() );
+ idGen.setIdentifierGeneratorStrategy( genGen.strategy() );
+ Parameter[] params = genGen.parameters();
+ for (Parameter parameter : params) {
+ idGen.addParam( parameter.name(), parameter.value() );
+ }
+ log.debug( "Add generic generator with name: {}", idGen.getName() );
+ }
+ else {
+ throw new AssertionFailure( "Unknown Generator annotation: " + ann );
+ }
+ return idGen;
+ }
+
+ /**
+ * Bind a class having JSR175 annotations
+ * The subclasses <b>have to</b> be binded after its mother class
+ */
+ public static void bindClass(
+ XClass clazzToProcess, Map<XClass, InheritanceState> inheritanceStatePerClass,
ExtendedMappings mappings
+ ) throws MappingException {
+ //TODO: be more strict with secondarytable allowance (not for ids, not for secondary
table join columns etc)
+ InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess );
+ AnnotatedClassType classType = mappings.getClassType( clazzToProcess );
+ if ( AnnotatedClassType.EMBEDDABLE_SUPERCLASS.equals( classType ) //will be processed
by their subentities
+ || AnnotatedClassType.NONE.equals( classType ) //to be ignored
+ || AnnotatedClassType.EMBEDDABLE.equals( classType ) //allow embeddable element
declaration
+ ) {
+ if ( AnnotatedClassType.NONE.equals( classType )
+ && clazzToProcess.isAnnotationPresent(
org.hibernate.annotations.Entity.class ) ) {
+ log.warn( "Class annotated @org.hibernate.annotations.Entity but not
javax.persistence.Entity "
+ + "(most likely a user error): {}", clazzToProcess.getName() );
+ }
+ return;
+ }
+ if ( !classType.equals( AnnotatedClassType.ENTITY ) ) {
+ //TODO make this test accurate by removing the none elements artifically added
+ throw new AnnotationException(
+ "Annotated class should have a @javax.persistence.Entity,
@javax.persistence.Embeddable or @javax.persistence.EmbeddedSuperclass annotation: "
+ clazzToProcess
+ .getName()
+ );
+ }
+ XAnnotatedElement annotatedClass = clazzToProcess;
+ log.info( "Binding entity from annotated class: {}", clazzToProcess.getName()
);
+ InheritanceState superEntityState =
+ InheritanceState.getSuperEntityInheritanceState(
+ clazzToProcess, inheritanceStatePerClass, mappings.getReflectionManager()
+ );
+ PersistentClass superEntity = superEntityState != null ?
+ mappings.getClass(
+ superEntityState.clazz.getName()
+ ) :
+ null;
+ if ( superEntity == null ) {
+ //check if superclass is not a potential persistent class
+ if ( inheritanceState.hasParents ) {
+ throw new AssertionFailure(
+ "Subclass has to be binded after it's mother class: "
+ + superEntityState.clazz.getName()
+ );
+ }
+ }
+ bindQueries( annotatedClass, mappings );
+ bindFilterDefs( annotatedClass, mappings );
+ bindTypeDefs( annotatedClass, mappings );
+ BinderHelper.bindAnyMetaDefs( annotatedClass, mappings );
+
+ String schema = "";
+ String table = ""; //might be no @Table annotation on the annotated class
+ String catalog = "";
+ String discrimValue = null;
+ List<String[]> uniqueConstraints = new ArrayList<String[]>();
+ Ejb3DiscriminatorColumn discriminatorColumn = null;
+ Ejb3JoinColumn[] inheritanceJoinedColumns = null;
+
+ if ( annotatedClass.isAnnotationPresent( javax.persistence.Table.class ) ) {
+ javax.persistence.Table tabAnn = annotatedClass.getAnnotation(
javax.persistence.Table.class );
+ table = tabAnn.name();
+ schema = tabAnn.schema();
+ catalog = tabAnn.catalog();
+ uniqueConstraints = TableBinder.buildUniqueConstraints( tabAnn.uniqueConstraints() );
+ }
+ final boolean hasJoinedColumns = inheritanceState.hasParents
+ && InheritanceType.JOINED.equals( inheritanceState.type );
+ if ( hasJoinedColumns ) {
+ //@Inheritance(JOINED) subclass need to link back to the super entity
+ PrimaryKeyJoinColumns jcsAnn = annotatedClass.getAnnotation(
PrimaryKeyJoinColumns.class );
+ boolean explicitInheritanceJoinedColumns = jcsAnn != null &&
jcsAnn.value().length != 0;
+ if ( explicitInheritanceJoinedColumns ) {
+ int nbrOfInhJoinedColumns = jcsAnn.value().length;
+ PrimaryKeyJoinColumn jcAnn;
+ inheritanceJoinedColumns = new Ejb3JoinColumn[nbrOfInhJoinedColumns];
+ for (int colIndex = 0; colIndex < nbrOfInhJoinedColumns; colIndex++) {
+ jcAnn = jcsAnn.value()[colIndex];
+ inheritanceJoinedColumns[colIndex] = Ejb3JoinColumn.buildJoinColumn(
+ jcAnn, null, superEntity.getIdentifier(),
+ (Map<String, Join>) null, (PropertyHolder) null, mappings
+ );
+ }
+ }
+ else {
+ PrimaryKeyJoinColumn jcAnn = annotatedClass.getAnnotation( PrimaryKeyJoinColumn.class
);
+ inheritanceJoinedColumns = new Ejb3JoinColumn[1];
+ inheritanceJoinedColumns[0] = Ejb3JoinColumn.buildJoinColumn(
+ jcAnn, null, superEntity.getIdentifier(),
+ (Map<String, Join>) null, (PropertyHolder) null, mappings
+ );
+ }
+ log.debug( "Subclass joined column(s) created" );
+ }
+ else {
+ if ( annotatedClass.isAnnotationPresent( javax.persistence.PrimaryKeyJoinColumns.class
)
+ || annotatedClass.isAnnotationPresent( javax.persistence.PrimaryKeyJoinColumn.class
) ) {
+ log.warn( "Root entity should not hold an PrimaryKeyJoinColum(s), will be
ignored" );
+ }
+ }
+
+ if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.type ) ) {
+ javax.persistence.DiscriminatorColumn discAnn = annotatedClass.getAnnotation(
+ javax.persistence.DiscriminatorColumn.class
+ );
+ DiscriminatorType discriminatorType = discAnn != null ?
+ discAnn.discriminatorType() :
+ DiscriminatorType.STRING;
+
+ org.hibernate.annotations.DiscriminatorFormula discFormulaAnn =
annotatedClass.getAnnotation(
+ org.hibernate.annotations.DiscriminatorFormula.class
+ );
+ if ( !inheritanceState.hasParents ) {
+ discriminatorColumn = Ejb3DiscriminatorColumn.buildDiscriminatorColumn(
+ discriminatorType, discAnn, discFormulaAnn, mappings
+ );
+ }
+ if ( discAnn != null && inheritanceState.hasParents ) {
+ log.warn(
+ "Discriminator column has to be defined in the root entity, it will be ignored
in subclass: {}",
+ clazzToProcess.getName()
+ );
+ }
+ discrimValue = annotatedClass.isAnnotationPresent( DiscriminatorValue.class ) ?
+ annotatedClass.getAnnotation( DiscriminatorValue.class ).value() :
+ null;
+ }
+
+ //we now know what kind of persistent entity it is
+ PersistentClass persistentClass;
+ //create persistent class
+ if ( !inheritanceState.hasParents ) {
+ persistentClass = new RootClass();
+ }
+ else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.type ) ) {
+ persistentClass = new SingleTableSubclass( superEntity );
+ }
+ else if ( InheritanceType.JOINED.equals( inheritanceState.type ) ) {
+ persistentClass = new JoinedSubclass( superEntity );
+ }
+ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.type ) ) {
+ persistentClass = new UnionSubclass( superEntity );
+ }
+ else {
+ throw new AssertionFailure( "Unknown inheritance type: " +
inheritanceState.type );
+ }
+ Proxy proxyAnn = annotatedClass.getAnnotation( Proxy.class );
+ BatchSize sizeAnn = annotatedClass.getAnnotation( BatchSize.class );
+ Where whereAnn = annotatedClass.getAnnotation( Where.class );
+ Entity entityAnn = annotatedClass.getAnnotation( Entity.class );
+ org.hibernate.annotations.Entity hibEntityAnn = annotatedClass.getAnnotation(
+ org.hibernate.annotations.Entity.class
+ );
+ org.hibernate.annotations.Cache cacheAnn = annotatedClass.getAnnotation(
+ org.hibernate.annotations.Cache.class
+ );
+ EntityBinder entityBinder = new EntityBinder(
+ entityAnn, hibEntityAnn, clazzToProcess, persistentClass, mappings
+ );
+ entityBinder.setDiscriminatorValue( discrimValue );
+ entityBinder.setBatchSize( sizeAnn );
+ entityBinder.setProxy( proxyAnn );
+ entityBinder.setWhere( whereAnn );
+ entityBinder.setCache( cacheAnn );
+ entityBinder.setInheritanceState( inheritanceState );
+ Filter filterAnn = annotatedClass.getAnnotation( Filter.class );
+ if ( filterAnn != null ) {
+ entityBinder.addFilter( filterAnn.name(), filterAnn.condition() );
+ }
+ Filters filtersAnn = annotatedClass.getAnnotation( Filters.class );
+ if ( filtersAnn != null ) {
+ for (Filter filter : filtersAnn.value()) {
+ entityBinder.addFilter( filter.name(), filter.condition() );
+ }
+ }
+ entityBinder.bindEntity();
+
+ if ( inheritanceState.hasTable() ) {
+ Check checkAnn = annotatedClass.getAnnotation( Check.class );
+ String constraints = checkAnn == null ?
+ null :
+ checkAnn.constraints();
+ entityBinder.bindTable(
+ schema, catalog, table, uniqueConstraints,
+ constraints, inheritanceState.hasDenormalizedTable() ?
+ superEntity.getTable() :
+ null
+ );
+ }
+ else {
+ if ( annotatedClass.isAnnotationPresent( Table.class ) ) {
+ log.warn( "Illegal use of @Table in a subclass of a SINGLE_TABLE hierarchy:
" + clazzToProcess
+ .getName() );
+ }
+ }
+// Map<String, Column[]> columnOverride =
PropertyHolderBuilder.buildHierarchyColumnOverride(
+// clazzToProcess,
+// persistentClass.getClassName()
+// );
+ PropertyHolder propertyHolder = PropertyHolderBuilder.buildPropertyHolder(
+ clazzToProcess,
+ persistentClass,
+ entityBinder, mappings
+ );
+
+ javax.persistence.SecondaryTable secTabAnn = annotatedClass.getAnnotation(
+ javax.persistence.SecondaryTable.class
+ );
+ javax.persistence.SecondaryTables secTabsAnn = annotatedClass.getAnnotation(
+ javax.persistence.SecondaryTables.class
+ );
+ entityBinder.firstLevelSecondaryTablesBinding( secTabAnn, secTabsAnn );
+
+ OnDelete onDeleteAnn = annotatedClass.getAnnotation( OnDelete.class );
+ boolean onDeleteAppropriate = false;
+ if ( InheritanceType.JOINED.equals( inheritanceState.type ) &&
inheritanceState.hasParents ) {
+ onDeleteAppropriate = true;
+ final JoinedSubclass jsc = (JoinedSubclass) persistentClass;
+ if ( persistentClass.getEntityPersisterClass() == null ) {
+ persistentClass.getRootClass().setEntityPersisterClass(
JoinedSubclassEntityPersister.class );
+ }
+ SimpleValue key = new DependantValue( jsc.getTable(), jsc.getIdentifier() );
+ jsc.setKey( key );
+ ForeignKey fk = annotatedClass.getAnnotation( ForeignKey.class );
+ if ( fk != null && !BinderHelper.isDefault( fk.name() ) ) {
+ key.setForeignKeyName( fk.name() );
+ }
+ if ( onDeleteAnn != null ) {
+ key.setCascadeDeleteEnabled( OnDeleteAction.CASCADE.equals( onDeleteAnn.action() )
);
+ }
+ else {
+ key.setCascadeDeleteEnabled( false );
+ }
+ //we are never in a second pass at that stage, so queue it
+ SecondPass sp = new JoinedSubclassFkSecondPass( jsc, inheritanceJoinedColumns, key,
mappings );
+ mappings.addSecondPass( sp );
+ mappings.addSecondPass( new CreateKeySecondPass( jsc ) );
+
+ }
+ else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.type ) ) {
+ if ( inheritanceState.hasParents ) {
+ if ( persistentClass.getEntityPersisterClass() == null ) {
+ persistentClass.getRootClass().setEntityPersisterClass(
SingleTableEntityPersister.class );
+ }
+ }
+ else {
+ if ( inheritanceState.hasSons || !discriminatorColumn.isImplicit() ) {
+ //need a discriminator column
+ bindDiscriminatorToPersistentClass(
+ (RootClass) persistentClass,
+ discriminatorColumn,
+ entityBinder.getSecondaryTables(),
+ propertyHolder
+ );
+ entityBinder.bindDiscriminatorValue();//bind it again since the type might have
changed
+ }
+ }
+ }
+ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.type ) ) {
+ if ( inheritanceState.hasParents ) {
+ if ( persistentClass.getEntityPersisterClass() == null ) {
+ persistentClass.getRootClass().setEntityPersisterClass(
UnionSubclassEntityPersister.class );
+ }
+ }
+ }
+ if ( onDeleteAnn != null && !onDeleteAppropriate ) {
+ log.warn(
+ "Inapropriate use of @OnDelete on entity, annotation ignored: {}",
propertyHolder.getEntityName()
+ );
+ }
+
+ //try to find class level generators
+ HashMap<String, IdGenerator> classGenerators = buildLocalGenerators(
annotatedClass, mappings );
+
+ // check properties
+ List<PropertyData> elements =
+ getElementsToProcess(
+ clazzToProcess, inheritanceStatePerClass, propertyHolder, entityBinder, mappings
+ );
+ if ( elements == null ) {
+ throw new AnnotationException( "No identifier specified for entity: " +
propertyHolder.getEntityName() );
+ }
+ final boolean subclassAndSingleTableStrategy = inheritanceState.type ==
InheritanceType.SINGLE_TABLE
+ && inheritanceState.hasParents;
+ //process idclass if any
+ Set<String> idProperties = new HashSet<String>();
+ IdClass idClass = null;
+ if ( !inheritanceState.hasParents ) {
+ //look for idClass
+ XClass current = inheritanceState.clazz;
+ InheritanceState state = inheritanceState;
+ do {
+ current = state.clazz;
+ if ( current.isAnnotationPresent( IdClass.class ) ) {
+ idClass = current.getAnnotation( IdClass.class );
+ break;
+ }
+ state = InheritanceState.getSuperclassInheritanceState(
+ current, inheritanceStatePerClass, mappings.getReflectionManager()
+ );
+ }
+ while ( state != null );
+ }
+ if ( idClass != null ) {
+ XClass compositeClass = mappings.getReflectionManager().toXClass( idClass.value() );
+ boolean isComponent = true;
+ boolean propertyAnnotated = entityBinder.isPropertyAnnotated( compositeClass );
+ String propertyAccessor = entityBinder.getPropertyAccessor( compositeClass );
+ String generatorType = "assigned";
+ String generator = BinderHelper.ANNOTATION_STRING_DEFAULT;
+ PropertyData inferredData = new PropertyPreloadedData(
+ entityBinder.getPropertyAccessor(), "id", compositeClass
+ );
+ HashMap<String, IdGenerator> localGenerators = new HashMap<String,
IdGenerator>();
+ boolean ignoreIdAnnotations = entityBinder.isIgnoreIdAnnotations();
+ entityBinder.setIgnoreIdAnnotations( true );
+ bindId(
+ generatorType,
+ generator,
+ inferredData,
+ null,
+ propertyHolder,
+ localGenerators,
+ isComponent,
+ propertyAnnotated,
+ propertyAccessor, entityBinder,
+ true,
+ false, mappings
+ );
+ inferredData = new PropertyPreloadedData(
+ propertyAccessor, "_identifierMapper", compositeClass
+ );
+ Component mapper = fillComponent(
+ propertyHolder,
+ inferredData,
+ propertyAnnotated,
+ propertyAccessor, false,
+ entityBinder,
+ true, true,
+ false, mappings
+ );
+ entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations );
+ persistentClass.setIdentifierMapper( mapper );
+ Property property = new Property();
+ property.setName( "_identifierMapper" );
+ property.setNodeName( "id" );
+ property.setUpdateable( false );
+ property.setInsertable( false );
+ property.setValue( mapper );
+ property.setPropertyAccessorName( "embedded" );
+ persistentClass.addProperty( property );
+ entityBinder.setIgnoreIdAnnotations( true );
+
+ Iterator properties = mapper.getPropertyIterator();
+ while ( properties.hasNext() ) {
+ idProperties.add( ( (Property) properties.next() ).getName() );
+ }
+ }
+ Set<String> missingIdProperties = new HashSet<String>( idProperties );
+ for (PropertyData propertyAnnotatedElement : elements) {
+ String propertyName = propertyAnnotatedElement.getPropertyName();
+ if ( !idProperties.contains( propertyName ) ) {
+ processElementAnnotations(
+ propertyHolder,
+ subclassAndSingleTableStrategy ?
+ Nullability.FORCED_NULL :
+ Nullability.NO_CONSTRAINT,
+ propertyAnnotatedElement.getProperty(),
+ propertyAnnotatedElement, classGenerators, entityBinder,
+ false, false, false, mappings
+ );
+ }
+ else {
+ missingIdProperties.remove( propertyName );
+ }
+ }
+
+ if ( missingIdProperties.size() != 0 ) {
+ StringBuilder missings = new StringBuilder();
+ for (String property : missingIdProperties) {
+ missings.append( property ).append( ", " );
+ }
+ throw new AnnotationException(
+ "Unable to find properties ("
+ + missings.substring( 0, missings.length() - 2 )
+ + ") in entity annotated with @IdClass:" +
persistentClass.getEntityName()
+ );
+ }
+
+ if ( !inheritanceState.hasParents ) {
+ final RootClass rootClass = (RootClass) persistentClass;
+ mappings.addSecondPass( new CreateKeySecondPass( rootClass ) );
+ }
+ else {
+ superEntity.addSubclass( (Subclass) persistentClass );
+ }
+
+ mappings.addClass( persistentClass );
+
+ //Process secondary tables and complementary definitions (ie o.h.a.Table)
+ mappings.addSecondPass( new SecondaryTableSecondPass( entityBinder, propertyHolder,
annotatedClass ) );
+
+ //add process complementary Table definition (index & all)
+ entityBinder.processComplementaryTableDefinitions( annotatedClass.getAnnotation(
org.hibernate.annotations.Table.class ) );
+ entityBinder.processComplementaryTableDefinitions( annotatedClass.getAnnotation(
org.hibernate.annotations.Tables.class ) );
+
+ }
+
+ /**
+ * Get the annotated elements
+ * Guess the annotated element from @Id or @EmbeddedId presence
+ * Change EntityBinder by side effect
+ */
+ private static List<PropertyData> getElementsToProcess(
+ XClass clazzToProcess, Map<XClass, InheritanceState> inheritanceStatePerClass,
+ PropertyHolder propertyHolder, EntityBinder entityBinder, ExtendedMappings mappings
+ ) {
+ InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess );
+ List<XClass> classesToProcess = orderClassesToBeProcessed(
+ clazzToProcess, inheritanceStatePerClass, inheritanceState, mappings
+ );
+ List<PropertyData> elements = new ArrayList<PropertyData>();
+ int deep = classesToProcess.size();
+ boolean hasIdentifier = false;
+
+ assert !inheritanceState.isEmbeddableSuperclass;
+ Boolean isExplicitPropertyAnnotated = null;
+ String explicitAccessType = null;
+ if ( inheritanceState.hasParents ) {
+ InheritanceState superEntityState =
+ InheritanceState.getSuperEntityInheritanceState(
+ clazzToProcess, inheritanceStatePerClass, mappings.getReflectionManager()
+ );
+ isExplicitPropertyAnnotated = superEntityState != null ?
+ superEntityState.isPropertyAnnotated :
+ null;
+ explicitAccessType = superEntityState != null ?
+ superEntityState.accessType :
+ null;
+ }
+ else {
+ AccessType access = clazzToProcess.getAnnotation( AccessType.class );
+ explicitAccessType = access != null ?
+ access.value() :
+ null;
+ if ( "property".equals( explicitAccessType ) ) {
+ isExplicitPropertyAnnotated = Boolean.TRUE;
+ }
+ else if ( "field".equals( explicitAccessType ) ) {
+ isExplicitPropertyAnnotated = Boolean.FALSE;
+ }
+ }
+ Boolean isPropertyAnnotated = isExplicitPropertyAnnotated == null ?
+ Boolean.TRUE :
+ //default to property and fallback if needed
+ isExplicitPropertyAnnotated;
+ String accessType = explicitAccessType != null ?
+ explicitAccessType :
+ "property";
+ /*
+ * delay the exception in case field access is used
+ */
+ AnnotationException exceptionWhileWalkingElements = null;
+ try {
+ for (int index = 0; index < deep; index++) {
+ XClass clazz = classesToProcess.get( index );
+
+ boolean currentHasIdentifier = addElementsOfAClass(
+ elements, propertyHolder, isPropertyAnnotated,
+ accessType, clazz, mappings
+ );
+ hasIdentifier = hasIdentifier || currentHasIdentifier;
+ }
+ }
+ catch ( AnnotationException e ) {
+ exceptionWhileWalkingElements = e;
+ }
+
+ //TODO remember why it should be !inheritanceState.hasParents
+ if ( !hasIdentifier && !inheritanceState.hasParents ) {
+ if ( isExplicitPropertyAnnotated != null ) {
+ //the original exception is legitimate
+ if ( exceptionWhileWalkingElements != null) throw exceptionWhileWalkingElements;
+ return null; //explicit but no @Id: the upper layer will raise an exception
+ }
+ isPropertyAnnotated = !isPropertyAnnotated;
+ accessType = "field";
+ elements.clear();
+ for (int index = 0; index < deep; index++) {
+ XClass clazz = classesToProcess.get( index );
+ boolean currentHasIdentifier = addElementsOfAClass(
+ elements, propertyHolder, isPropertyAnnotated,
+ accessType, clazz, mappings
+ );
+ hasIdentifier = hasIdentifier || currentHasIdentifier;
+ }
+ }
+
+ //the field show no id, fallback tot he original exception
+ if (!hasIdentifier && exceptionWhileWalkingElements != null) throw
exceptionWhileWalkingElements;
+
+ //TODO set the access type here?
+ entityBinder.setPropertyAnnotated( isPropertyAnnotated );
+ entityBinder.setPropertyAccessor( accessType );
+ inheritanceState.isPropertyAnnotated = isPropertyAnnotated;
+ inheritanceState.accessType = accessType;
+ return hasIdentifier || inheritanceState.hasParents ?
+ elements :
+ null;
+ }
+
+ private static List<XClass> orderClassesToBeProcessed(
+ XClass annotatedClass, Map<XClass, InheritanceState> inheritanceStatePerClass,
+ InheritanceState inheritanceState, ExtendedMappings mappings
+ ) {
+ //ordered to allow proper messages on properties subclassing
+ List<XClass> classesToProcess = new ArrayList<XClass>();
+ XClass currentClassInHierarchy = annotatedClass;
+ InheritanceState superclassState;
+ do {
+ classesToProcess.add( 0, currentClassInHierarchy );
+ XClass superClass = currentClassInHierarchy;
+ do {
+ superClass = superClass.getSuperclass();
+ superclassState = inheritanceStatePerClass.get( superClass );
+ }
+ while ( superClass != null && !mappings.getReflectionManager()
+ .equals( superClass, Object.class ) && superclassState == null );
+
+ currentClassInHierarchy = superClass;
+ }
+ while ( superclassState != null && superclassState.isEmbeddableSuperclass );
+
+ return classesToProcess;
+ }
+
+ private static void bindFilterDefs(XAnnotatedElement annotatedElement, ExtendedMappings
mappings) {
+ FilterDef defAnn = annotatedElement.getAnnotation( FilterDef.class );
+ FilterDefs defsAnn = annotatedElement.getAnnotation( FilterDefs.class );
+ if ( defAnn != null ) {
+ bindFilterDef( defAnn, mappings );
+ }
+ if ( defsAnn != null ) {
+ for (FilterDef def : defsAnn.value()) {
+ bindFilterDef( def, mappings );
+ }
+ }
+ }
+
+ private static void bindFilterDef(FilterDef defAnn, ExtendedMappings mappings) {
+ Map<String, org.hibernate.type.Type> params = new HashMap<String,
org.hibernate.type.Type>();
+ for (ParamDef param : defAnn.parameters()) {
+ params.put( param.name(), TypeFactory.heuristicType( param.type() ) );
+ }
+ FilterDefinition def = new FilterDefinition( defAnn.name(), defAnn.defaultCondition(),
params );
+ log.info( "Binding filter definition: {}", def.getFilterName() );
+ mappings.addFilterDefinition( def );
+ }
+
+ private static void bindTypeDefs(XAnnotatedElement annotatedElement, ExtendedMappings
mappings) {
+ TypeDef defAnn = annotatedElement.getAnnotation( TypeDef.class );
+ TypeDefs defsAnn = annotatedElement.getAnnotation( TypeDefs.class );
+ if ( defAnn != null ) {
+ bindTypeDef( defAnn, mappings );
+ }
+ if ( defsAnn != null ) {
+ for (TypeDef def : defsAnn.value()) {
+ bindTypeDef( def, mappings );
+ }
+ }
+ }
+
+ private static void bindTypeDef(TypeDef defAnn, ExtendedMappings mappings) {
+ Properties params = new Properties();
+ for (Parameter param : defAnn.parameters()) {
+ params.setProperty( param.name(), param.value() );
+ }
+ log.info( "Binding type definition: {}", defAnn.name() );
+ mappings.addTypeDef( defAnn.name(), defAnn.typeClass().getName(), params );
+ }
+
+ private static void bindDiscriminatorToPersistentClass(
+ RootClass rootClass,
+ Ejb3DiscriminatorColumn discriminatorColumn, Map<String, Join> secondaryTables,
+ PropertyHolder propertyHolder
+ ) {
+ if ( rootClass.getDiscriminator() == null ) {
+ if ( discriminatorColumn == null ) {
+ throw new AssertionFailure( "discriminator column should have been built"
);
+ }
+ discriminatorColumn.setJoins( secondaryTables );
+ discriminatorColumn.setPropertyHolder( propertyHolder );
+ SimpleValue discrim = new SimpleValue( rootClass.getTable() );
+ rootClass.setDiscriminator( discrim );
+ discriminatorColumn.linkWithValue( discrim );
+ discrim.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
+ rootClass.setPolymorphic( true );
+ log.debug( "Setting discriminator for entity {}", rootClass.getEntityName()
);
+ }
+ }
+
+ /**
+ * Add elements of a class
+ */
+ private static boolean addElementsOfAClass(
+ List<PropertyData> elements, PropertyHolder propertyHolder, boolean
isPropertyAnnotated,
+ String propertyAccessor, final XClass annotatedClass, ExtendedMappings mappings
+ ) {
+ boolean hasIdentifier = false;
+ AccessType access = annotatedClass.getAnnotation( AccessType.class );
+ String localPropertyAccessor = access != null ?
+ access.value() :
+ null;
+ String accessType = null;
+ if ( "property".equals( localPropertyAccessor ) || "field".equals(
localPropertyAccessor ) ) {
+ accessType = localPropertyAccessor;
+ }
+ else {
+ if ( localPropertyAccessor == null ) {
+ localPropertyAccessor = propertyAccessor;
+ }
+
+ if ( isPropertyAnnotated ) {
+ accessType = "property";
+ }
+ else {
+ accessType = "field";
+ }
+ }
+
+ log.debug( "Processing {} {} annotation", propertyHolder.getEntityName(),
accessType );
+ List<XProperty> properties = annotatedClass.getDeclaredProperties( accessType );
+ //order so that property are used in the same order when binding native query
+ Collections.sort( properties, new Comparator<XProperty>() {
+ public int compare(XProperty property1, XProperty property2) {
+ return property1.getName().compareTo( property2.getName() );
+ }
+ } );
+ for (XProperty p : properties) {
+ if ( !p.isTypeResolved() && !discoverTypeWithoutReflection( p ) &&
!mustBeSkipped( p, mappings ) ) {
+ throw new AnnotationException(
+ "Property " + StringHelper.qualify( propertyHolder.getEntityName(),
p.getName() ) +
+ " has an unbound type and no explicit target entity. Resolve this Generic
usage issue" +
+ " or set an explicit target attribute (eg @OneToMany(target=) or use an
explicit @Type"
+ );
+ }
+ final boolean currentHasIdentifier = addProperty( p, elements, localPropertyAccessor,
mappings );
+ hasIdentifier = hasIdentifier || currentHasIdentifier;
+ }
+ return hasIdentifier;
+ }
+
+ private static boolean discoverTypeWithoutReflection(XProperty p) {
+ if ( p.isAnnotationPresent( OneToOne.class ) && !p.getAnnotation(
OneToOne.class )
+ .targetEntity()
+ .equals( void.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( OneToMany.class ) && !p.getAnnotation(
OneToMany.class )
+ .targetEntity()
+ .equals( void.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( ManyToOne.class ) && !p.getAnnotation(
ManyToOne.class )
+ .targetEntity()
+ .equals( void.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( ManyToMany.class ) && !p.getAnnotation(
ManyToMany.class )
+ .targetEntity()
+ .equals( void.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( ManyToAny.class ) ) {
+ if ( !p.isCollection() && !p.isArray() ) {
+ throw new AnnotationException( "@ManyToAny used on a non collection non array
property: " + p.getName() );
+ }
+ return true;
+ }
+ else if ( p.isAnnotationPresent( Type.class ) ) {
+ return true;
+ }
+ else if ( p.isAnnotationPresent( Target.class ) ) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean addProperty(
+ XProperty property, List<PropertyData> annElts,
+ String propertyAccessor, ExtendedMappings mappings
+ ) {
+ boolean hasIdentifier = false;
+ PropertyData propertyAnnotatedElement = new PropertyInferredData(
+ property, propertyAccessor,
+ mappings.getReflectionManager() );
+ if ( !mustBeSkipped( propertyAnnotatedElement.getProperty(), mappings ) ) {
+ /*
+ * put element annotated by @Id in front
+ * since it has to be parsed before any assoctation by Hibernate
+ */
+ final XAnnotatedElement element = propertyAnnotatedElement.getProperty();
+ if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent(
EmbeddedId.class ) ) {
+ annElts.add( 0, propertyAnnotatedElement );
+ hasIdentifier = true;
+ }
+ else {
+ annElts.add( propertyAnnotatedElement );
+ hasIdentifier = false;
+ }
+ }
+ return hasIdentifier;
+ }
+
+ private static boolean mustBeSkipped(XProperty property, ExtendedMappings mappings) {
+ //TODO make those hardcoded tests more portable (through the bytecode provider?)
+ return property.isAnnotationPresent( Transient.class )
+ || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals(
property.getType().getName() )
+ || "org.hibernate.bytecode.javassist.FieldHandler".equals(
property.getType().getName() );
+ }
+
+ /**
+ * Process annotation of a particular property
+ */
+ private static void processElementAnnotations(
+ PropertyHolder propertyHolder, Nullability nullability, XProperty property,
+ PropertyData inferredData, HashMap<String, IdGenerator> classGenerators,
+ EntityBinder entityBinder, boolean isIdentifierMapper,
+ boolean isComponentEmbedded, boolean inSecondPass, ExtendedMappings mappings
+ )
+ throws MappingException {
+ /**
+ * inSecondPass can only be used to apply right away the second pass of a
composite-element
+ * Because it's a value type, there is no bidirectional association, hence second
pass
+ * ordering does not matter
+ */
+ Ejb3Column[] columns = null;
+ Ejb3JoinColumn[] joinColumns = null;
+ log.debug(
+ "Processing annotations of {}.{}", propertyHolder.getEntityName(),
inferredData.getPropertyName()
+ );
+
+ if ( property.isAnnotationPresent( Parent.class ) ) {
+ if ( propertyHolder.isComponent() ) {
+ propertyHolder.setParentProperty( property.getName() );
+ }
+ else {
+ throw new AnnotationException(
+ "@Parent cannot be applied outside an embeddable object: "
+ + StringHelper.qualify( propertyHolder.getPath(), property.getName() )
+ );
+ }
+ return;
+ }
+
+ //process @JoinColumn(s) before @Column(s) to handle collection of elements properly
+ {
+ JoinColumn[] anns = null;
+ if ( property.isAnnotationPresent( JoinColumn.class ) ) {
+ anns = new JoinColumn[] { property.getAnnotation( JoinColumn.class ) };
+ }
+ else if ( property.isAnnotationPresent( JoinColumns.class ) ) {
+ JoinColumns ann = property.getAnnotation( JoinColumns.class );
+ anns = ann.value();
+ int length = anns.length;
+ if ( length == 0 ) {
+ throw new AnnotationException( "Cannot bind an empty @JoinColumns" );
+ }
+ }
+ if ( anns != null ) {
+ joinColumns = Ejb3JoinColumn.buildJoinColumns(
+ anns, null, entityBinder.getSecondaryTables(),
+ propertyHolder, inferredData.getPropertyName(), mappings
+ );
+ }
+ }
+ if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent(
Formula.class ) ) {
+ Column ann = property.getAnnotation( Column.class );
+ Formula formulaAnn = property.getAnnotation( Formula.class );
+ columns = Ejb3Column.buildColumnFromAnnotation(
+ new Column[] { ann }, formulaAnn, nullability, propertyHolder, inferredData,
+ entityBinder.getSecondaryTables(), mappings
+ );
+ }
+ else if ( property.isAnnotationPresent( Columns.class ) ) {
+ Columns anns = property.getAnnotation( Columns.class );
+ columns = Ejb3Column.buildColumnFromAnnotation(
+ anns.columns(), null, nullability, propertyHolder, inferredData,
entityBinder.getSecondaryTables(),
+ mappings
+ );
+ }
+
+ //set default values if needed
+ if ( joinColumns == null &&
+ ( property.isAnnotationPresent( ManyToOne.class )
+ || property.isAnnotationPresent( OneToOne.class ) )
+ ) {
+ if ( property.isAnnotationPresent( JoinTable.class ) ) {
+ JoinTable joinTableAnn = property.getAnnotation( JoinTable.class );
+ joinColumns = Ejb3JoinColumn.buildJoinColumns(
+ joinTableAnn.inverseJoinColumns(), null, entityBinder.getSecondaryTables(),
+ propertyHolder, inferredData.getPropertyName(), mappings
+ );
+ if ( StringHelper.isEmpty( joinTableAnn.name() ) ) {
+ throw new AnnotationException(
+ "JoinTable.name() on a @ToOne association has to be explicit: "
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName()
)
+ );
+ }
+ }
+ else {
+ OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class );
+ String mappedBy = oneToOneAnn != null ?
+ oneToOneAnn.mappedBy() :
+ null;
+ joinColumns = Ejb3JoinColumn.buildJoinColumns(
+ (JoinColumn[]) null,
+ mappedBy, entityBinder.getSecondaryTables(),
+ propertyHolder, inferredData.getPropertyName(), mappings
+ );
+ }
+ }
+ else if ( joinColumns == null &&
+ ( property.isAnnotationPresent( OneToMany.class )
+ || property.isAnnotationPresent( CollectionOfElements.class ) ) ) {
+ OneToMany oneToMany = property.getAnnotation( OneToMany.class );
+ String mappedBy = oneToMany != null ?
+ oneToMany.mappedBy() :
+ "";
+ joinColumns = Ejb3JoinColumn.buildJoinColumns(
+ (JoinColumn[]) null,
+ mappedBy, entityBinder.getSecondaryTables(),
+ propertyHolder, inferredData.getPropertyName(), mappings
+ );
+ }
+ else if ( joinColumns == null && property.isAnnotationPresent(
org.hibernate.annotations.Any.class ) ) {
+ throw new AnnotationException( "@Any requires an explicit @JoinColumn(s): "
+ + StringHelper.qualify( propertyHolder.getPath(), property.getName() ) );
+ }
+ if ( columns == null && !property.isAnnotationPresent( ManyToMany.class ) ) {
+ //useful for collection of embedded elements
+ columns = Ejb3Column.buildColumnFromAnnotation(
+ null, null, nullability, propertyHolder, inferredData,
entityBinder.getSecondaryTables(), mappings
+ );
+ }
+
+ if ( nullability == Nullability.FORCED_NOT_NULL ) {
+ //force columns to not null
+ for (Ejb3Column col : columns) {
+ col.forceNotNull();
+ }
+ }
+
+ final XClass returnedClass = inferredData.getClassOrElement();
+ if ( !entityBinder.isIgnoreIdAnnotations() &&
+ ( property.isAnnotationPresent( Id.class )
+ || property.isAnnotationPresent( EmbeddedId.class ) ) ) {
+ if ( isIdentifierMapper ) {
+ throw new AnnotationException(
+ "@IdClass class should not have @Id nor @EmbeddedId properties"
+ );
+ }
+ log.debug( "{} is an id", inferredData.getPropertyName() );
+ //clone classGenerator and override with local values
+ HashMap<String, IdGenerator> localGenerators = (HashMap<String,
IdGenerator>) classGenerators.clone();
+ localGenerators.putAll( buildLocalGenerators( property, mappings ) );
+
+ //manage composite related metadata
+ //guess if its a component and find id data access (property, field etc)
+ final boolean isComponent = returnedClass.isAnnotationPresent( Embeddable.class )
+ || property.isAnnotationPresent( EmbeddedId.class );
+ boolean propertyAnnotated = entityBinder.isPropertyAnnotated( returnedClass );
+ String propertyAccessor = entityBinder.getPropertyAccessor( returnedClass );
+ //if ( isComponent && embeddableAnn != null && embeddableAnn.access()
== AccessType.FIELD ) propertyAccess = false;
+
+ GeneratedValue generatedValue = property.getAnnotation( GeneratedValue.class );
+ String generatorType = generatedValue != null ?
+ generatorType( generatedValue.strategy() ) :
+ "assigned";
+ String generator = generatedValue != null ?
+ generatedValue.generator() :
+ BinderHelper.ANNOTATION_STRING_DEFAULT;
+ if ( isComponent ) generatorType = "assigned"; //a component must not have
any generator
+
+ bindId(
+ generatorType,
+ generator,
+ inferredData,
+ columns,
+ propertyHolder,
+ localGenerators,
+ isComponent,
+ propertyAnnotated,
+ propertyAccessor, entityBinder,
+ false,
+ isIdentifierMapper, mappings
+ );
+
+ log.debug(
+ "Bind {} on {}", ( isComponent ? "@EmbeddedId" : "@Id"
), inferredData.getPropertyName()
+ );
+ }
+ else if ( property.isAnnotationPresent( Version.class ) ) {
+ if ( isIdentifierMapper ) {
+ throw new AnnotationException(
+ "@IdClass class should not have @Version property"
+ );
+ }
+ if ( !( propertyHolder.getPersistentClass() instanceof RootClass ) ) {
+ throw new AnnotationException(
+ "Unable to define/override @Version on a subclass: "
+ + propertyHolder.getEntityName()
+ );
+ }
+ if ( ! propertyHolder.isEntity() ) {
+ throw new AnnotationException(
+ "Unable to define @Version on an embedded class: "
+ + propertyHolder.getEntityName()
+ );
+ }
+ log.debug( "{} is a version property", inferredData.getPropertyName() );
+ RootClass rootClass = (RootClass) propertyHolder.getPersistentClass();
+ PropertyBinder propBinder = new PropertyBinder();
+ propBinder.setName( inferredData.getPropertyName() );
+ propBinder.setReturnedClassName( inferredData.getTypeName() );
+ propBinder.setLazy( false );
+ propBinder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ propBinder.setColumns( columns );
+ propBinder.setHolder( propertyHolder );
//PropertyHolderBuilder.buildPropertyHolder(rootClass)
+ propBinder.setProperty( property );
+ propBinder.setReturnedClass( inferredData.getPropertyClass() );
+
+ propBinder.setMappings( mappings );
+ Property prop = propBinder.bind();
+ rootClass.setVersion( prop );
+ SimpleValue simpleValue = (SimpleValue) prop.getValue();
+ if ( !simpleValue.isTypeSpecified() ) simpleValue.setTypeName( "integer" );
+ simpleValue.setNullValue( "undefined" );
+ rootClass.setOptimisticLockMode( Versioning.OPTIMISTIC_LOCK_VERSION );
+ log.debug(
+ "Version name: {}, unsavedValue: {}", rootClass.getVersion().getName(),
+ ( (SimpleValue) rootClass.getVersion().getValue() ).getNullValue()
+ );
+ }
+ else if ( property.isAnnotationPresent( ManyToOne.class ) ) {
+ ManyToOne ann = property.getAnnotation( ManyToOne.class );
+
+ //check validity
+ if ( property.isAnnotationPresent( Column.class )
+ || property.isAnnotationPresent( Columns.class ) ) {
+ throw new AnnotationException( "@Column(s) not allowed on a @ManyToOne property:
"
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
+ }
+
+ Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+ NotFound notFound = property.getAnnotation( NotFound.class );
+ boolean ignoreNotFound = notFound != null && notFound.action().equals(
NotFoundAction.IGNORE );
+ OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+ boolean onDeleteCascade = onDeleteAnn != null &&
OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+ JoinTable assocTable = property.getAnnotation( JoinTable.class );
+ if ( assocTable != null ) {
+ Join join = propertyHolder.addJoin( assocTable, false );
+ for (Ejb3JoinColumn joinColumn : joinColumns) {
+ joinColumn.setSecondaryTableName( join.getTable().getName() );
+ }
+ }
+ bindManyToOne(
+ getCascadeStrategy( ann.cascade(), hibernateCascade ),
+ joinColumns,
+ ann.optional(),
+ ignoreNotFound, onDeleteCascade,
+ mappings.getReflectionManager().toXClass( ann.targetEntity() ),
+ propertyHolder,
+ inferredData, false, isIdentifierMapper, inSecondPass, mappings
+ );
+ }
+ else if ( property.isAnnotationPresent( OneToOne.class ) ) {
+ OneToOne ann = property.getAnnotation( OneToOne.class );
+
+ //check validity
+ if ( property.isAnnotationPresent( Column.class )
+ || property.isAnnotationPresent( Columns.class ) ) {
+ throw new AnnotationException( "@Column(s) not allowed on a @OneToOne property:
"
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
+ }
+
+ //FIXME support a proper PKJCs
+ boolean trueOneToOne = property.isAnnotationPresent( PrimaryKeyJoinColumn.class )
+ || property.isAnnotationPresent( PrimaryKeyJoinColumns.class );
+ Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+ NotFound notFound = property.getAnnotation( NotFound.class );
+ boolean ignoreNotFound = notFound != null && notFound.action().equals(
NotFoundAction.IGNORE );
+ OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+ boolean onDeleteCascade = onDeleteAnn != null &&
OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+ JoinTable assocTable = property.getAnnotation( JoinTable.class );
+ if ( assocTable != null ) {
+ Join join = propertyHolder.addJoin( assocTable, false );
+ for (Ejb3JoinColumn joinColumn : joinColumns) {
+ joinColumn.setSecondaryTableName( join.getTable().getName() );
+ }
+ }
+ bindOneToOne(
+ getCascadeStrategy( ann.cascade(), hibernateCascade ),
+ joinColumns,
+ ann.optional(),
+ getFetchMode( ann.fetch() ),
+ ignoreNotFound, onDeleteCascade,
+ mappings.getReflectionManager().toXClass( ann.targetEntity() ),
+ propertyHolder,
+ inferredData, ann.mappedBy(), trueOneToOne, isIdentifierMapper, inSecondPass,
mappings
+ );
+ }
+ else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
+
+ //check validity
+ if ( property.isAnnotationPresent( Column.class )
+ || property.isAnnotationPresent( Columns.class ) ) {
+ throw new AnnotationException( "@Column(s) not allowed on a @Any property:
"
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
+ }
+
+ Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+ NotFound notFound = property.getAnnotation( NotFound.class );
+ boolean ignoreNotFound = notFound != null && notFound.action().equals(
NotFoundAction.IGNORE );
+ OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+ boolean onDeleteCascade = onDeleteAnn != null &&
OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+ JoinTable assocTable = property.getAnnotation( JoinTable.class );
+ if ( assocTable != null ) {
+ Join join = propertyHolder.addJoin( assocTable, false );
+ for (Ejb3JoinColumn joinColumn : joinColumns) {
+ joinColumn.setSecondaryTableName( join.getTable().getName() );
+ }
+ }
+ bindAny( getCascadeStrategy( null, hibernateCascade ), //@Any has not cascade
attribute
+ joinColumns, onDeleteCascade, nullability,
+ propertyHolder, inferredData, entityBinder,
+ isIdentifierMapper, mappings );
+ }
+ else if ( property.isAnnotationPresent( OneToMany.class )
+ || property.isAnnotationPresent( ManyToMany.class )
+ || property.isAnnotationPresent( CollectionOfElements.class )
+ || property.isAnnotationPresent( ManyToAny.class ) ) {
+ OneToMany oneToManyAnn = property.getAnnotation( OneToMany.class );
+ ManyToMany manyToManyAnn = property.getAnnotation( ManyToMany.class );
+ CollectionOfElements collectionOfElementsAnn = property.getAnnotation(
CollectionOfElements.class );
+ org.hibernate.annotations.IndexColumn indexAnn = property.getAnnotation(
+ org.hibernate.annotations.IndexColumn.class
+ );
+ JoinTable assocTable = property.getAnnotation( JoinTable.class );
+
+ IndexColumn indexColumn = IndexColumn.buildColumnFromAnnotation(
+ indexAnn, propertyHolder, inferredData, mappings
+ );
+ CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(
+ propertyHolder.getEntityName(),
+ property,
+ !indexColumn.isImplicit()
+ );
+ collectionBinder.setIndexColumn( indexColumn );
+ MapKey mapKeyAnn = property.getAnnotation( MapKey.class );
+ collectionBinder.setMapKey( mapKeyAnn );
+ collectionBinder.setPropertyName( inferredData.getPropertyName() );
+ BatchSize batchAnn = property.getAnnotation( BatchSize.class );
+ collectionBinder.setBatchSize( batchAnn );
+ javax.persistence.OrderBy ejb3OrderByAnn = property.getAnnotation(
javax.persistence.OrderBy.class );
+ OrderBy orderByAnn = property.getAnnotation( OrderBy.class );
+ collectionBinder.setEjb3OrderBy( ejb3OrderByAnn );
+ collectionBinder.setSqlOrderBy( orderByAnn );
+ Sort sortAnn = property.getAnnotation( Sort.class );
+ collectionBinder.setSort( sortAnn );
+ Cache cachAnn = property.getAnnotation( Cache.class );
+ collectionBinder.setCache( cachAnn );
+ collectionBinder.setPropertyHolder( propertyHolder );
+ Cascade hibernateCascade = property.getAnnotation( Cascade.class );
+ NotFound notFound = property.getAnnotation( NotFound.class );
+ boolean ignoreNotFound = notFound != null && notFound.action().equals(
NotFoundAction.IGNORE );
+ collectionBinder.setIgnoreNotFound( ignoreNotFound );
+ collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
+ collectionBinder.setMappings( mappings );
+ collectionBinder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+
+ Ejb3Column[] elementColumns = null;
+ PropertyData virtualProperty = new WrappedInferredData( inferredData,
"element" );
+ if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent(
+ Formula.class
+ ) ) {
+ Column ann = property.getAnnotation( Column.class );
+ Formula formulaAnn = property.getAnnotation( Formula.class );
+ elementColumns = Ejb3Column.buildColumnFromAnnotation(
+ new Column[] { ann },
+ formulaAnn,
+ nullability,
+ propertyHolder,
+ virtualProperty,
+ entityBinder.getSecondaryTables(),
+ mappings
+ );
+ }
+ else if ( property.isAnnotationPresent( Columns.class ) ) {
+ Columns anns = property.getAnnotation( Columns.class );
+ elementColumns = Ejb3Column.buildColumnFromAnnotation(
+ anns.columns(), null, nullability, propertyHolder, virtualProperty,
+ entityBinder.getSecondaryTables(), mappings
+ );
+ }
+ else {
+ elementColumns = Ejb3Column.buildColumnFromAnnotation(
+ null,
+ null,
+ nullability,
+ propertyHolder,
+ virtualProperty,
+ entityBinder.getSecondaryTables(),
+ mappings
+ );
+ }
+
+ org.hibernate.annotations.MapKey hibMapKeyAnn = property.getAnnotation(
+ org.hibernate.annotations.MapKey.class
+ );
+ PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData,
"mapkey" );
+ Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation(
+ hibMapKeyAnn != null && hibMapKeyAnn.columns().length > 0 ?
+ hibMapKeyAnn.columns() :
+ null,
+ null,
+ Nullability.FORCED_NOT_NULL,
+ propertyHolder,
+ mapKeyVirtualProperty,
+ entityBinder.getSecondaryTables(),
+ mappings
+ );
+ collectionBinder.setMapKeyColumns( mapColumns );
+
+ MapKeyManyToMany mapKeyManyToMany = property.getAnnotation( MapKeyManyToMany.class );
+ Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumns(
+ mapKeyManyToMany != null ?
+ mapKeyManyToMany.joinColumns() :
+ null,
+ null, entityBinder.getSecondaryTables(),
+ propertyHolder, mapKeyVirtualProperty.getPropertyName(), mappings
+ );
+ collectionBinder.setMapKeyManyToManyColumns( mapJoinColumns );
+
+ //potential element
+ collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) );
+ collectionBinder.setElementColumns( elementColumns );
+ collectionBinder.setProperty( property );
+
+ //TODO enhance exception with @ManyToAny and @CollectionOfElements
+ if ( oneToManyAnn != null && manyToManyAnn != null ) {
+ throw new AnnotationException(
+ "@OneToMany and @ManyToMany on the same property is not allowed: "
+ + propertyHolder.getEntityName() + "." +
inferredData.getPropertyName()
+ );
+ }
+ String mappedBy = null;
+ if ( oneToManyAnn != null ) {
+ for (Ejb3JoinColumn column : joinColumns) {
+ if ( column.isSecondary() ) {
+ throw new NotYetImplementedException( "Collections having FK in secondary
table" );
+ }
+ }
+ collectionBinder.setFkJoinColumns( joinColumns );
+ mappedBy = oneToManyAnn.mappedBy();
+ collectionBinder.setTargetEntity(
+ mappings.getReflectionManager().toXClass( oneToManyAnn.targetEntity() )
+ );
+ collectionBinder.setCascadeStrategy( getCascadeStrategy( oneToManyAnn.cascade(),
hibernateCascade ) );
+ collectionBinder.setOneToMany( true );
+ }
+ else if ( collectionOfElementsAnn != null ) {
+ for (Ejb3JoinColumn column : joinColumns) {
+ if ( column.isSecondary() ) {
+ throw new NotYetImplementedException( "Collections having FK in secondary
table" );
+ }
+ }
+ collectionBinder.setFkJoinColumns( joinColumns );
+ mappedBy = "";
+ collectionBinder.setTargetEntity(
+ mappings.getReflectionManager().toXClass( collectionOfElementsAnn.targetElement()
)
+ );
+ //collectionBinder.setCascadeStrategy( getCascadeStrategy(
embeddedCollectionAnn.cascade(), hibernateCascade ) );
+ collectionBinder.setOneToMany( true );
+ }
+ else if ( manyToManyAnn != null ) {
+ mappedBy = manyToManyAnn.mappedBy();
+ collectionBinder.setTargetEntity(
+ mappings.getReflectionManager().toXClass( manyToManyAnn.targetEntity() )
+ );
+ collectionBinder.setCascadeStrategy( getCascadeStrategy( manyToManyAnn.cascade(),
hibernateCascade ) );
+ collectionBinder.setOneToMany( false );
+ }
+ else if ( property.isAnnotationPresent( ManyToAny.class ) ) {
+ mappedBy = "";
+ collectionBinder.setTargetEntity(
+ mappings.getReflectionManager().toXClass( void.class )
+ );
+ collectionBinder.setCascadeStrategy( getCascadeStrategy( null, hibernateCascade ) );
+ collectionBinder.setOneToMany( false );
+ }
+ collectionBinder.setMappedBy( mappedBy );
+ bindJoinedTableAssociation(
+ assocTable, mappings, entityBinder, collectionBinder, propertyHolder, inferredData,
mappedBy
+ );
+
+ OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
+ boolean onDeleteCascade = onDeleteAnn != null &&
OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
+ collectionBinder.setCascadeDeleteEnabled( onDeleteCascade );
+ if ( isIdentifierMapper ) {
+ collectionBinder.setInsertable( false );
+ collectionBinder.setUpdatable( false );
+ }
+ if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the
generators unless necessary
+ HashMap<String, IdGenerator> localGenerators = (HashMap<String,
IdGenerator>) classGenerators.clone();
+ localGenerators.putAll( buildLocalGenerators( property, mappings ) );
+ collectionBinder.setLocalGenerators( localGenerators );
+
+ }
+ collectionBinder.bind();
+
+ }
+ else {
+ //define whether the type is a component or not
+ boolean isComponent = false;
+ Embeddable embeddableAnn = returnedClass.getAnnotation( Embeddable.class );
+ Embedded embeddedAnn = property.getAnnotation( Embedded.class );
+ isComponent = embeddedAnn != null || embeddableAnn != null;
+
+ if ( isComponent ) {
+ //process component object
+ //boolean propertyAccess = true;
+ //if ( embeddableAnn != null && embeddableAnn.access() == AccessType.FIELD )
propertyAccess = false;
+ boolean propertyAnnotated = entityBinder.isPropertyAnnotated( property );
+ String propertyAccessor = entityBinder.getPropertyAccessor( property );
+ bindComponent(
+ inferredData, propertyHolder, propertyAnnotated, propertyAccessor, entityBinder,
+ isIdentifierMapper,
+ mappings, isComponentEmbedded
+ );
+ }
+ else {
+ //provide the basic property mapping
+ boolean optional = true;
+ boolean lazy = false;
+ if ( property.isAnnotationPresent( Basic.class ) ) {
+ Basic ann = property.getAnnotation( Basic.class );
+ optional = ann.optional();
+ lazy = ann.fetch() == FetchType.LAZY;
+ }
+ //implicit type will check basic types and Serializable classes
+ if ( !optional && nullability != Nullability.FORCED_NULL ) {
+ //force columns to not null
+ for (Ejb3Column col : columns) {
+ col.forceNotNull();
+ }
+ }
+
+ PropertyBinder propBinder = new PropertyBinder();
+ propBinder.setName( inferredData.getPropertyName() );
+ propBinder.setReturnedClassName( inferredData.getTypeName() );
+ propBinder.setLazy( lazy );
+ propBinder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ propBinder.setColumns( columns );
+ propBinder.setHolder( propertyHolder );
+ propBinder.setProperty( property );
+ propBinder.setReturnedClass( inferredData.getPropertyClass() );
+ propBinder.setMappings( mappings );
+ if ( isIdentifierMapper ) {
+ propBinder.setInsertable( false );
+ propBinder.setUpdatable( false );
+ }
+ propBinder.bind();
+ }
+ }
+ //init index
+ //process indexes after everything: in second pass, many to one has to be done before
indexes
+ Index index = property.getAnnotation( Index.class );
+ if ( index != null ) {
+ if ( joinColumns != null ) {
+
+ for (Ejb3Column column : joinColumns) {
+ column.addIndex( index, inSecondPass );
+ }
+ }
+ else {
+ if ( columns != null ) {
+ for (Ejb3Column column : columns) {
+ column.addIndex( index, inSecondPass );
+ }
+ }
+ }
+ }
+
+ NaturalId naturalIdAnn = property.getAnnotation( NaturalId.class );
+ if ( naturalIdAnn != null ) {
+ if ( joinColumns != null ) {
+ for (Ejb3Column column : joinColumns) {
+ column.addUniqueKey( "_UniqueKey", inSecondPass );
+ }
+ }
+ else {
+ for (Ejb3Column column : columns) {
+ column.addUniqueKey( "_UniqueKey", inSecondPass );
+ }
+ }
+ }
+ }
+
+ //TODO move that to collection binder?
+ private static void bindJoinedTableAssociation(
+ JoinTable joinTableAnn, ExtendedMappings mappings, EntityBinder entityBinder,
+ CollectionBinder collectionBinder, PropertyHolder propertyHolder, PropertyData
inferredData,
+ String mappedBy
+ ) {
+ TableBinder associationTableBinder = new TableBinder();
+ JoinColumn[] annJoins;
+ JoinColumn[] annInverseJoins;
+ if ( joinTableAnn != null ) {
+ collectionBinder.setExplicitAssociationTable( true );
+ if ( !BinderHelper.isDefault( joinTableAnn.schema() ) )
+ associationTableBinder.setSchema( joinTableAnn.schema() );
+ if ( !BinderHelper.isDefault( joinTableAnn.catalog() ) )
+ associationTableBinder.setCatalog( joinTableAnn.catalog() );
+ if ( !BinderHelper.isDefault( joinTableAnn.name() ) ) associationTableBinder.setName(
joinTableAnn.name() );
+ associationTableBinder.setUniqueConstraints( joinTableAnn.uniqueConstraints() );
+
+ //set check constaint in the second pass
+
+ JoinColumn[] joins = joinTableAnn.joinColumns();
+
+ if ( joins.length == 0 ) {
+ annJoins = null;
+ }
+ else {
+ annJoins = joins;
+ }
+
+ JoinColumn[] inverseJoins = joinTableAnn.inverseJoinColumns();
+
+ if ( inverseJoins.length == 0 ) {
+ annInverseJoins = null;
+ }
+ else {
+ annInverseJoins = inverseJoins;
+ }
+ }
+ else {
+ annJoins = null;
+ annInverseJoins = null;
+ }
+ Ejb3JoinColumn[] joinColumns = Ejb3JoinColumn.buildJoinTableJoinColumns(
+ annJoins, entityBinder.getSecondaryTables(), propertyHolder,
inferredData.getPropertyName(), mappedBy,
+ mappings
+ );
+ Ejb3JoinColumn[] inverseJoinColumns = Ejb3JoinColumn.buildJoinTableJoinColumns(
+ annInverseJoins, entityBinder.getSecondaryTables(), propertyHolder,
inferredData.getPropertyName(),
+ mappedBy, mappings
+ );
+ associationTableBinder.setMappings( mappings );
+ collectionBinder.setTableBinder( associationTableBinder );
+ collectionBinder.setJoinColumns( joinColumns );
+ collectionBinder.setInverseJoinColumns( inverseJoinColumns );
+ }
+
+ private static void bindComponent(
+ PropertyData inferredData,
+ PropertyHolder propertyHolder,
+ boolean propertyAnnotated,
+ String propertyAccessor, EntityBinder entityBinder,
+ boolean isIdentifierMapper,
+ ExtendedMappings mappings, boolean isComponentEmbedded
+ ) {
+ Component comp = fillComponent(
+ propertyHolder, inferredData, propertyAnnotated, propertyAccessor, true,
entityBinder,
+ isComponentEmbedded, isIdentifierMapper,
+ false, mappings
+ );
+ XProperty property = inferredData.getProperty();
+ setupComponentTuplizer( property, comp );
+
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( inferredData.getPropertyName() );
+ binder.setValue( comp );
+ binder.setProperty( inferredData.getProperty() );
+ binder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ Property prop = binder.make();
+ propertyHolder.addProperty( prop );
+ }
+
+ public static Component fillComponent(
+ PropertyHolder propertyHolder, PropertyData inferredData,
+ boolean propertyAnnotated, String propertyAccessor, boolean isNullable,
+ EntityBinder entityBinder,
+ boolean isComponentEmbedded, boolean isIdentifierMapper, boolean inSecondPass,
ExtendedMappings mappings
+ ) {
+ /**
+ * inSecondPass can only be used to apply right away the second pass of a
composite-element
+ * Because it's a value type, there is no bidirectional association, hence second
pass
+ * ordering does not matter
+ */
+ Component comp = new Component( propertyHolder.getPersistentClass() );
+ comp.setEmbedded( isComponentEmbedded );
+ //yuk
+ comp.setTable( propertyHolder.getTable() );
+ if ( !isIdentifierMapper ) {
+ comp.setComponentClassName( inferredData.getClassOrElementName() );
+ }
+ else {
+ comp.setComponentClassName( comp.getOwner().getClassName() );
+ }
+ comp.setNodeName( inferredData.getPropertyName() );
+ String subpath = StringHelper.qualify( propertyHolder.getPath(),
inferredData.getPropertyName() );
+ log.debug( "Binding component with path: {}", subpath );
+ PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder(
+ comp, subpath,
+ inferredData, propertyHolder, mappings
+ );
+ List<PropertyData> classElements = new ArrayList<PropertyData>();
+ XClass returnedClassOrElement = inferredData.getClassOrElement();
+ addElementsOfAClass(
+ classElements,
+ subHolder,
+ propertyAnnotated,
+ propertyAccessor, returnedClassOrElement, mappings
+ );
+ //add elements of the embeddable superclass
+ XClass superClass = inferredData.getPropertyClass().getSuperclass();
+ while ( superClass != null && superClass.isAnnotationPresent(
MappedSuperclass.class ) ) {
+ //FIXME: proper support of typevariables incl var resolved at upper levels
+ addElementsOfAClass(
+ classElements,
+ subHolder,
+ entityBinder.isPropertyAnnotated( superClass ),
+ propertyAccessor, superClass, mappings
+ );
+ superClass = superClass.getSuperclass();
+ }
+ for (PropertyData propertyAnnotatedElement : classElements) {
+ processElementAnnotations(
+ subHolder, isNullable ?
+ Nullability.NO_CONSTRAINT :
+ Nullability.FORCED_NOT_NULL,
+ propertyAnnotatedElement.getProperty(), propertyAnnotatedElement,
+ new HashMap<String, IdGenerator>(), entityBinder, isIdentifierMapper,
isComponentEmbedded,
+ inSecondPass, mappings
+ );
+ }
+ return comp;
+ }
+
+ private static void bindId(
+ String generatorType, String generatorName,
+ PropertyData inferredData, Ejb3Column[] columns, PropertyHolder propertyHolder,
+ Map<String, IdGenerator> localGenerators,
+ boolean isComposite,
+ boolean isPropertyAnnotated,
+ String propertyAccessor, EntityBinder entityBinder, boolean isEmbedded,
+ boolean isIdentifierMapper, ExtendedMappings mappings
+ ) {
+ /*
+ * Fill simple value and property since and Id is a property
+ */
+ PersistentClass persistentClass = propertyHolder.getPersistentClass();
+ if ( !( persistentClass instanceof RootClass ) ) {
+ throw new AnnotationException(
+ "Unable to define/override @Id(s) on a subclass: "
+ + propertyHolder.getEntityName()
+ );
+ }
+ RootClass rootClass = (RootClass) persistentClass;
+ String persistentClassName = rootClass == null ?
+ null :
+ rootClass.getClassName();
+ SimpleValue id;
+ if ( isComposite ) {
+ id = fillComponent(
+ propertyHolder, inferredData, isPropertyAnnotated, propertyAccessor,
+ false, entityBinder, isEmbedded, isIdentifierMapper, false, mappings
+ );
+ Component componentId = (Component) id;
+ componentId.setKey( true );
+ if ( rootClass.getIdentifier() != null ) {
+ throw new AnnotationException( componentId.getComponentClassName() + " must not
have @Id properties when used as an @EmbeddedId" );
+ }
+ if ( componentId.getPropertySpan() == 0 ) {
+ throw new AnnotationException( componentId.getComponentClassName() + " has no
persistent id property" );
+ }
+ //tuplizers
+ XProperty property = inferredData.getProperty();
+ setupComponentTuplizer( property, componentId );
+ }
+ else {
+ for (Ejb3Column column : columns) {
+ column.forceNotNull(); //this is an id
+ }
+ SimpleValueBinder value = new SimpleValueBinder();
+ value.setPropertyName( inferredData.getPropertyName() );
+ value.setReturnedClassName( inferredData.getTypeName() );
+ value.setColumns( columns );
+ value.setPersistentClassName( persistentClassName );
+ value.setMappings( mappings );
+ value.setType( inferredData.getProperty(), inferredData.getClassOrElement() );
+ id = value.make();
+ }
+ rootClass.setIdentifier( id );
+ BinderHelper.makeIdGenerator( id, generatorType, generatorName, mappings,
localGenerators );
+ if ( isEmbedded ) {
+ rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null );
+ }
+ else {
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( inferredData.getPropertyName() );
+ binder.setValue( id );
+ binder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ binder.setProperty( inferredData.getProperty() );
+ Property prop = binder.make();
+ rootClass.setIdentifierProperty( prop );
+ }
+ }
+
+ private static void setupComponentTuplizer(XProperty property, Component component) {
+ if ( property == null ) return;
+ if ( property.isAnnotationPresent( Tuplizers.class ) ) {
+ for (Tuplizer tuplizer : property.getAnnotation( Tuplizers.class ).value()) {
+ EntityMode mode = EntityMode.parse( tuplizer.entityMode() );
+ component.addTuplizer( mode, tuplizer.impl().getName() );
+ }
+ }
+ if ( property.isAnnotationPresent( Tuplizer.class ) ) {
+ Tuplizer tuplizer = property.getAnnotation( Tuplizer.class );
+ EntityMode mode = EntityMode.parse( tuplizer.entityMode() );
+ component.addTuplizer( mode, tuplizer.impl().getName() );
+ }
+ }
+
+ private static void bindManyToOne(
+ String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional,
+ boolean ignoreNotFound, boolean cascadeOnDelete,
+ XClass targetEntity, PropertyHolder propertyHolder,
+ PropertyData inferredData, boolean unique, boolean isIdentifierMapper, boolean
inSecondPass,
+ ExtendedMappings mappings
+ ) {
+ //All FK columns should be in the same table
+ org.hibernate.mapping.ManyToOne value = new org.hibernate.mapping.ManyToOne(
columns[0].getTable() );
+ if ( isDefault( targetEntity, mappings ) ) {
+ value.setReferencedEntityName( inferredData.getClassOrElementName() );
+ }
+ else {
+ value.setReferencedEntityName( targetEntity.getName() );
+ }
+ defineFetchingStrategy( value, inferredData.getProperty() );
+ //value.setFetchMode( fetchMode );
+ value.setIgnoreNotFound( ignoreNotFound );
+ value.setCascadeDeleteEnabled( cascadeOnDelete );
+ //value.setLazy( fetchMode != FetchMode.JOIN );
+ if ( !optional ) {
+ for (Ejb3JoinColumn column : columns) {
+ column.setNullable( false );
+ }
+ }
+ value.setTypeName( inferredData.getClassOrElementName() );
+ final String propertyName = inferredData.getPropertyName();
+ value.setTypeUsingReflection( propertyHolder.getClassName(), propertyName );
+
+ ForeignKey fk = inferredData.getProperty().getAnnotation( ForeignKey.class );
+ String fkName = fk != null ?
+ fk.name() :
+ "";
+ if ( !BinderHelper.isDefault( fkName ) ) value.setForeignKeyName( fkName );
+
+ String path = propertyHolder.getPath() + "." + propertyName;
+ FkSecondPass secondPass = new ToOneFkSecondPass(
+ value, columns,
+ !optional && unique, //cannot have nullabe and unique on certain DBs like
Derby
+ propertyHolder.getEntityOwnerClassName(),
+ path, mappings
+ );
+ if ( inSecondPass ) {
+ secondPass.doSecondPass( mappings.getClasses() );
+ }
+ else {
+ mappings.addSecondPass(
+ secondPass
+ );
+ }
+ Ejb3Column.checkPropertyConsistency( columns, propertyHolder.getEntityName() +
propertyName );
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( propertyName );
+ binder.setValue( value );
+ //binder.setCascade(cascadeStrategy);
+ if ( isIdentifierMapper ) {
+ binder.setInsertable( false );
+ binder.setUpdatable( false );
+ }
+ else {
+ binder.setInsertable( columns[0].isInsertable() );
+ binder.setUpdatable( columns[0].isUpdatable() );
+ }
+ binder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ binder.setCascade( cascadeStrategy );
+ binder.setProperty(inferredData.getProperty());
+ Property prop = binder.make();
+ //composite FK columns are in the same table so its OK
+ propertyHolder.addProperty( prop, columns );
+ }
+
+ protected static void defineFetchingStrategy(ToOne toOne, XProperty property) {
+ LazyToOne lazy = property.getAnnotation( LazyToOne.class );
+ Fetch fetch = property.getAnnotation( Fetch.class );
+ ManyToOne manyToOne = property.getAnnotation( ManyToOne.class );
+ OneToOne oneToOne = property.getAnnotation( OneToOne.class );
+ FetchType fetchType;
+ if ( manyToOne != null ) {
+ fetchType = manyToOne.fetch();
+ }
+ else if ( oneToOne != null ) {
+ fetchType = oneToOne.fetch();
+ }
+ else {
+ throw new AssertionFailure(
+ "Define fetch strategy on a property not annotated with @OneToMany nor
@OneToOne"
+ );
+ }
+ if ( lazy != null ) {
+ toOne.setLazy( !( lazy.value() == LazyToOneOption.FALSE ) );
+ toOne.setUnwrapProxy( ( lazy.value() == LazyToOneOption.NO_PROXY ) );
+ }
+ else {
+ toOne.setLazy( fetchType == FetchType.LAZY );
+ toOne.setUnwrapProxy( false );
+ }
+ if ( fetch != null ) {
+ if ( fetch.value() == org.hibernate.annotations.FetchMode.JOIN ) {
+ toOne.setFetchMode( FetchMode.JOIN );
+ toOne.setLazy( false );
+ toOne.setUnwrapProxy( false );
+ }
+ else if ( fetch.value() == org.hibernate.annotations.FetchMode.SELECT ) {
+ toOne.setFetchMode( FetchMode.SELECT );
+ }
+ else if ( fetch.value() == org.hibernate.annotations.FetchMode.SUBSELECT ) {
+ throw new AnnotationException( "Use of FetchMode.SUBSELECT not allowed on ToOne
associations" );
+ }
+ else {
+ throw new AssertionFailure( "Unknown FetchMode: " + fetch.value() );
+ }
+ }
+ else {
+ toOne.setFetchMode( getFetchMode( fetchType ) );
+ }
+ }
+
+ private static void bindOneToOne(
+ String cascadeStrategy,
+ Ejb3JoinColumn[] joinColumns,
+ boolean optional,
+ FetchMode fetchMode,
+ boolean ignoreNotFound,
+ boolean cascadeOnDelete,
+ XClass targetEntity,
+ PropertyHolder propertyHolder,
+ PropertyData inferredData, String mappedBy,
+ boolean trueOneToOne,
+ boolean isIdentifierMapper, boolean inSecondPass, ExtendedMappings mappings
+ ) {
+ //column.getTable() => persistentClass.getTable()
+ final String propertyName = inferredData.getPropertyName();
+ log.debug( "Fetching {} with {}", propertyName, fetchMode );
+ boolean mapToPK = true;
+ if ( !trueOneToOne ) {
+ //try to find a hidden true one to one (FK == PK columns)
+ KeyValue identifier = propertyHolder.getIdentifier();
+ if ( identifier == null ) {
+ //this is a @OneToOne in a @EmbeddedId (the persistentClass.identifier is not set
yet, it's being built)
+ //by definition the PK cannot refers to itself so it cannot map to itself
+ mapToPK = false;
+ }
+ else {
+ Iterator idColumns = identifier.getColumnIterator();
+ List<String> idColumnNames = new ArrayList<String>();
+ org.hibernate.mapping.Column currentColumn;
+ while ( idColumns.hasNext() ) {
+ currentColumn = (org.hibernate.mapping.Column) idColumns.next();
+ idColumnNames.add( currentColumn.getName() );
+ }
+ for (Ejb3JoinColumn col : joinColumns) {
+ if ( !idColumnNames.contains( col.getMappingColumn().getName() ) ) {
+ mapToPK = false;
+ break;
+ }
+ }
+ }
+ }
+ if ( trueOneToOne || mapToPK || !BinderHelper.isDefault( mappedBy ) ) {
+ //is a true one-to-one
+ //FIXME referencedColumnName ignored => ordering may fail.
+ OneToOneSecondPass secondPass = new OneToOneSecondPass(
+ mappedBy,
+ propertyHolder.getEntityName(),
+ propertyName,
+ propertyHolder, inferredData, targetEntity, ignoreNotFound, cascadeOnDelete,
+ optional, cascadeStrategy, joinColumns, mappings
+ );
+ if ( inSecondPass ) {
+ secondPass.doSecondPass( mappings.getClasses() );
+ }
+ else {
+ mappings.addSecondPass(
+ secondPass, BinderHelper.isDefault( mappedBy )
+ );
+ }
+ }
+ else {
+ //has a FK on the table
+ bindManyToOne(
+ cascadeStrategy, joinColumns, optional, ignoreNotFound, cascadeOnDelete,
+ targetEntity,
+ propertyHolder, inferredData, true, isIdentifierMapper, inSecondPass, mappings
+ );
+ }
+ }
+
+ private static void bindAny(
+ String cascadeStrategy, Ejb3JoinColumn[] columns, boolean cascadeOnDelete, Nullability
nullability,
+ PropertyHolder propertyHolder, PropertyData inferredData, EntityBinder entityBinder,
+ boolean isIdentifierMapper, ExtendedMappings mappings
+ ) {
+ org.hibernate.annotations.Any anyAnn = inferredData.getProperty().getAnnotation(
org.hibernate.annotations.Any.class );
+ if ( anyAnn == null ) {
+ throw new AssertionFailure( "Missing @Any annotation: "
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
+ }
+ Any value = BinderHelper.buildAnyValue( anyAnn.metaDef(), columns, anyAnn.metaColumn(),
inferredData,
+ cascadeOnDelete, nullability, propertyHolder, entityBinder, anyAnn.optional(),
mappings );
+
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( inferredData.getPropertyName() );
+ binder.setValue( value );
+
+ binder.setLazy( anyAnn.fetch() == FetchType.LAZY );
+ //binder.setCascade(cascadeStrategy);
+ if ( isIdentifierMapper ) {
+ binder.setInsertable( false );
+ binder.setUpdatable( false );
+ }
+ else {
+ binder.setInsertable( columns[0].isInsertable() );
+ binder.setUpdatable( columns[0].isUpdatable() );
+ }
+ binder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ binder.setCascade( cascadeStrategy );
+ Property prop = binder.make();
+ //composite FK columns are in the same table so its OK
+ propertyHolder.addProperty( prop, columns );
+ }
+
+ private static String generatorType(GenerationType generatorEnum) {
+ switch ( generatorEnum ) {
+ case IDENTITY:
+ return "identity";
+ case AUTO:
+ return "native";
+ case TABLE:
+ return MultipleHiLoPerTableGenerator.class.getName();
+ case SEQUENCE:
+ return "seqhilo";
+ }
+ throw new AssertionFailure( "Unknown GeneratorType: " + generatorEnum );
+ }
+
+ private static EnumSet<CascadeType>
convertToHibernateCascadeType(javax.persistence.CascadeType[] ejbCascades) {
+ EnumSet<CascadeType> hibernateCascadeSet = EnumSet.noneOf( CascadeType.class );
+ if ( ejbCascades != null && ejbCascades.length > 0 ) {
+ for (javax.persistence.CascadeType cascade : ejbCascades) {
+ switch ( cascade ) {
+ case ALL:
+ hibernateCascadeSet.add( CascadeType.ALL );
+ break;
+ case PERSIST:
+ hibernateCascadeSet.add( CascadeType.PERSIST );
+ break;
+ case MERGE:
+ hibernateCascadeSet.add( CascadeType.MERGE );
+ break;
+ case REMOVE:
+ hibernateCascadeSet.add( CascadeType.REMOVE );
+ break;
+ case REFRESH:
+ hibernateCascadeSet.add( CascadeType.REFRESH );
+ break;
+ }
+ }
+ }
+
+ return hibernateCascadeSet;
+ }
+
+ private static String getCascadeStrategy(
+ javax.persistence.CascadeType[] ejbCascades, Cascade hibernateCascadeAnnotation
+ ) {
+ EnumSet<CascadeType> hibernateCascadeSet = convertToHibernateCascadeType(
ejbCascades );
+ CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ?
+ null :
+ hibernateCascadeAnnotation.value();
+
+ if ( hibernateCascades != null && hibernateCascades.length > 0 ) {
+ for (CascadeType cascadeType : hibernateCascades) {
+ hibernateCascadeSet.add( cascadeType );
+ }
+ }
+
+ StringBuilder cascade = new StringBuilder();
+ Iterator<CascadeType> cascadeType = hibernateCascadeSet.iterator();
+ while ( cascadeType.hasNext() ) {
+ switch ( cascadeType.next() ) {
+ case ALL:
+ cascade.append( "," ).append( "all" );
+ break;
+ case SAVE_UPDATE:
+ cascade.append( "," ).append( "save-update" );
+ break;
+ case PERSIST:
+ cascade.append( "," ).append( "persist" );
+ break;
+ case MERGE:
+ cascade.append( "," ).append( "merge" );
+ break;
+ case LOCK:
+ cascade.append( "," ).append( "lock" );
+ break;
+ case REFRESH:
+ cascade.append( "," ).append( "refresh" );
+ break;
+ case REPLICATE:
+ cascade.append( "," ).append( "replicate" );
+ break;
+ case EVICT:
+ cascade.append( "," ).append( "evict" );
+ break;
+ case DELETE:
+ cascade.append( "," ).append( "delete" );
+ break;
+ case DELETE_ORPHAN:
+ cascade.append( "," ).append( "delete-orphan" );
+ break;
+ case REMOVE:
+ cascade.append( "," ).append( "delete" );
+ break;
+ }
+ }
+ return cascade.length() > 0 ?
+ cascade.substring( 1 ) :
+ "none";
+ }
+
+ public static FetchMode getFetchMode(FetchType fetch) {
+ if ( fetch == FetchType.EAGER ) {
+ return FetchMode.JOIN;
+ }
+ else {
+ return FetchMode.SELECT;
+ }
+ }
+
+ private static HashMap<String, IdGenerator> buildLocalGenerators(XAnnotatedElement
annElt, Mappings mappings) {
+ HashMap<String, IdGenerator> generators = new HashMap<String,
IdGenerator>();
+ TableGenerator tabGen = annElt.getAnnotation( TableGenerator.class );
+ SequenceGenerator seqGen = annElt.getAnnotation( SequenceGenerator.class );
+ GenericGenerator genGen = annElt.getAnnotation( GenericGenerator.class );
+ if ( tabGen != null ) {
+ IdGenerator idGen = buildIdGenerator( tabGen, mappings );
+ generators.put( idGen.getName(), idGen );
+ }
+ if ( seqGen != null ) {
+ IdGenerator idGen = buildIdGenerator( seqGen, mappings );
+ generators.put( idGen.getName(), idGen );
+ }
+ if ( genGen != null ) {
+ IdGenerator idGen = buildIdGenerator( genGen, mappings );
+ generators.put( idGen.getName(), idGen );
+ }
+ return generators;
+ }
+
+ public static boolean isDefault(XClass clazz, ExtendedMappings mappings) {
+ return mappings.getReflectionManager().equals( clazz, void.class );
+ }
+
+ public static Map<XClass, InheritanceState> buildInheritanceStates(
+ List<XClass> orderedClasses, ReflectionManager reflectionManager
+ ) {
+ Map<XClass, InheritanceState> inheritanceStatePerClass = new HashMap<XClass,
InheritanceState>(
+ orderedClasses.size()
+ );
+ for (XClass clazz : orderedClasses) {
+ InheritanceState superclassState = InheritanceState.getSuperclassInheritanceState(
+ clazz, inheritanceStatePerClass,
+ reflectionManager
+ );
+ InheritanceState state = new InheritanceState( clazz );
+ if ( superclassState != null ) {
+ //the classes are ordered thus preventing an NPE
+ //FIXME if an entity has subclasses annotated @MappedSperclass wo sub @Entity this is
wrong
+ superclassState.hasSons = true;
+ InheritanceState superEntityState = InheritanceState.getSuperEntityInheritanceState(
+ clazz, inheritanceStatePerClass,
+ reflectionManager
+ );
+ state.hasParents = superEntityState != null;
+ final boolean nonDefault = state.type != null &&
!InheritanceType.SINGLE_TABLE.equals( state.type );
+ if ( superclassState.type != null ) {
+ final boolean mixingStrategy = state.type != null && !state.type.equals(
superclassState.type );
+ if ( nonDefault && mixingStrategy ) {
+ log.warn(
+ "Mixing inheritance strategy in a entity hierarchy is not allowed, ignoring
sub strategy in: {}",
+ clazz.getName()
+ );
+ }
+ state.type = superclassState.type;
+ }
+ }
+ inheritanceStatePerClass.put( clazz, state );
+ }
+ return inheritanceStatePerClass;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/AnnotationConfiguration.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,1073 @@
+// $Id: AnnotationConfiguration.java 14990 2008-07-29 18:14:14Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+
+import org.dom4j.Attribute;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import org.hibernate.AnnotationException;
+import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
+import org.hibernate.MappingException;
+import org.hibernate.SessionFactory;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.cfg.annotations.Version;
+import org.hibernate.cfg.annotations.reflection.EJB3ReflectionManager;
+import org.hibernate.event.EventListeners;
+import org.hibernate.event.PreInsertEventListener;
+import org.hibernate.event.PreUpdateEventListener;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.UniqueKey;
+import org.hibernate.util.JoinedIterator;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Similar to the {@link Configuration} object but handles EJB3 and Hibernate
+ * specific annotations as a metadata facility.
+ *
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ */
+public class AnnotationConfiguration extends Configuration {
+ private Logger log = LoggerFactory.getLogger( AnnotationConfiguration.class );
+
+ /**
+ * Class name of the class needed to enable Search.
+ */
+ private static final String SEARCH_STARTUP_CLASS =
"org.hibernate.search.event.EventListenerRegister";
+
+ /**
+ * Method to call to enable Search.
+ */
+ private static final String SEARCH_STARTUP_METHOD = "enableHibernateSearch";
+
+ static {
+ Version.touch(); //touch version
+ }
+
+ public static final String ARTEFACT = "hibernate.mapping.precedence";
+ public static final String DEFAULT_PRECEDENCE = "hbm, class";
+
+ private Map namedGenerators;
+ private Map<String, Map<String, Join>> joins;
+ private Map<String, AnnotatedClassType> classTypes;
+ private Set<String> defaultNamedQueryNames;
+ private Set<String> defaultNamedNativeQueryNames;
+ private Set<String> defaultSqlResulSetMappingNames;
+ private Set<String> defaultNamedGenerators;
+ private Map<String, Properties> generatorTables;
+ private Map<Table, List<String[]>> tableUniqueConstraints;
+ private Map<String, String> mappedByResolver;
+ private Map<String, String> propertyRefResolver;
+ private Map<String, AnyMetaDef> anyMetaDefs;
+ private List<XClass> annotatedClasses;
+ private Map<String, XClass> annotatedClassEntities;
+ private Map<String, Document> hbmEntities;
+ private List<CacheHolder> caches;
+ private List<Document> hbmDocuments; //user ordering matters, hence the list
+ private String precedence = null;
+ private boolean inSecondPass = false;
+ private transient ReflectionManager reflectionManager;
+ private boolean isDefaultProcessed = false;
+ private boolean isValidatorNotPresentLogged;
+
+ public AnnotationConfiguration() {
+ super();
+ }
+
+ public AnnotationConfiguration(SettingsFactory sf) {
+ super( sf );
+ }
+
+ protected List<XClass> orderAndFillHierarchy(List<XClass> original) {
+ //TODO remove embeddable
+ List<XClass> copy = new ArrayList<XClass>( original );
+ //for each class, copy all the relevant hierarchy
+ for (XClass clazz : original) {
+ XClass superClass = clazz.getSuperclass();
+ while ( superClass != null && !reflectionManager.equals( superClass,
Object.class ) && !copy.contains( superClass ) ) {
+ if ( superClass.isAnnotationPresent( Entity.class )
+ || superClass.isAnnotationPresent( MappedSuperclass.class ) ) {
+ copy.add( superClass );
+ }
+ superClass = superClass.getSuperclass();
+ }
+ }
+ List<XClass> workingCopy = new ArrayList<XClass>( copy );
+ List<XClass> newList = new ArrayList<XClass>( copy.size() );
+ while ( workingCopy.size() > 0 ) {
+ XClass clazz = workingCopy.get( 0 );
+ orderHierarchy( workingCopy, newList, copy, clazz );
+ }
+ return newList;
+ }
+
+ private void orderHierarchy(List<XClass> copy, List<XClass> newList,
List<XClass> original, XClass clazz) {
+ if ( clazz == null || reflectionManager.equals( clazz, Object.class ) ) return;
+ //process superclass first
+ orderHierarchy( copy, newList, original, clazz.getSuperclass() );
+ if ( original.contains( clazz ) ) {
+ if ( !newList.contains( clazz ) ) {
+ newList.add( clazz );
+ }
+ copy.remove( clazz );
+ }
+ }
+
+ /**
+ * Read a mapping from the class annotation metadata (JSR 175).
+ *
+ * @param persistentClass the mapped class
+ * @return the configuration object
+ */
+ public AnnotationConfiguration addAnnotatedClass(Class persistentClass) throws
MappingException {
+ XClass persistentXClass = reflectionManager.toXClass( persistentClass );
+ try {
+ annotatedClasses.add( persistentXClass );
+ return this;
+ }
+ catch (MappingException me) {
+ log.error( "Could not compile the mapping annotations", me );
+ throw me;
+ }
+ }
+
+ /**
+ * Read package level metadata
+ *
+ * @param packageName java package name
+ * @return the configuration object
+ */
+ public AnnotationConfiguration addPackage(String packageName) throws MappingException {
+ log.info( "Mapping package {}", packageName );
+ try {
+ AnnotationBinder.bindPackage( packageName, createExtendedMappings() );
+ return this;
+ }
+ catch (MappingException me) {
+ log.error( "Could not compile the mapping annotations", me );
+ throw me;
+ }
+ }
+
+ public ExtendedMappings createExtendedMappings() {
+ return new ExtendedMappings(
+ classes,
+ collections,
+ tables,
+ namedQueries,
+ namedSqlQueries,
+ sqlResultSetMappings,
+ defaultNamedQueryNames,
+ defaultNamedNativeQueryNames,
+ defaultSqlResulSetMappingNames,
+ defaultNamedGenerators,
+ imports,
+ secondPasses,
+ propertyReferences,
+ namingStrategy,
+ typeDefs,
+ filterDefinitions,
+ namedGenerators,
+ joins,
+ classTypes,
+ extendsQueue,
+ tableNameBinding, columnNameBindingPerTable, auxiliaryDatabaseObjects,
+ generatorTables,
+ tableUniqueConstraints,
+ mappedByResolver,
+ propertyRefResolver,
+ anyMetaDefs,
+ reflectionManager
+ );
+ }
+
+ @Override
+ public void setCacheConcurrencyStrategy(
+ String clazz, String concurrencyStrategy, String region, boolean cacheLazyProperty
+ ) throws MappingException {
+ caches.add( new CacheHolder( clazz, concurrencyStrategy, region, true,
cacheLazyProperty ) );
+ }
+
+ @Override
+ public void setCollectionCacheConcurrencyStrategy(String collectionRole, String
concurrencyStrategy, String region)
+ throws MappingException {
+ caches.add( new CacheHolder( collectionRole, concurrencyStrategy, region, false, false
) );
+ }
+
+ @Override
+ protected void reset() {
+ super.reset();
+ namedGenerators = new HashMap();
+ joins = new HashMap<String, Map<String, Join>>();
+ classTypes = new HashMap<String, AnnotatedClassType>();
+ generatorTables = new HashMap<String, Properties>();
+ defaultNamedQueryNames = new HashSet<String>();
+ defaultNamedNativeQueryNames = new HashSet<String>();
+ defaultSqlResulSetMappingNames = new HashSet<String>();
+ defaultNamedGenerators = new HashSet<String>();
+ tableUniqueConstraints = new HashMap<Table, List<String[]>>();
+ mappedByResolver = new HashMap<String, String>();
+ propertyRefResolver = new HashMap<String, String>();
+ annotatedClasses = new ArrayList<XClass>();
+ caches = new ArrayList<CacheHolder>();
+ hbmEntities = new HashMap<String, Document>();
+ annotatedClassEntities = new HashMap<String, XClass>();
+ hbmDocuments = new ArrayList<Document>();
+ namingStrategy = EJB3NamingStrategy.INSTANCE;
+ setEntityResolver( new EJB3DTDEntityResolver() );
+ anyMetaDefs = new HashMap<String, AnyMetaDef>();
+ reflectionManager = new EJB3ReflectionManager();
+ }
+
+ @Override
+ protected void secondPassCompile() throws MappingException {
+ log.debug( "Execute first pass mapping processing" );
+ //build annotatedClassEntities
+ {
+ List<XClass> tempAnnotatedClasses = new ArrayList<XClass>(
annotatedClasses.size() );
+ for (XClass clazz : annotatedClasses) {
+ if ( clazz.isAnnotationPresent( Entity.class ) ) {
+ annotatedClassEntities.put( clazz.getName(), clazz );
+ tempAnnotatedClasses.add( clazz );
+ }
+ else if ( clazz.isAnnotationPresent( MappedSuperclass.class ) ) {
+ tempAnnotatedClasses.add( clazz );
+ }
+ //only keep MappedSuperclasses and Entity in this list
+ }
+ annotatedClasses = tempAnnotatedClasses;
+ }
+
+ //process default values first
+ if ( !isDefaultProcessed ) {
+ AnnotationBinder.bindDefaults( createExtendedMappings() );
+ isDefaultProcessed = true;
+ }
+
+ //process entities
+ if ( precedence == null ) precedence = getProperties().getProperty( ARTEFACT );
+ if ( precedence == null ) precedence = DEFAULT_PRECEDENCE;
+ StringTokenizer precedences = new StringTokenizer( precedence, ",; ", false
);
+ if ( !precedences.hasMoreElements() ) {
+ throw new MappingException( ARTEFACT + " cannot be empty: " + precedence );
+ }
+ while ( precedences.hasMoreElements() ) {
+ String artifact = (String) precedences.nextElement();
+ removeConflictedArtifact( artifact );
+ processArtifactsOfType( artifact );
+ }
+
+ int cacheNbr = caches.size();
+ for (int index = 0; index < cacheNbr; index++) {
+ CacheHolder cacheHolder = caches.get( index );
+ if ( cacheHolder.isClass ) {
+ super.setCacheConcurrencyStrategy(
+ cacheHolder.role, cacheHolder.usage, cacheHolder.region, cacheHolder.cacheLazy
+ );
+ }
+ else {
+ super.setCollectionCacheConcurrencyStrategy( cacheHolder.role, cacheHolder.usage,
cacheHolder.region );
+ }
+ }
+ caches.clear();
+ try {
+ inSecondPass = true;
+ processFkSecondPassInOrder();
+ Iterator iter = secondPasses.iterator();
+ while ( iter.hasNext() ) {
+ SecondPass sp = (SecondPass) iter.next();
+ //do the second pass of fk before the others and remove them
+ if ( sp instanceof CreateKeySecondPass ) {
+ sp.doSecondPass( classes );
+ iter.remove();
+ }
+ }
+
+ iter = secondPasses.iterator();
+ while ( iter.hasNext() ) {
+ SecondPass sp = (SecondPass) iter.next();
+ //do the SecondaryTable second pass before any association becasue associations can
be built on joins
+ if ( sp instanceof SecondaryTableSecondPass ) {
+ sp.doSecondPass( classes );
+ iter.remove();
+ }
+ }
+ super.secondPassCompile();
+ inSecondPass = false;
+ }
+ catch (RecoverableException e) {
+ //the exception was not recoverable after all
+ throw (RuntimeException) e.getCause();
+ }
+ Iterator tables = tableUniqueConstraints.entrySet().iterator();
+ Table table;
+ Map.Entry entry;
+ String keyName;
+ int uniqueIndexPerTable;
+ while ( tables.hasNext() ) {
+ entry = (Map.Entry) tables.next();
+ table = (Table) entry.getKey();
+ List<String[]> uniqueConstraints = (List<String[]>) entry.getValue();
+ uniqueIndexPerTable = 0;
+ for (String[] columnNames : uniqueConstraints) {
+ keyName = "key" + uniqueIndexPerTable++;
+ buildUniqueKeyFromColumnNames( columnNames, table, keyName );
+ }
+ }
+ boolean applyOnDdl = getProperties().getProperty(
+ "hibernate.validator.apply_to_ddl",
//org.hibernate.validator.Environment.APPLY_TO_DDL
+ "true" )
+ .equalsIgnoreCase( "true" );
+
+ //TODO search for the method only once and cache it?
+ Constructor validatorCtr = null;
+ Method applyMethod = null;
+ try {
+ Class classValidator = ReflectHelper.classForName(
"org.hibernate.validator.ClassValidator", this.getClass() );
+ Class messageInterpolator = ReflectHelper.classForName(
"org.hibernate.validator.MessageInterpolator", this.getClass() );
+ validatorCtr = classValidator.getDeclaredConstructor(
+ Class.class, ResourceBundle.class, messageInterpolator, Map.class,
ReflectionManager.class
+ );
+ applyMethod = classValidator.getMethod( "apply", PersistentClass.class );
+ }
+ catch (ClassNotFoundException e) {
+ if ( !isValidatorNotPresentLogged ) {
+ log.info( "Hibernate Validator not found: ignoring" );
+ }
+ isValidatorNotPresentLogged = true;
+ }
+ catch (NoSuchMethodException e) {
+ throw new AnnotationException( e );
+ }
+ if ( applyMethod != null && applyOnDdl ) {
+ for (PersistentClass persistentClazz : (Collection<PersistentClass>)
classes.values()) {
+ //integrate the validate framework
+ String className = persistentClazz.getClassName();
+ if ( StringHelper.isNotEmpty( className ) ) {
+ try {
+ Object validator = validatorCtr.newInstance(
+ ReflectHelper.classForName( className ), null, null, null, reflectionManager
+ );
+ applyMethod.invoke( validator, persistentClazz );
+ }
+ catch (Exception e) {
+ log.warn( "Unable to apply constraints on DDL for " + className, e );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes FKSecondPass instances trying to resolve any
+ * graph circularity (ie PK made of a many to one linking to
+ * an entity having a PK made of a ManyToOne ...).
+ */
+ private void processFkSecondPassInOrder() {
+ log.debug( "processing fk mappings (*ToOne and JoinedSubclass)" );
+ List<FkSecondPass> fkSecondPasses = getFKSecondPassesOnly();
+
+ if (fkSecondPasses.size() == 0) {
+ return; // nothing to do here
+ }
+
+ // split FkSecondPass instances into primary key and non primary key FKs.
+ // While doing so build a map of class names to FkSecondPass instances depending on
this class.
+ Map<String, Set<FkSecondPass>> isADependencyOf = new HashMap<String,
Set<FkSecondPass>>();
+ List endOfQueueFkSecondPasses = new ArrayList( fkSecondPasses.size() );
+ for (FkSecondPass sp : fkSecondPasses) {
+ if ( sp.isInPrimaryKey() ) {
+ String referenceEntityName = sp.getReferencedEntityName();
+ PersistentClass classMapping = getClassMapping( referenceEntityName );
+ String dependentTable = classMapping.getTable().getQuotedName();
+ if ( !isADependencyOf.containsKey( dependentTable ) ) {
+ isADependencyOf.put( dependentTable, new HashSet<FkSecondPass>() );
+ }
+ isADependencyOf.get( dependentTable ).add( sp );
+ }
+ else {
+ endOfQueueFkSecondPasses.add( sp );
+ }
+ }
+
+ // using the isADependencyOf map we order the FkSecondPass recursively instances into
the right order for processing
+ List<FkSecondPass> orderedFkSecondPasses = new ArrayList( fkSecondPasses.size()
);
+ for (String tableName : isADependencyOf.keySet()) {
+ buildRecursiveOrderedFkSecondPasses(orderedFkSecondPasses, isADependencyOf, tableName,
tableName);
+ }
+
+ // process the ordered FkSecondPasses
+ for ( FkSecondPass sp : orderedFkSecondPasses ) {
+ sp.doSecondPass( classes );
+ }
+
+ processEndOfQueue(endOfQueueFkSecondPasses);
+ }
+
+ private void processEndOfQueue(List endOfQueueFkSecondPasses) {
+ /*
+ * If a second pass raises a recoverableException, queue it for next round
+ * stop of no pass has to be processed or if the number of pass to processes
+ * does not diminish between two rounds.
+ * If some failing pass remain, raise the original exception
+ */
+ boolean stopProcess = false;
+ RuntimeException originalException = null;
+ while ( ! stopProcess ) {
+ List failingSecondPasses = new ArrayList();
+ Iterator it = endOfQueueFkSecondPasses.listIterator();
+ while ( it.hasNext() ) {
+ final SecondPass pass = (SecondPass) it.next();
+ try {
+ pass.doSecondPass( classes );
+ }
+ catch (RecoverableException e) {
+ failingSecondPasses.add( pass );
+ if (originalException == null) originalException = (RuntimeException) e.getCause();
+ }
+ }
+ stopProcess = failingSecondPasses.size() == 0 || failingSecondPasses.size() ==
endOfQueueFkSecondPasses.size();
+ endOfQueueFkSecondPasses = failingSecondPasses;
+ }
+ if (endOfQueueFkSecondPasses.size() > 0) {
+ throw originalException;
+ }
+ }
+
+ /**
+ * @return Returns a list of all <code>secondPasses</code> instances which
are a instance of
+ * <code>FkSecondPass</code>.
+ */
+ private List<FkSecondPass> getFKSecondPassesOnly() {
+ Iterator iter = secondPasses.iterator();
+ List<FkSecondPass> fkSecondPasses = new
ArrayList<FkSecondPass>(secondPasses.size());
+ while ( iter.hasNext() ) {
+ SecondPass sp = (SecondPass) iter.next();
+ //do the second pass of fk before the others and remove them
+ if ( sp instanceof FkSecondPass ) {
+ fkSecondPasses.add( (FkSecondPass) sp );
+ iter.remove();
+ }
+ }
+ return fkSecondPasses;
+ }
+
+ /**
+ * Recursively builds a list of FkSecondPass instances ready to be processed in this
order.
+ * Checking all dependencies recursively seems quite expensive, but the original code
just relied
+ * on some sort of table name sorting which failed in certain circumstances.
+ *
+ * @param orderedFkSecondPasses The list containing the
<code>FkSecondPass<code> instances ready
+ * for processing.
+ * @param isADependencyOf Our lookup data structure to determine dependencies between
tables
+ * @param startTable Table name to start recursive algorithm.
+ * @param currentTable The current table name used to check for 'new'
dependencies.
+ *
+ * @see ANN-722 ANN-730
+ */
+ private void buildRecursiveOrderedFkSecondPasses(
+ List orderedFkSecondPasses,
+ Map<String, Set<FkSecondPass>> isADependencyOf, String startTable, String
currentTable) {
+
+ Set<FkSecondPass> dependencies = isADependencyOf.get(currentTable);
+
+ // bottom out
+ if (dependencies == null || dependencies.size() == 0) {
+ return;
+ }
+
+ for (FkSecondPass sp : dependencies) {
+ String dependentTable = sp.getValue().getTable().getQuotedName();
+ if (dependentTable.compareTo(startTable) == 0) {
+ StringBuilder sb = new StringBuilder(
+ "Foreign key circularity dependency involving the following tables: ");
+ throw new AnnotationException(sb.toString());
+ }
+ buildRecursiveOrderedFkSecondPasses(orderedFkSecondPasses, isADependencyOf,
startTable, dependentTable);
+ if (!orderedFkSecondPasses.contains(sp)) {
+ orderedFkSecondPasses.add(0, sp);
+ }
+ }
+ }
+
+ private void processArtifactsOfType(String artifact) {
+ if ( "hbm".equalsIgnoreCase( artifact ) ) {
+ log.debug( "Process hbm files" );
+ for (Document document : hbmDocuments) {
+ super.add( document );
+ }
+ hbmDocuments.clear();
+ hbmEntities.clear();
+ }
+ else if ( "class".equalsIgnoreCase( artifact ) ) {
+ log.debug( "Process annotated classes" );
+ //bind classes in the correct order calculating some inheritance state
+ List<XClass> orderedClasses = orderAndFillHierarchy( annotatedClasses );
+ Map<XClass, InheritanceState> inheritanceStatePerClass =
AnnotationBinder.buildInheritanceStates(
+ orderedClasses, reflectionManager
+ );
+ ExtendedMappings mappings = createExtendedMappings();
+ for (XClass clazz : orderedClasses) {
+ //todo use the same extended mapping
+ AnnotationBinder.bindClass( clazz, inheritanceStatePerClass, mappings );
+ }
+ annotatedClasses.clear();
+ annotatedClassEntities.clear();
+ }
+ else {
+ log.warn( "Unknown artifact: {}", artifact );
+ }
+ }
+
+ private void removeConflictedArtifact(String artifact) {
+ if ( "hbm".equalsIgnoreCase( artifact ) ) {
+ for (String entity : hbmEntities.keySet()) {
+ if ( annotatedClassEntities.containsKey( entity ) ) {
+ annotatedClasses.remove( annotatedClassEntities.get( entity ) );
+ annotatedClassEntities.remove( entity );
+ }
+ }
+ }
+ else if ( "class".equalsIgnoreCase( artifact ) ) {
+ for (String entity : annotatedClassEntities.keySet()) {
+ if ( hbmEntities.containsKey( entity ) ) {
+ hbmDocuments.remove( hbmEntities.get( entity ) );
+ hbmEntities.remove( entity );
+ }
+ }
+ }
+ }
+
+ private void buildUniqueKeyFromColumnNames(String[] columnNames, Table table, String
keyName) {
+ UniqueKey uc;
+ int size = columnNames.length;
+ Column[] columns = new Column[size];
+ Set<Column> unbound = new HashSet<Column>();
+ Set<Column> unboundNoLogical = new HashSet<Column>();
+ ExtendedMappings mappings = createExtendedMappings();
+ for (int index = 0; index < size; index++) {
+ String columnName;
+ try {
+ columnName = mappings.getPhysicalColumnName( columnNames[index], table );
+ columns[index] = new Column( columnName );
+ unbound.add( columns[index] );
+ //column equals and hashcode is based on column name
+ }
+ catch (MappingException e) {
+ unboundNoLogical.add( new Column( columnNames[index] ) );
+ }
+ }
+ for (Column column : columns) {
+ if ( table.containsColumn( column ) ) {
+ uc = table.getOrCreateUniqueKey( keyName );
+ uc.addColumn( table.getColumn( column ) );
+ unbound.remove( column );
+ }
+ }
+ if ( unbound.size() > 0 || unboundNoLogical.size() > 0 ) {
+ StringBuilder sb = new StringBuilder( "Unable to create unique key constraint
(" );
+ for (String columnName : columnNames) {
+ sb.append( columnName ).append( ", " );
+ }
+ sb.setLength( sb.length() - 2 );
+ sb.append( ") on table " ).append( table.getName() ).append( ": "
);
+ for (Column column : unbound) {
+ sb.append( column.getName() ).append( ", " );
+ }
+ for (Column column : unboundNoLogical) {
+ sb.append( column.getName() ).append( ", " );
+ }
+ sb.setLength( sb.length() - 2 );
+ sb.append( " not found" );
+ throw new AnnotationException( sb.toString() );
+ }
+ }
+
+ @Override
+ protected void parseMappingElement(Element subelement, String name) {
+ Attribute rsrc = subelement.attribute( "resource" );
+ Attribute file = subelement.attribute( "file" );
+ Attribute jar = subelement.attribute( "jar" );
+ Attribute pckg = subelement.attribute( "package" );
+ Attribute clazz = subelement.attribute( "class" );
+ if ( rsrc != null ) {
+ log.debug( "{} <- {}", name, rsrc );
+ addResource( rsrc.getValue() );
+ }
+ else if ( jar != null ) {
+ log.debug( "{} <- {}", name, jar );
+ addJar( new File( jar.getValue() ) );
+ }
+ else if ( file != null ) {
+ log.debug( "{} <- {}", name, file );
+ addFile( file.getValue() );
+ }
+ else if ( pckg != null ) {
+ log.debug( "{} <- {}", name, pckg );
+ addPackage( pckg.getValue() );
+ }
+ else if ( clazz != null ) {
+ log.debug( "{} <- {}", name, clazz );
+ Class loadedClass;
+ try {
+ loadedClass = ReflectHelper.classForName( clazz.getValue() );
+ }
+ catch (ClassNotFoundException cnf) {
+ throw new MappingException(
+ "Unable to load class declared as <mapping class=\"" +
clazz.getValue() + "\"/> in the configuration:",
+ cnf
+ );
+ }
+ catch (NoClassDefFoundError ncdf) {
+ throw new MappingException(
+ "Unable to load class declared as <mapping class=\"" +
clazz.getValue() + "\"/> in the configuration:",
+ ncdf
+ );
+ }
+
+ addAnnotatedClass( loadedClass );
+ }
+ else {
+ throw new MappingException( "<mapping> element in configuration specifies
no attributes" );
+ }
+ }
+
+ @Override
+ protected void add(org.dom4j.Document doc) throws MappingException {
+ boolean ejb3Xml = "entity-mappings".equals( doc.getRootElement().getName()
);
+ if ( inSecondPass ) {
+ //if in second pass bypass the queueing, getExtendedQueue reuse this method
+ if ( !ejb3Xml ) super.add( doc );
+ }
+ else {
+ if ( !ejb3Xml ) {
+ final Element hmNode = doc.getRootElement();
+ Attribute packNode = hmNode.attribute( "package" );
+ String defaultPackage = packNode != null
+ ? packNode.getValue()
+ : "";
+ Set<String> entityNames = new HashSet<String>();
+ findClassNames( defaultPackage, hmNode, entityNames );
+ for (String entity : entityNames) {
+ hbmEntities.put( entity, doc );
+ }
+ hbmDocuments.add( doc );
+ }
+ else {
+ List<String> classnames = ( (EJB3ReflectionManager) reflectionManager
).getXMLContext().addDocument( doc );
+ for (String classname : classnames) {
+ try {
+ annotatedClasses.add( reflectionManager.classForName( classname, this.getClass() )
);
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException( "Unable to load class defined in XML: " +
classname, e );
+ }
+ }
+ }
+ }
+ }
+
+ private static void findClassNames(
+ String defaultPackage, final Element startNode,
+ final java.util.Set names
+ ) {
+ // if we have some extends we need to check if those classes possibly could be inside
the
+ // same hbm.xml file...
+ Iterator[] classes = new Iterator[4];
+ classes[0] = startNode.elementIterator( "class" );
+ classes[1] = startNode.elementIterator( "subclass" );
+ classes[2] = startNode.elementIterator( "joined-subclass" );
+ classes[3] = startNode.elementIterator( "union-subclass" );
+
+ Iterator classIterator = new JoinedIterator( classes );
+ while ( classIterator.hasNext() ) {
+ Element element = (Element) classIterator.next();
+ String entityName = element.attributeValue( "entity-name" );
+ if ( entityName == null ) entityName = getClassName( element.attribute(
"name" ), defaultPackage );
+ names.add( entityName );
+ findClassNames( defaultPackage, element, names );
+ }
+ }
+
+ private static String getClassName(Attribute name, String defaultPackage) {
+ if ( name == null ) return null;
+ String unqualifiedName = name.getValue();
+ if ( unqualifiedName == null ) return null;
+ if ( unqualifiedName.indexOf( '.' ) < 0 && defaultPackage != null )
{
+ return defaultPackage + '.' + unqualifiedName;
+ }
+ return unqualifiedName;
+ }
+
+ public void setPrecedence(String precedence) {
+ this.precedence = precedence;
+ }
+
+ private static class CacheHolder {
+ public CacheHolder(String role, String usage, String region, boolean isClass, boolean
cacheLazy) {
+ this.role = role;
+ this.usage = usage;
+ this.region = region;
+ this.isClass = isClass;
+ this.cacheLazy = cacheLazy;
+ }
+
+ public String role;
+ public String usage;
+ public String region;
+ public boolean isClass;
+ public boolean cacheLazy;
+ }
+
+ @Override
+ public AnnotationConfiguration addInputStream(InputStream xmlInputStream) throws
MappingException {
+ try {
+ List errors = new ArrayList();
+ SAXReader saxReader = xmlHelper.createSAXReader( "XML InputStream", errors,
getEntityResolver() );
+ try {
+ saxReader.setFeature( "http://apache.org/xml/features/validation/schema",
true );
+ //saxReader.setFeature(
"http://apache.org/xml/features/validation/dynamic", true );
+ //set the default schema locators
+ saxReader.setProperty(
+ "http://apache.org/xml/properties/schema/external-schemaLocation",
+ "http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
+ );
+ }
+ catch (SAXException e) {
+ saxReader.setValidation( false );
+ }
+ org.dom4j.Document doc = saxReader
+ .read( new InputSource( xmlInputStream ) );
+
+ if ( errors.size() != 0 ) {
+ throw new MappingException( "invalid mapping", (Throwable) errors.get( 0 )
);
+ }
+ add( doc );
+ return this;
+ }
+ catch (DocumentException e) {
+ throw new MappingException( "Could not parse mapping document in input
stream", e );
+ }
+ finally {
+ try {
+ xmlInputStream.close();
+ }
+ catch (IOException ioe) {
+ log.warn( "Could not close input stream", ioe );
+ }
+ }
+ }
+
+ public SessionFactory buildSessionFactory() throws HibernateException {
+ //add validator events if the jar is available
+ boolean enableValidatorListeners = !"false".equalsIgnoreCase( getProperty(
"hibernate.validator.autoregister_listeners" ) );
+ Class validateEventListenerClass = null;
+ try {
+ validateEventListenerClass = ReflectHelper.classForName(
+ "org.hibernate.validator.event.ValidateEventListener",
+ AnnotationConfiguration.class );
+ }
+ catch (ClassNotFoundException e) {
+ //validator is not present
+ log.debug( "Validator not present in classpath, ignoring event listener
registration" );
+ }
+ if ( enableValidatorListeners && validateEventListenerClass != null ) {
+ //TODO so much duplication
+ Object validateEventListener;
+ try {
+ validateEventListener = validateEventListenerClass.newInstance();
+ }
+ catch (Exception e) {
+ throw new AnnotationException( "Unable to load Validator event listener", e
);
+ }
+ {
+ boolean present = false;
+ PreInsertEventListener[] listeners =
getEventListeners().getPreInsertEventListeners();
+ if ( listeners != null ) {
+ for (Object eventListener : listeners) {
+ //not isAssignableFrom since the user could subclass
+ present = present || validateEventListenerClass == eventListener.getClass();
+ }
+ if ( !present ) {
+ int length = listeners.length + 1;
+ PreInsertEventListener[] newListeners = new PreInsertEventListener[length];
+ System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
+ newListeners[length - 1] = (PreInsertEventListener) validateEventListener;
+ getEventListeners().setPreInsertEventListeners( newListeners );
+ }
+ }
+ else {
+ getEventListeners().setPreInsertEventListeners(
+ new PreInsertEventListener[] { (PreInsertEventListener) validateEventListener }
+ );
+ }
+ }
+
+ //update event listener
+ {
+ boolean present = false;
+ PreUpdateEventListener[] listeners =
getEventListeners().getPreUpdateEventListeners();
+ if ( listeners != null ) {
+ for (Object eventListener : listeners) {
+ //not isAssignableFrom since the user could subclass
+ present = present || validateEventListenerClass == eventListener.getClass();
+ }
+ if ( !present ) {
+ int length = listeners.length + 1;
+ PreUpdateEventListener[] newListeners = new PreUpdateEventListener[length];
+ System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
+ newListeners[length - 1] = (PreUpdateEventListener) validateEventListener;
+ getEventListeners().setPreUpdateEventListeners( newListeners );
+ }
+ }
+ else {
+ getEventListeners().setPreUpdateEventListeners(
+ new PreUpdateEventListener[] { (PreUpdateEventListener) validateEventListener }
+ );
+ }
+ }
+ }
+
+ enableHibernateSearch();
+
+ return super.buildSessionFactory();
+ }
+
+ /**
+ * Tries to automatically register Hibernate Search event listeners by locating the
+ * appropriate bootstrap class and calling the
<code>enableHibernateSearch</code> method.
+ */
+ private void enableHibernateSearch() {
+ // load the bootstrap class
+ Class searchStartupClass;
+ try {
+ searchStartupClass = ReflectHelper.classForName(SEARCH_STARTUP_CLASS,
AnnotationConfiguration.class);
+ } catch ( ClassNotFoundException e ) {
+ // TODO remove this together with SearchConfiguration after 3.1.0 release of Search
+ // try loading deprecated HibernateSearchEventListenerRegister
+ try {
+ searchStartupClass =
ReflectHelper.classForName("org.hibernate.cfg.search.HibernateSearchEventListenerRegister",
AnnotationConfiguration.class);
+ } catch ( ClassNotFoundException cnfe ) {
+ log.debug("Search not present in classpath, ignoring event listener
registration.");
+ return;
+ }
+ }
+
+ // call the method for registering the listeners
+ try {
+ Object searchStartupInstance = searchStartupClass.newInstance();
+ Method enableSearchMethod =
searchStartupClass.getDeclaredMethod(SEARCH_STARTUP_METHOD,
+ EventListeners.class, Properties.class);
+ enableSearchMethod.invoke(searchStartupInstance, getEventListeners(),
getProperties());
+ } catch ( InstantiationException e ) {
+ log.debug("Unable to instantiate {}, ignoring event listener registration.",
SEARCH_STARTUP_CLASS);
+ } catch ( IllegalAccessException e ) {
+ log.debug("Unable to instantiate {}, ignoring event listener registration.",
SEARCH_STARTUP_CLASS);
+ } catch ( NoSuchMethodException e ) {
+ log.debug("Method enableHibernateSearch() not found in {}.",
SEARCH_STARTUP_CLASS);
+ } catch ( InvocationTargetException e ) {
+ log.debug("Unable to execute {}, ignoring event listener registration.",
SEARCH_STARTUP_METHOD);
+ }
+ }
+
+ @Override
+ public AnnotationConfiguration addFile(String xmlFile) throws MappingException {
+ super.addFile( xmlFile );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addFile(File xmlFile) throws MappingException {
+ super.addFile( xmlFile );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addCacheableFile(File xmlFile) throws MappingException {
+ super.addCacheableFile( xmlFile );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addCacheableFile(String xmlFile) throws MappingException
{
+ super.addCacheableFile( xmlFile );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addXML(String xml) throws MappingException {
+ super.addXML( xml );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addURL(URL url) throws MappingException {
+ super.addURL( url );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addResource(String resourceName, ClassLoader classLoader)
throws MappingException {
+ super.addResource( resourceName, classLoader );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addDocument(org.w3c.dom.Document doc) throws
MappingException {
+ super.addDocument( doc );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addResource(String resourceName) throws MappingException
{
+ super.addResource( resourceName );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addClass(Class persistentClass) throws MappingException
{
+ super.addClass( persistentClass );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addJar(File jar) throws MappingException {
+ super.addJar( jar );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addDirectory(File dir) throws MappingException {
+ super.addDirectory( dir );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration setInterceptor(Interceptor interceptor) {
+ super.setInterceptor( interceptor );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration setProperties(Properties properties) {
+ super.setProperties( properties );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration addProperties(Properties extraProperties) {
+ super.addProperties( extraProperties );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration mergeProperties(Properties properties) {
+ super.mergeProperties( properties );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration setProperty(String propertyName, String value) {
+ super.setProperty( propertyName, value );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration configure() throws HibernateException {
+ super.configure();
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration configure(String resource) throws HibernateException {
+ super.configure( resource );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration configure(URL url) throws HibernateException {
+ super.configure( url );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration configure(File configFile) throws HibernateException {
+ super.configure( configFile );
+ return this;
+ }
+
+ @Override
+ protected AnnotationConfiguration doConfigure(InputStream stream, String resourceName)
throws HibernateException {
+ super.doConfigure( stream, resourceName );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration configure(org.w3c.dom.Document document) throws
HibernateException {
+ super.configure( document );
+ return this;
+ }
+
+ @Override
+ protected AnnotationConfiguration doConfigure(Document doc) throws HibernateException {
+ super.doConfigure( doc );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration setCacheConcurrencyStrategy(String clazz, String
concurrencyStrategy) throws MappingException {
+ super.setCacheConcurrencyStrategy( clazz, concurrencyStrategy );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration setCollectionCacheConcurrencyStrategy(String
collectionRole, String concurrencyStrategy) throws MappingException {
+ super.setCollectionCacheConcurrencyStrategy( collectionRole, concurrencyStrategy );
+ return this;
+ }
+
+ @Override
+ public AnnotationConfiguration setNamingStrategy(NamingStrategy namingStrategy) {
+ super.setNamingStrategy( namingStrategy );
+ return this;
+ }
+
+ //not a public API
+ public ReflectionManager getReflectionManager() {
+ return reflectionManager;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/BinderHelper.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/BinderHelper.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/BinderHelper.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,556 @@
+//$Id: BinderHelper.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.AnyMetaDefs;
+import org.hibernate.annotations.MetaValue;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XPackage;
+import org.hibernate.cfg.annotations.EntityBinder;
+import org.hibernate.cfg.annotations.Nullability;
+import org.hibernate.cfg.annotations.TableBinder;
+import org.hibernate.id.MultipleHiLoPerTableGenerator;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.mapping.Any;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.IdGenerator;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.Value;
+import org.hibernate.type.TypeFactory;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class BinderHelper {
+
+ public static final String ANNOTATION_STRING_DEFAULT = "";
+ private static Logger log = LoggerFactory.getLogger( BinderHelper.class );
+
+ private BinderHelper() {
+ }
+
+ static {
+ Set<String> primitiveNames = new HashSet<String>();
+ primitiveNames.add( byte.class.getName() );
+ primitiveNames.add( short.class.getName() );
+ primitiveNames.add( int.class.getName() );
+ primitiveNames.add( long.class.getName() );
+ primitiveNames.add( float.class.getName() );
+ primitiveNames.add( double.class.getName() );
+ primitiveNames.add( char.class.getName() );
+ primitiveNames.add( boolean.class.getName() );
+ PRIMITIVE_NAMES = Collections.unmodifiableSet( primitiveNames );
+ }
+
+ public static final Set<String> PRIMITIVE_NAMES;
+
+ /**
+ * create a property copy reusing the same value
+ */
+ public static Property shallowCopy(Property property) {
+ Property clone = new Property();
+ clone.setCascade( property.getCascade() );
+ clone.setInsertable( property.isInsertable() );
+ clone.setLazy( property.isLazy() );
+ clone.setName( property.getName() );
+ clone.setNodeName( property.getNodeName() );
+ clone.setNaturalIdentifier( property.isNaturalIdentifier() );
+ clone.setOptimisticLocked( property.isOptimisticLocked() );
+ clone.setOptional( property.isOptional() );
+ clone.setPersistentClass( property.getPersistentClass() );
+ clone.setPropertyAccessorName( property.getPropertyAccessorName() );
+ clone.setSelectable( property.isSelectable() );
+ clone.setUpdateable( property.isUpdateable() );
+ clone.setValue( property.getValue() );
+ return clone;
+ }
+
+ public static void createSyntheticPropertyReference(
+ Ejb3JoinColumn[] columns,
+ PersistentClass ownerEntity,
+ PersistentClass associatedEntity,
+ Value value,
+ boolean inverse, ExtendedMappings mappings
+ ) {
+ //associated entity only used for more precise exception, yuk!
+ if ( columns[0].isImplicit() || StringHelper.isNotEmpty( columns[0].getMappedBy() ) )
return;
+ int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType( columns, ownerEntity, mappings
);
+ PersistentClass associatedClass = columns[0].getPropertyHolder() != null ?
+ columns[0].getPropertyHolder().getPersistentClass() :
+ null;
+ if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) {
+ /**
+ * Create a synthetic property to refer to including an
+ * embedded component value containing all the properties
+ * mapped to the referenced columns
+ * We need to shallow copy those properties to mark them
+ * as non insertable / non updatable
+ */
+ StringBuilder propertyNameBuffer = new StringBuilder( "_" );
+ propertyNameBuffer.append( associatedClass.getEntityName().replace( '.',
'_' ) );
+ propertyNameBuffer.append( "_" ).append( columns[0].getPropertyName() );
+ String syntheticPropertyName = propertyNameBuffer.toString();
+ //find properties associated to a certain column
+ Object columnOwner = findColumnOwner( ownerEntity, columns[0].getReferencedColumn(),
mappings );
+ List<Property> properties = findPropertiesByColumns( columnOwner, columns,
mappings );
+ //create an embeddable component
+ Property synthProp = null;
+ if ( properties != null ) {
+ //todo how about properties.size() == 1, this should be much simpler
+ Component embeddedComp = columnOwner instanceof PersistentClass ?
+ new Component( (PersistentClass) columnOwner ) :
+ new Component( (Join) columnOwner );
+ embeddedComp.setEmbedded( true );
+ embeddedComp.setNodeName( syntheticPropertyName );
+ embeddedComp.setComponentClassName( embeddedComp.getOwner().getClassName() );
+ for (Property property : properties) {
+ Property clone = BinderHelper.shallowCopy( property );
+ clone.setInsertable( false );
+ clone.setUpdateable( false );
+ clone.setNaturalIdentifier( false );
+ embeddedComp.addProperty( clone );
+ }
+ synthProp = new Property();
+ synthProp.setName( syntheticPropertyName );
+ synthProp.setNodeName( syntheticPropertyName );
+ synthProp.setPersistentClass( ownerEntity );
+ synthProp.setUpdateable( false );
+ synthProp.setInsertable( false );
+ synthProp.setValue( embeddedComp );
+ synthProp.setPropertyAccessorName( "embedded" );
+ ownerEntity.addProperty( synthProp );
+ //make it unique
+ TableBinder.createUniqueConstraint( embeddedComp );
+ }
+ else {
+ //TODO use a ToOne type doing a second select
+ StringBuilder columnsList = new StringBuilder();
+ columnsList.append( "referencedColumnNames(" );
+ for (Ejb3JoinColumn column : columns) {
+ columnsList.append( column.getReferencedColumn() ).append( ", " );
+ }
+ columnsList.setLength( columnsList.length() - 2 );
+ columnsList.append( ") " );
+
+ if ( associatedEntity != null ) {
+ //overidden destination
+ columnsList.append( "of " )
+ .append( associatedEntity.getEntityName() )
+ .append( "." )
+ .append( columns[0].getPropertyName() )
+ .append( " " );
+ }
+ else {
+ if ( columns[0].getPropertyHolder() != null ) {
+ columnsList.append( "of " )
+ .append( columns[0].getPropertyHolder().getEntityName() )
+ .append( "." )
+ .append( columns[0].getPropertyName() )
+ .append( " " );
+ }
+ }
+ columnsList.append( "referencing " )
+ .append( ownerEntity.getEntityName() )
+ .append( " not mapped to a single property" );
+ throw new AnnotationException( columnsList.toString() );
+ }
+
+ /**
+ * creating the property ref to the new synthetic property
+ */
+ if ( value instanceof ToOne ) {
+ ( (ToOne) value ).setReferencedPropertyName( syntheticPropertyName );
+ mappings.addUniquePropertyReference( ownerEntity.getEntityName(),
syntheticPropertyName );
+ }
+ else if ( value instanceof Collection ) {
+ ( (Collection) value ).setReferencedPropertyName( syntheticPropertyName );
+ //not unique because we could create a mtm wo association table
+ mappings.addPropertyReference( ownerEntity.getEntityName(), syntheticPropertyName );
+ }
+ else {
+ throw new AssertionFailure(
+ "Do a property ref on an unexpected Value type: "
+ + value.getClass().getName()
+ );
+ }
+ mappings.addPropertyReferencedAssociation(
+ ( inverse ? "inverse__" : "" ) +
associatedClass.getEntityName(),
+ columns[0].getPropertyName(),
+ syntheticPropertyName
+ );
+ }
+ }
+
+
+ private static List<Property> findPropertiesByColumns(
+ Object columnOwner, Ejb3JoinColumn[] columns,
+ ExtendedMappings mappings
+ ) {
+ Map<Column, Set<Property>> columnsToProperty = new HashMap<Column,
Set<Property>>();
+ List<Column> orderedColumns = new ArrayList<Column>( columns.length );
+ Table referencedTable = null;
+ if ( columnOwner instanceof PersistentClass ) {
+ referencedTable = ( (PersistentClass) columnOwner ).getTable();
+ }
+ else if ( columnOwner instanceof Join ) {
+ referencedTable = ( (Join) columnOwner ).getTable();
+ }
+ else {
+ throw new AssertionFailure(
+ columnOwner == null ?
+ "columnOwner is null" :
+ "columnOwner neither PersistentClass nor Join: " +
columnOwner.getClass()
+ );
+ }
+ //build the list of column names
+ for (Ejb3JoinColumn column1 : columns) {
+ Column column = new Column(
+ mappings.getPhysicalColumnName( column1.getReferencedColumn(), referencedTable )
+ );
+ orderedColumns.add( column );
+ columnsToProperty.put( column, new HashSet<Property>() );
+ }
+ boolean isPersistentClass = columnOwner instanceof PersistentClass;
+ Iterator it = isPersistentClass ?
+ ( (PersistentClass) columnOwner ).getPropertyIterator() :
+ ( (Join) columnOwner ).getPropertyIterator();
+ while ( it.hasNext() ) {
+ matchColumnsByProperty( (Property) it.next(), columnsToProperty );
+ }
+ if ( isPersistentClass ) {
+ matchColumnsByProperty( ( (PersistentClass) columnOwner ).getIdentifierProperty(),
columnsToProperty );
+ }
+
+ //first naive implementation
+ //only check 1 columns properties
+ //TODO make it smarter by checking correctly ordered multi column properties
+ List<Property> orderedProperties = new ArrayList<Property>();
+ for (Column column : orderedColumns) {
+ boolean found = false;
+ for (Property property : columnsToProperty.get( column )) {
+ if ( property.getColumnSpan() == 1 ) {
+ orderedProperties.add( property );
+ found = true;
+ break;
+ }
+ }
+ if ( !found ) return null; //have to find it the hard way
+ }
+ return orderedProperties;
+ }
+
+ private static void matchColumnsByProperty(Property property, Map<Column,
Set<Property>> columnsToProperty) {
+ if ( property == null ) return;
+ if ( "noop".equals( property.getPropertyAccessorName() )
+ || "embedded".equals( property.getPropertyAccessorName() ) ) {
+ return;
+ }
+// FIXME cannot use subproperties becasue the caller needs top level properties
+// if ( property.isComposite() ) {
+// Iterator subProperties = ( (Component) property.getValue() ).getPropertyIterator();
+// while ( subProperties.hasNext() ) {
+// matchColumnsByProperty( (Property) subProperties.next(), columnsToProperty );
+// }
+// }
+ else {
+ Iterator columnIt = property.getColumnIterator();
+ while ( columnIt.hasNext() ) {
+ Object column = columnIt.next(); //can be a Formula so we don't cast
+ //noinspection SuspiciousMethodCalls
+ if ( columnsToProperty.containsKey( column ) ) {
+ columnsToProperty.get( column ).add( property );
+ }
+ }
+ }
+ }
+
+ /**
+ * Retrieve the property by path in a recursive way, including IndetifierProperty in the
loop
+ * If propertyName is null or empty, the IdentifierProperty is returned
+ */
+ public static Property findPropertyByName(PersistentClass associatedClass, String
propertyName) {
+ Property property = null;
+ Property idProperty = associatedClass.getIdentifierProperty();
+ String idName = idProperty != null ? idProperty.getName() : null;
+ try {
+ if ( propertyName == null
+ || propertyName.length() == 0
+ || propertyName.equals( idName ) ) {
+ //default to id
+ property = idProperty;
+ }
+ else {
+ if ( propertyName.indexOf( idName + "." ) == 0 ) {
+ property = idProperty;
+ propertyName = propertyName.substring( idName.length() + 1 );
+ }
+ StringTokenizer st = new StringTokenizer( propertyName, ".", false );
+ while ( st.hasMoreElements() ) {
+ String element = (String) st.nextElement();
+ if ( property == null ) {
+ property = associatedClass.getProperty( element );
+ }
+ else {
+ if ( !property.isComposite() ) return null;
+ property = ( (Component) property.getValue() ).getProperty( element );
+ }
+ }
+ }
+ }
+ catch (MappingException e) {
+ try {
+ //if we do not find it try to check the identifier mapper
+ if ( associatedClass.getIdentifierMapper() == null ) return null;
+ StringTokenizer st = new StringTokenizer( propertyName, ".", false );
+ while ( st.hasMoreElements() ) {
+ String element = (String) st.nextElement();
+ if ( property == null ) {
+ property = associatedClass.getIdentifierMapper().getProperty( element );
+ }
+ else {
+ if ( !property.isComposite() ) return null;
+ property = ( (Component) property.getValue() ).getProperty( element );
+ }
+ }
+ }
+ catch (MappingException ee) {
+ return null;
+ }
+ }
+ return property;
+ }
+
+ public static String getRelativePath(PropertyHolder propertyHolder, String propertyName)
{
+ if ( propertyHolder == null ) return propertyName;
+ String path = propertyHolder.getPath();
+ String entityName = propertyHolder.getPersistentClass().getEntityName();
+ if ( path.length() == entityName.length() ) {
+ return propertyName;
+ }
+ else {
+ return StringHelper.qualify( path.substring( entityName.length() + 1 ), propertyName
);
+ }
+ }
+
+ /**
+ * Find the column owner (ie PersistentClass or Join) of columnName.
+ * If columnName is null or empty, persistentClass is returned
+ */
+ public static Object findColumnOwner(
+ PersistentClass persistentClass, String columnName, ExtendedMappings mappings
+ ) {
+ if ( StringHelper.isEmpty( columnName ) ) {
+ return persistentClass; //shortcut for implicit referenced column names
+ }
+ PersistentClass current = persistentClass;
+ Object result = null;
+ boolean found = false;
+ do {
+ result = current;
+ Table currentTable = current.getTable();
+ try {
+ mappings.getPhysicalColumnName( columnName, currentTable );
+ found = true;
+ }
+ catch (MappingException me) {
+ //swallow it
+ }
+ Iterator joins = current.getJoinIterator();
+ while ( !found && joins.hasNext() ) {
+ result = joins.next();
+ currentTable = ( (Join) result ).getTable();
+ try {
+ mappings.getPhysicalColumnName( columnName, currentTable );
+ found = true;
+ }
+ catch (MappingException me) {
+ //swallow it
+ }
+ }
+ current = current.getSuperclass();
+ }
+ while ( !found && current != null );
+ return found ? result : null;
+ }
+
+ /**
+ * apply an id generator to a SimpleValue
+ */
+ public static void makeIdGenerator(
+ SimpleValue id, String generatorType, String generatorName, ExtendedMappings
mappings,
+ Map<String, IdGenerator> localGenerators
+ ) {
+ Table table = id.getTable();
+ table.setIdentifierValue( id );
+ //generator settings
+ id.setIdentifierGeneratorStrategy( generatorType );
+ Properties params = new Properties();
+ //always settable
+ params.setProperty(
+ PersistentIdentifierGenerator.TABLE, table.getName()
+ );
+
+ if ( id.getColumnSpan() == 1 ) {
+ params.setProperty(
+ PersistentIdentifierGenerator.PK,
+ ( (org.hibernate.mapping.Column) id.getColumnIterator().next() ).getName()
+ );
+ }
+ if ( !isDefault( generatorName ) ) {
+ //we have a named generator
+ IdGenerator gen = mappings.getGenerator( generatorName, localGenerators );
+ if ( gen == null ) {
+ throw new AnnotationException( "Unknown Id.generator: " + generatorName );
+ }
+ //This is quite vague in the spec but a generator could override the generate choice
+ String identifierGeneratorStrategy = gen.getIdentifierGeneratorStrategy();
+ //yuk! this is a hack not to override 'AUTO' even if generator is set
+ final boolean avoidOverriding =
+ identifierGeneratorStrategy.equals( "identity" )
+ || identifierGeneratorStrategy.equals( "seqhilo" )
+ || identifierGeneratorStrategy.equals(
MultipleHiLoPerTableGenerator.class.getName() );
+ if ( generatorType == null || !avoidOverriding ) {
+ id.setIdentifierGeneratorStrategy( identifierGeneratorStrategy );
+ }
+ //checkIfMatchingGenerator(gen, generatorType, generatorName);
+ Iterator genParams = gen.getParams().entrySet().iterator();
+ while ( genParams.hasNext() ) {
+ Map.Entry elt = (Map.Entry) genParams.next();
+ params.setProperty( (String) elt.getKey(), (String) elt.getValue() );
+ }
+ }
+ if ( "assigned".equals( generatorType ) ) id.setNullValue(
"undefined" );
+ id.setIdentifierGeneratorProperties( params );
+ }
+
+ public static boolean isDefault(String annotationString) {
+ return annotationString != null && annotationString.length() == 0;
+ //equivalent to (but faster) ANNOTATION_STRING_DEFAULT.equals( annotationString );
+ }
+
+ public static Any buildAnyValue(String anyMetaDefName, Ejb3JoinColumn[] columns,
javax.persistence.Column metaColumn, PropertyData inferredData,
+ boolean cascadeOnDelete, Nullability nullability, PropertyHolder
propertyHolder,
+ EntityBinder entityBinder, boolean optional, ExtendedMappings mappings) {
+ //All FK columns should be in the same table
+ Any value = new Any( columns[0].getTable() );
+ AnyMetaDef metaAnnDef = inferredData.getProperty().getAnnotation( AnyMetaDef.class );
+
+ if ( metaAnnDef != null ) {
+ //local has precedence over general and can be mapped for future reference if named
+ bindAnyMetaDefs( inferredData.getProperty(), mappings );
+ }
+ else {
+ metaAnnDef = mappings.getAnyMetaDef( anyMetaDefName );
+ }
+ if ( metaAnnDef != null ) {
+ value.setIdentifierType( metaAnnDef.idType() );
+ value.setMetaType( metaAnnDef.metaType() );
+
+ HashMap values = new HashMap();
+ org.hibernate.type.Type metaType = TypeFactory.heuristicType( value.getMetaType() );
+ for (MetaValue metaValue : metaAnnDef.metaValues()) {
+ try {
+ Object discrim = ( (org.hibernate.type.DiscriminatorType) metaType ).stringToObject(
metaValue
+ .value() );
+ String entityName = metaValue.targetEntity().getName();
+ values.put( discrim, entityName );
+ }
+ catch (ClassCastException cce) {
+ throw new MappingException( "metaType was not a DiscriminatorType: "
+ + metaType.getName() );
+ }
+ catch (Exception e) {
+ throw new MappingException( "could not interpret metaValue", e );
+ }
+ }
+ if ( !values.isEmpty() ) value.setMetaValues( values );
+ }
+ else {
+ throw new AnnotationException( "Unable to find @AnyMetaDef for an @(ManyTo)Any
mapping: "
+ + StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
+ }
+
+ value.setCascadeDeleteEnabled( cascadeOnDelete );
+ if ( !optional ) {
+ for (Ejb3JoinColumn column : columns) {
+ column.setNullable( false );
+ }
+ }
+
+ Ejb3Column[] metaColumns = Ejb3Column.buildColumnFromAnnotation( new
javax.persistence.Column[] { metaColumn }, null,
+ nullability, propertyHolder, inferredData, entityBinder.getSecondaryTables(),
mappings );
+ //set metaColumn to the right table
+ for (Ejb3Column column : metaColumns) {
+ column.setTable( value.getTable() );
+ }
+ //meta column
+ for (Ejb3Column column : metaColumns) {
+ column.linkWithValue( value );
+ }
+
+ //id columns
+ final String propertyName = inferredData.getPropertyName();
+ Ejb3Column.checkPropertyConsistency( columns, propertyHolder.getEntityName() +
propertyName );
+ for (Ejb3JoinColumn column : columns) {
+ column.linkWithValue( value );
+ }
+ return value;
+ }
+
+ public static void bindAnyMetaDefs(XAnnotatedElement annotatedElement, ExtendedMappings
mappings) {
+ AnyMetaDef defAnn = annotatedElement.getAnnotation( AnyMetaDef.class );
+ AnyMetaDefs defsAnn = annotatedElement.getAnnotation( AnyMetaDefs.class );
+ boolean mustHaveName = XClass.class.isAssignableFrom( annotatedElement.getClass() )
+ || XPackage.class.isAssignableFrom( annotatedElement.getClass() );
+ if ( defAnn != null ) {
+ checkAnyMetaDefValidity( mustHaveName, defAnn, annotatedElement );
+ bindAnyMetaDef( defAnn, mappings );
+ }
+ if ( defsAnn != null ) {
+ for (AnyMetaDef def : defsAnn.value()) {
+ checkAnyMetaDefValidity( mustHaveName, def, annotatedElement );
+ bindAnyMetaDef( def, mappings );
+ }
+ }
+ }
+
+ private static void checkAnyMetaDefValidity(boolean mustHaveName, AnyMetaDef defAnn,
XAnnotatedElement annotatedElement) {
+ if ( mustHaveName && isDefault( defAnn.name() ) ) {
+ String name = XClass.class.isAssignableFrom( annotatedElement.getClass() ) ?
+ ( (XClass) annotatedElement ).getName() :
+ ( (XPackage) annotatedElement ).getName();
+ throw new AnnotationException( "(a)AnyMetaDef.name cannot be null on an entity or a
package: " + name );
+ }
+ }
+
+ private static void bindAnyMetaDef(AnyMetaDef defAnn, ExtendedMappings mappings) {
+ if ( isDefault( defAnn.name() ) ) return; //don't map not named definitions
+ log.info( "Binding Any Meta definition: {}", defAnn.name() );
+ mappings.addAnyMetaDef( defAnn );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ClassPropertyHolder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,120 @@
+//$Id: ClassPropertyHolder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.persistence.JoinTable;
+
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.cfg.annotations.EntityBinder;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Table;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ClassPropertyHolder extends AbstractPropertyHolder {
+ private PersistentClass persistentClass;
+ private Map<String, Join> joins;
+ private transient Map<String, Join> joinsPerRealTableName;
+ private EntityBinder entityBinder;
+
+ public ClassPropertyHolder(
+ PersistentClass persistentClass, XClass clazzToProcess, Map<String, Join> joins,
ExtendedMappings mappings
+ ) {
+ super( persistentClass.getEntityName(), null, clazzToProcess, mappings );
+ this.persistentClass = persistentClass;
+ this.joins = joins;
+ }
+
+ public ClassPropertyHolder(
+ PersistentClass persistentClass, XClass clazzToProcess, EntityBinder entityBinder,
+ ExtendedMappings mappings
+ ) {
+ this( persistentClass, clazzToProcess, entityBinder.getSecondaryTables(), mappings );
+ this.entityBinder = entityBinder;
+ }
+
+ public String getEntityName() {
+ return persistentClass.getEntityName();
+ }
+
+ public void addProperty(Property prop, Ejb3Column[] columns) {
+ //Ejb3Column.checkPropertyConsistency( ); //already called earlier
+ if ( columns[0].isSecondary() ) {
+ //TODO move the getJoin() code here?
+ columns[0].getJoin().addProperty( prop );
+ }
+ else {
+ addProperty( prop );
+ }
+ }
+
+ public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
+ Join join = entityBinder.addJoin( joinTableAnn, this, noDelayInPkColumnCreation );
+ this.joins = entityBinder.getSecondaryTables();
+ return join;
+ }
+
+ public void addProperty(Property prop) {
+ if ( prop.getValue() instanceof Component ) {
+ //TODO handle quote and non quote table comparison
+ String tableName = prop.getValue().getTable().getName();
+ if ( getJoinsPerRealTableName().containsKey( tableName ) ) {
+ getJoinsPerRealTableName().get( tableName ).addProperty( prop );
+ }
+ else {
+ persistentClass.addProperty( prop );
+ }
+ }
+ else {
+ persistentClass.addProperty( prop );
+ }
+ }
+
+ /**
+ * Needed for proper compliance with naming strategy, the property table
+ * can be overriden if the properties are part of secondary tables
+ */
+ private Map<String, Join> getJoinsPerRealTableName() {
+ if ( joinsPerRealTableName == null ) {
+ joinsPerRealTableName = new HashMap<String, Join>( joins.size() );
+ for (Join join : joins.values()) {
+ joinsPerRealTableName.put( join.getTable().getName(), join );
+ }
+ }
+ return joinsPerRealTableName;
+ }
+
+ public String getClassName() {
+ return persistentClass.getClassName();
+ }
+
+ public String getEntityOwnerClassName() {
+ return getClassName();
+ }
+
+ public Table getTable() {
+ return persistentClass.getTable();
+ }
+
+ public boolean isComponent() {
+ return false;
+ }
+
+ public boolean isEntity() {
+ return true;
+ }
+
+ public PersistentClass getPersistentClass() {
+ return persistentClass;
+ }
+
+ public KeyValue getIdentifier() {
+ return persistentClass.getIdentifier();
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CollectionPropertyHolder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CollectionPropertyHolder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CollectionPropertyHolder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,75 @@
+//$Id: CollectionPropertyHolder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import javax.persistence.JoinTable;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Table;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class CollectionPropertyHolder extends AbstractPropertyHolder {
+ Collection collection;
+
+ public CollectionPropertyHolder(
+ Collection collection, String path, XClass clazzToProcess, XProperty property,
+ PropertyHolder parentPropertyHolder, ExtendedMappings mappings
+ ) {
+ super( path, parentPropertyHolder, clazzToProcess, mappings );
+ this.collection = collection;
+ setCurrentProperty( property );
+ }
+
+ public String getClassName() {
+ throw new AssertionFailure( "Collection property holder does not have a class
name" );
+ }
+
+ public String getEntityOwnerClassName() {
+ return null;
+ }
+
+ public Table getTable() {
+ return collection.getCollectionTable();
+ }
+
+ public void addProperty(Property prop) {
+ throw new AssertionFailure( "Cannot add property to a collection" );
+ }
+
+ public KeyValue getIdentifier() {
+ throw new AssertionFailure( "Identifier collection not yet managed" );
+ }
+
+ public PersistentClass getPersistentClass() {
+ return collection.getOwner();
+ }
+
+ public boolean isComponent() {
+ return false;
+ }
+
+ public boolean isEntity() {
+ return false;
+ }
+
+ public String getEntityName() {
+ return collection.getOwner().getEntityName();
+ }
+
+ public void addProperty(Property prop, Ejb3Column[] columns) {
+ //Ejb3Column.checkPropertyConsistency( ); //already called earlier
+ throw new AssertionFailure( "addProperty to a join table of a collection: does it
make sense?" );
+ }
+
+ public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
+ throw new AssertionFailure( "Add a <join> in a second pass" );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ComponentPropertyHolder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ComponentPropertyHolder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ComponentPropertyHolder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,136 @@
+//$Id: ComponentPropertyHolder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import javax.persistence.Column;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Table;
+
+/**
+ * Component implementation of property holder
+ *
+ * @author Emmanuel Bernard
+ */
+public class ComponentPropertyHolder extends AbstractPropertyHolder {
+ //TODO introduce a overrideTable() method for columns held by sec table rather than the
hack
+ // joinsPerRealTableName in ClassPropertyHolder
+ private Component component;
+
+ public String getEntityName() {
+ return component.getComponentClassName();
+ }
+
+ public void addProperty(Property prop, Ejb3Column[] columns) {
+ //Ejb3Column.checkPropertyConsistency( ); //already called earlier
+ /*
+ * Check table matches between the component and the columns
+ * if not, change the component table if no properties are set
+ * if a property is set already the core cannot support that
+ */
+ Table table = columns[0].getTable();
+ if ( !table.equals( component.getTable() ) ) {
+ if ( component.getPropertySpan() == 0 ) {
+ component.setTable( table );
+ }
+ else {
+ throw new AnnotationException(
+ "A component cannot hold properties split into 2 different tables: "
+ + this.getPath()
+ );
+ }
+ }
+ addProperty( prop );
+ }
+
+ public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
+ return parent.addJoin( joinTableAnn, noDelayInPkColumnCreation );
+
+ }
+
+ public ComponentPropertyHolder(
+ Component component, String path, PropertyData inferredData, PropertyHolder parent,
+ ExtendedMappings mappings
+ ) {
+ super( path, parent, inferredData.getPropertyClass(), mappings );
+ setCurrentProperty( inferredData.getProperty() );
+ this.component = component;
+ }
+
+ public String getClassName() {
+ return component.getComponentClassName();
+ }
+
+ public String getEntityOwnerClassName() {
+ return component.getOwner().getClassName();
+ }
+
+ public Table getTable() {
+ return component.getTable();
+ }
+
+ public void addProperty(Property prop) {
+ component.addProperty( prop );
+ }
+
+ public KeyValue getIdentifier() {
+ return component.getOwner().getIdentifier();
+ }
+
+ public PersistentClass getPersistentClass() {
+ return component.getOwner();
+ }
+
+ public boolean isComponent() {
+ return true;
+ }
+
+ public boolean isEntity() {
+ return false;
+ }
+
+ public void setParentProperty(String parentProperty) {
+ component.setParentProperty( parentProperty );
+ }
+
+ @Override
+ public Column[] getOverriddenColumn(String propertyName) {
+ //FIXME this is yukky
+ Column[] result = super.getOverriddenColumn( propertyName );
+ if ( result == null ) {
+ String userPropertyName = extractUserPropertyName( "id", propertyName );
+ if ( userPropertyName != null ) result = super.getOverriddenColumn( userPropertyName
);
+ }
+ if ( result == null ) {
+ String userPropertyName = extractUserPropertyName( "_identifierMapper",
propertyName );
+ if ( userPropertyName != null ) result = super.getOverriddenColumn( userPropertyName
);
+ }
+ return result;
+ }
+
+ private String extractUserPropertyName(String redundantString, String propertyName) {
+ String result = null;
+ String className = component.getOwner().getClassName();
+ if ( propertyName.startsWith( className )
+ && propertyName.length() > className.length() + 2 +
redundantString.length() // .id.
+ && propertyName.substring(
+ className.length() + 1, className.length() + 1 + redundantString.length()
+ ).equals( redundantString )
+ ) {
+ //remove id we might be in a @IdCLass case
+ result = className + propertyName.substring( className.length() + 1 +
redundantString.length() );
+ }
+ return result;
+ }
+
+ @Override
+ public JoinColumn[] getOverriddenJoinColumn(String propertyName) {
+ return super.getOverriddenJoinColumn( propertyName );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/CreateKeySecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,37 @@
+//$Id: CreateKeySecondPass.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.mapping.JoinedSubclass;
+import org.hibernate.mapping.RootClass;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class CreateKeySecondPass implements SecondPass {
+ private RootClass rootClass;
+ private JoinedSubclass joinedSubClass;
+
+ public CreateKeySecondPass(RootClass rootClass) {
+ this.rootClass = rootClass;
+ }
+
+ public CreateKeySecondPass(JoinedSubclass joinedSubClass) {
+ this.joinedSubClass = joinedSubClass;
+ }
+
+ public void doSecondPass(Map persistentClasses) throws MappingException {
+ if ( rootClass != null ) {
+ rootClass.createPrimaryKey();
+ }
+ else if ( joinedSubClass != null ) {
+ joinedSubClass.createPrimaryKey();
+ joinedSubClass.createForeignKey();
+ }
+ else {
+ throw new AssertionError( "rootClass and joinedSubClass are null" );
+ }
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/DefaultComponentSafeNamingStrategy.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/DefaultComponentSafeNamingStrategy.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/DefaultComponentSafeNamingStrategy.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,77 @@
+//$Id: DefaultComponentSafeNamingStrategy.java 14736 2008-06-04 14:23:42Z
hardy.ferentschik $
+package org.hibernate.cfg;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class DefaultComponentSafeNamingStrategy extends EJB3NamingStrategy {
+ public static final NamingStrategy INSTANCE = new DefaultComponentSafeNamingStrategy();
+
+ protected static String addUnderscores(String name) {
+ return name.replace( '.', '_' ).toLowerCase();
+ }
+
+ @Override
+ public String propertyToColumnName(String propertyName) {
+ return addUnderscores( propertyName );
+ }
+
+ @Override
+ public String collectionTableName(
+ String ownerEntity, String ownerEntityTable, String associatedEntity, String
associatedEntityTable,
+ String propertyName
+ ) {
+ return tableName(
+ new StringBuilder( ownerEntityTable ).append( "_" )
+ .append(
+ associatedEntityTable != null ?
+ associatedEntityTable :
+ addUnderscores( propertyName )
+ ).toString()
+ );
+ }
+
+
+ public String foreignKeyColumnName(
+ String propertyName, String propertyEntityName, String propertyTableName, String
referencedColumnName
+ ) {
+ String header = propertyName != null ? addUnderscores( propertyName ) :
propertyTableName;
+ if ( header == null ) throw new AssertionFailure( "NamingStrategy not properly
filled" );
+ return columnName( header + "_" + referencedColumnName );
+ }
+
+ @Override
+ public String logicalColumnName(String columnName, String propertyName) {
+ return StringHelper.isNotEmpty( columnName ) ? columnName : propertyName;
+ }
+
+ @Override
+ public String logicalCollectionTableName(
+ String tableName, String ownerEntityTable, String associatedEntityTable, String
propertyName
+ ) {
+ if ( tableName != null ) {
+ return tableName;
+ }
+ else {
+ //use of a stringbuffer to workaround a JDK bug
+ return new StringBuffer( ownerEntityTable ).append( "_" )
+ .append(
+ associatedEntityTable != null ?
+ associatedEntityTable :
+ propertyName
+ ).toString();
+ }
+
+ }
+
+ @Override
+ public String logicalCollectionColumnName(String columnName, String propertyName, String
referencedColumn) {
+ return StringHelper.isNotEmpty( columnName ) ?
+ columnName :
+ propertyName + "_" + referencedColumn;
+ }
+
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3DTDEntityResolver.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,75 @@
+//$Id: EJB3DTDEntityResolver.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.io.InputStream;
+
+import org.hibernate.util.DTDEntityResolver;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class EJB3DTDEntityResolver extends DTDEntityResolver {
+ public static final EntityResolver INSTANCE = new EJB3DTDEntityResolver();
+
+ private final Logger log = LoggerFactory.getLogger( EJB3DTDEntityResolver.class );
+
+ boolean resolved = false;
+
+ public boolean isResolved() {
+ return resolved;
+ }
+
+ public InputSource resolveEntity(String publicId, String systemId) {
+ InputSource is = super.resolveEntity( publicId, systemId );
+ if ( is == null ) {
+ if ( systemId != null ) {
+ if ( systemId.endsWith( "orm_1_0.xsd" ) ) {
+ log.debug(
+ "recognized EJB3 ORM namespace; attempting to resolve on classpath under
org/hibernate/ejb"
+ );
+ String path = "org/hibernate/ejb/" + "orm_1_0.xsd";
+ InputStream dtdStream = resolveInHibernateNamespace( path );
+ if ( dtdStream == null ) {
+ log.debug( "unable to locate [{}] on classpath", systemId );
+ }
+ else {
+ log.debug( "located [{}] in classpath", systemId );
+ InputSource source = new InputSource( dtdStream );
+ source.setPublicId( publicId );
+ source.setSystemId( systemId );
+ resolved = false;
+ return source;
+ }
+ }
+ else if ( systemId.endsWith( "persistence_1_0.xsd" ) ) {
+ log.debug(
+ "recognized EJB3 ORM namespace; attempting to resolve on classpath under
org/hibernate/ejb"
+ );
+ String path = "org/hibernate/ejb/" + "persistence_1_0.xsd";
+ InputStream dtdStream = resolveInHibernateNamespace( path );
+ if ( dtdStream == null ) {
+ log.debug( "unable to locate [{}] on classpath", systemId );
+ }
+ else {
+ log.debug( "located [{}] in classpath", systemId );
+ InputSource source = new InputSource( dtdStream );
+ source.setPublicId( publicId );
+ source.setSystemId( systemId );
+ resolved = true;
+ return source;
+ }
+ }
+ }
+ }
+ else {
+ resolved = true;
+ return is;
+ }
+ //use the default behavior
+ return null;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3NamingStrategy.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3NamingStrategy.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/EJB3NamingStrategy.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,86 @@
+//$Id: EJB3NamingStrategy.java 14741 2008-06-05 11:25:56Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.io.Serializable;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Naming strategy implementing the EJB3 standards
+ *
+ * @author Emmanuel Bernard
+ */
+public class EJB3NamingStrategy implements NamingStrategy, Serializable {
+ public static final NamingStrategy INSTANCE = new EJB3NamingStrategy();
+
+ public String classToTableName(String className) {
+ return StringHelper.unqualify( className );
+ }
+
+ public String propertyToColumnName(String propertyName) {
+ return StringHelper.unqualify( propertyName );
+ }
+
+ public String tableName(String tableName) {
+ return tableName;
+ }
+
+ public String columnName(String columnName) {
+ return columnName;
+ }
+
+ public String collectionTableName(
+ String ownerEntity, String ownerEntityTable, String associatedEntity, String
associatedEntityTable,
+ String propertyName
+ ) {
+ return tableName(
+ new StringBuilder( ownerEntityTable ).append( "_" )
+ .append(
+ associatedEntityTable != null ?
+ associatedEntityTable :
+ StringHelper.unqualify( propertyName )
+ ).toString()
+ );
+ }
+
+ public String joinKeyColumnName(String joinedColumn, String joinedTable) {
+ return columnName( joinedColumn );
+ }
+
+ public String foreignKeyColumnName(
+ String propertyName, String propertyEntityName, String propertyTableName, String
referencedColumnName
+ ) {
+ String header = propertyName != null ? StringHelper.unqualify( propertyName ) :
propertyTableName;
+ if ( header == null ) throw new AssertionFailure( "NamingStrategy not properly
filled" );
+ return columnName( header + "_" + referencedColumnName );
+ }
+
+ public String logicalColumnName(String columnName, String propertyName) {
+ return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify(
propertyName );
+ }
+
+ public String logicalCollectionTableName(
+ String tableName,
+ String ownerEntityTable, String associatedEntityTable, String propertyName
+ ) {
+ if ( tableName != null ) {
+ return tableName;
+ }
+ else {
+ //use of a stringbuffer to workaround a JDK bug
+ return new StringBuffer( ownerEntityTable ).append( "_" )
+ .append(
+ associatedEntityTable != null ?
+ associatedEntityTable :
+ StringHelper.unqualify( propertyName )
+ ).toString();
+ }
+ }
+
+ public String logicalCollectionColumnName(String columnName, String propertyName, String
referencedColumn) {
+ return StringHelper.isNotEmpty( columnName ) ?
+ columnName :
+ StringHelper.unqualify( propertyName ) + "_" + referencedColumn;
+ }
+}
Added: annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3Column.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3Column.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3Column.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,461 @@
+//$Id: Ejb3Column.java 14748 2008-06-06 10:35:35Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.annotations.Index;
+import org.hibernate.cfg.annotations.Nullability;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Formula;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.StringHelper;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+/**
+ * Wrap state of an EJB3 @Column annotation
+ * and build the Hibernate column mapping element
+ *
+ * @author Emmanuel Bernard
+ */
+public class Ejb3Column {
+ private static final Logger log = LoggerFactory.getLogger( Ejb3Column.class );
+ private Column mappingColumn;
+ private boolean insertable = true;
+ private boolean updatable = true;
+ private String secondaryTableName;
+ protected Map<String, Join> joins;
+ protected PropertyHolder propertyHolder;
+ private ExtendedMappings mappings;
+ private boolean isImplicit;
+ public static final int DEFAULT_COLUMN_LENGTH = 255;
+ public String sqlType;
+ private int length = DEFAULT_COLUMN_LENGTH;
+ private int precision;
+ private int scale;
+ private String logicalColumnName;
+ private String propertyName;
+ private boolean unique;
+ private boolean nullable = true;
+ private String formulaString;
+ private Formula formula;
+ private Table table;
+
+ public void setTable(Table table) {
+ this.table = table;
+ }
+
+ public String getLogicalColumnName() {
+ return logicalColumnName;
+ }
+
+ public String getSqlType() {
+ return sqlType;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getPrecision() {
+ return precision;
+ }
+
+ public int getScale() {
+ return scale;
+ }
+
+ public boolean isUnique() {
+ return unique;
+ }
+
+ public String getFormulaString() {
+ return formulaString;
+ }
+
+ public String getSecondaryTableName() {
+ return secondaryTableName;
+ }
+
+ public void setFormula(String formula) {
+ this.formulaString = formula;
+ }
+
+ public boolean isImplicit() {
+ return isImplicit;
+ }
+
+ public void setInsertable(boolean insertable) {
+ this.insertable = insertable;
+ }
+
+ public void setUpdatable(boolean updatable) {
+ this.updatable = updatable;
+ }
+
+ protected ExtendedMappings getMappings() {
+ return mappings;
+ }
+
+ public void setMappings(ExtendedMappings mappings) {
+ this.mappings = mappings;
+ }
+
+ public void setImplicit(boolean implicit) {
+ isImplicit = implicit;
+ }
+
+ public void setSqlType(String sqlType) {
+ this.sqlType = sqlType;
+ }
+
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ public void setPrecision(int precision) {
+ this.precision = precision;
+ }
+
+ public void setScale(int scale) {
+ this.scale = scale;
+ }
+
+ public void setLogicalColumnName(String logicalColumnName) {
+ this.logicalColumnName = logicalColumnName;
+ }
+
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public void setUnique(boolean unique) {
+ this.unique = unique;
+ }
+
+ public boolean isNullable() {
+ return mappingColumn.isNullable();
+ }
+
+ public Ejb3Column() {
+ }
+
+ public void bind() {
+ if ( StringHelper.isNotEmpty( formulaString ) ) {
+ log.debug( "binding formula {}", formulaString );
+ formula = new Formula();
+ formula.setFormula( formulaString );
+ }
+ else {
+ initMappingColumn(
+ logicalColumnName, propertyName, length, precision, scale, nullable, sqlType,
unique, true
+ );
+ log.debug( "Binding column {}. Unique {}. Nullable {}.", new Object[]
{mappingColumn.getName(), unique, nullable});
+ }
+ }
+
+ protected void initMappingColumn(
+ String columnName, String propertyName, int length, int precision, int scale, boolean
nullable,
+ String sqlType, boolean unique, boolean applyNamingStrategy
+ ) {
+ this.mappingColumn = new Column();
+ redefineColumnName( columnName, propertyName, applyNamingStrategy );
+ this.mappingColumn.setLength( length );
+ if ( precision > 0 ) { //revelent precision
+ this.mappingColumn.setPrecision( precision );
+ this.mappingColumn.setScale( scale );
+ }
+ this.mappingColumn.setNullable( nullable );
+ this.mappingColumn.setSqlType( sqlType );
+ this.mappingColumn.setUnique( unique );
+ }
+
+ public boolean isNameDeferred() {
+ return mappingColumn == null || StringHelper.isEmpty( mappingColumn.getName() );
+ }
+
+ public void redefineColumnName(String columnName, String propertyName, boolean
applyNamingStrategy) {
+ if ( applyNamingStrategy ) {
+ if ( StringHelper.isEmpty( columnName ) ) {
+ if ( propertyName != null ) {
+ mappingColumn.setName( mappings.getNamingStrategy().propertyToColumnName(
propertyName ) );
+ }
+ //Do nothing otherwise
+ }
+ else {
+ mappingColumn.setName( mappings.getNamingStrategy().columnName( columnName ) );
+ }
+ }
+ else {
+ if ( StringHelper.isNotEmpty( columnName ) ) mappingColumn.setName( columnName );
+ }
+ }
+
+ public String getName() {
+ return mappingColumn.getName();
+ }
+
+ public Column getMappingColumn() {
+ return mappingColumn;
+ }
+
+ public boolean isInsertable() {
+ return insertable;
+ }
+
+ public boolean isUpdatable() {
+ return updatable;
+ }
+
+ public void setNullable(boolean nullable) {
+ if ( mappingColumn != null ) {
+ mappingColumn.setNullable( nullable );
+ }
+ else {
+ this.nullable = nullable;
+ }
+ }
+
+ public void setJoins(Map<String, Join> joins) {
+ this.joins = joins;
+ }
+
+ public PropertyHolder getPropertyHolder() {
+ return propertyHolder;
+ }
+
+ public void setPropertyHolder(PropertyHolder propertyHolder) {
+ this.propertyHolder = propertyHolder;
+ }
+
+ protected void setMappingColumn(Column mappingColumn) {
+ this.mappingColumn = mappingColumn;
+ }
+
+ public void linkWithValue(SimpleValue value) {
+ if ( formula != null ) {
+ value.addFormula( formula );
+ }
+ else {
+ getMappingColumn().setValue( value );
+ value.addColumn( getMappingColumn() );
+ value.getTable().addColumn( getMappingColumn() );
+ addColumnBinding( value );
+ table = value.getTable();
+ }
+ }
+
+ protected void addColumnBinding(SimpleValue value) {
+ String logicalColumnName = mappings.getNamingStrategy()
+ .logicalColumnName( this.logicalColumnName, propertyName );
+ mappings.addColumnBinding( logicalColumnName, getMappingColumn(), value.getTable() );
+ }
+
+ /**
+ * Find appropriate table of the column.
+ * It can come from a secondary table or from the main table of the persistent class
+ *
+ * @return appropriate table
+ * @throws AnnotationException missing secondary table
+ */
+ public Table getTable() {
+ if ( table != null ) return table; //association table
+ if ( isSecondary() ) {
+ return getJoin().getTable();
+ }
+ else {
+ return propertyHolder.getTable();
+ }
+ }
+
+ public boolean isSecondary() {
+ if ( propertyHolder == null ) {
+ throw new AssertionFailure( "Should not call getTable() on column wo persistent
class defined" );
+ }
+ if ( StringHelper.isNotEmpty( secondaryTableName ) ) {
+ return true;
+ }
+ // else {
+ return false;
+ }
+
+ public Join getJoin() {
+ Join join = joins.get( secondaryTableName );
+ if ( join == null ) {
+ throw new AnnotationException(
+ "Cannot find the expected secondary table: no "
+ + secondaryTableName + " available for " +
propertyHolder.getClassName()
+ );
+ }
+ else {
+ return join;
+ }
+ }
+
+ public void forceNotNull() {
+ mappingColumn.setNullable( false );
+ }
+
+ public void setSecondaryTableName(String secondaryTableName) {
+ this.secondaryTableName = secondaryTableName;
+ }
+
+ public static Ejb3Column[] buildColumnFromAnnotation(
+ javax.persistence.Column[] anns,
+ org.hibernate.annotations.Formula formulaAnn, Nullability nullability, PropertyHolder
propertyHolder,
+ PropertyData inferredData,
+ Map<String, Join> secondaryTables,
+ ExtendedMappings mappings
+ ) {
+ Ejb3Column[] columns;
+ if ( formulaAnn != null ) {
+ Ejb3Column formulaColumn = new Ejb3Column();
+ formulaColumn.setFormula( formulaAnn.value() );
+ formulaColumn.setImplicit( false );
+ formulaColumn.setMappings( mappings );
+ formulaColumn.setPropertyHolder( propertyHolder );
+ formulaColumn.bind();
+ columns = new Ejb3Column[] { formulaColumn };
+ }
+ else {
+ javax.persistence.Column[] actualCols = anns;
+ javax.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn(
+ StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
+ );
+ if ( overriddenCols != null ) {
+ //check for overridden first
+ if ( anns != null && overriddenCols.length != anns.length ) {
+ throw new AnnotationException( "AttributeOverride.column() should override all
columns for now" );
+ }
+ actualCols = overriddenCols.length == 0 ? null : overriddenCols;
+ log.debug( "Column(s) overridden for property {}",
inferredData.getPropertyName() );
+ }
+ if ( actualCols == null ) {
+ columns = buildImplicitColumn( inferredData, secondaryTables, propertyHolder,
nullability, mappings );
+ }
+ else {
+ final int length = actualCols.length;
+ columns = new Ejb3Column[length];
+ for (int index = 0; index < length; index++) {
+ javax.persistence.Column col = actualCols[index];
+ String sqlType = col.columnDefinition().equals( "" ) ? null :
col.columnDefinition();
+ Ejb3Column column = new Ejb3Column();
+ column.setImplicit( false );
+ column.setSqlType( sqlType );
+ column.setLength( col.length() );
+ column.setPrecision( col.precision() );
+ column.setScale( col.scale() );
+ column.setLogicalColumnName( col.name() );
+ column.setPropertyName(
+ BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
+ );
+ column.setNullable(
+ col.nullable()
+ ); //TODO force to not null if available? This is a (bad) user choice.
+ column.setUnique( col.unique() );
+ column.setInsertable( col.insertable() );
+ column.setUpdatable( col.updatable() );
+ column.setSecondaryTableName( col.table() );
+ column.setPropertyHolder( propertyHolder );
+ column.setJoins( secondaryTables );
+ column.setMappings( mappings );
+ column.bind();
+ columns[index] = column;
+ }
+ }
+ }
+ return columns;
+ }
+
+ private static Ejb3Column[] buildImplicitColumn(
+ PropertyData inferredData, Map<String, Join> secondaryTables, PropertyHolder
propertyHolder,
+ Nullability nullability, ExtendedMappings mappings
+ ) {
+ Ejb3Column[] columns;
+ columns = new Ejb3Column[1];
+ Ejb3Column column = new Ejb3Column();
+ column.setImplicit( false );
+ //not following the spec but more clean
+ if ( nullability != Nullability.FORCED_NULL
+ && inferredData.getClassOrElement().isPrimitive()
+ && !inferredData.getProperty().isArray() ) {
+ column.setNullable( false );
+ }
+ column.setLength( DEFAULT_COLUMN_LENGTH );
+ column.setPropertyName(
+ BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
+ );
+ column.setPropertyHolder( propertyHolder );
+ column.setJoins( secondaryTables );
+ column.setMappings( mappings );
+ column.bind();
+ columns[0] = column;
+ return columns;
+ }
+
+ public static void checkPropertyConsistency(Ejb3Column[] columns, String propertyName)
{
+ int nbrOfColumns = columns.length;
+ if ( nbrOfColumns > 1 ) {
+ for (int currentIndex = 1; currentIndex < nbrOfColumns; currentIndex++) {
+ if ( columns[currentIndex].isInsertable() != columns[currentIndex - 1].isInsertable()
) {
+ throw new AnnotationException(
+ "Mixing insertable and non insertable columns in a property is not allowed:
" + propertyName
+ );
+ }
+ if ( columns[currentIndex].isNullable() != columns[currentIndex - 1].isNullable() )
{
+ throw new AnnotationException(
+ "Mixing nullable and non nullable columns in a property is not allowed:
" + propertyName
+ );
+ }
+ if ( columns[currentIndex].isUpdatable() != columns[currentIndex - 1].isUpdatable() )
{
+ throw new AnnotationException(
+ "Mixing updatable and non updatable columns in a property is not allowed:
" + propertyName
+ );
+ }
+ if ( !columns[currentIndex].getTable().equals( columns[currentIndex - 1].getTable() )
) {
+ throw new AnnotationException(
+ "Mixing different tables in a property is not allowed: " + propertyName
+ );
+ }
+ }
+ }
+ }
+
+ public void addIndex(Index index, boolean inSecondPass) {
+ if ( index == null ) return;
+ String indexName = index.name();
+ addIndex( indexName, inSecondPass );
+ }
+
+ void addIndex(String indexName, boolean inSecondPass) {
+ IndexOrUniqueKeySecondPass secondPass = new IndexOrUniqueKeySecondPass( indexName,
this, mappings, false );
+ if ( inSecondPass ) {
+ secondPass.doSecondPass( mappings.getClasses() );
+ }
+ else {
+ mappings.addSecondPass(
+ secondPass
+ );
+ }
+ }
+
+ void addUniqueKey(String uniqueKeyName, boolean inSecondPass) {
+ IndexOrUniqueKeySecondPass secondPass = new IndexOrUniqueKeySecondPass( uniqueKeyName,
this, mappings, true );
+ if ( inSecondPass ) {
+ secondPass.doSecondPass( mappings.getClasses() );
+ }
+ else {
+ mappings.addSecondPass(
+ secondPass
+ );
+ }
+ }
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3DiscriminatorColumn.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3DiscriminatorColumn.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3DiscriminatorColumn.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,82 @@
+//$Id: Ejb3DiscriminatorColumn.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.DiscriminatorType;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.annotations.DiscriminatorFormula;
+
+/**
+ * Discriminator column
+ *
+ * @author Emmanuel Bernard
+ */
+public class Ejb3DiscriminatorColumn extends Ejb3Column {
+
+
+ private static final String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "DTYPE";
+ private static final String DEFAULT_DISCRIMINATOR_TYPE = "string";
+
+ private String discriminatorTypeName;
+ private static final int DEFAULT_DISCRIMINATOR_LENGTH = 31;
+
+ public Ejb3DiscriminatorColumn() {
+ //discriminator default value
+ super();
+ setLogicalColumnName( DEFAULT_DISCRIMINATOR_COLUMN_NAME );
+ setNullable( false );
+ setDiscriminatorTypeName( DEFAULT_DISCRIMINATOR_TYPE );
+ setLength( DEFAULT_DISCRIMINATOR_LENGTH );
+ }
+
+ public String getDiscriminatorTypeName() {
+ return discriminatorTypeName;
+ }
+
+ public void setDiscriminatorTypeName(String discriminatorTypeName) {
+ this.discriminatorTypeName = discriminatorTypeName;
+ }
+
+ public static Ejb3DiscriminatorColumn buildDiscriminatorColumn(
+ DiscriminatorType type, DiscriminatorColumn discAnn, DiscriminatorFormula
discFormulaAnn,
+ ExtendedMappings mappings
+ ) {
+ Ejb3DiscriminatorColumn discriminatorColumn = new Ejb3DiscriminatorColumn();
+ discriminatorColumn.setMappings( mappings );
+ discriminatorColumn.setImplicit( true );
+ if ( discFormulaAnn != null ) {
+ discriminatorColumn.setImplicit( false );
+ discriminatorColumn.setFormula( discFormulaAnn.value() );
+ }
+ else if ( discAnn != null ) {
+ discriminatorColumn.setImplicit( false );
+ if ( !BinderHelper.isDefault( discAnn.columnDefinition() ) ) {
+ discriminatorColumn.setSqlType(
+ discAnn.columnDefinition()
+ );
+ }
+ if ( !BinderHelper.isDefault( discAnn.name() ) ) {
+ discriminatorColumn.setLogicalColumnName( discAnn.name() );
+ }
+ discriminatorColumn.setNullable( false );
+ }
+ if ( DiscriminatorType.CHAR.equals( type ) ) {
+ discriminatorColumn.setDiscriminatorTypeName( "character" );
+ discriminatorColumn.setImplicit( false );
+ }
+ else if ( DiscriminatorType.INTEGER.equals( type ) ) {
+ discriminatorColumn.setDiscriminatorTypeName( "integer" );
+ discriminatorColumn.setImplicit( false );
+ }
+ else if ( DiscriminatorType.STRING.equals( type ) || type == null ) {
+ if ( discAnn != null ) discriminatorColumn.setLength( discAnn.length() );
+ discriminatorColumn.setDiscriminatorTypeName( "string" );
+ }
+ else {
+ throw new AssertionFailure( "Unknown discriminator type: " + type );
+ }
+ discriminatorColumn.bind();
+ return discriminatorColumn;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,530 @@
+//$Id: Ejb3JoinColumn.java 14761 2008-06-11 13:51:06Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.persistence.JoinColumn;
+import javax.persistence.PrimaryKeyJoinColumn;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.common.util.StringHelper;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.Value;
+
+/**
+ * Wrap state of an EJB3 @JoinColumn annotation
+ * and build the Hibernate column mapping element
+ *
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings("unchecked")
+public class Ejb3JoinColumn extends Ejb3Column {
+ /**
+ * property name repated to this column
+ */
+ private String referencedColumn;
+ private String mappedBy;
+ //property name on the mapped by side if any
+ private String mappedByPropertyName;
+ //table name on the mapped by side if any
+ private String mappedByTableName;
+ private String mappedByEntityName;
+
+ //FIXME hacky solution to get the information at property ref resolution
+ public String getManyToManyOwnerSideEntityName() {
+ return manyToManyOwnerSideEntityName;
+ }
+
+ public void setManyToManyOwnerSideEntityName(String manyToManyOwnerSideEntityName) {
+ this.manyToManyOwnerSideEntityName = manyToManyOwnerSideEntityName;
+ }
+
+ private String manyToManyOwnerSideEntityName;
+
+ public void setReferencedColumn(String referencedColumn) {
+ this.referencedColumn = referencedColumn;
+ }
+
+ public String getMappedBy() {
+ return mappedBy;
+ }
+
+ public void setMappedBy(String mappedBy) {
+ this.mappedBy = mappedBy;
+ }
+
+ //Due to @AnnotationOverride overriding rules, I don't want the constructor to be
public
+ private Ejb3JoinColumn() {
+ setMappedBy( BinderHelper.ANNOTATION_STRING_DEFAULT );
+ }
+
+ //Due to @AnnotationOverride overriding rules, I don't want the constructor to be
public
+ //TODO get rid of it and use setters
+ private Ejb3JoinColumn(
+ String sqlType,
+ String name,
+ boolean nullable,
+ boolean unique,
+ boolean insertable,
+ boolean updatable,
+ String referencedColumn,
+ String secondaryTable,
+ Map<String, Join> joins,
+ PropertyHolder propertyHolder,
+ String propertyName,
+ String mappedBy,
+ boolean isImplicit,
+ ExtendedMappings mappings
+ ) {
+ super();
+ setImplicit( isImplicit );
+ setSqlType( sqlType );
+ setLogicalColumnName( name );
+ setNullable( nullable );
+ setUnique( unique );
+ setInsertable( insertable );
+ setUpdatable( updatable );
+ setSecondaryTableName( secondaryTable );
+ setPropertyHolder( propertyHolder );
+ setJoins( joins );
+ setMappings( mappings );
+ setPropertyName( BinderHelper.getRelativePath( propertyHolder, propertyName ) );
+ bind();
+ this.referencedColumn = referencedColumn;
+ this.mappedBy = mappedBy;
+ }
+
+ public String getReferencedColumn() {
+ return referencedColumn;
+ }
+
+ public static Ejb3JoinColumn[] buildJoinColumns(
+ JoinColumn[] anns,
+ String mappedBy, Map<String, Join> joins,
+ PropertyHolder propertyHolder,
+ String propertyName,
+ ExtendedMappings mappings
+ ) {
+ JoinColumn[] actualColumns = propertyHolder.getOverriddenJoinColumn(
+ StringHelper.qualify( propertyHolder.getPath(), propertyName )
+ );
+ if ( actualColumns == null ) actualColumns = anns;
+ if ( actualColumns == null || actualColumns.length == 0 ) {
+ return new Ejb3JoinColumn[] {
+ buildJoinColumn( (JoinColumn) null, mappedBy, joins, propertyHolder, propertyName,
mappings )
+ };
+ }
+ else {
+ int size = actualColumns.length;
+ Ejb3JoinColumn[] result = new Ejb3JoinColumn[size];
+ for (int index = 0; index < size; index++) {
+ result[index] = buildJoinColumn(
+ actualColumns[index],
+ mappedBy,
+ joins,
+ propertyHolder,
+ propertyName,
+ mappings
+ );
+ }
+ return result;
+ }
+ }
+
+ /**
+ * build join column for SecondaryTables
+ */
+ private static Ejb3JoinColumn buildJoinColumn(
+ JoinColumn ann,
+ String mappedBy, Map<String, Join> joins,
+ PropertyHolder propertyHolder,
+ String propertyName,
+ ExtendedMappings mappings
+ ) {
+ if ( ann != null ) {
+ if ( BinderHelper.isDefault( mappedBy ) ) {
+ throw new AnnotationException(
+ "Illegal attempt to define a @JoinColumn with a mappedBy association: "
+ + BinderHelper.getRelativePath( propertyHolder, propertyName )
+ );
+ }
+ Ejb3JoinColumn joinColumn = new Ejb3JoinColumn();
+ joinColumn.setJoinAnnotation( ann, null );
+ joinColumn.setJoins( joins );
+ joinColumn.setPropertyHolder( propertyHolder );
+ joinColumn.setPropertyName( BinderHelper.getRelativePath( propertyHolder, propertyName
) );
+ joinColumn.setImplicit( false );
+ joinColumn.setMappings( mappings );
+ joinColumn.bind();
+ return joinColumn;
+ }
+ else {
+ Ejb3JoinColumn joinColumn = new Ejb3JoinColumn();
+ joinColumn.setMappedBy( mappedBy );
+ joinColumn.setJoins( joins );
+ joinColumn.setPropertyHolder( propertyHolder );
+ joinColumn.setPropertyName( BinderHelper.getRelativePath( propertyHolder, propertyName
) );
+ joinColumn.setImplicit( true );
+ joinColumn.setMappings( mappings );
+ joinColumn.bind();
+ return joinColumn;
+ }
+ }
+
+
+ //FIXME default name still useful in association table
+ public void setJoinAnnotation(JoinColumn annJoin, String defaultName) {
+ if ( annJoin == null ) {
+ setImplicit( true );
+ }
+ else {
+ setImplicit( false );
+ if ( !BinderHelper.isDefault( annJoin.columnDefinition() ) ) setSqlType(
annJoin.columnDefinition() );
+ if ( !BinderHelper.isDefault( annJoin.name() ) ) setLogicalColumnName( annJoin.name()
);
+ setNullable( annJoin.nullable() );
+ setUnique( annJoin.unique() );
+ setInsertable( annJoin.insertable() );
+ setUpdatable( annJoin.updatable() );
+ setReferencedColumn( annJoin.referencedColumnName() );
+ setSecondaryTableName( annJoin.table() );
+ }
+ }
+
+ /**
+ * Build JoinColumn for a JOINED hierarchy
+ */
+ public static Ejb3JoinColumn buildJoinColumn(
+ PrimaryKeyJoinColumn pkJoinAnn,
+ JoinColumn joinAnn,
+ Value identifier,
+ Map<String, Join> joins,
+ PropertyHolder propertyHolder, ExtendedMappings mappings
+ ) {
+
+ Column col = (Column) identifier.getColumnIterator().next();
+ String defaultName = mappings.getLogicalColumnName( col.getQuotedName(),
identifier.getTable() );
+ if ( pkJoinAnn != null || joinAnn != null ) {
+ String colName;
+ String columnDefinition;
+ String referencedColumnName;
+ if ( pkJoinAnn != null ) {
+ colName = pkJoinAnn.name();
+ columnDefinition = pkJoinAnn.columnDefinition();
+ referencedColumnName = pkJoinAnn.referencedColumnName();
+ }
+ else {
+ colName = joinAnn.name();
+ columnDefinition = joinAnn.columnDefinition();
+ referencedColumnName = joinAnn.referencedColumnName();
+ }
+ String sqlType = "".equals( columnDefinition ) ? null : columnDefinition;
+ String name = "".equals( colName ) ? defaultName : colName;
+ return new Ejb3JoinColumn(
+ sqlType,
+ name, false, false,
+ true, true,
+ referencedColumnName,
+ null, joins,
+ propertyHolder, null, null, false, mappings
+ );
+ }
+ else {
+ return new Ejb3JoinColumn(
+ (String) null, defaultName,
+ false, false, true, true, null, (String) null,
+ joins, propertyHolder, null, null, true, mappings
+ );
+ }
+ }
+
+ /**
+ * Override persistent class on oneToMany Cases for late settings
+ * Must only be used on second level pass binding
+ */
+ public void setPersistentClass(PersistentClass persistentClass, Map<String, Join>
joins) {
+ //FIXME shouldn't we deduce the classname from the persistentclasS?
+ this.propertyHolder = PropertyHolderBuilder.buildPropertyHolder( persistentClass,
joins, getMappings() );
+ }
+
+ public static void checkIfJoinColumn(Object columns, PropertyHolder holder, PropertyData
property) {
+ if ( !( columns instanceof Ejb3JoinColumn[] ) ) {
+ throw new AnnotationException(
+ "@Column cannot be used on an association property: "
+ + holder.getEntityName()
+ + "."
+ + property.getPropertyName()
+ );
+ }
+ }
+
+ public void linkValueUsingDefaultColumnNaming(
+ Column referencedColumn, PersistentClass referencedEntity, SimpleValue value
+ ) {
+ String columnName;
+ String logicalReferencedColumn = getMappings().getLogicalColumnName(
+ referencedColumn.getQuotedName(), referencedEntity.getTable()
+ );
+ boolean mappedBySide = mappedByTableName != null || mappedByPropertyName != null;
+ boolean ownerSide = getPropertyName() != null;
+
+ Boolean isRefColumnQuoted = StringHelper.isQuoted( logicalReferencedColumn );
+ String unquotedLogicalReferenceColumn = isRefColumnQuoted ?
+ StringHelper.unquote( logicalReferencedColumn ) :
+ logicalReferencedColumn;
+
+ if ( mappedBySide ) {
+ String unquotedMappedbyTable = StringHelper.unquote( mappedByTableName );
+ columnName = getMappings().getNamingStrategy().foreignKeyColumnName(
+ mappedByPropertyName,
+ mappedByEntityName,
+ unquotedMappedbyTable,
+ unquotedLogicalReferenceColumn
+ );
+ //one element was quoted so we quote
+ if ( isRefColumnQuoted || StringHelper.isQuoted( mappedByTableName ) ) {
+ columnName = StringHelper.quote( columnName );
+ }
+ }
+ else if ( ownerSide ) {
+ String logicalTableName = getMappings().getLogicalTableName(
referencedEntity.getTable() );
+ String unquotedLogicalTableName = StringHelper.unquote( logicalTableName );
+ columnName = getMappings().getNamingStrategy().foreignKeyColumnName(
+ getPropertyName(),
+ referencedEntity.getEntityName(),
+ unquotedLogicalTableName,
+ unquotedLogicalReferenceColumn
+ );
+ //one element was quoted so we quote
+ if ( isRefColumnQuoted || StringHelper.isQuoted( logicalTableName ) ) {
+ columnName = StringHelper.quote( columnName );
+ }
+ }
+ else {
+ //is an intra-entity hierarchy table join so copy the name by default
+ String logicalTableName = getMappings().getLogicalTableName(
referencedEntity.getTable() );
+ String unquotedLogicalTableName = StringHelper.unquote( logicalTableName );
+ columnName = getMappings().getNamingStrategy().joinKeyColumnName(
+ unquotedLogicalReferenceColumn,
+ unquotedLogicalTableName
+ );
+ //one element was quoted so we quote
+ if ( isRefColumnQuoted || StringHelper.isQuoted( logicalTableName ) ) {
+ columnName = StringHelper.quote( columnName );
+ }
+ }
+ //yuk side effect on an implicit column
+ setLogicalColumnName( columnName );
+ setReferencedColumn( logicalReferencedColumn );
+ initMappingColumn(
+ columnName,
+ null, referencedColumn.getLength(),
+ referencedColumn.getPrecision(),
+ referencedColumn.getScale(),
+ getMappingColumn().isNullable(),
+ referencedColumn.getSqlType(),
+ getMappingColumn().isUnique(), false
+ );
+ linkWithValue( value );
+ }
+
+ /**
+ * used for mappedBy cases
+ */
+ public void linkValueUsingAColumnCopy(Column column, SimpleValue value) {
+ initMappingColumn(
+ //column.getName(),
+ column.getQuotedName(),
+ null, column.getLength(),
+ column.getPrecision(),
+ column.getScale(),
+ getMappingColumn().isNullable(),
+ column.getSqlType(),
+ getMappingColumn().isUnique(),
+ false //We do copy no strategy here
+ );
+ linkWithValue( value );
+ }
+
+ protected void addColumnBinding(SimpleValue value) {
+ if ( StringHelper.isEmpty( mappedBy ) ) {
+ String unquotedLogColName = StringHelper.unquote( getLogicalColumnName() );
+ String unquotedRefColumn = StringHelper.unquote( getReferencedColumn() );
+ String logicalColumnName = getMappings().getNamingStrategy()
+ .logicalCollectionColumnName( unquotedLogColName, getPropertyName(),
unquotedRefColumn );
+ if ( StringHelper.isQuoted( getLogicalColumnName() ) || StringHelper.isQuoted(
getLogicalColumnName() ) ) {
+ logicalColumnName = StringHelper.quote( logicalColumnName );
+ }
+ getMappings().addColumnBinding( logicalColumnName, getMappingColumn(),
value.getTable() );
+ }
+ }
+
+ //keep it JDK 1.4 compliant
+ //implicit way
+ public static final int NO_REFERENCE = 0;
+ //reference to the pk in an explicit order
+ public static final int PK_REFERENCE = 1;
+ //reference to non pk columns
+ public static final int NON_PK_REFERENCE = 2;
+
+ public static int checkReferencedColumnsType(
+ Ejb3JoinColumn[] columns, PersistentClass referencedEntity,
+ ExtendedMappings mappings
+ ) {
+ //convenient container to find whether a column is an id one or not
+ Set<Column> idColumns = new HashSet<Column>();
+ Iterator idColumnsIt = referencedEntity.getKey().getColumnIterator();
+ while ( idColumnsIt.hasNext() ) {
+ idColumns.add( (Column) idColumnsIt.next() );
+ }
+
+ boolean isFkReferencedColumnName = false;
+ boolean noReferencedColumn = true;
+ //build the list of potential tables
+ if ( columns.length == 0 ) return NO_REFERENCE; //shortcut
+ Object columnOwner = BinderHelper.findColumnOwner(
+ referencedEntity, columns[0].getReferencedColumn(), mappings
+ );
+ if ( columnOwner == null ) {
+ try {
+ throw new MappingException(
+ "Unable to find column with logical name: "
+ + columns[0].getReferencedColumn() + " in " +
referencedEntity.getTable() + " and its related "
+ + "supertables and secondary tables"
+ );
+ }
+ catch (MappingException e) {
+ throw new RecoverableException(e);
+ }
+ }
+ Table matchingTable = columnOwner instanceof PersistentClass ?
+ ( (PersistentClass) columnOwner ).getTable() :
+ ( (Join) columnOwner ).getTable();
+ //check each referenced column
+ for (Ejb3JoinColumn ejb3Column : columns) {
+ String logicalReferencedColumnName = ejb3Column.getReferencedColumn();
+ if ( StringHelper.isNotEmpty( logicalReferencedColumnName ) ) {
+ String referencedColumnName = null;
+ try {
+ referencedColumnName = mappings.getPhysicalColumnName( logicalReferencedColumnName,
matchingTable );
+ }
+ catch (MappingException me) {
+ //rewrite the exception
+ throw new MappingException(
+ "Unable to find column with logical name: "
+ + logicalReferencedColumnName + " in " + matchingTable.getName()
+ );
+ }
+ noReferencedColumn = false;
+ Column refCol = new Column( referencedColumnName );
+ boolean contains = idColumns.contains( refCol );
+ if ( !contains ) {
+ isFkReferencedColumnName = true;
+ break; //we know the state
+ }
+ }
+ }
+ if ( isFkReferencedColumnName ) {
+ return NON_PK_REFERENCE;
+ }
+ else if ( noReferencedColumn ) {
+ return NO_REFERENCE;
+ }
+ else if ( idColumns.size() != columns.length ) {
+ //reference use PK but is a subset or a superset
+ return NON_PK_REFERENCE;
+ }
+ else {
+ return PK_REFERENCE;
+ }
+ }
+
+ /**
+ * Called to apply column definitions from the referenced FK column to this column.
+ *
+ * @param column the referenced column.
+ */
+ public void overrideFromReferencedColumnIfNecessary(org.hibernate.mapping.Column column)
{
+
+ // columnDefinition can also be specified using @JoinColumn, hence we have to check
+ // whether it is set or not
+ if ( StringHelper.isEmpty( sqlType ) ) {
+ sqlType = column.getSqlType();
+ if ( getMappingColumn() != null ) getMappingColumn().setSqlType( sqlType );
+ }
+
+ // these properties can only be applied on the referenced column - we can just take
them over
+ getMappingColumn().setLength(column.getLength());
+ getMappingColumn().setPrecision(column.getPrecision());
+ getMappingColumn().setScale(column.getScale());
+ }
+
+ @Override
+ public void redefineColumnName(String columnName, String propertyName, boolean
applyNamingStrategy) {
+ if ( StringHelper.isNotEmpty( columnName ) ) {
+ getMappingColumn().setName(
+ applyNamingStrategy ?
+ getMappings().getNamingStrategy().columnName( columnName ) :
+ columnName
+ );
+ }
+ }
+
+ public static Ejb3JoinColumn[] buildJoinTableJoinColumns(
+ JoinColumn[] annJoins, Map<String, Join> secondaryTables,
+ PropertyHolder propertyHolder, String propertyName, String mappedBy, ExtendedMappings
mappings
+ ) {
+ Ejb3JoinColumn[] joinColumns;
+ if ( annJoins == null ) {
+ Ejb3JoinColumn currentJoinColumn = new Ejb3JoinColumn();
+ currentJoinColumn.setImplicit( true );
+ currentJoinColumn.setNullable( false ); //I break the spec, but it's for good
+ currentJoinColumn.setPropertyHolder( propertyHolder );
+ currentJoinColumn.setJoins( secondaryTables );
+ currentJoinColumn.setMappings( mappings );
+ currentJoinColumn.setPropertyName(
+ BinderHelper.getRelativePath( propertyHolder, propertyName )
+ );
+ currentJoinColumn.setMappedBy( mappedBy );
+ currentJoinColumn.bind();
+
+ joinColumns = new Ejb3JoinColumn[] {
+ currentJoinColumn
+
+ };
+ }
+ else {
+ joinColumns = new Ejb3JoinColumn[annJoins.length];
+ JoinColumn annJoin;
+ int length = annJoins.length;
+ for (int index = 0; index < length; index++) {
+ annJoin = annJoins[index];
+ Ejb3JoinColumn currentJoinColumn = new Ejb3JoinColumn();
+ currentJoinColumn.setImplicit( true );
+ currentJoinColumn.setPropertyHolder( propertyHolder );
+ currentJoinColumn.setJoins( secondaryTables );
+ currentJoinColumn.setMappings( mappings );
+ currentJoinColumn.setPropertyName( BinderHelper.getRelativePath( propertyHolder,
propertyName ) );
+ currentJoinColumn.setMappedBy( mappedBy );
+ currentJoinColumn.setJoinAnnotation( annJoin, propertyName );
+ currentJoinColumn.setNullable( false ); //I break the spec, but it's for good
+ //done after the annotation to override it
+ currentJoinColumn.bind();
+ joinColumns[index] = currentJoinColumn;
+ }
+ }
+ return joinColumns;
+ }
+
+ public void setMappedBy(String entityName, String logicalTableName, String
mappedByProperty) {
+ this.mappedByEntityName = entityName;
+ this.mappedByTableName = logicalTableName;
+ this.mappedByPropertyName = mappedByProperty;
+ }
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ExtendedMappings.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ExtendedMappings.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ExtendedMappings.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,282 @@
+//$Id: ExtendedMappings.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import javax.persistence.Embeddable;
+import javax.persistence.Entity;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.AnyMetaDef;
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.mapping.IdGenerator;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Table;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+/**
+ * Allow annotation related mappings
+ * <p/>
+ * at least for named generators
+ *
+ * @author Emmanuel Bernard
+ */
+public class ExtendedMappings extends Mappings {
+
+ private final Logger log = LoggerFactory.getLogger( ExtendedMappings.class );
+
+ private final Map<String, IdGenerator> namedGenerators;
+ private final Map<String, Map<String, Join>> joins;
+ private final Map<String, AnnotatedClassType> classTypes;
+ private final Map<String, Properties> generatorTables;
+ private final Map<Table, List<String[]>> tableUniqueConstraints;
+ private final Map<String, String> mappedByResolver;
+ private final Map<String, String> propertyRefResolver;
+ private final ReflectionManager reflectionManager;
+ private final Set<String> defaultNamedQueryNames;
+ private final Set<String> defaultNamedNativeQueryNames;
+ private final Set<String> defaultSqlResulSetMappingNames;
+ private final Set<String> defaultNamedGenerators;
+ private final Map<String, AnyMetaDef> anyMetaDefs;
+
+ ExtendedMappings(
+ Map classes, Map collections, Map tables, Map queries, Map sqlqueries, Map
sqlResultSetMappings,
+ Set<String> defaultNamedQueryNames, Set<String>
defaultNamedNativeQueryNames,
+ Set<String> defaultSqlResulSetMappingNames, Set<String>
defaultNamedGenerators, Map imports,
+ List secondPasses, List propertyReferences, NamingStrategy namingStrategy, Map
typeDefs,
+ Map filterDefinitions, Map namedGenerators, Map<String, Map<String, Join>>
joins, Map<String,
+ AnnotatedClassType> classTypes, Map extendsQueue, Map<String,
TableDescription> tableNameBinding,
+ Map<Table, ColumnNames> columnNameBindingPerTable,
+ final List auxiliaryDatabaseObjects,
+ Map<String, Properties> generatorTables,
+ Map<Table, List<String[]>> tableUniqueConstraints,
+ Map<String, String> mappedByResolver,
+ Map<String, String> propertyRefResolver,
+ Map<String, AnyMetaDef> anyMetaDefs,
+ ReflectionManager reflectionManager
+ ) {
+ super(
+ classes,
+ collections,
+ tables,
+ queries,
+ sqlqueries,
+ sqlResultSetMappings,
+ imports,
+ secondPasses,
+ propertyReferences,
+ namingStrategy,
+ typeDefs,
+ filterDefinitions,
+ extendsQueue,
+ auxiliaryDatabaseObjects,
+ tableNameBinding,
+ columnNameBindingPerTable
+ );
+ this.namedGenerators = namedGenerators;
+ this.joins = joins;
+ this.classTypes = classTypes;
+ this.generatorTables = generatorTables;
+ this.tableUniqueConstraints = tableUniqueConstraints;
+ this.mappedByResolver = mappedByResolver;
+ this.propertyRefResolver = propertyRefResolver;
+ this.reflectionManager = reflectionManager;
+ this.defaultNamedQueryNames = defaultNamedQueryNames;
+ this.defaultNamedNativeQueryNames = defaultNamedNativeQueryNames;
+ this.defaultSqlResulSetMappingNames = defaultSqlResulSetMappingNames;
+ this.defaultNamedGenerators = defaultNamedGenerators;
+ this.anyMetaDefs = anyMetaDefs;
+ }
+
+ public void addGenerator(IdGenerator generator) throws MappingException {
+ if ( !defaultNamedGenerators.contains( generator.getName() ) ) {
+ Object old = namedGenerators.put( generator.getName(), generator );
+ if ( old != null ) log.warn( "duplicate generator name: {}",
generator.getName() );
+ }
+ }
+
+ public void addJoins(PersistentClass persistentClass, Map<String, Join> joins)
throws MappingException {
+ Object old = this.joins.put( persistentClass.getEntityName(), joins );
+ if ( old != null ) log.warn( "duplicate joins for class: {}",
persistentClass.getEntityName() );
+ }
+
+ public AnnotatedClassType addClassType(XClass clazz) {
+ AnnotatedClassType type;
+ if ( clazz.isAnnotationPresent( Entity.class ) ) {
+ type = AnnotatedClassType.ENTITY;
+ }
+ else if ( clazz.isAnnotationPresent( Embeddable.class ) ) {
+ type = AnnotatedClassType.EMBEDDABLE;
+ }
+ else if ( clazz.isAnnotationPresent( MappedSuperclass.class ) ) {
+ type = AnnotatedClassType.EMBEDDABLE_SUPERCLASS;
+ }
+ else {
+ type = AnnotatedClassType.NONE;
+ }
+ classTypes.put( clazz.getName(), type );
+ return type;
+ }
+
+ /**
+ * get and maintain a cache of class type.
+ * A class can be an entity, a embedded objet or nothing.
+ */
+ public AnnotatedClassType getClassType(XClass clazz) {
+ AnnotatedClassType type = classTypes.get( clazz.getName() );
+ if ( type == null ) {
+ return addClassType( clazz );
+ }
+ else {
+ return type;
+ }
+ }
+
+ public IdGenerator getGenerator(String name) {
+ return getGenerator( name, null );
+ }
+
+ public Map<String, Join> getJoins(String persistentClass) {
+ return joins.get( persistentClass );
+ }
+
+ /**
+ * Try to find the generator from the localGenerators
+ * and then from the global generator list
+ *
+ * @param name generator name
+ * @param localGenerators local generators to find to
+ * @return the appropriate idgenerator or null if not found
+ */
+ public IdGenerator getGenerator(String name, Map<String, IdGenerator>
localGenerators) {
+ if ( localGenerators != null ) {
+ IdGenerator result = localGenerators.get( name );
+ if ( result != null ) return result;
+ }
+ return namedGenerators.get( name );
+ }
+
+ public void addGeneratorTable(String name, Properties params) {
+ Object old = generatorTables.put( name, params );
+ if ( old != null ) log.warn( "duplicate generator table: {}", name );
+ }
+
+ public Properties getGeneratorTableProperties(String name, Map<String, Properties>
localGeneratorTables) {
+ if ( localGeneratorTables != null ) {
+ Properties result = localGeneratorTables.get( name );
+ if ( result != null ) return result;
+ }
+ return generatorTables.get( name );
+ }
+
+ public void addUniqueConstraints(Table table, List uniqueConstraints) {
+ List oldConstraints = tableUniqueConstraints.get( table );
+ if ( oldConstraints == null ) {
+ oldConstraints = new ArrayList();
+ tableUniqueConstraints.put( table, oldConstraints );
+ }
+ oldConstraints.addAll( uniqueConstraints );
+ }
+
+ public Map<Table, List<String[]>> getTableUniqueConstraints() {
+ return tableUniqueConstraints;
+ }
+
+ public void addMappedBy(String entityName, String propertyName, String
inversePropertyName) {
+ mappedByResolver.put( entityName + "." + propertyName, inversePropertyName
);
+ }
+
+ public String getFromMappedBy(String entityName, String propertyName) {
+ return mappedByResolver.get( entityName + "." + propertyName );
+ }
+
+ public void addPropertyReferencedAssociation(String entityName, String propertyName,
String propertyRef) {
+ propertyRefResolver.put( entityName + "." + propertyName, propertyRef );
+ }
+
+ public String getPropertyReferencedAssociation(String entityName, String propertyName)
{
+ return propertyRefResolver.get( entityName + "." + propertyName );
+ }
+
+ @Override
+ public void addUniquePropertyReference(String referencedClass, String propertyName) {
+ super.addUniquePropertyReference( referencedClass, propertyName );
+ }
+
+ @Override
+ public void addPropertyReference(String referencedClass, String propertyName) {
+ super.addPropertyReference( referencedClass, propertyName );
+ }
+
+ public ReflectionManager getReflectionManager() {
+ return reflectionManager;
+ }
+
+ public void addDefaultQuery(String name, NamedQueryDefinition query) {
+ super.addQuery( name, query );
+ defaultNamedQueryNames.add( name );
+ }
+
+ public void addDefaultSQLQuery(String name, NamedSQLQueryDefinition query) {
+ super.addSQLQuery( name, query );
+ defaultNamedNativeQueryNames.add( name );
+ }
+
+ public void addDefaultGenerator(IdGenerator idGen) {
+ this.addGenerator( idGen );
+ defaultNamedGenerators.add( idGen.getName() );
+
+ }
+
+ public void addDefaultResultSetMapping(ResultSetMappingDefinition definition) {
+ final String name = definition.getName();
+ if ( !defaultSqlResulSetMappingNames.contains( name )
+ && super.getResultSetMapping( name ) != null ) {
+ resultSetMappings.remove( name );
+ }
+ super.addResultSetMapping( definition );
+ defaultSqlResulSetMappingNames.add( name );
+ }
+
+ @Override
+ public void addQuery(String name, NamedQueryDefinition query) throws MappingException {
+ if ( !defaultNamedQueryNames.contains( name ) ) super.addQuery( name, query );
+ }
+
+ @Override
+ public void addResultSetMapping(ResultSetMappingDefinition definition) {
+ if ( !defaultSqlResulSetMappingNames.contains( definition.getName() ) )
+ super.addResultSetMapping( definition );
+ }
+
+ @Override
+ public void addSQLQuery(String name, NamedSQLQueryDefinition query) throws
MappingException {
+ if ( !defaultNamedNativeQueryNames.contains( name ) ) super.addSQLQuery( name, query
);
+ }
+
+ public Map getClasses() {
+ return classes;
+ }
+
+ public void addAnyMetaDef(AnyMetaDef defAnn) {
+ if ( anyMetaDefs.containsKey( defAnn.name() ) ) {
+ throw new AnnotationException( "Two @AnyMetaDef with the same name defined:
" + defAnn.name() );
+ }
+ anyMetaDefs.put( defAnn.name(), defAnn );
+ }
+
+ public AnyMetaDef getAnyMetaDef(String name) {
+ return anyMetaDefs.get( name );
+ }
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/FkSecondPass.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/FkSecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/FkSecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,56 @@
+//$Id: FkSecondPass.java 14779 2008-06-18 17:56:27Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Value;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class FkSecondPass implements SecondPass {
+ protected SimpleValue value;
+ protected Ejb3JoinColumn[] columns;
+ /**
+ * unique counter is needed to differentiate 2 instances of FKSecondPass
+ * as they are compared.
+ * Fairly hacky but IBM VM sometimes returns the same hashCode for 2 different objects
+ * TODO is it doable to rely on the Ejb3JoinColumn names? Not sure at they could be
inferred
+ */
+ private int uniqueCounter;
+ private static AtomicInteger globalCounter = new AtomicInteger();
+
+ public FkSecondPass(SimpleValue value, Ejb3JoinColumn[] columns) {
+ this.value = value;
+ this.columns = columns;
+ this.uniqueCounter = globalCounter.getAndIncrement();
+ }
+
+ public int getUniqueCounter() {
+ return uniqueCounter;
+ }
+
+ public Value getValue() {
+ return value;
+ }
+
+ public boolean equals(Object o) {
+ if ( this == o ) return true;
+ if ( !( o instanceof FkSecondPass ) ) return false;
+
+ FkSecondPass that = (FkSecondPass) o;
+
+ if ( uniqueCounter != that.uniqueCounter ) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return uniqueCounter;
+ }
+
+ public abstract String getReferencedEntityName();
+
+ public abstract boolean isInPrimaryKey();
+}
Added: annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexColumn.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexColumn.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexColumn.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,87 @@
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.mapping.Join;
+
+/**
+ * index column
+ *
+ * @author inger
+ */
+public class IndexColumn
+ extends Ejb3Column {
+
+ private int base;
+
+ //FIXME move to a getter setter strategy for readeability
+ public IndexColumn(
+ boolean isImplicit,
+ String sqlType,
+ int length,
+ int precision,
+ int scale,
+ String name,
+ boolean nullable,
+ boolean unique,
+ boolean insertable,
+ boolean updatable,
+ String secondaryTableName,
+ Map<String, Join> joins,
+ PropertyHolder propertyHolder,
+ ExtendedMappings mappings
+ ) {
+ super();
+ setImplicit( isImplicit );
+ setSqlType( sqlType );
+ setLength( length );
+ setPrecision( precision );
+ setScale( scale );
+ setLogicalColumnName( name );
+ setNullable( nullable );
+ setUnique( unique );
+ setInsertable( insertable );
+ setUpdatable( updatable );
+ setSecondaryTableName( secondaryTableName );
+ setPropertyHolder( propertyHolder );
+ setJoins( joins );
+ setMappings( mappings );
+ bind();
+ //super(isImplicit, sqlType, length, precision, scale, name, nullable, unique,
insertable, updatable, secondaryTableName, joins, propertyHolder, mappings);
+
+ }
+
+ public int getBase() {
+ return base;
+ }
+
+ public void setBase(int base) {
+ this.base = base;
+ }
+
+ public static IndexColumn buildColumnFromAnnotation(
+ org.hibernate.annotations.IndexColumn ann,
+ PropertyHolder propertyHolder,
+ PropertyData inferredData,
+ ExtendedMappings mappings
+ ) {
+ IndexColumn column;
+ if ( ann != null ) {
+ String sqlType = BinderHelper.isDefault( ann.columnDefinition() ) ? null :
ann.columnDefinition();
+ String name = BinderHelper.isDefault( ann.name() ) ? inferredData.getPropertyName() :
ann.name();
+ //TODO move it to a getter based system and remove the constructor
+ column = new IndexColumn(
+ false, sqlType, 0, 0, 0, name, ann.nullable(),
+ false, true, true, null, null, propertyHolder, mappings
+ );
+ column.setBase( ann.base() );
+ }
+ else {
+ column = new IndexColumn(
+ true, null, 0, 0, 0, null, true,
+ false, true, true, null, null, propertyHolder, mappings
+ );
+ }
+ return column;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexOrUniqueKeySecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexOrUniqueKeySecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/IndexOrUniqueKeySecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,81 @@
+//$Id: IndexOrUniqueKeySecondPass.java 14747 2008-06-06 08:16:25Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.MappingException;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class IndexOrUniqueKeySecondPass implements SecondPass {
+ private Table table;
+ private final String indexName;
+ private final String[] columns;
+ private final ExtendedMappings mappings;
+ private final Ejb3Column column;
+ private final boolean unique;
+
+ /**
+ * Build an index
+ */
+ public IndexOrUniqueKeySecondPass(Table table, String indexName, String[] columns,
ExtendedMappings mappings) {
+ this.table = table;
+ this.indexName = indexName;
+ this.columns = columns;
+ this.mappings = mappings;
+ this.column = null;
+ this.unique = false;
+ }
+
+ /**
+ * Build an index
+ */
+ public IndexOrUniqueKeySecondPass(String indexName, Ejb3Column column, ExtendedMappings
mappings) {
+ this( indexName, column, mappings, false );
+ }
+
+ /**
+ * Build an index if unique is false or a Unique Key if unique is true
+ */
+ public IndexOrUniqueKeySecondPass(String indexName, Ejb3Column column,
+ ExtendedMappings mappings, boolean unique) {
+ this.indexName = indexName;
+ this.column = column;
+ this.columns = null;
+ this.mappings = mappings;
+ this.unique = unique;
+ }
+
+ public void doSecondPass(Map persistentClasses) throws MappingException {
+ if ( columns != null ) {
+ for (String columnName : columns) {
+ addConstraintToColumn( columnName );
+ }
+ }
+ if ( column != null ) {
+ this.table = column.getTable();
+ addConstraintToColumn( mappings.getLogicalColumnName(
column.getMappingColumn().getQuotedName(), table ) );
+ }
+ }
+
+ private void addConstraintToColumn(String columnName) {
+ Column column = table.getColumn(
+ new Column(
+ mappings.getPhysicalColumnName( columnName, table )
+ )
+ );
+ if ( column == null ) {
+ throw new AnnotationException(
+ "@Index references a unknown column: " + columnName
+ );
+ }
+ if ( unique )
+ table.getOrCreateUniqueKey( indexName ).addColumn( column );
+ else
+ table.getOrCreateIndex( indexName ).addColumn( column );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/InheritanceState.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/InheritanceState.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/InheritanceState.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,90 @@
+//$Id: InheritanceState.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.MappedSuperclass;
+
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.annotations.common.reflection.XClass;
+
+/**
+ * Some extra data to the inheritance position of a class
+ *
+ * @author Emmanuel Bernard
+ */
+public class InheritanceState {
+ public InheritanceState(XClass clazz) {
+ this.clazz = clazz;
+ extractInheritanceType();
+ }
+
+ public XClass clazz;
+ /**
+ * has son either mappedsuperclass son or entity son
+ */
+ public boolean hasSons = false;
+ /**
+ * a mother entity is available
+ */
+ public boolean hasParents = false;
+ public InheritanceType type;
+ public boolean isEmbeddableSuperclass = false;
+
+ /**
+ * only defined on embedded superclasses
+ */
+ public String accessType = null;
+ public Boolean isPropertyAnnotated;
+
+ private void extractInheritanceType() {
+ XAnnotatedElement element = clazz;
+ Inheritance inhAnn = element.getAnnotation( Inheritance.class );
+ MappedSuperclass mappedSuperClass = element.getAnnotation( MappedSuperclass.class );
+ if ( mappedSuperClass != null ) {
+ isEmbeddableSuperclass = true;
+ type = inhAnn == null ? null : inhAnn.strategy();
+ }
+ else {
+ type = inhAnn == null ? InheritanceType.SINGLE_TABLE : inhAnn.strategy();
+ }
+ }
+
+ boolean hasTable() {
+ return !hasParents || !InheritanceType.SINGLE_TABLE.equals( type );
+ }
+
+ boolean hasDenormalizedTable() {
+ return hasParents && InheritanceType.TABLE_PER_CLASS.equals( type );
+ }
+
+ public static InheritanceState getSuperEntityInheritanceState(
+ XClass clazz, Map<XClass, InheritanceState> states,
+ ReflectionManager reflectionManager
+ ) {
+ XClass superclass = clazz;
+ do {
+ superclass = superclass.getSuperclass();
+ InheritanceState currentState = states.get( superclass );
+ if ( currentState != null && !currentState.isEmbeddableSuperclass ) return
currentState;
+ }
+ while ( superclass != null && !reflectionManager.equals( superclass,
Object.class ) );
+ return null;
+ }
+
+ public static InheritanceState getSuperclassInheritanceState(
+ XClass clazz, Map<XClass, InheritanceState> states,
+ ReflectionManager reflectionManager
+ ) {
+ XClass superclass = clazz;
+ do {
+ superclass = superclass.getSuperclass();
+ InheritanceState currentState = states.get( superclass );
+ if ( currentState != null ) return currentState;
+ }
+ while ( superclass != null && !reflectionManager.equals( superclass,
Object.class ) );
+ return null;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/JoinedSubclassFkSecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/JoinedSubclassFkSecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/JoinedSubclassFkSecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,36 @@
+//$Id: JoinedSubclassFkSecondPass.java 14779 2008-06-18 17:56:27Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.cfg.annotations.TableBinder;
+import org.hibernate.mapping.JoinedSubclass;
+import org.hibernate.mapping.SimpleValue;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings({"serial", "unchecked"})
+public class JoinedSubclassFkSecondPass extends FkSecondPass {
+ private JoinedSubclass entity;
+ private ExtendedMappings mappings;
+
+ public JoinedSubclassFkSecondPass(JoinedSubclass entity, Ejb3JoinColumn[]
inheritanceJoinedColumns, SimpleValue key, ExtendedMappings mappings) {
+ super( key, inheritanceJoinedColumns );
+ this.entity = entity;
+ this.mappings = mappings;
+ }
+
+ public String getReferencedEntityName() {
+ return entity.getSuperclass().getEntityName();
+ }
+
+ public boolean isInPrimaryKey() {
+ return true;
+ }
+
+ public void doSecondPass(Map persistentClasses) throws MappingException {
+ TableBinder.bindFk( entity.getSuperclass(), entity, columns, value, false, mappings );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/NotYetImplementedException.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/NotYetImplementedException.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/NotYetImplementedException.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,25 @@
+//$Id: NotYetImplementedException.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import org.hibernate.MappingException;
+
+/**
+ * Mapping not yet implemented
+ *
+ * @author Emmanuel Bernard
+ */
+public class NotYetImplementedException extends MappingException {
+
+ public NotYetImplementedException(String msg, Throwable root) {
+ super( msg, root );
+ }
+
+ public NotYetImplementedException(Throwable root) {
+ super( root );
+ }
+
+ public NotYetImplementedException(String s) {
+ super( s );
+ }
+
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,263 @@
+//$Id: OneToOneSecondPass.java 14759 2008-06-10 14:14:15Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.ForeignKey;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.cfg.annotations.PropertyBinder;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.ManyToOne;
+import org.hibernate.mapping.OneToOne;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.type.ForeignKeyDirection;
+import org.hibernate.util.StringHelper;
+
+/**
+ * We have to handle OneToOne in a second pass because:
+ * -
+ */
+public class OneToOneSecondPass implements SecondPass {
+ private String mappedBy;
+ private ExtendedMappings mappings;
+ private String ownerEntity;
+ private String ownerProperty;
+ private PropertyHolder propertyHolder;
+ private boolean ignoreNotFound;
+ private PropertyData inferredData;
+ private XClass targetEntity;
+ private boolean cascadeOnDelete;
+ private boolean optional;
+ private String cascadeStrategy;
+ private Ejb3JoinColumn[] joinColumns;
+
+ //that suck, we should read that from the property mainly
+ public OneToOneSecondPass(
+ String mappedBy, String ownerEntity, String ownerProperty,
+ PropertyHolder propertyHolder, PropertyData inferredData, XClass targetEntity, boolean
ignoreNotFound,
+ boolean cascadeOnDelete, boolean optional, String cascadeStrategy, Ejb3JoinColumn[]
columns,
+ ExtendedMappings mappings
+ ) {
+ this.ownerEntity = ownerEntity;
+ this.ownerProperty = ownerProperty;
+ this.mappedBy = mappedBy;
+ this.propertyHolder = propertyHolder;
+ this.mappings = mappings;
+ this.ignoreNotFound = ignoreNotFound;
+ this.inferredData = inferredData;
+ this.targetEntity = targetEntity;
+ this.cascadeOnDelete = cascadeOnDelete;
+ this.optional = optional;
+ this.cascadeStrategy = cascadeStrategy;
+ this.joinColumns = columns;
+ }
+
+ //TODO refactor this code, there is a lot of duplication in this method
+ public void doSecondPass(Map persistentClasses) throws MappingException {
+ org.hibernate.mapping.OneToOne value = new org.hibernate.mapping.OneToOne(
+ propertyHolder.getTable(), propertyHolder.getPersistentClass()
+ );
+ final String propertyName = inferredData.getPropertyName();
+ value.setPropertyName( propertyName );
+ String referencedEntityName;
+ if ( AnnotationBinder.isDefault( targetEntity, mappings ) ) {
+ referencedEntityName = inferredData.getClassOrElementName();
+ }
+ else {
+ referencedEntityName = targetEntity.getName();
+ }
+ value.setReferencedEntityName( referencedEntityName );
+ AnnotationBinder.defineFetchingStrategy( value, inferredData.getProperty() );
+ //value.setFetchMode( fetchMode );
+ value.setCascadeDeleteEnabled( cascadeOnDelete );
+ //value.setLazy( fetchMode != FetchMode.JOIN );
+
+ if ( !optional ) value.setConstrained( true );
+ value.setForeignKeyType(
+ value.isConstrained() ?
+ ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT :
+ ForeignKeyDirection.FOREIGN_KEY_TO_PARENT
+ );
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( propertyName );
+ binder.setValue( value );
+ binder.setCascade( cascadeStrategy );
+ binder.setPropertyAccessorName( inferredData.getDefaultAccess() );
+ Property prop = binder.make();
+ if ( BinderHelper.isDefault( mappedBy ) ) {
+ /*
+ * we need to check if the columns are in the right order
+ * if not, then we need to create a many to one and formula
+ * but actually, since entities linked by a one to one need
+ * to share the same composite id class, this cannot happen in hibernate
+ */
+ boolean rightOrder = true;
+
+ if ( rightOrder ) {
+ String path = StringHelper.qualify( propertyHolder.getPath(), propertyName );
+ ( new ToOneFkSecondPass(
+ value, joinColumns,
+ !optional, //cannot have nullabe and unique on certain DBs
+ propertyHolder.getEntityOwnerClassName(),
+ path, mappings
+ ) ).doSecondPass( persistentClasses );
+ //no column associated since its a one to one
+ propertyHolder.addProperty( prop );
+ }
+ else {
+ //this is a many to one with Formula
+
+ }
+ }
+ else {
+ PersistentClass otherSide = (PersistentClass) persistentClasses.get(
value.getReferencedEntityName() );
+ Property otherSideProperty;
+ try {
+ if ( otherSide == null ) {
+ throw new MappingException( "Unable to find entity: " +
value.getReferencedEntityName() );
+ }
+ otherSideProperty = BinderHelper.findPropertyByName( otherSide, mappedBy );
+ }
+ catch (MappingException e) {
+ throw new AnnotationException(
+ "Unknown mappedBy in: " + StringHelper.qualify( ownerEntity,
ownerProperty )
+ + ", referenced property unknown: "
+ + StringHelper.qualify( value.getReferencedEntityName(), mappedBy )
+ );
+ }
+ if ( otherSideProperty == null ) {
+ throw new AnnotationException(
+ "Unknown mappedBy in: " + StringHelper.qualify( ownerEntity,
ownerProperty )
+ + ", referenced property unknown: "
+ + StringHelper.qualify( value.getReferencedEntityName(), mappedBy )
+ );
+ }
+ if ( otherSideProperty.getValue() instanceof OneToOne ) {
+ propertyHolder.addProperty( prop );
+ }
+ else if ( otherSideProperty.getValue() instanceof ManyToOne ) {
+ Iterator it = otherSide.getJoinIterator();
+ Join otherSideJoin = null;
+ while ( it.hasNext() ) {
+ otherSideJoin = (Join) it.next();
+ if ( otherSideJoin.containsProperty( otherSideProperty ) ) {
+ break;
+ }
+ }
+ if ( otherSideJoin != null ) {
+ //@OneToOne @JoinTable
+ Join mappedByJoin = buildJoinFromMappedBySide(
+ (PersistentClass) persistentClasses.get( ownerEntity ), otherSideProperty,
otherSideJoin
+ );
+ ManyToOne manyToOne = new ManyToOne( mappedByJoin.getTable() );
+ //FIXME use ignore not found here
+ manyToOne.setIgnoreNotFound( ignoreNotFound );
+ manyToOne.setCascadeDeleteEnabled( value.isCascadeDeleteEnabled() );
+ manyToOne.setEmbedded( value.isEmbedded() );
+ manyToOne.setFetchMode( value.getFetchMode() );
+ manyToOne.setLazy( value.isLazy() );
+ manyToOne.setReferencedEntityName( value.getReferencedEntityName() );
+ manyToOne.setUnwrapProxy( value.isUnwrapProxy() );
+ prop.setValue( manyToOne );
+ Iterator otherSideJoinKeyColumns = otherSideJoin.getKey().getColumnIterator();
+ while ( otherSideJoinKeyColumns.hasNext() ) {
+ Column column = (Column) otherSideJoinKeyColumns.next();
+ Column copy = new Column();
+ copy.setLength( column.getLength() );
+ copy.setScale( column.getScale() );
+ copy.setValue( manyToOne );
+ copy.setName( column.getQuotedName() );
+ copy.setNullable( column.isNullable() );
+ copy.setPrecision( column.getPrecision() );
+ copy.setUnique( column.isUnique() );
+ copy.setSqlType( column.getSqlType() );
+ copy.setCheckConstraint( column.getCheckConstraint() );
+ copy.setComment( column.getComment() );
+ copy.setDefaultValue( column.getDefaultValue() );
+ manyToOne.addColumn( copy );
+ }
+ mappedByJoin.addProperty( prop );
+ }
+ else {
+ propertyHolder.addProperty( prop );
+ }
+
+ value.setReferencedPropertyName( mappedBy );
+
+ String propertyRef = value.getReferencedPropertyName();
+ if ( propertyRef != null ) {
+ mappings.addUniquePropertyReference(
+ value.getReferencedEntityName(),
+ propertyRef
+ );
+ }
+ }
+ else {
+ throw new AnnotationException(
+ "Referenced property not a (One|Many)ToOne: "
+ + StringHelper.qualify(
+ otherSide.getEntityName(), mappedBy
+ )
+ + " in mappedBy of "
+ + StringHelper.qualify( ownerEntity, ownerProperty )
+ );
+ }
+ }
+ ForeignKey fk = inferredData.getProperty().getAnnotation( ForeignKey.class );
+ String fkName = fk != null ? fk.name() : "";
+ if ( !BinderHelper.isDefault( fkName ) ) value.setForeignKeyName( fkName );
+ }
+
+ /**
+ * Builds the <code>Join</code> instance for the mapped by side of a
<i>OneToOne</i> association using
+ * a join tables.
+ * <p>
+ * Note:<br/>
+ * <ul>
+ * <li>From the mappedBy side we should not create the PK nor the FK, this is
handled from the other side.</li>
+ * <li>This method is a dirty dupe of EntityBinder.bindSecondaryTable</i>.
+ * </p>
+ */
+ private Join buildJoinFromMappedBySide(PersistentClass persistentClass, Property
otherSideProperty, Join originalJoin) {
+ Join join = new Join();
+ join.setPersistentClass( persistentClass );
+
+ //no check constraints available on joins
+ join.setTable( originalJoin.getTable() );
+ join.setInverse( true );
+ SimpleValue key = new DependantValue( join.getTable(), persistentClass.getIdentifier()
);
+ //TODO support @ForeignKey
+ join.setKey( key );
+ join.setSequentialSelect( false );
+ //TODO support for inverse and optional
+ join.setOptional( true ); //perhaps not quite per-spec, but a Good Thing anyway
+ key.setCascadeDeleteEnabled( false );
+ Iterator mappedByColumns = otherSideProperty.getValue().getColumnIterator();
+ while ( mappedByColumns.hasNext() ) {
+ Column column = (Column) mappedByColumns.next();
+ Column copy = new Column();
+ copy.setLength( column.getLength() );
+ copy.setScale( column.getScale() );
+ copy.setValue( key );
+ copy.setName( column.getQuotedName() );
+ copy.setNullable( column.isNullable() );
+ copy.setPrecision( column.getPrecision() );
+ copy.setUnique( column.isUnique() );
+ copy.setSqlType( column.getSqlType() );
+ copy.setCheckConstraint( column.getCheckConstraint() );
+ copy.setComment( column.getComment() );
+ copy.setDefaultValue( column.getDefaultValue() );
+ key.addColumn( copy );
+ }
+ persistentClass.addJoin( join );
+ return join;
+ }
+}
+
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyData.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyData.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyData.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,42 @@
+package org.hibernate.cfg;
+
+import org.hibernate.MappingException;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+
+public interface PropertyData {
+
+ /**
+ * @return default member access (whether field or property)
+ * @throws MappingException No getter or field found or wrong JavaBean spec usage
+ */
+ public String getDefaultAccess();
+
+ /**
+ * @return property name
+ * @throws MappingException No getter or field found or wrong JavaBean spec usage
+ */
+ public String getPropertyName() throws MappingException;
+
+ /**
+ * Returns the returned class itself or the element type if an array
+ */
+ public XClass getClassOrElement() throws MappingException;
+
+ /**
+ * Return the class itself
+ */
+ public XClass getPropertyClass() throws MappingException;
+
+ /**
+ * Returns the returned class name itself or the element type if an array
+ */
+ public String getClassOrElementName() throws MappingException;
+
+ /**
+ * Returns the returned class name itself
+ */
+ public String getTypeName() throws MappingException;
+
+ public XProperty getProperty();
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolder.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,54 @@
+package org.hibernate.cfg;
+
+import javax.persistence.Column;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Table;
+
+/**
+ * Property holder abstract property containers from their direct implementation
+ *
+ * @author Emmanuel Bernard
+ */
+public interface PropertyHolder {
+ String getClassName();
+
+ String getEntityOwnerClassName();
+
+ Table getTable();
+
+ void addProperty(Property prop);
+
+ KeyValue getIdentifier();
+
+ PersistentClass getPersistentClass();
+
+ boolean isComponent();
+
+ boolean isEntity();
+
+ void setParentProperty(String parentProperty);
+
+ String getPath();
+
+ /**
+ * return null if the column is not overridden, or an array of column if true
+ */
+ Column[] getOverriddenColumn(String propertyName);
+
+ /**
+ * return null if the column is not overridden, or an array of column if true
+ */
+ JoinColumn[] getOverriddenJoinColumn(String propertyName);
+
+ String getEntityName();
+
+ void addProperty(Property prop, Ejb3Column[] columns);
+
+ Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation);
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolderBuilder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolderBuilder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyHolderBuilder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,67 @@
+//$Id: PropertyHolderBuilder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.annotations.EntityBinder;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+
+/**
+ * This factory is here ot build a PropertyHolder and prevent .mapping interface adding
+ *
+ * @author Emmanuel Bernard
+ */
+public final class PropertyHolderBuilder {
+ private PropertyHolderBuilder() {
+ }
+
+ public static PropertyHolder buildPropertyHolder(
+ XClass clazzToProcess,
+ PersistentClass persistentClass,
+ EntityBinder entityBinder,
+ //Map<String, Join> joins,
+ ExtendedMappings mappings
+ ) {
+ return new ClassPropertyHolder( persistentClass, clazzToProcess, entityBinder, mappings
);
+ }
+
+ /**
+ * build a component property holder
+ *
+ * @param component component to wrap
+ * @param path component path
+ * @param mappings
+ * @return PropertyHolder
+ */
+ public static PropertyHolder buildPropertyHolder(
+ Component component, String path, PropertyData inferredData, PropertyHolder parent,
+ ExtendedMappings mappings
+ ) {
+ return new ComponentPropertyHolder( component, path, inferredData, parent, mappings );
+ }
+
+ /**
+ * buid a property holder on top of a collection
+ */
+ public static PropertyHolder buildPropertyHolder(
+ Collection collection, String path, XClass clazzToProcess, XProperty property,
+ PropertyHolder parentPropertyHolder, ExtendedMappings mappings
+ ) {
+ return new CollectionPropertyHolder( collection, path, clazzToProcess, property,
parentPropertyHolder, mappings );
+ }
+
+ /**
+ * must only be used on second level phases (<join> has to be settled already)
+ */
+ public static PropertyHolder buildPropertyHolder(
+ PersistentClass persistentClass, Map<String, Join> joins,
+ ExtendedMappings mappings
+ ) {
+ return new ClassPropertyHolder( persistentClass, null, joins, mappings );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyInferredData.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyInferredData.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyInferredData.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,72 @@
+//$Id: PropertyInferredData.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import org.hibernate.MappingException;
+import org.hibernate.annotations.AccessType;
+import org.hibernate.annotations.Target;
+import org.hibernate.annotations.common.reflection.ReflectionManager;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+
+/**
+ * Retrieve all inferred data from an annnoted element
+ *
+ * @author Emmanuel Bernard
+ * @author Paolo Perrotta
+ */
+public class PropertyInferredData implements PropertyData {
+ private final String defaultAccess;
+
+ private final XProperty property;
+ private final ReflectionManager reflectionManager;
+
+ /**
+ * Take the annoted element for lazy process
+ */
+ public PropertyInferredData(XProperty property, String propertyAccessor,
ReflectionManager reflectionManager) {
+ this.property = property;
+ this.defaultAccess = propertyAccessor;
+ this.reflectionManager = reflectionManager;
+ }
+
+ public String getDefaultAccess() throws MappingException {
+ // if(skip())
+ // return defaultAccess;
+ AccessType access = property.getAnnotation( AccessType.class );
+ return access != null ? access.value() : defaultAccess;
+ }
+
+ public String getPropertyName() throws MappingException {
+ return property.getName();
+ }
+
+ public XClass getPropertyClass() throws MappingException {
+ if ( property.isAnnotationPresent( Target.class ) ) {
+ return reflectionManager.toXClass( property.getAnnotation( Target.class ).value() );
+ }
+ else {
+ return property.getType();
+ }
+ }
+
+ public XClass getClassOrElement() throws MappingException {
+ if ( property.isAnnotationPresent( Target.class ) ) {
+ return reflectionManager.toXClass( property.getAnnotation( Target.class ).value() );
+ }
+ else {
+ return property.getClassOrElementClass();
+ }
+ }
+
+ public String getClassOrElementName() throws MappingException {
+ return getClassOrElement().getName();
+ }
+
+ public String getTypeName() throws MappingException {
+ return getPropertyClass().getName();
+ }
+
+ public XProperty getProperty() {
+ return property;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/PropertyPreloadedData.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,48 @@
+//$Id: PropertyPreloadedData.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import org.hibernate.MappingException;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+
+public class PropertyPreloadedData implements PropertyData {
+ private final String defaultAccess;
+
+ private final String propertyName;
+
+ private final XClass returnedClass;
+
+ public PropertyPreloadedData(String defaultAccess, String propertyName, XClass
returnedClass) {
+ this.defaultAccess = defaultAccess;
+ this.propertyName = propertyName;
+ this.returnedClass = returnedClass;
+ }
+
+ public String getDefaultAccess() throws MappingException {
+ return defaultAccess;
+ }
+
+ public String getPropertyName() throws MappingException {
+ return propertyName;
+ }
+
+ public XClass getClassOrElement() throws MappingException {
+ return getPropertyClass();
+ }
+
+ public XClass getPropertyClass() throws MappingException {
+ return returnedClass;
+ }
+
+ public String getClassOrElementName() throws MappingException {
+ return getTypeName();
+ }
+
+ public String getTypeName() throws MappingException {
+ return returnedClass == null ? null : returnedClass.getName();
+ }
+
+ public XProperty getProperty() {
+ return null; //instead of UnsupportedOperationException
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/RecoverableException.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/RecoverableException.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/RecoverableException.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,25 @@
+//$
+package org.hibernate.cfg;
+
+import org.hibernate.AnnotationException;
+
+/**
+ * Should neven be exposed to the client
+ * An exception that wrap an underlying exception whith the hope
+ * subsequent processing will recover from it.
+ *
+ * @author Emmanuel Bernard
+ */
+public class RecoverableException extends AnnotationException {
+ public RecoverableException(String msg, Throwable root) {
+ super( msg, root );
+ }
+
+ public RecoverableException(Throwable root) {
+ super( root );
+ }
+
+ public RecoverableException(String s) {
+ super( s );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/SecondaryTableSecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/SecondaryTableSecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/SecondaryTableSecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,28 @@
+//$Id: SecondaryTableSecondPass.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Map;
+
+import org.hibernate.MappingException;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.cfg.annotations.EntityBinder;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class SecondaryTableSecondPass implements SecondPass {
+ private EntityBinder entityBinder;
+ private PropertyHolder propertyHolder;
+ private XAnnotatedElement annotatedClass;
+
+ public SecondaryTableSecondPass(EntityBinder entityBinder, PropertyHolder
propertyHolder, XAnnotatedElement annotatedClass) {
+ this.entityBinder = entityBinder;
+ this.propertyHolder = propertyHolder;
+ this.annotatedClass = annotatedClass;
+ }
+
+ public void doSecondPass(Map persistentClasses) throws MappingException {
+ entityBinder.finalSecondaryTableBinding( propertyHolder );
+
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,102 @@
+// $Id: ToOneFkSecondPass.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import java.util.Iterator;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.annotations.TableBinder;
+import org.hibernate.mapping.ManyToOne;
+import org.hibernate.mapping.OneToOne;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.Component;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Enable a proper set of the FK columns in respect with the id column order
+ * Allow the correct implementation of the default EJB3 values which needs both
+ * sides of the association to be resolved
+ *
+ * @author Emmanuel Bernard
+ */
+public class ToOneFkSecondPass extends FkSecondPass {
+ private boolean unique;
+ private ExtendedMappings mappings;
+ private String path;
+ private String entityClassName;
+
+ public ToOneFkSecondPass(
+ ToOne value, Ejb3JoinColumn[] columns, boolean unique, String entityClassName, String
path, ExtendedMappings mappings
+ ) {
+ super( value, columns );
+ this.mappings = mappings;
+ this.unique = unique;
+ this.entityClassName = entityClassName;
+ this.path = entityClassName != null ? path.substring( entityClassName.length() + 1 ) :
path;
+ }
+
+ public String getReferencedEntityName() {
+ return ( (ToOne) value ).getReferencedEntityName();
+ }
+
+ public boolean isInPrimaryKey() {
+ if ( entityClassName == null ) return false;
+ final PersistentClass persistentClass = mappings.getClass( entityClassName );
+ Property property = persistentClass.getIdentifierProperty();
+ if ( path == null ) {
+ return false;
+ }
+ else if ( property != null) {
+ //try explicit identifier property
+ return path.startsWith( property.getName() + "." );
+ }
+ else {
+ //try the embedded property
+ //embedded property starts their path with 'id.' See PropertyPreloadedData( )
use when idClass != null in AnnotationBinder
+ if ( path.startsWith( "id." ) ) {
+ KeyValue valueIdentifier = persistentClass.getIdentifier();
+ String localPath = path.substring( 3 );
+ if ( valueIdentifier instanceof Component ) {
+ Iterator it = ( (Component) valueIdentifier ).getPropertyIterator();
+ while ( it.hasNext() ) {
+ Property idProperty = (Property) it.next();
+ if ( localPath.startsWith( idProperty.getName() ) ) return true;
+ }
+
+ }
+ }
+ }
+ return false;
+ }
+
+ public void doSecondPass(java.util.Map persistentClasses) throws MappingException {
+ if ( value instanceof ManyToOne ) {
+ ManyToOne manyToOne = (ManyToOne) value;
+ PersistentClass ref = (PersistentClass) persistentClasses.get(
manyToOne.getReferencedEntityName() );
+ if ( ref == null ) {
+ throw new AnnotationException(
+ "@OneToOne or @ManyToOne on "
+ + StringHelper.qualify( entityClassName, path )
+ + " references an unknown entity: "
+ + manyToOne.getReferencedEntityName()
+ );
+ }
+ BinderHelper.createSyntheticPropertyReference( columns, ref, null, manyToOne, false,
mappings );
+ TableBinder.bindFk( ref, null, columns, manyToOne, unique, mappings );
+ /*
+ * HbmBinder does this only when property-ref != null, but IMO, it makes sense event
if it is null
+ */
+ if ( !manyToOne.isIgnoreNotFound() ) manyToOne.createPropertyRefConstraints(
persistentClasses );
+ }
+ else if ( value instanceof OneToOne ) {
+ ( (OneToOne) value ).createForeignKey();
+ }
+ else {
+ throw new AssertionFailure( "FkSecondPass for a wrong value type: " +
value.getClass().getName() );
+ }
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/WrappedInferredData.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/WrappedInferredData.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/WrappedInferredData.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,48 @@
+//$Id: WrappedInferredData.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg;
+
+import org.hibernate.MappingException;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class WrappedInferredData implements PropertyData {
+ private PropertyData wrappedInferredData;
+ private String propertyName;
+
+ public XClass getClassOrElement() throws MappingException {
+ return wrappedInferredData.getClassOrElement();
+ }
+
+ public String getClassOrElementName() throws MappingException {
+ return wrappedInferredData.getClassOrElementName();
+ }
+
+ public String getDefaultAccess() {
+ return wrappedInferredData.getDefaultAccess();
+ }
+
+ public XProperty getProperty() {
+ return wrappedInferredData.getProperty();
+ }
+
+ public XClass getPropertyClass() throws MappingException {
+ return wrappedInferredData.getPropertyClass();
+ }
+
+ public String getPropertyName() throws MappingException {
+ return propertyName;
+ }
+
+ public String getTypeName() throws MappingException {
+ return wrappedInferredData.getTypeName();
+ }
+
+ public WrappedInferredData(PropertyData inferredData, String suffix) {
+ this.wrappedInferredData = inferredData;
+ this.propertyName = StringHelper.qualify( inferredData.getPropertyName(), suffix );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ArrayBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+package org.hibernate.cfg.annotations;
+
+import org.hibernate.mapping.Array;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+
+/**
+ * Bind an Array
+ *
+ * @author Anthony Patricio
+ */
+public class ArrayBinder extends ListBinder {
+
+ public ArrayBinder() {
+ }
+
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new Array( persistentClass );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/BagBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/BagBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/BagBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,19 @@
+package org.hibernate.cfg.annotations;
+
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+
+/**
+ * Bind a bag.
+ *
+ * @author Matthew Inger
+ */
+public class BagBinder extends CollectionBinder {
+
+ public BagBinder() {
+ }
+
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new org.hibernate.mapping.Bag( persistentClass );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/CollectionBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,1429 @@
+package org.hibernate.cfg.annotations;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Embeddable;
+import javax.persistence.FetchType;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.MapKey;
+import javax.persistence.OneToMany;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CollectionId;
+import org.hibernate.annotations.CollectionOfElements;
+import org.hibernate.annotations.Fetch;
+import org.hibernate.annotations.Filter;
+import org.hibernate.annotations.FilterJoinTable;
+import org.hibernate.annotations.FilterJoinTables;
+import org.hibernate.annotations.Filters;
+import org.hibernate.annotations.ForeignKey;
+import org.hibernate.annotations.Immutable;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+import org.hibernate.annotations.Loader;
+import org.hibernate.annotations.ManyToAny;
+import org.hibernate.annotations.OptimisticLock;
+import org.hibernate.annotations.OrderBy;
+import org.hibernate.annotations.Persister;
+import org.hibernate.annotations.SQLDelete;
+import org.hibernate.annotations.SQLDeleteAll;
+import org.hibernate.annotations.SQLInsert;
+import org.hibernate.annotations.SQLUpdate;
+import org.hibernate.annotations.Sort;
+import org.hibernate.annotations.SortType;
+import org.hibernate.annotations.Where;
+import org.hibernate.annotations.WhereJoinTable;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.AnnotatedClassType;
+import org.hibernate.cfg.AnnotationBinder;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.CollectionSecondPass;
+import org.hibernate.cfg.Ejb3Column;
+import org.hibernate.cfg.Ejb3JoinColumn;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.IndexColumn;
+import org.hibernate.cfg.PropertyData;
+import org.hibernate.cfg.PropertyHolder;
+import org.hibernate.cfg.PropertyHolderBuilder;
+import org.hibernate.cfg.PropertyInferredData;
+import org.hibernate.cfg.PropertyPreloadedData;
+import org.hibernate.cfg.SecondPass;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.mapping.Any;
+import org.hibernate.mapping.Backref;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.IdGenerator;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.ManyToOne;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.SingleTableSubclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for binding different types of collections to Hibernate configuration
objects.
+ *
+ * @author inger
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings({"unchecked", "serial"})
+public abstract class CollectionBinder {
+
+ private Logger log = LoggerFactory.getLogger( CollectionBinder.class );
+
+ protected Collection collection;
+ protected String propertyName;
+ PropertyHolder propertyHolder;
+ int batchSize;
+ private String mappedBy;
+ private XClass collectionType;
+ private XClass targetEntity;
+ private ExtendedMappings mappings;
+ private Ejb3JoinColumn[] inverseJoinColumns;
+ private String cascadeStrategy;
+ String cacheConcurrencyStrategy;
+ String cacheRegionName;
+ private boolean oneToMany;
+ protected IndexColumn indexColumn;
+ private String orderBy;
+ protected String hqlOrderBy;
+ private boolean isSorted;
+ private Class comparator;
+ private boolean hasToBeSorted;
+ protected boolean cascadeDeleteEnabled;
+ protected String mapKeyPropertyName;
+ private boolean insertable = true;
+ private boolean updatable = true;
+ private Ejb3JoinColumn[] fkJoinColumns;
+ private boolean isExplicitAssociationTable;
+ private Ejb3Column[] elementColumns;
+ private boolean isEmbedded;
+ private XProperty property;
+ private boolean ignoreNotFound;
+ private TableBinder tableBinder;
+ private Ejb3Column[] mapKeyColumns;
+ private Ejb3JoinColumn[] mapKeyManyToManyColumns;
+ protected HashMap<String, IdGenerator> localGenerators;
+
+ public void setUpdatable(boolean updatable) {
+ this.updatable = updatable;
+ }
+
+ public void setInsertable(boolean insertable) {
+ this.insertable = insertable;
+ }
+
+
+ public void setCascadeStrategy(String cascadeStrategy) {
+ this.cascadeStrategy = cascadeStrategy;
+ }
+
+ public void setPropertyAccessorName(String propertyAccessorName) {
+ this.propertyAccessorName = propertyAccessorName;
+ }
+
+ private String propertyAccessorName;
+
+ public void setInverseJoinColumns(Ejb3JoinColumn[] inverseJoinColumns) {
+ this.inverseJoinColumns = inverseJoinColumns;
+ }
+
+ public void setJoinColumns(Ejb3JoinColumn[] joinColumns) {
+ this.joinColumns = joinColumns;
+ }
+
+ private Ejb3JoinColumn[] joinColumns;
+
+ public void setPropertyHolder(PropertyHolder propertyHolder) {
+ this.propertyHolder = propertyHolder;
+ }
+
+ public void setBatchSize(BatchSize batchSize) {
+ this.batchSize = batchSize == null ? -1 : batchSize.size();
+ }
+
+ public void setEjb3OrderBy(javax.persistence.OrderBy orderByAnn) {
+ if ( orderByAnn != null ) {
+ hqlOrderBy = orderByAnn.value();
+ }
+ }
+
+ public void setSqlOrderBy(OrderBy orderByAnn) {
+ if ( orderByAnn != null ) {
+ if ( !BinderHelper.isDefault( orderByAnn.clause() ) ) orderBy = orderByAnn.clause();
+ }
+ }
+
+ public void setSort(Sort sortAnn) {
+ if ( sortAnn != null ) {
+ isSorted = !SortType.UNSORTED.equals( sortAnn.type() );
+ if ( isSorted && SortType.COMPARATOR.equals( sortAnn.type() ) ) {
+ comparator = sortAnn.comparator();
+ }
+ }
+ }
+
+ /**
+ * collection binder factory
+ */
+ public static CollectionBinder getCollectionBinder(
+ String entityName, XProperty property,
+ boolean isIndexed
+ ) {
+ if ( property.isArray() ) {
+ if ( property.getElementClass().isPrimitive() ) {
+ return new PrimitiveArrayBinder();
+ }
+ else {
+ return new ArrayBinder();
+ }
+ }
+ else if ( property.isCollection() ) {
+ //TODO consider using an XClass
+ Class returnedClass = property.getCollectionClass();
+ if ( java.util.Set.class.equals( returnedClass ) ) {
+ if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ throw new AnnotationException( "Set do not support @CollectionId: "
+ + StringHelper.qualify( entityName, property.getName() ) );
+ }
+ return new SetBinder();
+ }
+ else if ( java.util.SortedSet.class.equals( returnedClass ) ) {
+ if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ throw new AnnotationException( "Set do not support @CollectionId: "
+ + StringHelper.qualify( entityName, property.getName() ) );
+ }
+ return new SetBinder( true );
+ }
+ else if ( java.util.Map.class.equals( returnedClass ) ) {
+ if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ throw new AnnotationException( "Map do not support @CollectionId: "
+ + StringHelper.qualify( entityName, property.getName() ) );
+ }
+ return new MapBinder();
+ }
+ else if ( java.util.SortedMap.class.equals( returnedClass ) ) {
+ if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ throw new AnnotationException( "Map do not support @CollectionId: "
+ + StringHelper.qualify( entityName, property.getName() ) );
+ }
+ return new MapBinder( true );
+ }
+ else if ( java.util.Collection.class.equals( returnedClass ) ) {
+ if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ return new IdBagBinder();
+ }
+ else {
+ return new BagBinder();
+ }
+ }
+ else if ( java.util.List.class.equals( returnedClass ) ) {
+ if ( isIndexed ) {
+ if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ throw new AnnotationException( "List do not support @CollectionId and
@IndexColumn at the same time: "
+ + StringHelper.qualify( entityName, property.getName() ) );
+ }
+ return new ListBinder();
+ }
+ else if ( property.isAnnotationPresent( CollectionId.class ) ) {
+ return new IdBagBinder();
+ }
+ else {
+ return new BagBinder();
+ }
+ }
+ else {
+ throw new AnnotationException(
+ returnedClass.getName() + " collection not yet supported: "
+ + StringHelper.qualify( entityName, property.getName() )
+ );
+ }
+ }
+ else {
+ throw new AnnotationException(
+ "Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or
@CollectionOfElements: "
+ + StringHelper.qualify( entityName, property.getName() )
+ );
+ }
+ }
+
+ protected CollectionBinder() {
+ }
+
+ protected CollectionBinder(boolean sorted) {
+ this.hasToBeSorted = sorted;
+ }
+
+ public void setMappedBy(String mappedBy) {
+ this.mappedBy = mappedBy;
+ }
+
+ public void setTableBinder(TableBinder tableBinder) {
+ this.tableBinder = tableBinder;
+ }
+
+ public void setCollectionType(XClass collectionType) {
+ this.collectionType = collectionType;
+ }
+
+ public void setTargetEntity(XClass targetEntity) {
+ this.targetEntity = targetEntity;
+ }
+
+ public void setMappings(ExtendedMappings mappings) {
+ this.mappings = mappings;
+ }
+
+ protected abstract Collection createCollection(PersistentClass persistentClass);
+
+ public Collection getCollection() {
+ return collection;
+ }
+
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
+ public void bind() {
+ this.collection = createCollection( propertyHolder.getPersistentClass() );
+ log.debug( "Collection role: {}", StringHelper.qualify(
propertyHolder.getPath(), propertyName ) );
+ collection.setRole( StringHelper.qualify( propertyHolder.getPath(), propertyName ) );
+ collection.setNodeName( propertyName );
+
+ if ( property.isAnnotationPresent( org.hibernate.annotations.MapKey.class ) &&
mapKeyPropertyName != null ) {
+ throw new AnnotationException(
+ "Cannot mix @javax.persistence.MapKey and @org.hibernate.annotations.MapKey
"
+ + "on the same collection: " + StringHelper.qualify(
+ propertyHolder.getPath(), propertyName
+ )
+ );
+ }
+
+ //set laziness
+ defineFetchingStrategy();
+ collection.setBatchSize( batchSize );
+ if ( orderBy != null && hqlOrderBy != null ) {
+ throw new AnnotationException(
+ "Cannot use sql order by clause in conjunction of EJB3 order by clause: "
+ safeCollectionRole()
+ );
+ }
+
+ collection.setMutable( !property.isAnnotationPresent( Immutable.class ) );
+ OptimisticLock lockAnn = property.getAnnotation( OptimisticLock.class );
+ if ( lockAnn != null ) collection.setOptimisticLocked( !lockAnn.excluded() );
+ Persister persisterAnn = property.getAnnotation( Persister.class );
+ if ( persisterAnn != null ) collection.setCollectionPersisterClass( persisterAnn.impl()
);
+
+ // set ordering
+ if ( orderBy != null ) collection.setOrderBy( orderBy );
+ if ( isSorted ) {
+ collection.setSorted( true );
+ if ( comparator != null ) {
+ try {
+ collection.setComparator( (Comparator) comparator.newInstance() );
+ }
+ catch (ClassCastException e) {
+ throw new AnnotationException(
+ "Comparator not implementing java.util.Comparator class: "
+ + comparator.getName() + "(" + safeCollectionRole() + ")"
+ );
+ }
+ catch (Exception e) {
+ throw new AnnotationException(
+ "Could not instantiate comparator class: "
+ + comparator.getName() + "(" + safeCollectionRole() + ")"
+ );
+ }
+ }
+ }
+ else {
+ if ( hasToBeSorted ) {
+ throw new AnnotationException(
+ "A sorted collection has to define @Sort: "
+ + safeCollectionRole()
+ );
+ }
+ }
+
+ //set cache
+ if ( StringHelper.isNotEmpty( cacheConcurrencyStrategy ) ) {
+ collection.setCacheConcurrencyStrategy( cacheConcurrencyStrategy );
+ collection.setCacheRegionName( cacheRegionName );
+ }
+
+ //SQL overriding
+ SQLInsert sqlInsert = property.getAnnotation( SQLInsert.class );
+ SQLUpdate sqlUpdate = property.getAnnotation( SQLUpdate.class );
+ SQLDelete sqlDelete = property.getAnnotation( SQLDelete.class );
+ SQLDeleteAll sqlDeleteAll = property.getAnnotation( SQLDeleteAll.class );
+ Loader loader = property.getAnnotation( Loader.class );
+ if ( sqlInsert != null ) {
+ collection.setCustomSQLInsert( sqlInsert.sql().trim(), sqlInsert.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlInsert.check().toString().toLowerCase() )
+ );
+
+ }
+ if ( sqlUpdate != null ) {
+ collection.setCustomSQLUpdate( sqlUpdate.sql(), sqlUpdate.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlUpdate.check().toString().toLowerCase() )
+ );
+ }
+ if ( sqlDelete != null ) {
+ collection.setCustomSQLDelete( sqlDelete.sql(), sqlDelete.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlDelete.check().toString().toLowerCase() )
+ );
+ }
+ if ( sqlDeleteAll != null ) {
+ collection.setCustomSQLDeleteAll( sqlDeleteAll.sql(), sqlDeleteAll.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlDeleteAll.check().toString().toLowerCase()
)
+ );
+ }
+ if ( loader != null ) {
+ collection.setLoaderName( loader.namedQuery() );
+ }
+
+ //work on association
+ boolean isMappedBy = !BinderHelper.isDefault( mappedBy );
+ collection.setInverse( isMappedBy );
+
+ //many to many may need some second pass informations
+ if ( !oneToMany && isMappedBy ) {
+ mappings.addMappedBy( getCollectionType().getName(), mappedBy, propertyName );
+ }
+ //TODO reducce tableBinder != null and oneToMany
+ XClass collectionType = getCollectionType();
+ SecondPass sp = getSecondPass(
+ fkJoinColumns,
+ joinColumns,
+ inverseJoinColumns,
+ elementColumns,
+ mapKeyColumns, mapKeyManyToManyColumns, isEmbedded,
+ property, collectionType,
+ ignoreNotFound, oneToMany,
+ tableBinder, mappings
+ );
+ if ( collectionType.isAnnotationPresent( Embeddable.class )
+ || property.isAnnotationPresent( CollectionOfElements.class ) ) {
+ // do it right away, otherwise @ManyToon on composite element call addSecondPass
+ // and raise a ConcurrentModificationException
+ //sp.doSecondPass( CollectionHelper.EMPTY_MAP );
+ mappings.addSecondPass( sp, !isMappedBy );
+ }
+ else {
+ mappings.addSecondPass( sp, !isMappedBy );
+ }
+
+ mappings.addCollection( collection );
+
+ //property building
+ PropertyBinder binder = new PropertyBinder();
+ binder.setName( propertyName );
+ binder.setValue( collection );
+ binder.setCascade( cascadeStrategy );
+ if ( cascadeStrategy != null && cascadeStrategy.indexOf(
"delete-orphan" ) >= 0 ) {
+ collection.setOrphanDelete( true );
+ }
+ binder.setPropertyAccessorName( propertyAccessorName );
+ binder.setProperty( property );
+ binder.setInsertable( insertable );
+ binder.setUpdatable( updatable );
+ Property prop = binder.make();
+ //we don't care about the join stuffs because the column is on the association
table.
+ propertyHolder.addProperty( prop );
+ }
+
+ private void defineFetchingStrategy() {
+ LazyCollection lazy = property.getAnnotation( LazyCollection.class );
+ Fetch fetch = property.getAnnotation( Fetch.class );
+ OneToMany oneToMany = property.getAnnotation( OneToMany.class );
+ ManyToMany manyToMany = property.getAnnotation( ManyToMany.class );
+ CollectionOfElements elements = property.getAnnotation( CollectionOfElements.class );
+ ManyToAny manyToAny = property.getAnnotation( ManyToAny.class );
+ FetchType fetchType;
+ if ( oneToMany != null ) {
+ fetchType = oneToMany.fetch();
+ }
+ else if ( manyToMany != null ) {
+ fetchType = manyToMany.fetch();
+ }
+ else if ( elements != null ) {
+ fetchType = elements.fetch();
+ }
+ else if ( manyToAny != null ) {
+ fetchType = FetchType.LAZY;
+ }
+ else {
+ throw new AssertionFailure(
+ "Define fetch strategy on a property not annotated with @ManyToOne nor
@OneToMany nor @CollectionOfElements"
+ );
+ }
+ if ( lazy != null ) {
+ collection.setLazy( !( lazy.value() == LazyCollectionOption.FALSE ) );
+ collection.setExtraLazy( lazy.value() == LazyCollectionOption.EXTRA );
+ }
+ else {
+ collection.setLazy( fetchType == FetchType.LAZY );
+ collection.setExtraLazy( false );
+ }
+ if ( fetch != null ) {
+ if ( fetch.value() == org.hibernate.annotations.FetchMode.JOIN ) {
+ collection.setFetchMode( FetchMode.JOIN );
+ collection.setLazy( false );
+ }
+ else if ( fetch.value() == org.hibernate.annotations.FetchMode.SELECT ) {
+ collection.setFetchMode( FetchMode.SELECT );
+ }
+ else if ( fetch.value() == org.hibernate.annotations.FetchMode.SUBSELECT ) {
+ collection.setFetchMode( FetchMode.SELECT );
+ collection.setSubselectLoadable( true );
+ collection.getOwner().setSubselectLoadableCollections( true );
+ }
+ else {
+ throw new AssertionFailure( "Unknown FetchMode: " + fetch.value() );
+ }
+ }
+ else {
+ collection.setFetchMode( AnnotationBinder.getFetchMode( fetchType ) );
+ }
+ }
+
+ private XClass getCollectionType() {
+ if ( AnnotationBinder.isDefault( targetEntity, mappings ) ) {
+ if ( collectionType != null ) {
+ return collectionType;
+ }
+ else {
+ String errorMsg = "Collection has neither generic type or
OneToMany.targetEntity() defined: "
+ + safeCollectionRole();
+ throw new AnnotationException( errorMsg );
+ }
+ }
+ else {
+ return targetEntity;
+ }
+ }
+
+ public SecondPass getSecondPass(
+ final Ejb3JoinColumn[] fkJoinColumns, final Ejb3JoinColumn[] keyColumns,
+ final Ejb3JoinColumn[] inverseColumns,
+ final Ejb3Column[] elementColumns,
+ final Ejb3Column[] mapKeyColumns, final Ejb3JoinColumn[] mapKeyManyToManyColumns,
final boolean isEmbedded,
+ final XProperty property, final XClass collType,
+ final boolean ignoreNotFound, final boolean unique,
+ final TableBinder assocTableBinder, final ExtendedMappings mappings
+ ) {
+
+ return new CollectionSecondPass( mappings, collection ) {
+
+ public void secondPass(java.util.Map persistentClasses, java.util.Map inheritedMetas)
+ throws MappingException {
+ bindStarToManySecondPass(
+ persistentClasses, collType, fkJoinColumns, keyColumns, inverseColumns,
elementColumns,
+ isEmbedded, property, unique, assocTableBinder, ignoreNotFound, mappings
+ );
+
+ }
+ };
+ }
+
+ /**
+ * return true if it's a Fk, false if it's an association table
+ */
+ protected boolean bindStarToManySecondPass(
+ Map persistentClasses, XClass collType, Ejb3JoinColumn[] fkJoinColumns,
+ Ejb3JoinColumn[] keyColumns, Ejb3JoinColumn[] inverseColumns, Ejb3Column[]
elementColumns,
+ boolean isEmbedded,
+ XProperty property, boolean unique,
+ TableBinder associationTableBinder, boolean ignoreNotFound, ExtendedMappings mappings
+ ) {
+ PersistentClass persistentClass = (PersistentClass) persistentClasses.get(
collType.getName() );
+ boolean reversePropertyInJoin = false;
+ if ( persistentClass != null && StringHelper.isNotEmpty( this.mappedBy ) ) {
+ try {
+ reversePropertyInJoin = 0 != persistentClass.getJoinNumber(
+ persistentClass.getRecursiveProperty( this.mappedBy )
+ );
+ }
+ catch (MappingException e) {
+ StringBuilder error = new StringBuilder( 80 );
+ error.append( "mappedBy reference an unknown target entity property: " )
+ .append( collType ).append( "." ).append( this.mappedBy )
+ .append( " in " )
+ .append( collection.getOwnerEntityName() )
+ .append( "." )
+ .append( property.getName() );
+ throw new AnnotationException( error.toString() );
+ }
+ }
+ if ( persistentClass != null
+ && !reversePropertyInJoin
+ && oneToMany
+ && !this.isExplicitAssociationTable
+ && ( joinColumns[0].isImplicit() && !BinderHelper.isDefault(
this.mappedBy ) //implicit @JoinColumn
+ || !fkJoinColumns[0].isImplicit() ) //this is an explicit @JoinColumn
+ ) {
+ //this is a Foreign key
+ bindOneToManySecondPass(
+ getCollection(),
+ persistentClasses,
+ fkJoinColumns,
+ collType,
+ cascadeDeleteEnabled,
+ ignoreNotFound, hqlOrderBy,
+ mappings
+ );
+ return true;
+ }
+ else {
+ //this is an association table
+ bindManyToManySecondPass(
+ this.collection,
+ persistentClasses,
+ keyColumns,
+ inverseColumns,
+ elementColumns,
+ isEmbedded, collType,
+ ignoreNotFound, unique,
+ cascadeDeleteEnabled,
+ associationTableBinder, property, propertyHolder, hqlOrderBy, mappings
+ );
+ return false;
+ }
+ }
+
+ protected void bindOneToManySecondPass(
+ Collection collection, Map persistentClasses, Ejb3JoinColumn[] fkJoinColumns,
+ XClass collectionType,
+ boolean cascadeDeleteEnabled, boolean ignoreNotFound, String hqlOrderBy,
ExtendedMappings extendedMappings
+ ) {
+
+ log.debug("Binding a OneToMany: {}.{} through a foreign key",
propertyHolder.getEntityName(), propertyName);
+ org.hibernate.mapping.OneToMany oneToMany = new org.hibernate.mapping.OneToMany(
collection.getOwner() );
+ collection.setElement( oneToMany );
+ oneToMany.setReferencedEntityName( collectionType.getName() );
+ oneToMany.setIgnoreNotFound( ignoreNotFound );
+
+ String assocClass = oneToMany.getReferencedEntityName();
+ PersistentClass associatedClass = (PersistentClass) persistentClasses.get( assocClass
);
+ String orderBy = buildOrderByClauseFromHql( hqlOrderBy, associatedClass,
collection.getRole() );
+ if ( orderBy != null ) collection.setOrderBy( orderBy );
+ if ( mappings == null ) {
+ throw new AssertionFailure(
+ "CollectionSecondPass for oneToMany should not be called with null
mappings"
+ );
+ }
+ Map<String, Join> joins = mappings.getJoins( assocClass );
+ if ( associatedClass == null ) {
+ throw new MappingException(
+ "Association references unmapped class: " + assocClass
+ );
+ }
+ oneToMany.setAssociatedClass( associatedClass );
+ for (Ejb3JoinColumn column : fkJoinColumns) {
+ column.setPersistentClass( associatedClass, joins );
+ column.setJoins( joins );
+ collection.setCollectionTable( column.getTable() );
+ }
+ log.info(
+ "Mapping collection: " + collection.getRole() + " -> " +
collection.getCollectionTable().getName()
+ );
+ bindFilters( false );
+ bindCollectionSecondPass( collection, null, fkJoinColumns, cascadeDeleteEnabled,
property, mappings );
+ if ( !collection.isInverse()
+ && !collection.getKey().isNullable() ) {
+ // for non-inverse one-to-many, with a not-null fk, add a backref!
+ String entityName = oneToMany.getReferencedEntityName();
+ PersistentClass referenced = mappings.getClass( entityName );
+ Backref prop = new Backref();
+ prop.setName( '_' + fkJoinColumns[0].getPropertyName() + "Backref"
);
+ prop.setUpdateable( false );
+ prop.setSelectable( false );
+ prop.setCollectionRole( collection.getRole() );
+ prop.setEntityName( collection.getOwner().getEntityName() );
+ prop.setValue( collection.getKey() );
+ referenced.addProperty( prop );
+ }
+ }
+
+
+ private void bindFilters(boolean hasAssociationTable) {
+ Filter simpleFilter = property.getAnnotation( Filter.class );
+ //set filtering
+ //test incompatible choices
+ //if ( StringHelper.isNotEmpty( where ) ) collection.setWhere( where );
+ if ( simpleFilter != null ) {
+ if ( hasAssociationTable ) {
+ collection.addManyToManyFilter( simpleFilter.name(), getCondition( simpleFilter ) );
+ }
+ else {
+ collection.addFilter( simpleFilter.name(), getCondition( simpleFilter ) );
+ }
+ }
+ Filters filters = property.getAnnotation( Filters.class );
+ if ( filters != null ) {
+ for (Filter filter : filters.value()) {
+ if ( hasAssociationTable ) {
+ collection.addManyToManyFilter( filter.name(), getCondition( filter ) );
+ }
+ else {
+ collection.addFilter( filter.name(), getCondition( filter ) );
+ }
+ }
+ }
+ FilterJoinTable simpleFilterJoinTable = property.getAnnotation( FilterJoinTable.class
);
+ if ( simpleFilterJoinTable != null ) {
+ if ( hasAssociationTable ) {
+ collection.addFilter( simpleFilterJoinTable.name(), getCondition(
simpleFilterJoinTable ) );
+ }
+ else {
+ throw new AnnotationException(
+ "Illegal use of @FilterJoinTable on an association without join table:"
+ + StringHelper.qualify( propertyHolder.getPath(), propertyName )
+ );
+ }
+ }
+ FilterJoinTables filterJoinTables = property.getAnnotation( FilterJoinTables.class );
+ if ( filterJoinTables != null ) {
+ for (FilterJoinTable filter : filterJoinTables.value()) {
+ if ( hasAssociationTable ) {
+ collection.addFilter( filter.name(), getCondition( filter ) );
+ }
+ else {
+ throw new AnnotationException(
+ "Illegal use of @FilterJoinTable on an association without join table:"
+ + StringHelper.qualify( propertyHolder.getPath(), propertyName )
+ );
+ }
+ }
+ }
+
+ Where where = property.getAnnotation( Where.class );
+ String whereClause = where == null ? null : where.clause();
+ if ( StringHelper.isNotEmpty( whereClause ) ) {
+ if ( hasAssociationTable ) {
+ collection.setManyToManyWhere( whereClause );
+ }
+ else {
+ collection.setWhere( whereClause );
+ }
+ }
+
+ WhereJoinTable whereJoinTable = property.getAnnotation( WhereJoinTable.class );
+ String whereJoinTableClause = whereJoinTable == null ? null : whereJoinTable.clause();
+ if ( StringHelper.isNotEmpty( whereJoinTableClause ) ) {
+ if ( hasAssociationTable ) {
+ collection.setWhere( whereJoinTableClause );
+ }
+ else {
+ throw new AnnotationException(
+ "Illegal use of @WhereJoinTable on an association without join table:"
+ + StringHelper.qualify( propertyHolder.getPath(), propertyName )
+ );
+ }
+ }
+// This cannot happen in annotations since the second fetch is hardcoded to join
+// if ( ( ! collection.getManyToManyFilterMap().isEmpty() ||
collection.getManyToManyWhere() != null ) &&
+// collection.getFetchMode() == FetchMode.JOIN &&
+// collection.getElement().getFetchMode() != FetchMode.JOIN ) {
+// throw new MappingException(
+// "association with join table defining filter or where without join
fetching " +
+// "not valid within collection using join fetching [" +
collection.getRole() + "]"
+// );
+// }
+ }
+
+ private String getCondition(FilterJoinTable filter) {
+ //set filtering
+ String name = filter.name();
+ String cond = filter.condition();
+ return getCondition( cond, name );
+ }
+
+ private String getCondition(Filter filter) {
+ //set filtering
+ String name = filter.name();
+ String cond = filter.condition();
+ return getCondition( cond, name );
+ }
+
+ private String getCondition(String cond, String name) {
+ if ( BinderHelper.isDefault( cond ) ) {
+ cond = mappings.getFilterDefinition( name ).getDefaultFilterCondition();
+ if ( StringHelper.isEmpty( cond ) ) {
+ throw new AnnotationException(
+ "no filter condition found for filter " + name + " in "
+ + StringHelper.qualify( propertyHolder.getPath(), propertyName )
+ );
+ }
+ }
+ return cond;
+ }
+
+ public void setCache(Cache cacheAnn) {
+ if ( cacheAnn != null ) {
+ cacheRegionName = BinderHelper.isDefault( cacheAnn.region() ) ? null :
cacheAnn.region();
+ cacheConcurrencyStrategy = EntityBinder.getCacheConcurrencyStrategy( cacheAnn.usage()
);
+ }
+ else {
+ cacheConcurrencyStrategy = null;
+ cacheRegionName = null;
+ }
+ }
+
+ public void setOneToMany(boolean oneToMany) {
+ this.oneToMany = oneToMany;
+ }
+
+ public void setIndexColumn(IndexColumn indexColumn) {
+ this.indexColumn = indexColumn;
+ }
+
+ public void setMapKey(MapKey key) {
+ if ( key != null ) {
+ mapKeyPropertyName = key.name();
+ }
+ }
+
+ private static String buildOrderByClauseFromHql(String hqlOrderBy, PersistentClass
associatedClass, String role) {
+ String orderByString = null;
+ if ( hqlOrderBy != null ) {
+ List<String> properties = new ArrayList<String>();
+ List<String> ordering = new ArrayList<String>();
+ StringBuilder orderByBuffer = new StringBuilder();
+ if ( hqlOrderBy.length() == 0 ) {
+ //order by id
+ Iterator it = associatedClass.getIdentifier().getColumnIterator();
+ while ( it.hasNext() ) {
+ Selectable col = (Selectable) it.next();
+ orderByBuffer.append( col.getText() ).append( " asc" ).append( ",
" );
+ }
+ }
+ else {
+ StringTokenizer st = new StringTokenizer( hqlOrderBy, " ,", false );
+ String currentOrdering = null;
+ //FIXME make this code decent
+ while ( st.hasMoreTokens() ) {
+ String token = st.nextToken();
+ if ( isNonPropertyToken( token ) ) {
+ if ( currentOrdering != null ) {
+ throw new AnnotationException(
+ "Error while parsing HQL orderBy clause: " + hqlOrderBy
+ + " (" + role + ")"
+ );
+ }
+ currentOrdering = token;
+ }
+ else {
+ //Add ordering of the previous
+ if ( currentOrdering == null ) {
+ //default ordering
+ ordering.add( "asc" );
+ }
+ else {
+ ordering.add( currentOrdering );
+ currentOrdering = null;
+ }
+ properties.add( token );
+ }
+ }
+ ordering.remove( 0 ); //first one is the algorithm starter
+ // add last one ordering
+ if ( currentOrdering == null ) {
+ //default ordering
+ ordering.add( "asc" );
+ }
+ else {
+ ordering.add( currentOrdering );
+ currentOrdering = null;
+ }
+ int index = 0;
+
+ for (String property : properties) {
+ Property p = BinderHelper.findPropertyByName( associatedClass, property );
+ if ( p == null ) {
+ throw new AnnotationException(
+ "property from @OrderBy clause not found: "
+ + associatedClass.getEntityName() + "." + property
+ );
+ }
+ PersistentClass pc = p.getPersistentClass();
+ String table;
+ if ( pc == null ) {
+ //we are touching a @IdClass property, the pc is not set
+ //this means pc == associatedClass
+ //TODO check whether @ManyToOne @JoinTable in @IdClass used for @OrderBy works:
doh!
+ table = "";
+ }
+
+ else if (pc == associatedClass
+ || (associatedClass instanceof SingleTableSubclass && pc
+ .getMappedClass().isAssignableFrom(
+ associatedClass.getMappedClass()))) {
+ table = "";
+ } else {
+ table = pc.getTable().getQuotedName() + ".";
+ }
+
+ Iterator propertyColumns = p.getColumnIterator();
+ while ( propertyColumns.hasNext() ) {
+ Selectable column = (Selectable) propertyColumns.next();
+ orderByBuffer.append( table )
+ .append( column.getText() )
+ .append( " " )
+ .append( ordering.get( index ) )
+ .append( ", " );
+ }
+ index++;
+ }
+ }
+ orderByString = orderByBuffer.substring( 0, orderByBuffer.length() - 2 );
+ }
+ return orderByString;
+ }
+
+ private static String buildOrderByClauseFromHql(String hqlOrderBy, Component component,
String role) {
+ String orderByString = null;
+ if ( hqlOrderBy != null ) {
+ List<String> properties = new ArrayList<String>();
+ List<String> ordering = new ArrayList<String>();
+ StringBuilder orderByBuffer = new StringBuilder();
+ if ( hqlOrderBy.length() == 0 ) {
+ //TODO : Check that. Maybe order by key for maps
+ }
+ else {
+ StringTokenizer st = new StringTokenizer( hqlOrderBy, " ,", false );
+ String currentOrdering = null;
+ //FIXME make this code decent
+ while ( st.hasMoreTokens() ) {
+ String token = st.nextToken();
+ if ( isNonPropertyToken( token ) ) {
+ if ( currentOrdering != null ) {
+ throw new AnnotationException(
+ "Error while parsing HQL orderBy clause: " + hqlOrderBy
+ + " (" + role + ")"
+ );
+ }
+ currentOrdering = token;
+ }
+ else {
+ //Add ordering of the previous
+ if ( currentOrdering == null ) {
+ //default ordering
+ ordering.add( "asc" );
+ }
+ else {
+ ordering.add( currentOrdering );
+ currentOrdering = null;
+ }
+ properties.add( token );
+ }
+ }
+ ordering.remove( 0 ); //first one is the algorithm starter
+ // add last one ordering
+ if ( currentOrdering == null ) {
+ //default ordering
+ ordering.add( "asc" );
+ }
+ else {
+ ordering.add( currentOrdering );
+ currentOrdering = null;
+ }
+ int index = 0;
+
+ for (String property : properties) {
+ Property p = component.getProperty( property );
+ if ( p == null ) {
+ throw new AnnotationException(
+ "property from @OrderBy clause not found: "
+ + role + "." + property
+ );
+ }
+
+ Iterator propertyColumns = p.getColumnIterator();
+ while ( propertyColumns.hasNext() ) {
+ Selectable column = (Selectable) propertyColumns.next();
+ orderByBuffer.append( column.getText() )
+ .append( " " )
+ .append( ordering.get( index ) )
+ .append( ", " );
+ }
+ index++;
+ }
+
+ if ( orderByBuffer.length() >= 2 ) {
+ orderByString = orderByBuffer.substring( 0, orderByBuffer.length() - 2 );
+ }
+ }
+ }
+ return orderByString;
+ }
+
+ private static boolean isNonPropertyToken(String token) {
+ if ( " ".equals( token ) ) return true;
+ if ( ",".equals( token ) ) return true;
+ if ( token.equalsIgnoreCase( "desc" ) ) return true;
+ if ( token.equalsIgnoreCase( "asc" ) ) return true;
+ return false;
+ }
+
+ private static SimpleValue buildCollectionKey(
+ Collection collValue, Ejb3JoinColumn[] joinColumns, boolean cascadeDeleteEnabled,
+ XProperty property, ExtendedMappings mappings
+ ) {
+ //binding key reference using column
+ KeyValue keyVal;
+ //give a chance to override the referenced property name
+ //has to do that here because the referencedProperty creation happens in a FKSecondPass
for Many to one yuk!
+ if ( joinColumns.length > 0 && StringHelper.isNotEmpty(
joinColumns[0].getMappedBy() ) ) {
+ String entityName = joinColumns[0].getManyToManyOwnerSideEntityName() != null ?
+ "inverse__" + joinColumns[0].getManyToManyOwnerSideEntityName() :
+ joinColumns[0].getPropertyHolder().getEntityName();
+ String propRef = mappings.getPropertyReferencedAssociation(
+ entityName,
+ joinColumns[0].getMappedBy()
+ );
+ if ( propRef != null ) {
+ collValue.setReferencedPropertyName( propRef );
+ mappings.addPropertyReference( collValue.getOwnerEntityName(), propRef );
+ }
+ }
+ String propRef = collValue.getReferencedPropertyName();
+ if ( propRef == null ) {
+ keyVal = collValue.getOwner().getIdentifier();
+ }
+ else {
+ keyVal = (KeyValue) collValue.getOwner()
+ .getRecursiveProperty( propRef )
+ .getValue();
+ }
+ DependantValue key = new DependantValue( collValue.getCollectionTable(), keyVal );
+ key.setTypeName( null );
+ Ejb3Column.checkPropertyConsistency( joinColumns, collValue.getOwnerEntityName() );
+ key.setNullable( joinColumns.length == 0 || joinColumns[0].isNullable() );
+ key.setUpdateable( joinColumns.length == 0 || joinColumns[0].isUpdatable() );
+ key.setCascadeDeleteEnabled( cascadeDeleteEnabled );
+ collValue.setKey( key );
+ ForeignKey fk = property != null ? property.getAnnotation( ForeignKey.class ) : null;
+ String fkName = fk != null ? fk.name() : "";
+ if ( !BinderHelper.isDefault( fkName ) ) key.setForeignKeyName( fkName );
+ return key;
+ }
+
+ protected void bindManyToManySecondPass(
+ Collection collValue,
+ Map persistentClasses,
+ Ejb3JoinColumn[] joinColumns,
+ Ejb3JoinColumn[] inverseJoinColumns,
+ Ejb3Column[] elementColumns,
+ boolean isEmbedded,
+ XClass collType,
+ boolean ignoreNotFound, boolean unique,
+ boolean cascadeDeleteEnabled,
+ TableBinder associationTableBinder, XProperty property, PropertyHolder
parentPropertyHolder,
+ String hqlOrderBy, ExtendedMappings mappings
+ ) throws MappingException {
+
+ PersistentClass collectionEntity = (PersistentClass) persistentClasses.get(
collType.getName() );
+ boolean isCollectionOfEntities = collectionEntity != null;
+ ManyToAny anyAnn = property.getAnnotation( ManyToAny.class );
+ if ( log.isDebugEnabled() ) {
+ String path = collValue.getOwnerEntityName() + "." +
joinColumns[0].getPropertyName();
+ if ( isCollectionOfEntities && unique ) {
+ log.debug( "Binding a OneToMany: {} through an association table", path );
+ }
+ else if ( isCollectionOfEntities ) {
+ log.debug( "Binding as ManyToMany: {}", path );
+ }
+ else if ( anyAnn != null ) {
+ log.debug( "Binding a ManyToAny: {}", path );
+ }
+ else {
+ log.debug( "Binding a collection of element: {}", path );
+ }
+ }
+ //check for user error
+ if ( !isCollectionOfEntities ) {
+ if ( property.isAnnotationPresent( ManyToMany.class ) || property.isAnnotationPresent(
OneToMany.class ) ) {
+ String path = collValue.getOwnerEntityName() + "." +
joinColumns[0].getPropertyName();
+ throw new AnnotationException(
+ "Use of @OneToMany or @ManyToMany targeting an unmapped class: " + path +
"[" + collType + "]"
+ );
+ }
+ else if ( anyAnn != null ) {
+ if ( !property.isAnnotationPresent( JoinTable.class ) ) {
+ String path = collValue.getOwnerEntityName() + "." +
joinColumns[0].getPropertyName();
+ throw new AnnotationException(
+ "@JoinTable is mandatory when @ManyToAny is used: " + path
+ );
+ }
+ }
+ else {
+ JoinTable joinTableAnn = property.getAnnotation( JoinTable.class );
+ if ( joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0
) {
+ String path = collValue.getOwnerEntityName() + "." +
joinColumns[0].getPropertyName();
+ throw new AnnotationException(
+ "Use of @JoinTable.inverseJoinColumns targeting an unmapped class: " +
path + "[" + collType + "]"
+ );
+ }
+ }
+ }
+
+ boolean mappedBy = !BinderHelper.isDefault( joinColumns[0].getMappedBy() );
+ if ( mappedBy ) {
+ if ( !isCollectionOfEntities ) {
+ StringBuilder error = new StringBuilder( 80 )
+ .append(
+ "Collection of elements must not have mappedBy or association reference an
unmapped entity: "
+ )
+ .append( collValue.getOwnerEntityName() )
+ .append( "." )
+ .append( joinColumns[0].getPropertyName() );
+ throw new AnnotationException( error.toString() );
+ }
+ Property otherSideProperty;
+ try {
+ otherSideProperty = collectionEntity.getRecursiveProperty(
joinColumns[0].getMappedBy() );
+ }
+ catch (MappingException e) {
+ StringBuilder error = new StringBuilder( 80 );
+ error.append( "mappedBy reference an unknown target entity property: " )
+ .append( collType ).append( "." ).append( joinColumns[0].getMappedBy() )
+ .append( " in " )
+ .append( collValue.getOwnerEntityName() )
+ .append( "." )
+ .append( joinColumns[0].getPropertyName() );
+ throw new AnnotationException( error.toString() );
+ }
+ Table table;
+ if ( otherSideProperty.getValue() instanceof Collection ) {
+ //this is a collection on the other side
+ table = ( (Collection) otherSideProperty.getValue() ).getCollectionTable();
+ }
+ else {
+ //This is a ToOne with a @JoinTable or a regular property
+ table = otherSideProperty.getValue().getTable();
+ }
+ collValue.setCollectionTable( table );
+ String entityName = collectionEntity.getEntityName();
+ for (Ejb3JoinColumn column : joinColumns) {
+ //column.setDefaultColumnHeader( joinColumns[0].getMappedBy() ); //seems not to be
used, make sense
+ column.setManyToManyOwnerSideEntityName( entityName );
+ }
+ }
+ else {
+ //TODO: only for implicit columns?
+ //FIXME NamingStrategy
+ for (Ejb3JoinColumn column : joinColumns) {
+ String mappedByProperty = mappings.getFromMappedBy(
+ collValue.getOwnerEntityName(), column.getPropertyName()
+ );
+ Table ownerTable = collValue.getOwner().getTable();
+ column.setMappedBy(
+ collValue.getOwner().getEntityName(), mappings.getLogicalTableName( ownerTable ),
+ mappedByProperty
+ );
+// String header = ( mappedByProperty == null ) ? mappings.getLogicalTableName(
ownerTable ) : mappedByProperty;
+// column.setDefaultColumnHeader( header );
+ }
+ if ( StringHelper.isEmpty( associationTableBinder.getName() ) ) {
+ //default value
+ associationTableBinder.setDefaultName(
+ collValue.getOwner().getEntityName(),
+ mappings.getLogicalTableName( collValue.getOwner().getTable() ),
+ collectionEntity != null ? collectionEntity.getEntityName() : null,
+ collectionEntity != null ? mappings.getLogicalTableName(
collectionEntity.getTable() ) : null,
+ joinColumns[0].getPropertyName()
+ );
+ }
+ collValue.setCollectionTable( associationTableBinder.bind() );
+ }
+ bindFilters( isCollectionOfEntities );
+ bindCollectionSecondPass( collValue, collectionEntity, joinColumns,
cascadeDeleteEnabled, property, mappings );
+
+ ManyToOne element = null;
+ if ( isCollectionOfEntities ) {
+ element =
+ new ManyToOne( collValue.getCollectionTable() );
+ collValue.setElement( element );
+ element.setReferencedEntityName( collType.getName() );
+ //element.setFetchMode( fetchMode );
+ //element.setLazy( fetchMode != FetchMode.JOIN );
+ //make the second join non lazy
+ element.setFetchMode( FetchMode.JOIN );
+ element.setLazy( false );
+ element.setIgnoreNotFound( ignoreNotFound );
+ if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
+ collValue.setManyToManyOrdering(
+ buildOrderByClauseFromHql( hqlOrderBy, collectionEntity, collValue.getRole() )
+ );
+ }
+ ForeignKey fk = property != null ? property.getAnnotation( ForeignKey.class ) : null;
+ String fkName = fk != null ? fk.inverseName() : "";
+ if ( !BinderHelper.isDefault( fkName ) ) element.setForeignKeyName( fkName );
+ }
+ else if ( anyAnn != null ) {
+ //@ManyToAny
+ //Make sure that collTyp is never used during the @ManyToAny branch: it will be set to
void.class
+ PropertyData inferredData = new PropertyInferredData( property,
"unsupported", mappings.getReflectionManager() );
+ //override the table
+ for (Ejb3Column column : inverseJoinColumns) {
+ column.setTable( collValue.getCollectionTable() );
+ }
+ Any any = BinderHelper.buildAnyValue( anyAnn.metaDef(), inverseJoinColumns,
anyAnn.metaColumn(),
+ inferredData, cascadeDeleteEnabled, Nullability.NO_CONSTRAINT,
+ propertyHolder, new EntityBinder(), true, mappings );
+ collValue.setElement( any );
+ }
+ else {
+ XClass elementClass;
+ AnnotatedClassType classType;
+// Map<String, javax.persistence.Column[]> columnOverrides =
PropertyHolderBuilder.buildColumnOverride(
+// property, StringHelper.qualify( collValue.getRole(), "element" )
+// );
+ //FIXME the "element" is lost
+ PropertyHolder holder = null;
+ if ( BinderHelper.PRIMITIVE_NAMES.contains( collType.getName() ) ) {
+ classType = AnnotatedClassType.NONE;
+ elementClass = null;
+ }
+ else {
+ elementClass = collType;
+ classType = mappings.getClassType( elementClass );
+
+ holder = PropertyHolderBuilder.buildPropertyHolder(
+ collValue,
+ collValue.getRole(), // + ".element",
+ elementClass,
+ property, parentPropertyHolder, mappings
+ );
+ //force in case of attribute override
+ boolean attributeOverride = property.isAnnotationPresent( AttributeOverride.class )
+ || property.isAnnotationPresent( AttributeOverrides.class );
+ if ( isEmbedded || attributeOverride ) {
+ classType = AnnotatedClassType.EMBEDDABLE;
+ }
+ }
+
+ if ( AnnotatedClassType.EMBEDDABLE.equals( classType ) ) {
+ EntityBinder entityBinder = new EntityBinder();
+ PersistentClass owner = collValue.getOwner();
+ boolean isPropertyAnnotated;
+ //FIXME support @Access for collection of elements
+ //String accessType = access != null ? access.value() : null;
+ if ( owner.getIdentifierProperty() != null ) {
+ isPropertyAnnotated =
owner.getIdentifierProperty().getPropertyAccessorName().equals( "property" );
+ }
+ else if ( owner.getIdentifierMapper() != null &&
owner.getIdentifierMapper().getPropertySpan() > 0 ) {
+ Property prop = (Property)
owner.getIdentifierMapper().getPropertyIterator().next();
+ isPropertyAnnotated = prop.getPropertyAccessorName().equals( "property"
);
+ }
+ else {
+ throw new AssertionFailure( "Unable to guess collection property accessor
name" );
+ }
+
+ //boolean propertyAccess = embeddable == null || AccessType.PROPERTY.equals(
embeddable.access() );
+ PropertyData inferredData = new PropertyPreloadedData( "property",
"element", elementClass );
+ //TODO be smart with isNullable
+ Component component = AnnotationBinder.fillComponent(
+ holder, inferredData, isPropertyAnnotated, isPropertyAnnotated ?
"property" : "field", true,
+ entityBinder, false, false,
+ true, mappings
+ );
+
+ collValue.setElement( component );
+
+ if ( StringHelper.isNotEmpty( hqlOrderBy ) ) {
+ String path = collValue.getOwnerEntityName() + "." +
joinColumns[0].getPropertyName();
+ String orderBy = buildOrderByClauseFromHql( hqlOrderBy, component, path );
+ if ( orderBy != null ) {
+ collValue.setOrderBy( orderBy );
+ }
+ }
+ }
+ else {
+ SimpleValueBinder elementBinder = new SimpleValueBinder();
+ elementBinder.setMappings( mappings );
+ elementBinder.setReturnedClassName( collType.getName() );
+ if ( elementColumns == null || elementColumns.length == 0 ) {
+ elementColumns = new Ejb3Column[1];
+ Ejb3Column column = new Ejb3Column();
+ column.setImplicit( false );
+ //not following the spec but more clean
+ column.setNullable( true );
+ column.setLength( Ejb3Column.DEFAULT_COLUMN_LENGTH );
+ column.setLogicalColumnName( Collection.DEFAULT_ELEMENT_COLUMN_NAME );
+ //TODO create an EMPTY_JOINS collection
+ column.setJoins( new HashMap<String, Join>() );
+ column.setMappings( mappings );
+ column.bind();
+ elementColumns[0] = column;
+ }
+ //override the table
+ for (Ejb3Column column : elementColumns) {
+ column.setTable( collValue.getCollectionTable() );
+ }
+ elementBinder.setColumns( elementColumns );
+ elementBinder.setType( property, elementClass );
+ collValue.setElement( elementBinder.make() );
+ }
+ }
+
+ checkFilterConditions( collValue );
+
+ //FIXME: do optional = false
+ if ( isCollectionOfEntities ) {
+ bindManytoManyInverseFk( collectionEntity, inverseJoinColumns, element, unique,
mappings );
+ }
+
+ }
+
+ private static void checkFilterConditions(Collection collValue) {
+ //for now it can't happen, but sometime soon...
+ if ( ( collValue.getFilterMap().size() != 0 || StringHelper.isNotEmpty(
collValue.getWhere() ) ) &&
+ collValue.getFetchMode() == FetchMode.JOIN &&
+ !( collValue.getElement() instanceof SimpleValue ) && //SimpleValue
(CollectionOfElements) are always SELECT but it does not matter
+ collValue.getElement().getFetchMode() != FetchMode.JOIN ) {
+ throw new MappingException(
+ "@ManyToMany or @CollectionOfElements defining filter or where without join
fetching "
+ + "not valid within collection using join fetching[" +
collValue.getRole() + "]"
+ );
+ }
+ }
+
+ private static void bindCollectionSecondPass(
+ Collection collValue, PersistentClass collectionEntity, Ejb3JoinColumn[] joinColumns,
+ boolean cascadeDeleteEnabled, XProperty property,
+ ExtendedMappings mappings
+ ) {
+ BinderHelper.createSyntheticPropertyReference(
+ joinColumns, collValue.getOwner(), collectionEntity, collValue, false, mappings
+ );
+ SimpleValue key = buildCollectionKey( collValue, joinColumns, cascadeDeleteEnabled,
property, mappings );
+ TableBinder.bindFk( collValue.getOwner(), collectionEntity, joinColumns, key, false,
mappings );
+ }
+
+ public void setCascadeDeleteEnabled(boolean onDeleteCascade) {
+ this.cascadeDeleteEnabled = onDeleteCascade;
+ }
+
+ private String safeCollectionRole() {
+ if ( propertyHolder != null ) {
+ return propertyHolder.getEntityName() + "." + propertyName;
+ }
+ else {
+ return "";
+ }
+ }
+
+
+ /**
+ * bind the inverse FK of a ManyToMany
+ * If we are in a mappedBy case, read the columns from the associated
+ * colletion element
+ * Otherwise delegates to the usual algorithm
+ */
+ public static void bindManytoManyInverseFk(
+ PersistentClass referencedEntity, Ejb3JoinColumn[] columns, SimpleValue value, boolean
unique,
+ ExtendedMappings mappings
+ ) {
+ final String mappedBy = columns[0].getMappedBy();
+ if ( StringHelper.isNotEmpty( mappedBy ) ) {
+ final Property property = referencedEntity.getRecursiveProperty( mappedBy );
+ Iterator mappedByColumns;
+ if ( property.getValue() instanceof Collection ) {
+ mappedByColumns = ( (Collection) property.getValue() ).getKey().getColumnIterator();
+ }
+ else {
+ //find the appropriate reference key, can be in a join
+ Iterator joinsIt = referencedEntity.getJoinIterator();
+ KeyValue key = null;
+ while ( joinsIt.hasNext() ) {
+ Join join = (Join) joinsIt.next();
+ if ( join.containsProperty( property ) ) {
+ key = join.getKey();
+ break;
+ }
+ }
+ if ( key == null ) key = property.getPersistentClass().getIdentifier();
+ mappedByColumns = key.getColumnIterator();
+ }
+ while ( mappedByColumns.hasNext() ) {
+ Column column = (Column) mappedByColumns.next();
+ columns[0].linkValueUsingAColumnCopy( column, value );
+ }
+ String referencedPropertyName =
+ mappings.getPropertyReferencedAssociation(
+ "inverse__" + referencedEntity.getEntityName(), mappedBy
+ );
+ if ( referencedPropertyName != null ) {
+ //TODO always a many to one?
+ ( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName );
+ mappings.addUniquePropertyReference( referencedEntity.getEntityName(),
referencedPropertyName );
+ }
+ value.createForeignKey();
+ }
+ else {
+ BinderHelper.createSyntheticPropertyReference( columns, referencedEntity, null, value,
true, mappings );
+ TableBinder.bindFk( referencedEntity, null, columns, value, unique, mappings );
+ }
+ }
+
+ public void setFkJoinColumns(Ejb3JoinColumn[] ejb3JoinColumns) {
+ this.fkJoinColumns = ejb3JoinColumns;
+ }
+
+ public void setExplicitAssociationTable(boolean explicitAssocTable) {
+ this.isExplicitAssociationTable = explicitAssocTable;
+ }
+
+ public void setElementColumns(Ejb3Column[] elementColumns) {
+ this.elementColumns = elementColumns;
+ }
+
+ public void setEmbedded(boolean annotationPresent) {
+ this.isEmbedded = annotationPresent;
+ }
+
+ public void setProperty(XProperty property) {
+ this.property = property;
+ }
+
+ public void setIgnoreNotFound(boolean ignoreNotFound) {
+ this.ignoreNotFound = ignoreNotFound;
+ }
+
+ public void setMapKeyColumns(Ejb3Column[] mapKeyColumns) {
+ this.mapKeyColumns = mapKeyColumns;
+ }
+
+ public void setMapKeyManyToManyColumns(Ejb3JoinColumn[] mapJoinColumns) {
+ this.mapKeyManyToManyColumns = mapJoinColumns;
+ }
+
+ public void setLocalGenerators(HashMap<String, IdGenerator> localGenerators) {
+ this.localGenerators = localGenerators;
+ }
+}
\ No newline at end of file
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,808 @@
+//$Id: EntityBinder.java 14741 2008-06-05 11:25:56Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.SecondaryTable;
+import javax.persistence.SecondaryTables;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.EntityMode;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.AccessType;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+import org.hibernate.annotations.FetchMode;
+import org.hibernate.annotations.ForceDiscriminator;
+import org.hibernate.annotations.Immutable;
+import org.hibernate.annotations.Loader;
+import org.hibernate.annotations.OptimisticLockType;
+import org.hibernate.annotations.Persister;
+import org.hibernate.annotations.PolymorphismType;
+import org.hibernate.annotations.Proxy;
+import org.hibernate.annotations.SQLDelete;
+import org.hibernate.annotations.SQLDeleteAll;
+import org.hibernate.annotations.SQLInsert;
+import org.hibernate.annotations.SQLUpdate;
+import org.hibernate.annotations.Tables;
+import org.hibernate.annotations.Tuplizer;
+import org.hibernate.annotations.Tuplizers;
+import org.hibernate.annotations.Where;
+import org.hibernate.annotations.common.reflection.XAnnotatedElement;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.cfg.AnnotationBinder;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.Ejb3JoinColumn;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.InheritanceState;
+import org.hibernate.cfg.PropertyHolder;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.engine.FilterDefinition;
+import org.hibernate.engine.Versioning;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.TableOwner;
+import org.hibernate.mapping.Value;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Stateful holder and processor for binding Entity information
+ *
+ * @author Emmanuel Bernard
+ */
+public class EntityBinder {
+ private String name;
+ private XClass annotatedClass;
+ private PersistentClass persistentClass;
+ private ExtendedMappings mappings;
+ private Logger log = LoggerFactory.getLogger( EntityBinder.class );
+ private String discriminatorValue = "";
+ private boolean isPropertyAnnotated = false;
+ private boolean dynamicInsert;
+ private boolean dynamicUpdate;
+ private boolean explicitHibernateEntityAnnotation;
+ private OptimisticLockType optimisticLockType;
+ private PolymorphismType polymorphismType;
+ private boolean selectBeforeUpdate;
+ private int batchSize;
+ private boolean lazy;
+ private XClass proxyClass;
+ private String where;
+ private java.util.Map<String, Join> secondaryTables = new HashMap<String,
Join>();
+ private java.util.Map<String, Object> secondaryTableJoins = new HashMap<String,
Object>();
+ private String cacheConcurrentStrategy;
+ private String cacheRegion;
+ private java.util.Map<String, String> filters = new HashMap<String,
String>();
+ private InheritanceState inheritanceState;
+ private boolean ignoreIdAnnotations;
+ private boolean cacheLazyProperty;
+ private String propertyAccessor;
+
+ public boolean isPropertyAnnotated() {
+ return isPropertyAnnotated;
+ }
+
+ /**
+ * Use as a fake one for Collection of elements
+ */
+ public EntityBinder() {
+ }
+
+ public EntityBinder(
+ Entity ejb3Ann, org.hibernate.annotations.Entity hibAnn,
+ XClass annotatedClass, PersistentClass persistentClass,
+ ExtendedMappings mappings
+ ) {
+ this.mappings = mappings;
+ this.persistentClass = persistentClass;
+ this.annotatedClass = annotatedClass;
+ bindEjb3Annotation( ejb3Ann );
+ bindHibernateAnnotation( hibAnn );
+ }
+
+ private void bindHibernateAnnotation(org.hibernate.annotations.Entity hibAnn) {
+ if ( hibAnn != null ) {
+ dynamicInsert = hibAnn.dynamicInsert();
+ dynamicUpdate = hibAnn.dynamicUpdate();
+ optimisticLockType = hibAnn.optimisticLock();
+ selectBeforeUpdate = hibAnn.selectBeforeUpdate();
+ polymorphismType = hibAnn.polymorphism();
+ explicitHibernateEntityAnnotation = true;
+ //persister handled in bind
+ }
+ else {
+ //default values when the annotation is not there
+ dynamicInsert = false;
+ dynamicUpdate = false;
+ optimisticLockType = OptimisticLockType.VERSION;
+ polymorphismType = PolymorphismType.IMPLICIT;
+ selectBeforeUpdate = false;
+ }
+ }
+
+ private void bindEjb3Annotation(Entity ejb3Ann) {
+ if ( ejb3Ann == null ) throw new AssertionFailure( "@Entity should always be not
null" );
+ if ( BinderHelper.isDefault( ejb3Ann.name() ) ) {
+ name = StringHelper.unqualify( annotatedClass.getName() );
+ }
+ else {
+ name = ejb3Ann.name();
+ }
+ }
+
+ public void setDiscriminatorValue(String discriminatorValue) {
+ this.discriminatorValue = discriminatorValue;
+ }
+
+ public void bindEntity() {
+ persistentClass.setAbstract( annotatedClass.isAbstract() );
+ persistentClass.setClassName( annotatedClass.getName() );
+ persistentClass.setNodeName( name );
+ //persistentClass.setDynamic(false); //no longer needed with the Entity name
refactoring?
+ persistentClass.setEntityName( annotatedClass.getName() );
+ bindDiscriminatorValue();
+
+ persistentClass.setLazy( lazy );
+ if ( proxyClass != null ) {
+ persistentClass.setProxyInterfaceName( proxyClass.getName() );
+ }
+ persistentClass.setDynamicInsert( dynamicInsert );
+ persistentClass.setDynamicUpdate( dynamicUpdate );
+
+ if ( persistentClass instanceof RootClass ) {
+ RootClass rootClass = (RootClass) persistentClass;
+ boolean mutable = true;
+ //priority on @Immutable, then @Entity.mutable()
+ if ( annotatedClass.isAnnotationPresent( Immutable.class ) ) {
+ mutable = false;
+ }
+ else {
+ org.hibernate.annotations.Entity entityAnn =
+ annotatedClass.getAnnotation( org.hibernate.annotations.Entity.class );
+ if ( entityAnn != null ) {
+ mutable = entityAnn.mutable();
+ }
+ }
+ rootClass.setMutable( mutable );
+ rootClass.setExplicitPolymorphism( isExplicitPolymorphism( polymorphismType ) );
+ if ( StringHelper.isNotEmpty( where ) ) rootClass.setWhere( where );
+ if ( cacheConcurrentStrategy != null ) {
+ rootClass.setCacheConcurrencyStrategy( cacheConcurrentStrategy );
+ rootClass.setCacheRegionName( cacheRegion );
+ rootClass.setLazyPropertiesCacheable( cacheLazyProperty );
+ }
+ rootClass.setForceDiscriminator( annotatedClass.isAnnotationPresent(
ForceDiscriminator.class ) );
+ }
+ else {
+ if ( explicitHibernateEntityAnnotation ) {
+ log.warn( "(a)org.hibernate.annotations.Entity used on a non root entity: ignored
for {}",
+ annotatedClass.getName() );
+ }
+ if ( annotatedClass.isAnnotationPresent( Immutable.class ) ) {
+ log.warn( "@Immutable used on a non root entity: ignored for {}",
+ annotatedClass.getName() );
+ }
+ }
+ persistentClass.setOptimisticLockMode( getVersioning( optimisticLockType ) );
+ persistentClass.setSelectBeforeUpdate( selectBeforeUpdate );
+
+ //set persister if needed
+ //@Persister has precedence over @Entity.persister
+ Persister persisterAnn = annotatedClass.getAnnotation( Persister.class );
+ Class persister = null;
+ if ( persisterAnn != null ) {
+ persister = persisterAnn.impl();
+ }
+ else {
+ org.hibernate.annotations.Entity entityAnn = annotatedClass.getAnnotation(
org.hibernate.annotations.Entity.class );
+ if ( entityAnn != null && !BinderHelper.isDefault( entityAnn.persister() ) )
{
+ try {
+ persister = ReflectHelper.classForName( entityAnn.persister() );
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw new AnnotationException( "Could not find persister class: " +
persister );
+ }
+ }
+ }
+ if ( persister != null ) persistentClass.setEntityPersisterClass( persister );
+
+ persistentClass.setBatchSize( batchSize );
+
+ //SQL overriding
+ SQLInsert sqlInsert = annotatedClass.getAnnotation( SQLInsert.class );
+ SQLUpdate sqlUpdate = annotatedClass.getAnnotation( SQLUpdate.class );
+ SQLDelete sqlDelete = annotatedClass.getAnnotation( SQLDelete.class );
+ SQLDeleteAll sqlDeleteAll = annotatedClass.getAnnotation( SQLDeleteAll.class );
+ Loader loader = annotatedClass.getAnnotation( Loader.class );
+ if ( sqlInsert != null ) {
+ persistentClass.setCustomSQLInsert( sqlInsert.sql().trim(), sqlInsert.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlInsert.check().toString().toLowerCase() )
+ );
+
+ }
+ if ( sqlUpdate != null ) {
+ persistentClass.setCustomSQLUpdate( sqlUpdate.sql(), sqlUpdate.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlUpdate.check().toString().toLowerCase() )
+ );
+ }
+ if ( sqlDelete != null ) {
+ persistentClass.setCustomSQLDelete( sqlDelete.sql(), sqlDelete.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlDelete.check().toString().toLowerCase() )
+ );
+ }
+ if ( sqlDeleteAll != null ) {
+ persistentClass.setCustomSQLDelete( sqlDeleteAll.sql(), sqlDeleteAll.callable(),
+ ExecuteUpdateResultCheckStyle.parse( sqlDeleteAll.check().toString().toLowerCase()
)
+ );
+ }
+ if ( loader != null ) {
+ persistentClass.setLoaderName( loader.namedQuery() );
+ }
+
+ //tuplizers
+ if ( annotatedClass.isAnnotationPresent( Tuplizers.class ) ) {
+ for (Tuplizer tuplizer : annotatedClass.getAnnotation( Tuplizers.class ).value()) {
+ EntityMode mode = EntityMode.parse( tuplizer.entityMode() );
+ persistentClass.addTuplizer( mode, tuplizer.impl().getName() );
+ }
+ }
+ if ( annotatedClass.isAnnotationPresent( Tuplizer.class ) ) {
+ Tuplizer tuplizer = annotatedClass.getAnnotation( Tuplizer.class );
+ EntityMode mode = EntityMode.parse( tuplizer.entityMode() );
+ persistentClass.addTuplizer( mode, tuplizer.impl().getName() );
+ }
+
+ if ( !inheritanceState.hasParents ) {
+ Iterator<Map.Entry<String, String>> iter = filters.entrySet().iterator();
+ while ( iter.hasNext() ) {
+ Map.Entry<String, String> filter = iter.next();
+ String filterName = filter.getKey();
+ String cond = filter.getValue();
+ if ( BinderHelper.isDefault( cond ) ) {
+ FilterDefinition definition = mappings.getFilterDefinition( filterName );
+ cond = definition == null ? null : definition.getDefaultFilterCondition();
+ if ( StringHelper.isEmpty( cond ) ) {
+ throw new AnnotationException(
+ "no filter condition found for filter " + filterName + " in "
+ this.name
+ );
+ }
+ }
+ persistentClass.addFilter( filterName, cond );
+ }
+ }
+ else {
+ if ( filters.size() > 0 ) {
+ log.warn( "@Filter not allowed on subclasses (ignored): {}",
persistentClass.getEntityName() );
+ }
+ }
+ log.debug( "Import with entity name {}", name );
+ try {
+ mappings.addImport( persistentClass.getEntityName(), name );
+ String entityName = persistentClass.getEntityName();
+ if ( !entityName.equals( name ) ) {
+ mappings.addImport( entityName, entityName );
+ }
+ }
+ catch (MappingException me) {
+ throw new AnnotationException( "Use of the same entity name twice: " + name,
me );
+ }
+ }
+
+ public void bindDiscriminatorValue() {
+ if ( StringHelper.isEmpty( discriminatorValue ) ) {
+ Value discriminator = persistentClass.getDiscriminator();
+ if ( discriminator == null ) {
+ persistentClass.setDiscriminatorValue( name );
+ }
+ else if ( "character".equals( discriminator.getType().getName() ) ) {
+ throw new AnnotationException(
+ "Using default @DiscriminatorValue for a discriminator of type CHAR is not
safe"
+ );
+ }
+ else if ( "integer".equals( discriminator.getType().getName() ) ) {
+ persistentClass.setDiscriminatorValue( String.valueOf( name.hashCode() ) );
+ }
+ else {
+ persistentClass.setDiscriminatorValue( name ); //Spec compliant
+ }
+ }
+ else {
+ //persistentClass.getDiscriminator()
+ persistentClass.setDiscriminatorValue( discriminatorValue );
+ }
+ }
+
+ int getVersioning(OptimisticLockType type) {
+ switch ( type ) {
+ case VERSION:
+ return Versioning.OPTIMISTIC_LOCK_VERSION;
+ case NONE:
+ return Versioning.OPTIMISTIC_LOCK_NONE;
+ case DIRTY:
+ return Versioning.OPTIMISTIC_LOCK_DIRTY;
+ case ALL:
+ return Versioning.OPTIMISTIC_LOCK_ALL;
+ default:
+ throw new AssertionFailure( "optimistic locking not supported: " + type );
+ }
+ }
+
+ private boolean isExplicitPolymorphism(PolymorphismType type) {
+ switch ( type ) {
+ case IMPLICIT:
+ return false;
+ case EXPLICIT:
+ return true;
+ default:
+ throw new AssertionFailure( "Unknown polymorphism type: " + type );
+ }
+ }
+
+ public void setBatchSize(BatchSize sizeAnn) {
+ if ( sizeAnn != null ) {
+ batchSize = sizeAnn.size();
+ }
+ else {
+ batchSize = -1;
+ }
+ }
+
+ public void setProxy(Proxy proxy) {
+ if ( proxy != null ) {
+ lazy = proxy.lazy();
+ if ( !lazy ) {
+ proxyClass = null;
+ }
+ else {
+ if ( AnnotationBinder.isDefault(
+ mappings.getReflectionManager().toXClass( proxy.proxyClass() ), mappings
+ ) ) {
+ proxyClass = annotatedClass;
+ }
+ else {
+ proxyClass = mappings.getReflectionManager().toXClass( proxy.proxyClass() );
+ }
+ }
+ }
+ else {
+ lazy = true; //needed to allow association lazy loading.
+ proxyClass = annotatedClass;
+ }
+ }
+
+ public void setWhere(Where whereAnn) {
+ if ( whereAnn != null ) {
+ where = whereAnn.clause();
+ }
+ }
+
+ private String getClassTableName(String tableName) {
+ if ( StringHelper.isEmpty( tableName ) ) {
+ return mappings.getNamingStrategy().classToTableName( name );
+ }
+ else {
+ return mappings.getNamingStrategy().tableName( tableName );
+ }
+ }
+
+ public void bindTable(
+ String schema, String catalog,
+ String tableName, List uniqueConstraints,
+ String constraints, Table denormalizedSuperclassTable
+ ) {
+ String logicalName = StringHelper.isNotEmpty( tableName ) ?
+ tableName :
+ StringHelper.unqualify( name );
+ Table table = TableBinder.fillTable(
+ schema, catalog,
+ getClassTableName( tableName ),
+ logicalName,
+ persistentClass.isAbstract(), uniqueConstraints, constraints,
+ denormalizedSuperclassTable, mappings
+ );
+
+ if ( persistentClass instanceof TableOwner ) {
+ log.info( "Bind entity {} on table {}", persistentClass.getEntityName(),
table.getName() );
+ ( (TableOwner) persistentClass ).setTable( table );
+ }
+ else {
+ throw new AssertionFailure( "binding a table for a subclass" );
+ }
+ }
+
+ public void finalSecondaryTableBinding(PropertyHolder propertyHolder) {
+ /*
+ * Those operations has to be done after the id definition of the persistence class.
+ * ie after the properties parsing
+ */
+ Iterator joins = secondaryTables.values().iterator();
+ Iterator joinColumns = secondaryTableJoins.values().iterator();
+
+ while ( joins.hasNext() ) {
+ Object uncastedColumn = joinColumns.next();
+ Join join = (Join) joins.next();
+ createPrimaryColumnsToSecondaryTable( uncastedColumn, propertyHolder, join );
+ }
+ mappings.addJoins( persistentClass, secondaryTables );
+ }
+
+ private void createPrimaryColumnsToSecondaryTable(Object uncastedColumn, PropertyHolder
propertyHolder, Join join) {
+ Ejb3JoinColumn[] ejb3JoinColumns;
+ PrimaryKeyJoinColumn[] pkColumnsAnn = null;
+ JoinColumn[] joinColumnsAnn = null;
+ if ( uncastedColumn instanceof PrimaryKeyJoinColumn[] ) {
+ pkColumnsAnn = (PrimaryKeyJoinColumn[]) uncastedColumn;
+ }
+ if ( uncastedColumn instanceof JoinColumn[] ) {
+ joinColumnsAnn = (JoinColumn[]) uncastedColumn;
+ }
+ if ( pkColumnsAnn == null && joinColumnsAnn == null ) {
+ ejb3JoinColumns = new Ejb3JoinColumn[1];
+ ejb3JoinColumns[0] = Ejb3JoinColumn.buildJoinColumn(
+ null,
+ null,
+ persistentClass.getIdentifier(),
+ secondaryTables,
+ propertyHolder, mappings
+ );
+ }
+ else {
+ int nbrOfJoinColumns = pkColumnsAnn != null ?
+ pkColumnsAnn.length :
+ joinColumnsAnn.length;
+ if ( nbrOfJoinColumns == 0 ) {
+ ejb3JoinColumns = new Ejb3JoinColumn[1];
+ ejb3JoinColumns[0] = Ejb3JoinColumn.buildJoinColumn(
+ null,
+ null,
+ persistentClass.getIdentifier(),
+ secondaryTables,
+ propertyHolder, mappings
+ );
+ }
+ else {
+ ejb3JoinColumns = new Ejb3JoinColumn[nbrOfJoinColumns];
+ if ( pkColumnsAnn != null ) {
+ for (int colIndex = 0; colIndex < nbrOfJoinColumns; colIndex++) {
+ ejb3JoinColumns[colIndex] = Ejb3JoinColumn.buildJoinColumn(
+ pkColumnsAnn[colIndex],
+ null,
+ persistentClass.getIdentifier(),
+ secondaryTables,
+ propertyHolder, mappings
+ );
+ }
+ }
+ else {
+ for (int colIndex = 0; colIndex < nbrOfJoinColumns; colIndex++) {
+ ejb3JoinColumns[colIndex] = Ejb3JoinColumn.buildJoinColumn(
+ null,
+ joinColumnsAnn[colIndex],
+ persistentClass.getIdentifier(),
+ secondaryTables,
+ propertyHolder, mappings
+ );
+ }
+ }
+ }
+ }
+
+ for (Ejb3JoinColumn joinColumn : ejb3JoinColumns) {
+ joinColumn.forceNotNull();
+ }
+ bindJoinToPersistentClass( join, ejb3JoinColumns );
+ }
+
+ private void bindJoinToPersistentClass(
+ Join join, Ejb3JoinColumn[] ejb3JoinColumns
+ ) {
+ SimpleValue key = new DependantValue( join.getTable(), persistentClass.getIdentifier()
);
+ join.setKey( key );
+ setFKNameIfDefined( join );
+ key.setCascadeDeleteEnabled( false );
+ TableBinder.bindFk( persistentClass, null, ejb3JoinColumns, key, false, mappings );
+ join.createPrimaryKey();
+ join.createForeignKey();
+ persistentClass.addJoin( join );
+ }
+
+ private void setFKNameIfDefined(Join join) {
+ org.hibernate.annotations.Table matchingTable = findMatchingComplimentTableAnnotation(
join );
+ if ( matchingTable != null && !BinderHelper.isDefault(
matchingTable.foreignKey().name() ) ) {
+ ( (SimpleValue) join.getKey() ).setForeignKeyName( matchingTable.foreignKey().name()
);
+ }
+ }
+
+ private org.hibernate.annotations.Table findMatchingComplimentTableAnnotation(Join join)
{
+ String tableName = join.getTable().getQuotedName();
+ org.hibernate.annotations.Table table = annotatedClass.getAnnotation(
org.hibernate.annotations.Table.class );
+ org.hibernate.annotations.Table matchingTable = null;
+ if ( table != null && tableName.equals( table.appliesTo() ) ) {
+ matchingTable = table;
+ }
+ else {
+ Tables tables = annotatedClass.getAnnotation( Tables.class );
+ if ( tables != null ) {
+ for (org.hibernate.annotations.Table current : tables.value()) {
+ if ( tableName.equals( current.appliesTo() ) ) {
+ matchingTable = current;
+ break;
+ }
+ }
+ }
+ }
+ return matchingTable;
+ }
+
+ public void firstLevelSecondaryTablesBinding(
+ SecondaryTable secTable, SecondaryTables secTables
+ ) {
+ if ( secTables != null ) {
+ //loop through it
+ for (SecondaryTable tab : secTables.value()) {
+ addJoin( tab, null, null, false );
+ }
+ }
+ else {
+ if ( secTable != null ) addJoin( secTable, null, null, false );
+ }
+ }
+
+ //Used for @*ToMany @JoinTable
+ public Join addJoin(JoinTable joinTable, PropertyHolder holder, boolean
noDelayInPkColumnCreation) {
+ return addJoin( null, joinTable, holder, noDelayInPkColumnCreation );
+ }
+
+ /**
+ * A non null propertyHolder means than we process the Pk creation without delay
+ */
+ private Join addJoin(
+ SecondaryTable secondaryTable, JoinTable joinTable, PropertyHolder propertyHolder,
+ boolean noDelayInPkColumnCreation
+ ) {
+ Join join = new Join();
+ join.setPersistentClass( persistentClass );
+ String schema;
+ String catalog;
+ String table;
+ String realTable;
+ UniqueConstraint[] uniqueConstraintsAnn;
+ if ( secondaryTable != null ) {
+ schema = secondaryTable.schema();
+ catalog = secondaryTable.catalog();
+ table = secondaryTable.name();
+ realTable = mappings.getNamingStrategy().tableName( table ); //always an explicit
table name
+ uniqueConstraintsAnn = secondaryTable.uniqueConstraints();
+ }
+ else if ( joinTable != null ) {
+ schema = joinTable.schema();
+ catalog = joinTable.catalog();
+ table = joinTable.name();
+ realTable = mappings.getNamingStrategy().tableName( table ); //always an explicit
table name
+ uniqueConstraintsAnn = joinTable.uniqueConstraints();
+ }
+ else {
+ throw new AssertionFailure( "Both JoinTable and SecondaryTable are null" );
+ }
+ List uniqueConstraints = new ArrayList( uniqueConstraintsAnn == null ?
+ 0 :
+ uniqueConstraintsAnn.length );
+ if ( uniqueConstraintsAnn != null && uniqueConstraintsAnn.length != 0 ) {
+ for (UniqueConstraint uc : uniqueConstraintsAnn) {
+ uniqueConstraints.add( uc.columnNames() );
+ }
+ }
+ Table tableMapping = TableBinder.fillTable(
+ schema,
+ catalog,
+ realTable,
+ table, false, uniqueConstraints, null, null, mappings
+ );
+ //no check constraints available on joins
+ join.setTable( tableMapping );
+
+ //somehow keep joins() for later.
+ //Has to do the work later because it needs persistentClass id!
+ Object joinColumns = null;
+ //get the appropriate pk columns
+ if ( secondaryTable != null ) {
+ joinColumns = secondaryTable.pkJoinColumns();
+ }
+ else if ( joinTable != null ) {
+ joinColumns = joinTable.joinColumns();
+ }
+ log.info(
+ "Adding secondary table to entity {} -> {}",
persistentClass.getEntityName(), join.getTable().getName()
+ );
+
+ org.hibernate.annotations.Table matchingTable = findMatchingComplimentTableAnnotation(
join );
+ if ( matchingTable != null ) {
+ join.setSequentialSelect( FetchMode.JOIN != matchingTable.fetch() );
+ join.setInverse( matchingTable.inverse() );
+ join.setOptional( matchingTable.optional() );
+ if ( !BinderHelper.isDefault( matchingTable.sqlInsert().sql() ) ) {
+ join.setCustomSQLInsert( matchingTable.sqlInsert().sql().trim(),
+ matchingTable.sqlInsert().callable(),
+ ExecuteUpdateResultCheckStyle.parse(
matchingTable.sqlInsert().check().toString().toLowerCase() )
+ );
+ }
+ if ( !BinderHelper.isDefault( matchingTable.sqlUpdate().sql() ) ) {
+ join.setCustomSQLUpdate( matchingTable.sqlUpdate().sql().trim(),
+ matchingTable.sqlUpdate().callable(),
+ ExecuteUpdateResultCheckStyle.parse(
matchingTable.sqlUpdate().check().toString().toLowerCase() )
+ );
+ }
+ if ( !BinderHelper.isDefault( matchingTable.sqlDelete().sql() ) ) {
+ join.setCustomSQLDelete( matchingTable.sqlDelete().sql().trim(),
+ matchingTable.sqlDelete().callable(),
+ ExecuteUpdateResultCheckStyle.parse(
matchingTable.sqlDelete().check().toString().toLowerCase() )
+ );
+ }
+ }
+ else {
+ //default
+ join.setSequentialSelect( false );
+ join.setInverse( false );
+ join.setOptional( true ); //perhaps not quite per-spec, but a Good Thing anyway
+ }
+
+ if ( noDelayInPkColumnCreation ) {
+ createPrimaryColumnsToSecondaryTable( joinColumns, propertyHolder, join );
+ }
+ else {
+ secondaryTables.put( realTable, join );
+ secondaryTableJoins.put( realTable, joinColumns );
+ }
+ return join;
+ }
+
+ public java.util.Map<String, Join> getSecondaryTables() {
+ return secondaryTables;
+ }
+
+ public void setCache(Cache cacheAnn) {
+ if ( cacheAnn != null ) {
+ cacheRegion = BinderHelper.isDefault( cacheAnn.region() ) ?
+ null :
+ cacheAnn.region();
+ cacheConcurrentStrategy = getCacheConcurrencyStrategy( cacheAnn.usage() );
+ if ( "all".equalsIgnoreCase( cacheAnn.include() ) ) {
+ cacheLazyProperty = true;
+ }
+ else if ( "non-lazy".equalsIgnoreCase( cacheAnn.include() ) ) {
+ cacheLazyProperty = false;
+ }
+ else {
+ throw new AnnotationException( "Unknown lazy property annotations: " +
cacheAnn.include() );
+ }
+ }
+ else {
+ cacheConcurrentStrategy = null;
+ cacheRegion = null;
+ cacheLazyProperty = true;
+ }
+ }
+
+ public static String getCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) {
+ switch ( strategy ) {
+ case NONE:
+ return null;
+ case READ_ONLY:
+ return org.hibernate.cache.access.AccessType.READ_ONLY.getName();
+ case READ_WRITE:
+ return org.hibernate.cache.access.AccessType.READ_WRITE.getName();
+ case NONSTRICT_READ_WRITE:
+ return org.hibernate.cache.access.AccessType.NONSTRICT_READ_WRITE.getName();
+ case TRANSACTIONAL:
+ return org.hibernate.cache.access.AccessType.TRANSACTIONAL.getName();
+ default:
+ throw new AssertionFailure( "CacheConcurrencyStrategy unknown: " + strategy
);
+ }
+ }
+
+ public void addFilter(String name, String condition) {
+ filters.put( name, condition );
+ }
+
+ public void setInheritanceState(InheritanceState inheritanceState) {
+ this.inheritanceState = inheritanceState;
+ }
+
+ public boolean isIgnoreIdAnnotations() {
+ return ignoreIdAnnotations;
+ }
+
+ public void setIgnoreIdAnnotations(boolean ignoreIdAnnotations) {
+ this.ignoreIdAnnotations = ignoreIdAnnotations;
+ }
+
+ public void processComplementaryTableDefinitions(org.hibernate.annotations.Table table)
{
+ //comment and index are processed here
+ if ( table == null ) return;
+ String appliedTable = table.appliesTo();
+ Iterator tables = persistentClass.getTableClosureIterator();
+ Table hibTable = null;
+ while ( tables.hasNext() ) {
+ Table pcTable = (Table) tables.next();
+ if ( pcTable.getQuotedName().equals( appliedTable ) ) {
+ //we are in the correct table to find columns
+ hibTable = pcTable;
+ break;
+ }
+ hibTable = null;
+ }
+ if ( hibTable == null ) {
+ //maybe a join/secondary table
+ for ( Join join : secondaryTables.values() ) {
+ if ( join.getTable().getQuotedName().equals( appliedTable ) ) {
+ hibTable = join.getTable();
+ break;
+ }
+ }
+ }
+ if ( hibTable == null ) {
+ throw new AnnotationException(
+ "(a)org.hibernate.annotations.Table references an unknown table: " +
appliedTable
+ );
+ }
+ if ( !BinderHelper.isDefault( table.comment() ) ) hibTable.setComment( table.comment()
);
+ TableBinder.addIndexes( hibTable, table.indexes(), mappings );
+ }
+
+ public void processComplementaryTableDefinitions(Tables tables) {
+ if ( tables == null ) return;
+ for (org.hibernate.annotations.Table table : tables.value()) {
+ processComplementaryTableDefinitions( table );
+ }
+ }
+
+ public void setPropertyAnnotated(boolean propertyAnnotated) {
+ this.isPropertyAnnotated = propertyAnnotated;
+ }
+
+ public String getPropertyAccessor() {
+ return propertyAccessor;
+ }
+
+ public void setPropertyAccessor(String propertyAccessor) {
+ this.propertyAccessor = propertyAccessor;
+ }
+
+ public boolean isPropertyAnnotated(XAnnotatedElement element) {
+ AccessType access = element.getAnnotation( AccessType.class );
+ if ( access == null ) return isPropertyAnnotated;
+ String propertyAccessor = access.value();
+ if ( "property".equals( propertyAccessor ) ) {
+ return Boolean.TRUE;
+ }
+ else if ( "field".equals( propertyAccessor ) ) {
+ return Boolean.FALSE;
+ }
+ else {
+ return isPropertyAnnotated;
+ }
+ }
+
+ public String getPropertyAccessor(XAnnotatedElement element) {
+ AccessType access = element.getAnnotation( AccessType.class );
+ if ( access == null ) return propertyAccessor;
+ return access.value();
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,89 @@
+//$Id: IdBagBinder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.annotations.CollectionId;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.Ejb3Column;
+import org.hibernate.cfg.Ejb3JoinColumn;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.PropertyData;
+import org.hibernate.cfg.PropertyInferredData;
+import org.hibernate.cfg.WrappedInferredData;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.IdentifierCollection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class IdBagBinder extends BagBinder {
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new org.hibernate.mapping.IdentifierBag( persistentClass );
+ }
+
+ @Override
+ protected boolean bindStarToManySecondPass(
+ Map persistentClasses, XClass collType, Ejb3JoinColumn[] fkJoinColumns,
Ejb3JoinColumn[] keyColumns,
+ Ejb3JoinColumn[] inverseColumns, Ejb3Column[] elementColumns, boolean isEmbedded,
XProperty property,
+ boolean unique, TableBinder associationTableBinder, boolean ignoreNotFound,
ExtendedMappings mappings
+ ) {
+ boolean result = super.bindStarToManySecondPass(
+ persistentClasses, collType, fkJoinColumns, keyColumns, inverseColumns,
elementColumns, isEmbedded,
+ property, unique, associationTableBinder, ignoreNotFound, mappings
+ );
+ CollectionId collectionIdAnn = property.getAnnotation( CollectionId.class );
+ if ( collectionIdAnn != null ) {
+ SimpleValueBinder simpleValue = new SimpleValueBinder();
+
+ PropertyData propertyData = new WrappedInferredData(
+ new PropertyInferredData( property, null, //default access should not be useful
+ mappings.getReflectionManager() ),
+ "id" );
+ Ejb3Column[] idColumns = Ejb3Column.buildColumnFromAnnotation(
+ collectionIdAnn.columns(),
+ null,
+ Nullability.FORCED_NOT_NULL,
+ propertyHolder,
+ propertyData,
+ Collections.EMPTY_MAP,
+ mappings
+ );
+ Table table = collection.getCollectionTable();
+ simpleValue.setTable( table );
+ simpleValue.setColumns( idColumns );
+ Type typeAnn = collectionIdAnn.type();
+ if ( typeAnn != null && !BinderHelper.isDefault( typeAnn.type() ) ) {
+ simpleValue.setExplicitType( typeAnn );
+ }
+ else {
+ throw new AnnotationException( "@CollectionId is missing type: "
+ + StringHelper.qualify( propertyHolder.getPath(), propertyName ) );
+ }
+ simpleValue.setMappings( mappings );
+ SimpleValue id = simpleValue.make();
+ ( (IdentifierCollection) collection ).setIdentifier( id );
+ String generator = collectionIdAnn.generator();
+ String generatorType;
+ if ( "identity".equals( generator ) || "assigned".equals(
generator )
+ || "sequence".equals( generator ) || "native".equals( generator
) ) {
+ generatorType = generator;
+ generator = "";
+ }
+ else {
+ generatorType = null;
+ }
+ BinderHelper.makeIdGenerator( id, generatorType, generator, mappings, localGenerators
);
+ }
+ return result;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ListBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ListBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ListBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,115 @@
+package org.hibernate.cfg.annotations;
+
+import java.util.Map;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.OrderBy;
+import org.hibernate.annotations.Sort;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.annotations.common.util.StringHelper;
+import org.hibernate.cfg.CollectionSecondPass;
+import org.hibernate.cfg.Ejb3Column;
+import org.hibernate.cfg.Ejb3JoinColumn;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.PropertyHolder;
+import org.hibernate.cfg.PropertyHolderBuilder;
+import org.hibernate.cfg.SecondPass;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.IndexBackref;
+import org.hibernate.mapping.List;
+import org.hibernate.mapping.OneToMany;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.SimpleValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Bind a list to the underlying Hibernate configuration
+ *
+ * @author Matthew Inger
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings({"unchecked", "serial"})
+public class ListBinder extends CollectionBinder {
+ private Logger log = LoggerFactory.getLogger( ListBinder.class );
+
+ public ListBinder() {
+ }
+
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new org.hibernate.mapping.List( persistentClass );
+ }
+
+ public void setSqlOrderBy(OrderBy orderByAnn) {
+ if ( orderByAnn != null ) log.warn( "@OrderBy not allowed for a indexed
collection, annotation ignored." );
+ }
+
+ public void setSort(Sort sortAnn) {
+ if ( sortAnn != null ) log.warn( "@Sort not allowed for a indexed collection,
annotation ignored." );
+ }
+
+ @Override
+ public SecondPass getSecondPass(
+ final Ejb3JoinColumn[] fkJoinColumns, final Ejb3JoinColumn[] keyColumns,
+ final Ejb3JoinColumn[] inverseColumns,
+ final Ejb3Column[] elementColumns,
+ Ejb3Column[] mapKeyColumns, final Ejb3JoinColumn[] mapKeyManyToManyColumns, final
boolean isEmbedded,
+ final XProperty property, final XClass collType,
+ final boolean ignoreNotFound, final boolean unique,
+ final TableBinder assocTableBinder, final ExtendedMappings mappings
+ ) {
+ return new CollectionSecondPass( mappings, ListBinder.this.collection ) {
+ public void secondPass(Map persistentClasses, Map inheritedMetas)
+ throws MappingException {
+ bindStarToManySecondPass(
+ persistentClasses, collType, fkJoinColumns, keyColumns, inverseColumns,
elementColumns,
+ isEmbedded, property, unique, assocTableBinder, ignoreNotFound, mappings
+ );
+ bindIndex( mappings );
+ }
+ };
+ }
+
+ private void bindIndex(final ExtendedMappings mappings) {
+ if ( indexColumn.isImplicit() == false ) {
+ PropertyHolder valueHolder = PropertyHolderBuilder.buildPropertyHolder(
+ this.collection,
+ StringHelper.qualify( this.collection.getRole(), "key" ),
+ (XClass) null,
+ (XProperty) null, propertyHolder, mappings
+ );
+ List list = (List) this.collection;
+ if ( !list.isOneToMany() ) indexColumn.forceNotNull();
+ indexColumn.setPropertyHolder( valueHolder );
+ SimpleValueBinder value = new SimpleValueBinder();
+ value.setColumns( new Ejb3Column[] { indexColumn } );
+ value.setExplicitType( "integer" );
+ value.setMappings( mappings );
+ SimpleValue indexValue = value.make();
+ indexColumn.linkWithValue( indexValue );
+ list.setIndex( indexValue );
+ list.setBaseIndex( indexColumn.getBase() );
+ if ( list.isOneToMany() && !list.getKey().isNullable() &&
!list.isInverse() ) {
+ String entityName = ( (OneToMany) list.getElement() ).getReferencedEntityName();
+ PersistentClass referenced = mappings.getClass( entityName );
+ IndexBackref ib = new IndexBackref();
+ ib.setName( '_' + propertyName + "IndexBackref" );
+ ib.setUpdateable( false );
+ ib.setSelectable( false );
+ ib.setCollectionRole( list.getRole() );
+ ib.setEntityName( list.getOwner().getEntityName() );
+ ib.setValue( list.getIndex() );
+ referenced.addProperty( ib );
+ }
+ }
+ else {
+ Collection coll = this.collection;
+ throw new AnnotationException(
+ "List/array has to be annotated with an @IndexColumn: "
+ + coll.getRole()
+ );
+ }
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/MapBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/MapBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/MapBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,388 @@
+//$Id: MapBinder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.FetchMode;
+import org.hibernate.MappingException;
+import org.hibernate.annotations.MapKeyManyToMany;
+import org.hibernate.annotations.MapKey;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.AnnotatedClassType;
+import org.hibernate.cfg.AnnotationBinder;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.CollectionSecondPass;
+import org.hibernate.cfg.Ejb3Column;
+import org.hibernate.cfg.Ejb3JoinColumn;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.PropertyData;
+import org.hibernate.cfg.PropertyHolder;
+import org.hibernate.cfg.PropertyHolderBuilder;
+import org.hibernate.cfg.PropertyPreloadedData;
+import org.hibernate.cfg.SecondPass;
+import org.hibernate.dialect.HSQLDialect;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.Formula;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.ManyToOne;
+import org.hibernate.mapping.OneToMany;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.Value;
+import org.hibernate.sql.Template;
+import org.hibernate.util.StringHelper;
+
+/**
+ * Implementation to bind a Map
+ *
+ * @author Emmanuel Bernard
+ */
+public class MapBinder extends CollectionBinder {
+ public MapBinder(boolean sorted) {
+ super( sorted );
+ }
+
+ public MapBinder() {
+ super();
+ }
+
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new org.hibernate.mapping.Map( persistentClass );
+ }
+
+ @Override
+ public SecondPass getSecondPass(
+ final Ejb3JoinColumn[] fkJoinColumns, final Ejb3JoinColumn[] keyColumns,
+ final Ejb3JoinColumn[] inverseColumns,
+ final Ejb3Column[] elementColumns,
+ final Ejb3Column[] mapKeyColumns, final Ejb3JoinColumn[] mapKeyManyToManyColumns,
final boolean isEmbedded,
+ final XProperty property, final XClass collType,
+ final boolean ignoreNotFound, final boolean unique,
+ final TableBinder assocTableBinder, final ExtendedMappings mappings
+ ) {
+ return new CollectionSecondPass( mappings, MapBinder.this.collection ) {
+ public void secondPass(Map persistentClasses, Map inheritedMetas)
+ throws MappingException {
+ bindStarToManySecondPass(
+ persistentClasses, collType, fkJoinColumns, keyColumns, inverseColumns,
elementColumns,
+ isEmbedded, property, unique, assocTableBinder, ignoreNotFound, mappings
+ );
+ bindKeyFromAssociationTable(
+ collType, persistentClasses, mapKeyPropertyName, property, isEmbedded, mappings,
+ mapKeyColumns, mapKeyManyToManyColumns,
+ inverseColumns != null ? inverseColumns[0].getPropertyName() : null
+ );
+ }
+ };
+ }
+
+ private void bindKeyFromAssociationTable(
+ XClass collType, Map persistentClasses, String mapKeyPropertyName, XProperty
property,
+ boolean isEmbedded, ExtendedMappings mappings, Ejb3Column[] mapKeyColumns,
+ Ejb3JoinColumn[] mapKeyManyToManyColumns, String targetPropertyName
+ ) {
+ if ( mapKeyPropertyName != null ) {
+ //this is an EJB3 @MapKey
+ PersistentClass associatedClass = (PersistentClass) persistentClasses.get(
collType.getName() );
+ if ( associatedClass == null ) throw new AnnotationException( "Associated class
not found: " + collType );
+ Property mapProperty = BinderHelper.findPropertyByName( associatedClass,
mapKeyPropertyName );
+ if ( mapProperty == null ) {
+ throw new AnnotationException(
+ "Map key property not found: " + collType + "." +
mapKeyPropertyName
+ );
+ }
+ org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
+ Value indexValue = createFormulatedValue( mapProperty.getValue(), map,
targetPropertyName, associatedClass );
+ map.setIndex( indexValue );
+ }
+ else {
+ //this is a true Map mapping
+ //TODO ugly copy/pastle from CollectionBinder.bindManyToManySecondPass
+ String mapKeyType;
+ Class target = void.class;
+ /*
+ * target has priority over reflection for the map key type
+ */
+ if ( property.isAnnotationPresent( org.hibernate.annotations.MapKey.class ) ) {
+ target = property.getAnnotation( org.hibernate.annotations.MapKey.class
).targetElement();
+ }
+ else if ( property.isAnnotationPresent( MapKeyManyToMany.class ) ) {
+ target = property.getAnnotation( MapKeyManyToMany.class ).targetEntity();
+ }
+ if ( !void.class.equals( target ) ) {
+ mapKeyType = target.getName();
+ }
+ else {
+ mapKeyType = property.getMapKey().getName();
+ }
+ PersistentClass collectionEntity = (PersistentClass) persistentClasses.get( mapKeyType
);
+ boolean isIndexOfEntities = collectionEntity != null;
+ ManyToOne element = null;
+ org.hibernate.mapping.Map mapValue = (org.hibernate.mapping.Map) this.collection;
+ if ( isIndexOfEntities ) {
+ element = new ManyToOne( mapValue.getCollectionTable() );
+ mapValue.setIndex( element );
+ element.setReferencedEntityName( mapKeyType );
+ //element.setFetchMode( fetchMode );
+ //element.setLazy( fetchMode != FetchMode.JOIN );
+ //make the second join non lazy
+ element.setFetchMode( FetchMode.JOIN );
+ element.setLazy( false );
+ //does not make sense for a map key element.setIgnoreNotFound( ignoreNotFound );
+ }
+ else {
+ XClass elementClass;
+ AnnotatedClassType classType;
+ // Map<String, javax.persistence.Column[]> columnOverrides =
PropertyHolderBuilder.buildColumnOverride(
+ // property, StringHelper.qualify( collValue.getRole(), "element" )
+ // );
+ //FIXME the "element" is lost
+ PropertyHolder holder = null;
+ if ( BinderHelper.PRIMITIVE_NAMES.contains( mapKeyType ) ) {
+ classType = AnnotatedClassType.NONE;
+ elementClass = null;
+ }
+ else {
+ try {
+ elementClass = mappings.getReflectionManager().classForName( mapKeyType,
MapBinder.class );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException( "Unable to find class: " + mapKeyType, e
);
+ }
+ classType = mappings.getClassType( elementClass );
+
+ holder = PropertyHolderBuilder.buildPropertyHolder(
+ mapValue,
+ StringHelper.qualify( mapValue.getRole(), "mapkey" ),
+ elementClass,
+ property, propertyHolder, mappings
+ );
+ //force in case of attribute override
+ boolean attributeOverride = property.isAnnotationPresent( AttributeOverride.class )
+ || property.isAnnotationPresent( AttributeOverrides.class );
+ if ( isEmbedded || attributeOverride ) {
+ classType = AnnotatedClassType.EMBEDDABLE;
+ }
+ }
+
+ if ( AnnotatedClassType.EMBEDDABLE.equals( classType ) ) {
+ EntityBinder entityBinder = new EntityBinder();
+ PersistentClass owner = mapValue.getOwner();
+ boolean isPropertyAnnotated;
+ //FIXME support @Access for collection of elements
+ //String accessType = access != null ? access.value() : null;
+ if ( owner.getIdentifierProperty() != null ) {
+ isPropertyAnnotated = owner.getIdentifierProperty()
+ .getPropertyAccessorName()
+ .equals( "property" );
+ }
+ else
+ if ( owner.getIdentifierMapper() != null &&
owner.getIdentifierMapper().getPropertySpan() > 0 ) {
+ Property prop = (Property)
owner.getIdentifierMapper().getPropertyIterator().next();
+ isPropertyAnnotated = prop.getPropertyAccessorName().equals( "property"
);
+ }
+ else {
+ throw new AssertionFailure( "Unable to guess collection property accessor
name" );
+ }
+
+ //boolean propertyAccess = embeddable == null || AccessType.PROPERTY.equals(
embeddable.access() );
+ //FIXME "index" is it right?
+ PropertyData inferredData = new PropertyPreloadedData( "property",
"index", elementClass );
+ //TODO be smart with isNullable
+ Component component = AnnotationBinder.fillComponent(
+ holder, inferredData, isPropertyAnnotated, isPropertyAnnotated ?
"property" : "field", true,
+ entityBinder, false, false,
+ true, mappings
+ );
+ mapValue.setIndex( component );
+ }
+ else {
+ SimpleValueBinder elementBinder = new SimpleValueBinder();
+ elementBinder.setMappings( mappings );
+ elementBinder.setReturnedClassName( mapKeyType );
+
+ Ejb3Column[] elementColumns = mapKeyColumns;
+ if ( elementColumns == null || elementColumns.length == 0 ) {
+ elementColumns = new Ejb3Column[1];
+ Ejb3Column column = new Ejb3Column();
+ column.setImplicit( false );
+ column.setNullable( true );
+ column.setLength( Ejb3Column.DEFAULT_COLUMN_LENGTH );
+ column.setLogicalColumnName( Collection.DEFAULT_KEY_COLUMN_NAME );
+ //TODO create an EMPTY_JOINS collection
+ column.setJoins( new HashMap<String, Join>() );
+ column.setMappings( mappings );
+ column.bind();
+ elementColumns[0] = column;
+ }
+ //override the table
+ for (Ejb3Column column : elementColumns) {
+ column.setTable( mapValue.getCollectionTable() );
+ }
+ elementBinder.setColumns( elementColumns );
+ //do not call setType as it extract the type from @Type
+ //the algorithm generally does not apply for map key anyway
+ MapKey mapKeyAnn = property.getAnnotation( org.hibernate.annotations.MapKey.class
);
+ if (mapKeyAnn != null && ! BinderHelper.isDefault( mapKeyAnn.type().type() )
) {
+ elementBinder.setExplicitType( mapKeyAnn.type() );
+ }
+ mapValue.setIndex( elementBinder.make() );
+ }
+ }
+ //FIXME pass the Index Entity JoinColumns
+ if ( !collection.isOneToMany() ) {
+ //index column shoud not be null
+ for (Ejb3JoinColumn col : mapKeyManyToManyColumns) {
+ col.forceNotNull();
+ }
+ }
+ if ( isIndexOfEntities ) {
+ bindManytoManyInverseFk(
+ collectionEntity,
+ mapKeyManyToManyColumns,
+ element,
+ false, //a map key column has no unique constraint
+ mappings
+ );
+ }
+ }
+ }
+
+ protected Value createFormulatedValue(
+ Value value, Collection collection, String targetPropertyName, PersistentClass
associatedClass
+ ) {
+ Value element = collection.getElement();
+ String fromAndWhere = null;
+ if ( !( element instanceof OneToMany ) ) {
+ String referencedPropertyName = null;
+ if ( element instanceof ToOne ) {
+ referencedPropertyName = ( (ToOne) element ).getReferencedPropertyName();
+ }
+ else if ( element instanceof DependantValue ) {
+ //TODO this never happen I think
+ if ( propertyName != null ) {
+ referencedPropertyName = collection.getReferencedPropertyName();
+ }
+ else {
+ throw new AnnotationException( "SecondaryTable JoinColumn cannot reference a
non primary key" );
+ }
+ }
+ Iterator referencedEntityColumns;
+ if ( referencedPropertyName == null ) {
+ referencedEntityColumns = associatedClass.getIdentifier().getColumnIterator();
+ }
+ else {
+ Property referencedProperty = associatedClass.getRecursiveProperty(
referencedPropertyName );
+ referencedEntityColumns = referencedProperty.getColumnIterator();
+ }
+ String alias = "$alias$";
+ StringBuilder fromAndWhereSb = new StringBuilder( " from " )
+ .append( associatedClass.getTable().getName() )
+ //.append(" as ") //Oracle doesn't support it in subqueries
+ .append( " " )
+ .append( alias ).append( " where " );
+ Iterator collectionTableColumns = element.getColumnIterator();
+ while ( collectionTableColumns.hasNext() ) {
+ Column colColumn = (Column) collectionTableColumns.next();
+ Column refColumn = (Column) referencedEntityColumns.next();
+ fromAndWhereSb.append( alias ).append( '.' ).append(
refColumn.getQuotedName() )
+ .append( '=' ).append( colColumn.getQuotedName() ).append( " and
" );
+ }
+ fromAndWhere = fromAndWhereSb.substring( 0, fromAndWhereSb.length() - 5 );
+ }
+
+ if ( value instanceof Component ) {
+ Component component = (Component) value;
+ Iterator properties = component.getPropertyIterator();
+ Component indexComponent = new Component( collection );
+ indexComponent.setComponentClassName( component.getComponentClassName() );
+ //TODO I don't know if this is appropriate
+ indexComponent.setNodeName( "index" );
+ while ( properties.hasNext() ) {
+ Property current = (Property) properties.next();
+ Property newProperty = new Property();
+ newProperty.setCascade( current.getCascade() );
+ newProperty.setGeneration( current.getGeneration() );
+ newProperty.setInsertable( false );
+ newProperty.setUpdateable( false );
+ newProperty.setMetaAttributes( current.getMetaAttributes() );
+ newProperty.setName( current.getName() );
+ newProperty.setNodeName( current.getNodeName() );
+ newProperty.setNaturalIdentifier( false );
+ //newProperty.setOptimisticLocked( false );
+ newProperty.setOptional( false );
+ newProperty.setPersistentClass( current.getPersistentClass() );
+ newProperty.setPropertyAccessorName( current.getPropertyAccessorName() );
+ newProperty.setSelectable( current.isSelectable() );
+ newProperty.setValue( createFormulatedValue( current.getValue(), collection,
targetPropertyName,
+ associatedClass
+ ) );
+ indexComponent.addProperty( newProperty );
+ }
+ return indexComponent;
+ }
+ else if ( value instanceof SimpleValue ) {
+ SimpleValue sourceValue = (SimpleValue) value;
+ SimpleValue targetValue;
+ if ( value instanceof ManyToOne ) {
+ ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
+ ManyToOne targetManyToOne = new ManyToOne( collection.getCollectionTable() );
+ targetManyToOne.setFetchMode( FetchMode.DEFAULT );
+ targetManyToOne.setLazy( true );
+ //targetValue.setIgnoreNotFound( ); does not make sense for a map key
+ targetManyToOne.setReferencedEntityName( sourceManyToOne.getReferencedEntityName()
);
+ targetValue = targetManyToOne;
+ }
+ else {
+ targetValue = new SimpleValue( collection.getCollectionTable() );
+ targetValue.setTypeName( sourceValue.getTypeName() );
+ targetValue.setTypeParameters( sourceValue.getTypeParameters() );
+ }
+ Iterator columns = sourceValue.getColumnIterator();
+ Random random = new Random();
+ while ( columns.hasNext() ) {
+ Object current = columns.next();
+ Formula formula = new Formula();
+ String formulaString;
+ if ( current instanceof Column ) {
+ formulaString = ( (Column) current ).getQuotedName();
+ }
+ else if ( current instanceof Formula ) {
+ formulaString = ( (Formula) current ).getFormula();
+ }
+ else {
+ throw new AssertionFailure( "Unknown element in column iterator: " +
current.getClass() );
+ }
+ if ( fromAndWhere != null ) {
+ formulaString = Template.renderWhereStringTemplate( formulaString,
"$alias$", new HSQLDialect() );
+ formulaString = "(select " + formulaString + fromAndWhere +
")";
+ formulaString = StringHelper.replace(
+ formulaString,
+ "$alias$",
+ "a" + random.nextInt( 16 )
+ );
+ }
+ formula.setFormula( formulaString );
+ targetValue.addFormula( formula );
+
+ }
+ return targetValue;
+ }
+ else {
+ throw new AssertionFailure( "Unknown type encounters for map key: " +
value.getClass() );
+ }
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Nullability.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Nullability.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Nullability.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,12 @@
+package org.hibernate.cfg.annotations;
+
+/**
+ * Are the columns forced to null, not null or not forced
+ *
+ * @author Emmanuel Bernard
+ */
+public enum Nullability {
+ FORCED_NULL,
+ FORCED_NOT_NULL,
+ NO_CONSTRAINT
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PrimitiveArrayBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,16 @@
+//$Id: PrimitiveArrayBinder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.PrimitiveArray;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class PrimitiveArrayBinder extends ArrayBinder {
+ @Override
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new PrimitiveArray( persistentClass );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/PropertyBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,195 @@
+//$Id: PropertyBinder.java 14801 2008-06-24 19:03:32Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import javax.persistence.EmbeddedId;
+import javax.persistence.Id;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.annotations.Generated;
+import org.hibernate.annotations.GenerationTime;
+import org.hibernate.annotations.Immutable;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.OptimisticLock;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.Ejb3Column;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.PropertyHolder;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.PropertyGeneration;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Value;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class PropertyBinder {
+ private Logger log = LoggerFactory.getLogger( PropertyBinder.class );
+ private String name;
+ private String returnedClassName;
+ private boolean lazy;
+ private String propertyAccessorName;
+ private Ejb3Column[] columns;
+ private PropertyHolder holder;
+ private ExtendedMappings mappings;
+ private Value value;
+ private boolean insertable = true;
+ private boolean updatable = true;
+ private String cascade;
+ /*
+ * property can be null
+ * prefer propertyName to property.getName() since some are overloaded
+ */
+ private XProperty property;
+ private XClass returnedClass;
+
+ public void setInsertable(boolean insertable) {
+ this.insertable = insertable;
+ }
+
+ public void setUpdatable(boolean updatable) {
+ this.updatable = updatable;
+ }
+
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setReturnedClassName(String returnedClassName) {
+ this.returnedClassName = returnedClassName;
+ }
+
+ public void setLazy(boolean lazy) {
+ this.lazy = lazy;
+ }
+
+ public void setPropertyAccessorName(String propertyAccessorName) {
+ this.propertyAccessorName = propertyAccessorName;
+ }
+
+ public void setColumns(Ejb3Column[] columns) {
+ insertable = columns[0].isInsertable();
+ updatable = columns[0].isUpdatable();
+ //consistency is checked later when we know the property name
+ this.columns = columns;
+ }
+
+ public void setHolder(PropertyHolder holder) {
+ this.holder = holder;
+ }
+
+ public void setValue(Value value) {
+ this.value = value;
+ }
+
+ public void setCascade(String cascadeStrategy) {
+ this.cascade = cascadeStrategy;
+ }
+
+ public void setMappings(ExtendedMappings mappings) {
+ this.mappings = mappings;
+ }
+
+ private void validateBind() {
+ if (property.isAnnotationPresent(Immutable.class)) {
+ throw new AnnotationException("@Immutable on property not allowed. " +
+ "Only allowed on entity level or on a collection.");
+ }
+ }
+
+ private void validateMake() {
+ //TODO check necessary params for a make
+ }
+
+ public Property bind() {
+ validateBind();
+ log.debug( "binding property {} with lazy={}", name, lazy );
+ String containerClassName = holder == null ?
+ null :
+ holder.getClassName();
+ SimpleValueBinder value = new SimpleValueBinder();
+ value.setMappings( mappings );
+ value.setPropertyName( name );
+ value.setReturnedClassName( returnedClassName );
+ value.setColumns( columns );
+ value.setPersistentClassName( containerClassName );
+ value.setType( property, returnedClass );
+ value.setMappings( mappings );
+ SimpleValue propertyValue = value.make();
+ setValue( propertyValue );
+ Property prop = make();
+ holder.addProperty( prop, columns );
+ return prop;
+ }
+
+ public Property make() {
+ validateMake();
+ log.debug( "Building property " + name );
+ Property prop = new Property();
+ prop.setName( name );
+ prop.setNodeName( name );
+ prop.setValue( value );
+ prop.setLazy( lazy );
+ prop.setCascade( cascade );
+ prop.setPropertyAccessorName( propertyAccessorName );
+ Generated ann = property != null ?
+ property.getAnnotation( Generated.class ) :
+ null;
+ GenerationTime generated = ann != null ?
+ ann.value() :
+ null;
+ if ( generated != null ) {
+ if ( !GenerationTime.NEVER.equals( generated ) ) {
+ if ( property.isAnnotationPresent( javax.persistence.Version.class )
+ && GenerationTime.INSERT.equals( generated ) ) {
+ throw new AnnotationException( "@Generated(INSERT) on a @Version property not
allowed, use ALWAYS: "
+ + StringHelper.qualify( holder.getPath(), name ) );
+ }
+ insertable = false;
+ if ( GenerationTime.ALWAYS.equals( generated ) ) {
+ updatable = false;
+ }
+ prop.setGeneration( PropertyGeneration.parse( generated.toString().toLowerCase() )
);
+ }
+ }
+ NaturalId naturalId = property != null ?
+ property.getAnnotation( NaturalId.class ) :
+ null;
+ if ( naturalId != null ) {
+ if ( !naturalId.mutable() ) {
+ updatable = false;
+ }
+ prop.setNaturalIdentifier( true );
+ }
+ prop.setInsertable( insertable );
+ prop.setUpdateable( updatable );
+ OptimisticLock lockAnn = property != null ?
+ property.getAnnotation( OptimisticLock.class ) :
+ null;
+ if ( lockAnn != null ) {
+ prop.setOptimisticLocked( !lockAnn.excluded() );
+ //TODO this should go to the core as a mapping validation checking
+ if ( lockAnn.excluded() && (
+ property.isAnnotationPresent( javax.persistence.Version.class )
+ || property.isAnnotationPresent( Id.class )
+ || property.isAnnotationPresent( EmbeddedId.class ) ) ) {
+ throw new AnnotationException( "(a)OptimisticLock.exclude=true incompatible with
@Id, @EmbeddedId and @Version: "
+ + StringHelper.qualify( holder.getPath(), name ) );
+ }
+ }
+ log.trace( "Cascading " + name + " with " + cascade );
+ return prop;
+ }
+
+ public void setProperty(XProperty property) {
+ this.property = property;
+ }
+
+ public void setReturnedClass(XClass returnedClass) {
+ this.returnedClass = returnedClass;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,388 @@
+//$Id: QueryBinder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.util.HashMap;
+import javax.persistence.NamedNativeQueries;
+import javax.persistence.NamedNativeQuery;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.QueryHint;
+import javax.persistence.SqlResultSetMapping;
+import javax.persistence.SqlResultSetMappings;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.CacheMode;
+import org.hibernate.FlushMode;
+import org.hibernate.LockMode;
+import org.hibernate.annotations.CacheModeType;
+import org.hibernate.annotations.FlushModeType;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.NotYetImplementedException;
+import org.hibernate.engine.NamedQueryDefinition;
+import org.hibernate.engine.NamedSQLQueryDefinition;
+import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Query binder
+ *
+ * @author Emmanuel Bernard
+ */
+public abstract class QueryBinder {
+ private static final Logger log = LoggerFactory.getLogger( QueryBinder.class );
+
+ public static void bindQuery(NamedQuery queryAnn, ExtendedMappings mappings, boolean
isDefault) {
+ if ( queryAnn == null ) return;
+ if ( BinderHelper.isDefault( queryAnn.name() ) ) {
+ throw new AnnotationException( "A named query must have a name when used in class
or package level" );
+ }
+ //EJBQL Query
+ QueryHint[] hints = queryAnn.hints();
+ String queryName = queryAnn.query();
+ NamedQueryDefinition query = new NamedQueryDefinition(
+ queryName,
+ getBoolean( queryName, "org.hibernate.cacheable", hints ),
+ getString( queryName, "org.hibernate.cacheRegion", hints ),
+ getInteger( queryName, "org.hibernate.timeout", hints ),
+ getInteger( queryName, "org.hibernate.fetchSize", hints ),
+ getFlushMode( queryName, hints ),
+ getCacheMode( queryName, hints ),
+ getBoolean( queryName, "org.hibernate.readOnly", hints ),
+ getString( queryName, "org.hibernate.comment", hints ),
+ null
+ );
+ if ( isDefault ) {
+ mappings.addDefaultQuery( queryAnn.name(), query );
+ }
+ else {
+ mappings.addQuery( queryAnn.name(), query );
+ }
+ log.info( "Binding Named query: {} => {}", queryAnn.name(),
queryAnn.query() );
+ }
+
+
+ public static void bindNativeQuery(NamedNativeQuery queryAnn, ExtendedMappings mappings,
boolean isDefault) {
+ if ( queryAnn == null ) return;
+ //ResultSetMappingDefinition mappingDefinition = mappings.getResultSetMapping(
queryAnn.resultSetMapping() );
+ if ( BinderHelper.isDefault( queryAnn.name() ) ) {
+ throw new AnnotationException( "A named query must have a name when used in class
or package level" );
+ }
+ NamedSQLQueryDefinition query;
+ String resultSetMapping = queryAnn.resultSetMapping();
+ QueryHint[] hints = queryAnn.hints();
+ String queryName = queryAnn.query();
+ if ( !BinderHelper.isDefault( resultSetMapping ) ) {
+ //sql result set usage
+ query = new NamedSQLQueryDefinition(
+ queryName,
+ resultSetMapping,
+ null,
+ getBoolean( queryName, "org.hibernate.cacheable", hints ),
+ getString( queryName, "org.hibernate.cacheRegion", hints ),
+ getInteger( queryName, "org.hibernate.timeout", hints ),
+ getInteger( queryName, "org.hibernate.fetchSize", hints ),
+ getFlushMode( queryName, hints ),
+ getCacheMode( queryName, hints ),
+ getBoolean( queryName, "org.hibernate.readOnly", hints ),
+ getString( queryName, "org.hibernate.comment", hints ),
+ null,
+ getBoolean( queryName, "org.hibernate.callable", hints )
+ );
+ }
+ else if ( !void.class.equals( queryAnn.resultClass() ) ) {
+ //class mapping usage
+ //FIXME should be done in a second pass due to entity name?
+ final NativeSQLQueryRootReturn entityQueryReturn =
+ new NativeSQLQueryRootReturn( "alias1", queryAnn.resultClass().getName(),
new HashMap(), LockMode.READ );
+ query = new NamedSQLQueryDefinition(
+ queryName,
+ new NativeSQLQueryReturn[] { entityQueryReturn },
+ null,
+ getBoolean( queryName, "org.hibernate.cacheable", hints ),
+ getString( queryName, "org.hibernate.cacheRegion", hints ),
+ getInteger( queryName, "org.hibernate.timeout", hints ),
+ getInteger( queryName, "org.hibernate.fetchSize", hints ),
+ getFlushMode( queryName, hints ),
+ getCacheMode( queryName, hints ),
+ getBoolean( queryName, "org.hibernate.readOnly", hints ),
+ getString( queryName, "org.hibernate.comment", hints ),
+ null,
+ getBoolean( queryName, "org.hibernate.callable", hints )
+ );
+ }
+ else {
+ throw new NotYetImplementedException( "Pure native scalar queries are not yet
supported" );
+ }
+ if ( isDefault ) {
+ mappings.addDefaultSQLQuery( queryAnn.name(), query );
+ }
+ else {
+ mappings.addSQLQuery( queryAnn.name(), query );
+ }
+ log.info( "Binding named native query: {} => {}", queryAnn.name(),
queryAnn.query() );
+ }
+
+ public static void bindNativeQuery(org.hibernate.annotations.NamedNativeQuery queryAnn,
ExtendedMappings mappings) {
+ if ( queryAnn == null ) return;
+ //ResultSetMappingDefinition mappingDefinition = mappings.getResultSetMapping(
queryAnn.resultSetMapping() );
+ if ( BinderHelper.isDefault( queryAnn.name() ) ) {
+ throw new AnnotationException( "A named query must have a name when used in class
or package level" );
+ }
+ NamedSQLQueryDefinition query;
+ String resultSetMapping = queryAnn.resultSetMapping();
+ if ( !BinderHelper.isDefault( resultSetMapping ) ) {
+ //sql result set usage
+ query = new NamedSQLQueryDefinition(
+ queryAnn.query(),
+ resultSetMapping,
+ null,
+ queryAnn.cacheable(),
+ BinderHelper.isDefault( queryAnn.cacheRegion() ) ? null : queryAnn.cacheRegion(),
+ queryAnn.timeout() < 0 ? null : queryAnn.timeout(),
+ queryAnn.fetchSize() < 0 ? null : queryAnn.fetchSize(),
+ getFlushMode( queryAnn.flushMode() ),
+ getCacheMode( queryAnn.cacheMode() ),
+ queryAnn.readOnly(),
+ BinderHelper.isDefault( queryAnn.comment() ) ? null : queryAnn.comment(),
+ null,
+ queryAnn.callable()
+ );
+ }
+ else if ( !void.class.equals( queryAnn.resultClass() ) ) {
+ //class mapping usage
+ //FIXME should be done in a second pass due to entity name?
+ final NativeSQLQueryRootReturn entityQueryReturn =
+ new NativeSQLQueryRootReturn( "alias1", queryAnn.resultClass().getName(),
new HashMap(), LockMode.READ );
+ query = new NamedSQLQueryDefinition(
+ queryAnn.query(),
+ new NativeSQLQueryReturn[] { entityQueryReturn },
+ null,
+ queryAnn.cacheable(),
+ BinderHelper.isDefault( queryAnn.cacheRegion() ) ? null : queryAnn.cacheRegion(),
+ queryAnn.timeout() < 0 ? null : queryAnn.timeout(),
+ queryAnn.fetchSize() < 0 ? null : queryAnn.fetchSize(),
+ getFlushMode( queryAnn.flushMode() ),
+ getCacheMode( queryAnn.cacheMode() ),
+ queryAnn.readOnly(),
+ BinderHelper.isDefault( queryAnn.comment() ) ? null : queryAnn.comment(),
+ null,
+ queryAnn.callable()
+ );
+ }
+ else {
+ throw new NotYetImplementedException( "Pure native scalar queries are not yet
supported" );
+ }
+ mappings.addSQLQuery( queryAnn.name(), query );
+ log.info( "Binding named native query: {} => {}", queryAnn.name(),
queryAnn.query() );
+ }
+
+ public static void bindQueries(NamedQueries queriesAnn, ExtendedMappings mappings,
boolean isDefault) {
+ if ( queriesAnn == null ) return;
+ for (NamedQuery q : queriesAnn.value()) {
+ bindQuery( q, mappings, isDefault );
+ }
+ }
+
+ public static void bindNativeQueries(NamedNativeQueries queriesAnn, ExtendedMappings
mappings, boolean isDefault) {
+ if ( queriesAnn == null ) return;
+ for (NamedNativeQuery q : queriesAnn.value()) {
+ bindNativeQuery( q, mappings, isDefault );
+ }
+ }
+
+ public static void bindNativeQueries(
+ org.hibernate.annotations.NamedNativeQueries queriesAnn, ExtendedMappings mappings
+ ) {
+ if ( queriesAnn == null ) return;
+ for (org.hibernate.annotations.NamedNativeQuery q : queriesAnn.value()) {
+ bindNativeQuery( q, mappings );
+ }
+ }
+
+ public static void bindQuery(org.hibernate.annotations.NamedQuery queryAnn,
ExtendedMappings mappings) {
+ if ( queryAnn == null ) return;
+ if ( BinderHelper.isDefault( queryAnn.name() ) ) {
+ throw new AnnotationException( "A named query must have a name when used in class
or package level" );
+ }
+
+ FlushMode flushMode;
+ flushMode = getFlushMode( queryAnn.flushMode() );
+
+ NamedQueryDefinition query = new NamedQueryDefinition(
+ queryAnn.query(),
+ queryAnn.cacheable(),
+ BinderHelper.isDefault( queryAnn.cacheRegion() ) ? null : queryAnn.cacheRegion(),
+ queryAnn.timeout() < 0 ? null : queryAnn.timeout(),
+ queryAnn.fetchSize() < 0 ? null : queryAnn.fetchSize(),
+ flushMode,
+ getCacheMode( queryAnn.cacheMode() ),
+ queryAnn.readOnly(),
+ BinderHelper.isDefault( queryAnn.comment() ) ? null : queryAnn.comment(),
+ null
+ );
+
+ mappings.addQuery( queryAnn.name(), query );
+ if ( log.isInfoEnabled() ) log.info( "Binding named query: " +
queryAnn.name() + " => " + queryAnn.query() );
+ }
+
+ private static FlushMode getFlushMode(FlushModeType flushModeType) {
+ FlushMode flushMode;
+ switch ( flushModeType ) {
+ case ALWAYS:
+ flushMode = FlushMode.ALWAYS;
+ break;
+ case AUTO:
+ flushMode = FlushMode.AUTO;
+ break;
+ case COMMIT:
+ flushMode = FlushMode.COMMIT;
+ break;
+ case NEVER:
+ flushMode = FlushMode.MANUAL;
+ break;
+ case MANUAL:
+ flushMode = FlushMode.MANUAL;
+ break;
+ case PERSISTENCE_CONTEXT:
+ flushMode = null;
+ break;
+ default:
+ throw new AssertionFailure( "Unknown flushModeType: " + flushModeType );
+ }
+ return flushMode;
+ }
+
+ private static CacheMode getCacheMode(CacheModeType cacheModeType) {
+ switch ( cacheModeType ) {
+ case GET:
+ return CacheMode.GET;
+ case IGNORE:
+ return CacheMode.IGNORE;
+ case NORMAL:
+ return CacheMode.NORMAL;
+ case PUT:
+ return CacheMode.PUT;
+ case REFRESH:
+ return CacheMode.REFRESH;
+ default:
+ throw new AssertionFailure( "Unknown cacheModeType: " + cacheModeType );
+ }
+ }
+
+
+ public static void bindQueries(org.hibernate.annotations.NamedQueries queriesAnn,
ExtendedMappings mappings) {
+ if ( queriesAnn == null ) return;
+ for (org.hibernate.annotations.NamedQuery q : queriesAnn.value()) {
+ bindQuery( q, mappings );
+ }
+ }
+
+ public static void bindSqlResultsetMappings(SqlResultSetMappings ann, ExtendedMappings
mappings, boolean isDefault) {
+ if ( ann == null ) return;
+ for (SqlResultSetMapping rs : ann.value()) {
+ //no need to handle inSecondPass
+ mappings.addSecondPass( new ResultsetMappingSecondPass( rs, mappings, true ) );
+ }
+ }
+
+ public static void bindSqlResultsetMapping(SqlResultSetMapping ann, ExtendedMappings
mappings, boolean isDefault) {
+ //no need to handle inSecondPass
+ mappings.addSecondPass( new ResultsetMappingSecondPass( ann, mappings, isDefault ) );
+ }
+
+ private static CacheMode getCacheMode(String query, QueryHint[] hints) {
+ for (QueryHint hint : hints) {
+ if ( "org.hibernate.cacheMode".equals( hint.name() ) ) {
+ if ( hint.value().equalsIgnoreCase( CacheMode.GET.toString() ) ) {
+ return CacheMode.GET;
+ }
+ else if ( hint.value().equalsIgnoreCase( CacheMode.IGNORE.toString() ) ) {
+ return CacheMode.IGNORE;
+ }
+ else if ( hint.value().equalsIgnoreCase( CacheMode.NORMAL.toString() ) ) {
+ return CacheMode.NORMAL;
+ }
+ else if ( hint.value().equalsIgnoreCase( CacheMode.PUT.toString() ) ) {
+ return CacheMode.PUT;
+ }
+ else if ( hint.value().equalsIgnoreCase( CacheMode.REFRESH.toString() ) ) {
+ return CacheMode.REFRESH;
+ }
+ else {
+ throw new AnnotationException( "Unknown CacheMode in hint: " + query +
":" + hint.name() );
+ }
+ }
+ }
+ return null;
+ }
+
+ private static FlushMode getFlushMode(String query, QueryHint[] hints) {
+ for (QueryHint hint : hints) {
+ if ( "org.hibernate.flushMode".equals( hint.name() ) ) {
+ if ( hint.value().equalsIgnoreCase( FlushMode.ALWAYS.toString() ) ) {
+ return FlushMode.ALWAYS;
+ }
+ else if ( hint.value().equalsIgnoreCase( FlushMode.AUTO.toString() ) ) {
+ return FlushMode.AUTO;
+ }
+ else if ( hint.value().equalsIgnoreCase( FlushMode.COMMIT.toString() ) ) {
+ return FlushMode.COMMIT;
+ }
+ else if ( hint.value().equalsIgnoreCase( FlushMode.NEVER.toString() ) ) {
+ return FlushMode.MANUAL;
+ }
+ else if ( hint.value().equalsIgnoreCase( FlushMode.MANUAL.toString() ) ) {
+ return FlushMode.MANUAL;
+ }
+ else {
+ throw new AnnotationException( "Unknown FlushMode in hint: " + query +
":" + hint.name() );
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean getBoolean(String query, String hintName, QueryHint[] hints) {
+ for (QueryHint hint : hints) {
+ if ( hintName.equals( hint.name() ) ) {
+ if ( hint.value().equalsIgnoreCase( "true" ) ) {
+ return true;
+ }
+ else if ( hint.value().equalsIgnoreCase( "false" ) ) {
+ return false;
+ }
+ else {
+ throw new AnnotationException( "Not a boolean in hint: " + query +
":" + hint.name() );
+ }
+ }
+ }
+ return false;
+ }
+
+ private static String getString(String query, String hintName, QueryHint[] hints) {
+ for (QueryHint hint : hints) {
+ if ( hintName.equals( hint.name() ) ) {
+ return hint.value();
+ }
+ }
+ return null;
+ }
+
+ private static Integer getInteger(String query, String hintName, QueryHint[] hints) {
+ for (QueryHint hint : hints) {
+ if ( hintName.equals( hint.name() ) ) {
+ try {
+ return Integer.decode( hint.value() );
+ }
+ catch (NumberFormatException nfe) {
+ throw new AnnotationException( "Not an integer in hint: " + query +
":" + hint.name(), nfe );
+ }
+ }
+ }
+ return null;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/ResultsetMappingSecondPass.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,231 @@
+//$Id: ResultsetMappingSecondPass.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.persistence.ColumnResult;
+import javax.persistence.EntityResult;
+import javax.persistence.FieldResult;
+import javax.persistence.SqlResultSetMapping;
+
+import org.hibernate.LockMode;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.QuerySecondPass;
+import org.hibernate.engine.ResultSetMappingDefinition;
+import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
+import org.hibernate.engine.query.sql.NativeSQLQueryScalarReturn;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.Value;
+import org.hibernate.util.CollectionHelper;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ResultsetMappingSecondPass implements QuerySecondPass {
+ private Logger log = LoggerFactory.getLogger( ResultsetMappingSecondPass.class );
+ private SqlResultSetMapping ann;
+ private ExtendedMappings mappings;
+ private boolean isDefault;
+
+ public ResultsetMappingSecondPass(SqlResultSetMapping ann, ExtendedMappings mappings,
boolean isDefault) {
+ this.ann = ann;
+ this.mappings = mappings;
+ this.isDefault = isDefault;
+ }
+
+ public void doSecondPass(Map persistentClasses) throws MappingException {
+ //TODO add parameters checkings
+ if ( ann == null ) return;
+ ResultSetMappingDefinition definition = new ResultSetMappingDefinition( ann.name() );
+ log.info( "Binding resultset mapping: {}", definition.getName() );
+
+ int entityAliasIndex = 0;
+
+ for (EntityResult entity : ann.entities()) {
+ //TODO parameterize lock mode?
+ List properties = new ArrayList();
+ List propertyNames = new ArrayList();
+ Map propertyresults = new HashMap();
+ for (FieldResult field : entity.fields()) {
+ //use an ArrayList cause we might have several columns per root property
+ String name = field.name();
+ if ( name.indexOf( '.' ) == -1 ) {
+ //regular property
+ properties.add( field );
+ propertyNames.add( name );
+ }
+ else {
+ /**
+ * Reorder properties
+ * 1. get the parent property
+ * 2. list all the properties following the expected one in the parent property
+ * 3. calculate the lowest index and insert the property
+ */
+ PersistentClass pc = mappings.getClass( entity.entityClass().getName() );
+ if ( pc == null ) {
+ throw new MappingException(
+ "Entity not found " + entity.entityClass().getName()
+ + " in SqlResultsetMapping " + ann.name()
+ );
+ }
+ int dotIndex = name.lastIndexOf( '.' );
+ String reducedName = name.substring( 0, dotIndex );
+ Iterator parentPropIter = getSubPropertyIterator( pc, reducedName );
+ List followers = getFollowers( parentPropIter, reducedName, name );
+
+ int index = propertyNames.size();
+ int followersSize = followers.size();
+ for (int loop = 0; loop < followersSize; loop++) {
+ String follower = (String) followers.get( loop );
+ int currentIndex = getIndexOfFirstMatchingProperty( propertyNames, follower );
+ index = currentIndex != -1 && currentIndex < index ? currentIndex :
index;
+ }
+ propertyNames.add( index, name );
+ properties.add( index, field );
+ }
+ }
+
+ Set uniqueReturnProperty = new HashSet();
+ Iterator iterator = properties.iterator();
+ while ( iterator.hasNext() ) {
+ FieldResult propertyresult = (FieldResult) iterator.next();
+ String name = propertyresult.name();
+ if ( "class".equals( name ) ) {
+ throw new MappingException(
+ "class is not a valid property name to use in a @FieldResult, use
@Entity(discriminatorColumn) instead"
+ );
+ }
+ ArrayList allResultColumns = new ArrayList();
+ allResultColumns.add( propertyresult.column() );
+
+ if ( uniqueReturnProperty.contains( name ) ) {
+ throw new MappingException(
+ "duplicate @FieldResult for property " + name +
+ " on @Entity " + entity.entityClass().getName() + " in " +
ann.name()
+ );
+ }
+ uniqueReturnProperty.add( name );
+ String key = StringHelper.root( name );
+ ArrayList intermediateResults = (ArrayList) propertyresults.get( key );
+ if ( intermediateResults == null ) {
+ propertyresults.put( key, allResultColumns );
+ }
+ else {
+ intermediateResults.addAll( allResultColumns );
+ }
+ }
+ Iterator entries = propertyresults.entrySet().iterator();
+ while ( entries.hasNext() ) {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if ( entry.getValue() instanceof ArrayList ) {
+ ArrayList list = (ArrayList) entry.getValue();
+ entry.setValue( list.toArray( new String[list.size()] ) );
+ }
+ }
+
+ if ( !BinderHelper.isDefault( entity.discriminatorColumn() ) ) {
+ propertyresults.put( "class", new String[] { entity.discriminatorColumn() }
);
+ }
+
+ propertyresults = propertyresults.isEmpty() ? CollectionHelper.EMPTY_MAP :
propertyresults;
+ NativeSQLQueryRootReturn result =
+ new NativeSQLQueryRootReturn(
+ "alias" + entityAliasIndex++, entity.entityClass().getName(),
propertyresults, LockMode.READ
+ );
+ definition.addQueryReturn( result );
+ }
+
+ for (ColumnResult column : ann.columns()) {
+ definition.addQueryReturn( new NativeSQLQueryScalarReturn( column.name(), null ) );
+ }
+
+ if ( isDefault ) {
+ mappings.addDefaultResultSetMapping( definition );
+ }
+ else {
+ mappings.addResultSetMapping( definition );
+ }
+ }
+
+ private List getFollowers(Iterator parentPropIter, String reducedName, String name) {
+ boolean hasFollowers = false;
+ List followers = new ArrayList();
+ while ( parentPropIter.hasNext() ) {
+ String currentPropertyName = ( (Property) parentPropIter.next() ).getName();
+ String currentName = reducedName + '.' + currentPropertyName;
+ if ( hasFollowers ) {
+ followers.add( currentName );
+ }
+ if ( name.equals( currentName ) ) hasFollowers = true;
+ }
+ return followers;
+ }
+
+ private Iterator getSubPropertyIterator(PersistentClass pc, String reducedName) {
+ Value value = pc.getRecursiveProperty( reducedName ).getValue();
+ Iterator parentPropIter;
+ if ( value instanceof Component ) {
+ Component comp = (Component) value;
+ parentPropIter = comp.getPropertyIterator();
+ }
+ else if ( value instanceof ToOne ) {
+ ToOne toOne = (ToOne) value;
+ PersistentClass referencedPc = mappings.getClass( toOne.getReferencedEntityName() );
+ if ( toOne.getReferencedPropertyName() != null ) {
+ try {
+ parentPropIter = ( (Component) referencedPc.getRecursiveProperty(
+ toOne.getReferencedPropertyName()
+ ).getValue() ).getPropertyIterator();
+ }
+ catch (ClassCastException e) {
+ throw new MappingException(
+ "dotted notation reference neither a component nor a many/one to one",
e
+ );
+ }
+ }
+ else {
+ try {
+ if ( referencedPc.getIdentifierMapper() == null ) {
+ parentPropIter = ( (Component) referencedPc.getIdentifierProperty()
+ .getValue() ).getPropertyIterator();
+ }
+ else {
+ parentPropIter = referencedPc.getIdentifierMapper().getPropertyIterator();
+ }
+ }
+ catch (ClassCastException e) {
+ throw new MappingException(
+ "dotted notation reference neither a component nor a many/one to one",
e
+ );
+ }
+ }
+ }
+ else {
+ throw new MappingException( "dotted notation reference neither a component nor a
many/one to one" );
+ }
+ return parentPropIter;
+ }
+
+ private static int getIndexOfFirstMatchingProperty(List propertyNames, String follower)
{
+ int propertySize = propertyNames.size();
+ for (int propIndex = 0; propIndex < propertySize; propIndex++) {
+ if ( ( (String) propertyNames.get( propIndex ) ).startsWith( follower ) ) {
+ return propIndex;
+ }
+ }
+ return -1;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SetBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SetBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SetBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,39 @@
+package org.hibernate.cfg.annotations;
+
+import org.hibernate.annotations.OrderBy;
+import org.hibernate.cfg.Environment;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Bind a set.
+ *
+ * @author Matthew Inger
+ */
+public class SetBinder extends CollectionBinder {
+ private final Logger log = LoggerFactory.getLogger( SetBinder.class );
+
+ public SetBinder() {
+ }
+
+ public SetBinder(boolean sorted) {
+ super( sorted );
+ }
+
+ protected Collection createCollection(PersistentClass persistentClass) {
+ return new org.hibernate.mapping.Set( persistentClass );
+ }
+
+ public void setSqlOrderBy(OrderBy orderByAnn) {
+ if ( orderByAnn != null ) {
+ if ( Environment.jvmSupportsLinkedHashCollections() ) {
+ super.setSqlOrderBy( orderByAnn );
+ }
+ else {
+ log.warn( "Attribute \"order-by\" ignored in JDK1.3 or less" );
+ }
+ }
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,248 @@
+//$Id: SimpleValueBinder.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.io.Serializable;
+import java.sql.Types;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Properties;
+import javax.persistence.Enumerated;
+import javax.persistence.Lob;
+import javax.persistence.Temporal;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.annotations.Parameter;
+import org.hibernate.annotations.Type;
+import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.Ejb3Column;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.NotYetImplementedException;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.type.ByteArrayBlobType;
+import org.hibernate.type.CharacterArrayClobType;
+import org.hibernate.type.EnumType;
+import org.hibernate.type.PrimitiveByteArrayBlobType;
+import org.hibernate.type.PrimitiveCharacterArrayClobType;
+import org.hibernate.type.SerializableToBlobType;
+import org.hibernate.type.StringClobType;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class SimpleValueBinder {
+ private Logger log = LoggerFactory.getLogger( SimpleValueBinder.class );
+ private String propertyName;
+ private String returnedClassName;
+ private Ejb3Column[] columns;
+ private String persistentClassName;
+ private String explicitType = "";
+ private Properties typeParameters = new Properties();
+ private ExtendedMappings mappings;
+ private Table table;
+
+ public void setPropertyName(String propertyName) {
+ this.propertyName = propertyName;
+ }
+
+ public void setReturnedClassName(String returnedClassName) {
+ this.returnedClassName = returnedClassName;
+ }
+
+ public void setTable(Table table) {
+ this.table = table;
+ }
+
+ public void setColumns(Ejb3Column[] columns) {
+ this.columns = columns;
+ }
+
+
+ public void setPersistentClassName(String persistentClassName) {
+ this.persistentClassName = persistentClassName;
+ }
+
+ //TODO execute it lazily to be order safe
+ public void setType(XProperty property, XClass returnedClass) {
+ if ( returnedClass == null ) return; //we cannot guess anything
+ XClass returnedClassOrElement = returnedClass;
+ boolean isArray = false;
+ if ( property.isArray() ) {
+ returnedClassOrElement = property.getElementClass();
+ isArray = true;
+ }
+ Properties typeParameters = this.typeParameters;
+ typeParameters.clear();
+ String type = BinderHelper.ANNOTATION_STRING_DEFAULT;
+ if ( property.isAnnotationPresent( Temporal.class ) ) {
+ Temporal ann = property.getAnnotation( Temporal.class );
+ boolean isDate;
+ if ( mappings.getReflectionManager().equals( returnedClassOrElement, Date.class ) ) {
+ isDate = true;
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement,
Calendar.class ) ) {
+ isDate = false;
+ }
+ else {
+ throw new AnnotationException(
+ "@Temporal should only be set on a java.util.Date or java.util.Calendar
property: "
+ + StringHelper.qualify( persistentClassName, propertyName )
+ );
+ }
+
+ switch ( ann.value() ) {
+ case DATE:
+ type = isDate ? "date" : "calendar_date";
+ break;
+ case TIME:
+ type = "time";
+ if ( !isDate ) {
+ throw new NotYetImplementedException(
+ "Calendar cannot persist TIME only"
+ + StringHelper.qualify( persistentClassName, propertyName )
+ );
+ }
+ break;
+ case TIMESTAMP:
+ type = isDate ? "timestamp" : "calendar";
+ break;
+ default:
+ throw new AssertionFailure( "Unknown temporal type: " + ann.value() );
+ }
+ }
+ else if ( property.isAnnotationPresent( Lob.class ) ) {
+
+ if ( mappings.getReflectionManager().equals( returnedClassOrElement,
java.sql.Clob.class ) ) {
+ type = "clob";
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement,
java.sql.Blob.class ) ) {
+ type = "blob";
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement, String.class
) ) {
+ type = StringClobType.class.getName();
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement,
Character.class ) && isArray ) {
+ type = CharacterArrayClobType.class.getName();
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement, char.class )
&& isArray ) {
+ type = PrimitiveCharacterArrayClobType.class.getName();
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement, Byte.class )
&& isArray ) {
+ type = ByteArrayBlobType.class.getName();
+ }
+ else if ( mappings.getReflectionManager().equals( returnedClassOrElement, byte.class )
&& isArray ) {
+ type = PrimitiveByteArrayBlobType.class.getName();
+ }
+ else if ( mappings.getReflectionManager()
+ .toXClass( Serializable.class )
+ .isAssignableFrom( returnedClassOrElement ) ) {
+ type = SerializableToBlobType.class.getName();
+ //typeParameters = new Properties();
+ typeParameters.setProperty(
+ SerializableToBlobType.CLASS_NAME,
+ returnedClassOrElement.getName()
+ );
+ }
+ else {
+ type = "blob";
+ }
+ }
+ //implicit type will check basic types and Serializable classes
+ if ( columns == null ) {
+ throw new AssertionFailure( "SimpleValueBinder.setColumns should be set before
SimpleValueBinder.setType" );
+ }
+ if ( BinderHelper.ANNOTATION_STRING_DEFAULT.equals( type ) ) {
+ if ( returnedClassOrElement.isEnum() ) {
+ type = EnumType.class.getName();
+ typeParameters = new Properties();
+ typeParameters.setProperty( EnumType.ENUM, returnedClassOrElement.getName() );
+ String schema = columns[0].getTable().getSchema();
+ schema = schema == null ? "" : schema;
+ String catalog = columns[0].getTable().getCatalog();
+ catalog = catalog == null ? "" : catalog;
+ typeParameters.setProperty( EnumType.SCHEMA, schema );
+ typeParameters.setProperty( EnumType.CATALOG, catalog );
+ typeParameters.setProperty( EnumType.TABLE, columns[0].getTable().getName() );
+ typeParameters.setProperty( EnumType.COLUMN, columns[0].getName() );
+ Enumerated enumAnn = property.getAnnotation( Enumerated.class );
+ if ( enumAnn != null ) {
+ javax.persistence.EnumType enumType = enumAnn.value();
+ if ( javax.persistence.EnumType.ORDINAL.equals( enumType ) ) {
+ typeParameters.setProperty( EnumType.TYPE, String.valueOf( Types.INTEGER ) );
+ }
+ else if ( javax.persistence.EnumType.STRING.equals( enumType ) ) {
+ typeParameters.setProperty( EnumType.TYPE, String.valueOf( Types.VARCHAR ) );
+ }
+ else {
+ throw new AssertionFailure( "Unknown EnumType: " + enumType );
+ }
+ }
+ }
+ }
+ explicitType = type;
+ this.typeParameters = typeParameters;
+ Type annType = (Type) property.getAnnotation( Type.class );
+ setExplicitType( annType );
+ }
+
+ public void setExplicitType(String explicitType) {
+ this.explicitType = explicitType;
+ }
+
+ //FIXME raise an assertion failure if setExplicitType(String) and setExplicitType(Type)
are use at the same time
+ public void setExplicitType(Type typeAnn) {
+ if ( typeAnn != null ) {
+ explicitType = typeAnn.type();
+ typeParameters.clear();
+ for (Parameter param : typeAnn.parameters()) {
+ typeParameters.setProperty( param.name(), param.value() );
+ }
+ }
+ }
+
+ public void setMappings(ExtendedMappings mappings) {
+ this.mappings = mappings;
+ }
+
+ private void validate() {
+ //TODO check necessary params
+ Ejb3Column.checkPropertyConsistency( columns, propertyName );
+ }
+
+ public SimpleValue make() {
+ validate();
+ log.debug( "building SimpleValue for {}", propertyName );
+ if ( table == null ) {
+ table = columns[0].getTable();
+ }
+ SimpleValue simpleValue = new SimpleValue( table );
+ return fillSimpleValue( simpleValue );
+ }
+
+ public SimpleValue fillSimpleValue(SimpleValue simpleValue) {
+ String type = BinderHelper.isDefault( explicitType ) ? returnedClassName :
explicitType;
+ org.hibernate.mapping.TypeDef typeDef = mappings.getTypeDef( type );
+ if ( typeDef != null ) {
+ type = typeDef.getTypeClass();
+ simpleValue.setTypeParameters( typeDef.getParameters() );
+ }
+ if ( typeParameters != null && typeParameters.size() != 0 ) {
+ //explicit type params takes precedence over type def params
+ simpleValue.setTypeParameters( typeParameters );
+ }
+ simpleValue.setTypeName( type );
+ if ( persistentClassName != null ) {
+ simpleValue.setTypeUsingReflection( persistentClassName, propertyName );
+ }
+ for (Ejb3Column column : columns) {
+ column.linkWithValue( simpleValue );
+ }
+ return simpleValue;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/TableBinder.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/TableBinder.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/TableBinder.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,386 @@
+//$Id: TableBinder.java 14761 2008-06-11 13:51:06Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.AssertionFailure;
+import org.hibernate.annotations.Index;
+import org.hibernate.annotations.common.util.StringHelper;
+import org.hibernate.cfg.BinderHelper;
+import org.hibernate.cfg.Ejb3JoinColumn;
+import org.hibernate.cfg.ExtendedMappings;
+import org.hibernate.cfg.IndexOrUniqueKeySecondPass;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.DependantValue;
+import org.hibernate.mapping.JoinedSubclass;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.SimpleValue;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.ToOne;
+import org.hibernate.mapping.Value;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Table related operations
+ *
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings("unchecked")
+public class TableBinder {
+ //TODO move it to a getter/setter strategy
+ private static Logger log = LoggerFactory.getLogger( TableBinder.class );
+ private String schema;
+ private String catalog;
+ private String name;
+ private boolean isAbstract;
+ private List<String[]> uniqueConstraints;
+ String constraints;
+ Table denormalizedSuperTable;
+ ExtendedMappings mappings;
+ private String ownerEntityTable;
+ private String associatedEntityTable;
+ private String propertyName;
+ private String ownerEntity;
+ private String associatedEntity;
+
+ public void setSchema(String schema) {
+ this.schema = schema;
+ }
+
+ public void setCatalog(String catalog) {
+ this.catalog = catalog;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setAbstract(boolean anAbstract) {
+ isAbstract = anAbstract;
+ }
+
+ public void setUniqueConstraints(UniqueConstraint[] uniqueConstraints) {
+ this.uniqueConstraints = TableBinder.buildUniqueConstraints( uniqueConstraints );
+ }
+
+ public void setConstraints(String constraints) {
+ this.constraints = constraints;
+ }
+
+ public void setDenormalizedSuperTable(Table denormalizedSuperTable) {
+ this.denormalizedSuperTable = denormalizedSuperTable;
+ }
+
+ public void setMappings(ExtendedMappings mappings) {
+ this.mappings = mappings;
+ }
+
+ // only bind association table currently
+ public Table bind() {
+ //logicalName only accurate for assoc table...
+ String unquotedOwnerTable = StringHelper.unquote( ownerEntityTable );
+ String unquotedAssocTable = StringHelper.unquote( associatedEntityTable );
+
+ String logicalName = mappings.getNamingStrategy()
+ .logicalCollectionTableName(
+ name,
+ unquotedOwnerTable,
+ unquotedAssocTable,
+ propertyName );
+ if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted(
associatedEntityTable ) ) {
+ logicalName = StringHelper.quote( logicalName );
+ }
+ String extendedName;
+ if ( name != null ) {
+ extendedName = mappings.getNamingStrategy().tableName( name );
+ }
+ else {
+ extendedName = mappings.getNamingStrategy()
+ .collectionTableName(
+ ownerEntity,
+ unquotedOwnerTable,
+ associatedEntity,
+ unquotedAssocTable,
+ propertyName
+ );
+ if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted(
associatedEntityTable ) ) {
+ extendedName = StringHelper.quote( extendedName );
+ }
+ }
+ return fillTable(
+ schema, catalog,
+ extendedName, logicalName, isAbstract, uniqueConstraints, constraints,
+ denormalizedSuperTable, mappings
+ );
+ }
+
+ public static Table fillTable(
+ String schema, String catalog, String realTableName, String logicalName, boolean
isAbstract,
+ List uniqueConstraints, String constraints, Table denormalizedSuperTable,
ExtendedMappings mappings
+ ) {
+ schema = BinderHelper.isDefault( schema ) ? mappings.getSchemaName() : schema;
+ catalog = BinderHelper.isDefault( catalog ) ? mappings.getCatalogName() : catalog;
+ Table table;
+ if ( denormalizedSuperTable != null ) {
+ table = mappings.addDenormalizedTable(
+ schema,
+ catalog,
+ realTableName,
+ isAbstract,
+ null, //subselect
+ denormalizedSuperTable
+ );
+ }
+ else {
+ table = mappings.addTable(
+ schema,
+ catalog,
+ realTableName,
+ null, //subselect
+ isAbstract
+ );
+ }
+ if ( uniqueConstraints != null && uniqueConstraints.size() > 0 ) {
+ mappings.addUniqueConstraints( table, uniqueConstraints );
+ }
+ if ( constraints != null ) table.addCheckConstraint( constraints );
+ //logicalName is null if we are in the second pass
+ if ( logicalName != null ) {
+ mappings.addTableBinding( schema, catalog, logicalName, realTableName,
denormalizedSuperTable );
+ }
+ return table;
+ }
+
+ public static void bindFk(
+ PersistentClass referencedEntity, PersistentClass destinationEntity, Ejb3JoinColumn[]
columns,
+ SimpleValue value,
+ boolean unique, ExtendedMappings mappings
+ ) {
+ PersistentClass associatedClass;
+ if ( destinationEntity != null ) {
+ //overidden destination
+ associatedClass = destinationEntity;
+ }
+ else {
+ associatedClass = columns[0].getPropertyHolder() == null ? null :
columns[0].getPropertyHolder()
+ .getPersistentClass();
+ }
+ final String mappedByProperty = columns[0].getMappedBy();
+ if ( StringHelper.isNotEmpty( mappedByProperty ) ) {
+ /**
+ * Get the columns of the mapped-by property
+ * copy them and link the copy to the actual value
+ */
+ log.debug("Retrieving property {}.{}", associatedClass.getEntityName(),
mappedByProperty);
+
+ final Property property = associatedClass.getRecursiveProperty(
columns[0].getMappedBy() );
+ Iterator mappedByColumns;
+ if ( property.getValue() instanceof Collection ) {
+ Collection collection = ( (Collection) property.getValue() );
+ Value element = collection.getElement();
+ if ( element == null ) {
+ throw new AnnotationException(
+ "Illegal use of mappedBy on both sides of the relationship: "
+ + associatedClass.getEntityName() + "." + mappedByProperty
+ );
+ }
+ mappedByColumns = element.getColumnIterator();
+ }
+ else {
+ mappedByColumns = property.getValue().getColumnIterator();
+ }
+ while ( mappedByColumns.hasNext() ) {
+ Column column = (Column) mappedByColumns.next();
+ columns[0].overrideFromReferencedColumnIfNecessary( column );
+ columns[0].linkValueUsingAColumnCopy( column, value );
+ }
+ }
+ else if ( columns[0].isImplicit() ) {
+ /**
+ * if columns are implicit, then create the columns based on the
+ * referenced entity id columns
+ */
+ Iterator idColumns;
+ if ( referencedEntity instanceof JoinedSubclass ) {
+ idColumns = ( (JoinedSubclass) referencedEntity ).getKey().getColumnIterator();
+ }
+ else {
+ idColumns = referencedEntity.getIdentifier().getColumnIterator();
+ }
+ while ( idColumns.hasNext() ) {
+ Column column = (Column) idColumns.next();
+ columns[0].overrideFromReferencedColumnIfNecessary( column );
+ columns[0].linkValueUsingDefaultColumnNaming( column, referencedEntity, value );
+ }
+ }
+ else {
+ int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType( columns, referencedEntity,
mappings );
+
+ if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) {
+ String referencedPropertyName;
+ if ( value instanceof ToOne ) {
+ referencedPropertyName = ( (ToOne) value ).getReferencedPropertyName();
+ }
+ else if ( value instanceof DependantValue ) {
+ String propertyName = columns[0].getPropertyName();
+ if ( propertyName != null ) {
+ Collection collection = (Collection) referencedEntity.getRecursiveProperty(
propertyName )
+ .getValue();
+ referencedPropertyName = collection.getReferencedPropertyName();
+ }
+ else {
+ throw new AnnotationException( "SecondaryTable JoinColumn cannot reference a
non primary key" );
+ }
+
+ }
+ else {
+ throw new AssertionFailure(
+ "Do a property ref on an unexpected Value type: "
+ + value.getClass().getName()
+ );
+ }
+ if ( referencedPropertyName == null ) {
+ throw new AssertionFailure(
+ "No property ref found while expected"
+ );
+ }
+ Property synthProp = referencedEntity.getRecursiveProperty( referencedPropertyName
);
+ if ( synthProp == null ) {
+ throw new AssertionFailure(
+ "Cannot find synthProp: " + referencedEntity.getEntityName() +
"." + referencedPropertyName
+ );
+ }
+ linkJoinColumnWithValueOverridingNameIfImplicit(
+ referencedEntity, synthProp.getColumnIterator(), columns, value
+ );
+
+ }
+ else {
+ if ( Ejb3JoinColumn.NO_REFERENCE == fkEnum ) {
+ //implicit case, we hope PK and FK columns are in the same order
+ if ( columns.length != referencedEntity.getIdentifier().getColumnSpan() ) {
+ throw new AnnotationException(
+ "A Foreign key refering " + referencedEntity.getEntityName()
+ + " from " + associatedClass.getEntityName()
+ + " has the wrong number of column. should be " +
referencedEntity.getIdentifier()
+ .getColumnSpan()
+ );
+ }
+ linkJoinColumnWithValueOverridingNameIfImplicit(
+ referencedEntity,
+ referencedEntity.getIdentifier().getColumnIterator(),
+ columns,
+ value
+ );
+ }
+ else {
+ //explicit referencedColumnName
+ Iterator idColItr = referencedEntity.getKey().getColumnIterator();
+ org.hibernate.mapping.Column col;
+ Table table = referencedEntity.getTable(); //works cause the pk has to be on the
primary table
+ if ( !idColItr.hasNext() ) log.debug( "No column in the identifier!" );
+ while ( idColItr.hasNext() ) {
+ boolean match = false;
+ //for each PK column, find the associated FK column.
+ col = (org.hibernate.mapping.Column) idColItr.next();
+ for (Ejb3JoinColumn joinCol : columns) {
+ String referencedColumn = joinCol.getReferencedColumn();
+ referencedColumn = mappings.getPhysicalColumnName( referencedColumn, table );
+ if ( referencedColumn.equals( col.getName() ) ) {
+ //proper join column
+ if ( joinCol.isNameDeferred() ) {
+ joinCol.linkValueUsingDefaultColumnNaming(
+ col, referencedEntity, value
+ );
+ }
+ else {
+ joinCol.linkWithValue( value );
+ }
+ joinCol.overrideFromReferencedColumnIfNecessary( col );
+ match = true;
+ break;
+ }
+ }
+ if ( !match ) {
+ throw new AnnotationException(
+ "Column name " + col.getName() + " of "
+ + referencedEntity.getEntityName() + " not found in
JoinColumns.referencedColumnName"
+ );
+ }
+ }
+ }
+ }
+ }
+ value.createForeignKey();
+ if ( unique == true ) {
+ createUniqueConstraint( value );
+ }
+ }
+
+ private static void linkJoinColumnWithValueOverridingNameIfImplicit(
+ PersistentClass referencedEntity, Iterator columnIterator, Ejb3JoinColumn[] columns,
SimpleValue value
+ ) {
+ for (Ejb3JoinColumn joinCol : columns) {
+ Column synthCol = (Column) columnIterator.next();
+ if ( joinCol.isNameDeferred() ) {
+ //this has to be the default value
+ joinCol.linkValueUsingDefaultColumnNaming( synthCol, referencedEntity, value );
+ }
+ else {
+ joinCol.linkWithValue( value );
+ joinCol.overrideFromReferencedColumnIfNecessary( synthCol );
+ }
+ }
+ }
+
+ public static void createUniqueConstraint(Value value) {
+ Iterator iter = value.getColumnIterator();
+ ArrayList cols = new ArrayList();
+ while ( iter.hasNext() ) {
+ cols.add( iter.next() );
+ }
+ value.getTable().createUniqueKey( cols );
+ }
+
+ public static void addIndexes(Table hibTable, Index[] indexes, ExtendedMappings
mappings) {
+ for (Index index : indexes) {
+ //no need to handle inSecondPass here since it is only called from EntityBinder
+ mappings.addSecondPass(
+ new IndexOrUniqueKeySecondPass( hibTable, index.name(), index.columnNames(),
mappings )
+ );
+ }
+ }
+
+ public static List<String[]> buildUniqueConstraints(UniqueConstraint[]
constraintsArray) {
+ List<String[]> result = new ArrayList<String[]>();
+ if ( constraintsArray.length != 0 ) {
+ for (UniqueConstraint uc : constraintsArray) {
+ result.add( uc.columnNames() );
+ }
+ }
+ return result;
+ }
+
+ public void setDefaultName(
+ String ownerEntity, String ownerEntityTable, String associatedEntity, String
associatedEntityTable,
+ String propertyName
+ ) {
+ this.ownerEntity = ownerEntity;
+ this.ownerEntityTable = ownerEntityTable;
+ this.associatedEntity = associatedEntity;
+ this.associatedEntityTable = associatedEntityTable;
+ this.propertyName = propertyName;
+ this.name = null;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Version.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Version.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/Version.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,20 @@
+//$Id: Version.java 15098 2008-08-18 17:54:58Z hardy.ferentschik $
+package org.hibernate.cfg.annotations;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class Version {
+ public static final String VERSION = "3.4.0.GA";
+ private static Logger log = LoggerFactory.getLogger( Version.class );
+
+ static {
+ log.info( "Hibernate Annotations {}", VERSION );
+ }
+
+ public static void touch() {
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3OverridenAnnotationReader.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3OverridenAnnotationReader.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3OverridenAnnotationReader.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,2081 @@
+package org.hibernate.cfg.annotations.reflection;
+
+import java.beans.Introspector;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.persistence.AssociationOverride;
+import javax.persistence.AssociationOverrides;
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.ColumnResult;
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.DiscriminatorType;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Embeddable;
+import javax.persistence.Embedded;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.EntityResult;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.ExcludeDefaultListeners;
+import javax.persistence.ExcludeSuperclassListeners;
+import javax.persistence.FetchType;
+import javax.persistence.FieldResult;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.JoinTable;
+import javax.persistence.Lob;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKey;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.NamedNativeQueries;
+import javax.persistence.NamedNativeQuery;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.OrderBy;
+import javax.persistence.PostLoad;
+import javax.persistence.PostPersist;
+import javax.persistence.PostRemove;
+import javax.persistence.PostUpdate;
+import javax.persistence.PrePersist;
+import javax.persistence.PreRemove;
+import javax.persistence.PreUpdate;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.PrimaryKeyJoinColumns;
+import javax.persistence.QueryHint;
+import javax.persistence.SecondaryTable;
+import javax.persistence.SecondaryTables;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.SqlResultSetMapping;
+import javax.persistence.SqlResultSetMappings;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.persistence.Version;
+
+import org.dom4j.Attribute;
+import org.dom4j.Element;
+import org.hibernate.AnnotationException;
+import org.hibernate.annotations.AccessType;
+import org.hibernate.annotations.CollectionOfElements;
+import org.hibernate.annotations.Columns;
+import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor;
+import org.hibernate.annotations.common.annotationfactory.AnnotationFactory;
+import org.hibernate.annotations.common.reflection.AnnotationReader;
+import org.hibernate.annotations.common.reflection.Filter;
+import org.hibernate.annotations.common.reflection.ReflectionUtil;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Encapsulates the overriding of Java annotations from an EJB 3.0 descriptor.
+ *
+ * @author Paolo Perrotta
+ * @author Davide Marchignoli
+ * @author Emmanuel Bernard
+ */
+@SuppressWarnings("unchecked")
+public class EJB3OverridenAnnotationReader implements AnnotationReader {
+ private Logger log = LoggerFactory.getLogger( EJB3OverridenAnnotationReader.class );
+ private static final Map<Class, String> annotationToXml;
+ private static final String SCHEMA_VALIDATION = "Activate schema validation for
more informations";
+ private static final Filter FILTER = new Filter() {
+ public boolean returnStatic() {
+ return false;
+ }
+
+ public boolean returnTransient() {
+ return false;
+ }
+ };
+
+ static {
+ annotationToXml = new HashMap<Class, String>();
+ annotationToXml.put( Entity.class, "entity" );
+ annotationToXml.put( MappedSuperclass.class, "mapped-superclass" );
+ annotationToXml.put( Embeddable.class, "embeddable" );
+ annotationToXml.put( Table.class, "table" );
+ annotationToXml.put( SecondaryTable.class, "secondary-table" );
+ annotationToXml.put( SecondaryTables.class, "secondary-table" );
+ annotationToXml.put( PrimaryKeyJoinColumn.class, "primary-key-join-column"
);
+ annotationToXml.put( PrimaryKeyJoinColumns.class, "primary-key-join-column"
);
+ annotationToXml.put( IdClass.class, "id-class" );
+ annotationToXml.put( Inheritance.class, "inheritance" );
+ annotationToXml.put( DiscriminatorValue.class, "discriminator-value" );
+ annotationToXml.put( DiscriminatorColumn.class, "discriminator-column" );
+ annotationToXml.put( SequenceGenerator.class, "sequence-generator" );
+ annotationToXml.put( TableGenerator.class, "table-generator" );
+ annotationToXml.put( NamedQuery.class, "named-query" );
+ annotationToXml.put( NamedQueries.class, "named-query" );
+ annotationToXml.put( NamedNativeQuery.class, "named-native-query" );
+ annotationToXml.put( NamedNativeQueries.class, "named-native-query" );
+ annotationToXml.put( SqlResultSetMapping.class, "sql-result-set-mapping" );
+ annotationToXml.put( SqlResultSetMappings.class, "sql-result-set-mapping" );
+ annotationToXml.put( ExcludeDefaultListeners.class,
"exclude-default-listeners" );
+ annotationToXml.put( ExcludeSuperclassListeners.class,
"exclude-superclass-listeners" );
+ annotationToXml.put( AccessType.class, "access" );
+ annotationToXml.put( AttributeOverride.class, "attribute-override" );
+ annotationToXml.put( AttributeOverrides.class, "attribute-override" );
+ annotationToXml.put( AttributeOverride.class, "association-override" );
+ annotationToXml.put( AttributeOverrides.class, "association-override" );
+ annotationToXml.put( Id.class, "id" );
+ annotationToXml.put( EmbeddedId.class, "embedded-id" );
+ annotationToXml.put( GeneratedValue.class, "generated-value" );
+ annotationToXml.put( Column.class, "column" );
+ annotationToXml.put( Columns.class, "column" );
+ annotationToXml.put( Temporal.class, "temporal" );
+ annotationToXml.put( Lob.class, "lob" );
+ annotationToXml.put( Enumerated.class, "enumerated" );
+ annotationToXml.put( Version.class, "version" );
+ annotationToXml.put( Transient.class, "transient" );
+ annotationToXml.put( Basic.class, "basic" );
+ annotationToXml.put( Embedded.class, "embedded" );
+ annotationToXml.put( ManyToOne.class, "many-to-one" );
+ annotationToXml.put( OneToOne.class, "one-to-one" );
+ annotationToXml.put( OneToMany.class, "one-to-many" );
+ annotationToXml.put( ManyToMany.class, "many-to-many" );
+ annotationToXml.put( JoinTable.class, "join-table" );
+ annotationToXml.put( JoinColumn.class, "join-column" );
+ annotationToXml.put( JoinColumns.class, "join-column" );
+ annotationToXml.put( MapKey.class, "map-key" );
+ annotationToXml.put( OrderBy.class, "order-by" );
+ annotationToXml.put( EntityListeners.class, "entity-listeners" );
+ annotationToXml.put( PrePersist.class, "pre-persist" );
+ annotationToXml.put( PreRemove.class, "pre-remove" );
+ annotationToXml.put( PreUpdate.class, "pre-update" );
+ annotationToXml.put( PostPersist.class, "post-persist" );
+ annotationToXml.put( PostRemove.class, "post-remove" );
+ annotationToXml.put( PostUpdate.class, "post-update" );
+ annotationToXml.put( PostLoad.class, "post-load" );
+ }
+
+ private XMLContext xmlContext;
+ private String className;
+ private String propertyName;
+ private PropertyType propertyType;
+ private transient Annotation[] annotations;
+ private transient Map<Class, Annotation> annotationsMap;
+ private static final String WORD_SEPARATOR = "-";
+ private transient List<Element> elementsForProperty;
+ private AccessibleObject mirroredAttribute;
+ private final AnnotatedElement element;
+
+ private enum PropertyType {
+ PROPERTY,
+ FIELD,
+ METHOD
+ }
+
+ public EJB3OverridenAnnotationReader(AnnotatedElement el, XMLContext xmlContext) {
+ this.element = el;
+ this.xmlContext = xmlContext;
+ if ( el instanceof Class ) {
+ Class clazz = (Class) el;
+ className = clazz.getName();
+ }
+ else if ( el instanceof Field ) {
+ Field field = (Field) el;
+ className = field.getDeclaringClass().getName();
+ propertyName = field.getName();
+ propertyType = PropertyType.FIELD;
+ String expectedGetter = "get" + Character.toUpperCase( propertyName.charAt(
0 ) ) + propertyName.substring(
+ 1
+ );
+ try {
+ mirroredAttribute = field.getDeclaringClass().getDeclaredMethod( expectedGetter );
+ }
+ catch (NoSuchMethodException e) {
+ //no method
+ }
+ }
+ else if ( el instanceof Method ) {
+ Method method = (Method) el;
+ className = method.getDeclaringClass().getName();
+ propertyName = method.getName();
+ if ( ReflectionUtil.isProperty(
+ method,
+ null, //this is yukky!! we'd rather get the TypeEnvironment()
+ FILTER
+ ) ) {
+ if ( propertyName.startsWith( "get" ) ) {
+ propertyName = Introspector.decapitalize( propertyName.substring(
"get".length() ) );
+ }
+ else if ( propertyName.startsWith( "is" ) ) {
+ propertyName = Introspector.decapitalize( propertyName.substring(
"is".length() ) );
+ }
+ else {
+ throw new RuntimeException( "Method " + propertyName + " is not a
property getter" );
+ }
+ propertyType = PropertyType.PROPERTY;
+ try {
+ mirroredAttribute = method.getDeclaringClass().getDeclaredField( propertyName );
+ }
+ catch (NoSuchFieldException e) {
+ //no method
+ }
+ }
+ else {
+ propertyType = PropertyType.METHOD;
+ }
+ }
+ else {
+ className = null;
+ propertyName = null;
+ }
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+ initAnnotations();
+ return (T) annotationsMap.get( annotationType );
+ }
+
+ public <T extends Annotation> boolean isAnnotationPresent(Class<T>
annotationType) {
+ initAnnotations();
+ return (T) annotationsMap.get( annotationType ) != null;
+ }
+
+ public Annotation[] getAnnotations() {
+ initAnnotations();
+ return annotations;
+ }
+
+ private void initAnnotations() {
+ if ( annotations == null ) {
+ XMLContext.Default defaults = xmlContext.getDefault( className );
+ if ( className != null && propertyName == null ) {
+ //is a class
+ Element tree = xmlContext.getXMLTree( className, null );
+ Annotation[] annotations = getJavaAnnotations();
+ List<Annotation> annotationList = new ArrayList<Annotation>(
annotations.length + 5 );
+ annotationsMap = new HashMap<Class, Annotation>( annotations.length + 5 );
+ for (Annotation annotation : annotations) {
+ if ( !annotationToXml.containsKey( annotation.annotationType() ) ) {
+ //unknown annotations are left over
+ annotationList.add( annotation );
+ }
+ }
+ addIfNotNull( annotationList, getEntity( tree, defaults ) );
+ addIfNotNull( annotationList, getMappedSuperclass( tree, defaults ) );
+ addIfNotNull( annotationList, getEmbeddable( tree, defaults ) );
+ addIfNotNull( annotationList, getTable( tree, defaults ) );
+ addIfNotNull( annotationList, getSecondaryTables( tree, defaults ) );
+ addIfNotNull( annotationList, getPrimaryKeyJoinColumns( tree, defaults ) );
+ addIfNotNull( annotationList, getIdClass( tree, defaults ) );
+ addIfNotNull( annotationList, getInheritance( tree, defaults ) );
+ addIfNotNull( annotationList, getDiscriminatorValue( tree, defaults ) );
+ addIfNotNull( annotationList, getDiscriminatorColumn( tree, defaults ) );
+ addIfNotNull( annotationList, getSequenceGenerator( tree, defaults ) );
+ addIfNotNull( annotationList, getTableGenerator( tree, defaults ) );
+ addIfNotNull( annotationList, getNamedQueries( tree, defaults ) );
+ addIfNotNull( annotationList, getNamedNativeQueries( tree, defaults ) );
+ addIfNotNull( annotationList, getSqlResultSetMappings( tree, defaults ) );
+ addIfNotNull( annotationList, getExcludeDefaultListeners( tree, defaults ) );
+ addIfNotNull( annotationList, getExcludeSuperclassListeners( tree, defaults ) );
+ addIfNotNull( annotationList, getAccessType( tree, defaults ) );
+ addIfNotNull( annotationList, getAttributeOverrides( tree, defaults ) );
+ addIfNotNull( annotationList, getAssociationOverrides( tree, defaults ) );
+ addIfNotNull( annotationList, getEntityListeners( tree, defaults ) );
+ //FIXME use annotationsMap rather than annotationList this will be faster since the
annotation type is usually known at put() time
+ this.annotations = annotationList.toArray( new Annotation[annotationList.size()] );
+ for (Annotation ann : this.annotations) {
+ annotationsMap.put( ann.annotationType(), ann );
+ }
+ checkForOrphanProperties( tree );
+ }
+ else if ( className != null ) { //&& propertyName != null ) { //always true
but less confusing
+ Element tree = xmlContext.getXMLTree( className, propertyName );
+ Annotation[] annotations = getJavaAnnotations();
+ List<Annotation> annotationList = new ArrayList<Annotation>(
annotations.length + 5 );
+ annotationsMap = new HashMap<Class, Annotation>( annotations.length + 5 );
+ for (Annotation annotation : annotations) {
+ if ( !annotationToXml.containsKey( annotation.annotationType() ) ) {
+ //unknown annotations are left over
+ annotationList.add( annotation );
+ }
+ }
+ preCalculateElementsForProperty( tree );
+ Transient transientAnn = getTransient( defaults );
+ if ( transientAnn != null ) {
+ annotationList.add( transientAnn );
+ }
+ else {
+ if ( defaults.canUseJavaAnnotations() ) {
+ Annotation annotation = getJavaAnnotation( AccessType.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ getId( annotationList, defaults );
+ getEmbeddedId( annotationList, defaults );
+ getEmbedded( annotationList, defaults );
+ getBasic( annotationList, defaults );
+ getVersion( annotationList, defaults );
+ getAssociation( ManyToOne.class, annotationList, defaults );
+ getAssociation( OneToOne.class, annotationList, defaults );
+ getAssociation( OneToMany.class, annotationList, defaults );
+ getAssociation( ManyToMany.class, annotationList, defaults );
+ addIfNotNull( annotationList, getSequenceGenerator( elementsForProperty, defaults )
);
+ addIfNotNull( annotationList, getTableGenerator( elementsForProperty, defaults ) );
+ addIfNotNull( annotationList, getAttributeOverrides( elementsForProperty, defaults )
);
+
+ }
+ processEventAnnotations( annotationList, defaults );
+ //FIXME use annotationsMap rather than annotationList this will be faster since the
annotation type is usually known at put() time
+ this.annotations = annotationList.toArray( new Annotation[annotationList.size()] );
+ for (Annotation ann : this.annotations) {
+ annotationsMap.put( ann.annotationType(), ann );
+ }
+ }
+ else {
+ this.annotations = getJavaAnnotations();
+ annotationsMap = new HashMap<Class, Annotation>( annotations.length + 5 );
+ for (Annotation ann : this.annotations) {
+ annotationsMap.put( ann.annotationType(), ann );
+ }
+ }
+ }
+ }
+
+ private void checkForOrphanProperties(Element tree) {
+ Class clazz;
+ try {
+ clazz = ReflectHelper.classForName( className, this.getClass() );
+ }
+ catch (ClassNotFoundException e) {
+ return; //a primitive type most likely
+ }
+ Element element = tree != null ? tree.element( "attributes" ) : null;
+ //put entity.attributes elements
+ if ( element != null ) {
+ //precompute the list of properties
+ //TODO is it really useful...
+ Set<String> properties = new HashSet<String>();
+ for (Field field : clazz.getFields()) {
+ properties.add( field.getName() );
+ }
+ for (Method method : clazz.getMethods()) {
+ String name = method.getName();
+ if ( name.startsWith( "get" ) ) {
+ properties.add( Introspector.decapitalize( name.substring( "get".length()
) ) );
+ }
+ else if ( name.startsWith( "is" ) ) {
+ properties.add( Introspector.decapitalize( name.substring( "is".length() )
) );
+ }
+ }
+ for (Element subelement : (List<Element>) element.elements()) {
+ String propertyName = subelement.attributeValue( "name" );
+ if ( !properties.contains( propertyName ) ) {
+ log.warn( "Property {} not found in class"
+ + " but described in <mapping-file/> (possible typo error)",
+ StringHelper.qualify( className, propertyName ) );
+ }
+ }
+ }
+ }
+
+ /**
+ * Addes the Annotation to the list (only if it's not null) and then returns it.
+ */
+ private Annotation addIfNotNull(List<Annotation> annotationList, Annotation
element) {
+ if ( element != null ) {
+ annotationList.add( element );
+ }
+ return element;
+ }
+
+ //TODO mutualize the next 2 methods
+ private Annotation getTableGenerator(List<Element> elementsForProperty,
XMLContext.Default defaults) {
+ for (Element element : elementsForProperty) {
+ Element subelement = element != null ? element.element( annotationToXml.get(
TableGenerator.class ) ) : null;
+ if ( subelement != null ) {
+ return buildTableGeneratorAnnotation( subelement, defaults );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( TableGenerator.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ private Annotation getSequenceGenerator(List<Element> elementsForProperty,
XMLContext.Default defaults) {
+ for (Element element : elementsForProperty) {
+ Element subelement = element != null ? element.element( annotationToXml.get(
SequenceGenerator.class ) ) : null;
+ if ( subelement != null ) {
+ return buildSequenceGeneratorAnnotation( subelement );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( SequenceGenerator.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void processEventAnnotations(List<Annotation> annotationList,
XMLContext.Default defaults) {
+ boolean eventElement = false;
+ for (Element element : elementsForProperty) {
+ String elementName = element.getName();
+ if ( "pre-persist".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PrePersist.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ else if ( "pre-remove".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PreRemove.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ else if ( "pre-update".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PreUpdate.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ else if ( "post-persist".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PostPersist.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ else if ( "post-remove".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PostRemove.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ else if ( "post-update".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PostUpdate.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ else if ( "post-load".equals( elementName ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PostLoad.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ eventElement = true;
+ }
+ }
+ if ( !eventElement && defaults.canUseJavaAnnotations() ) {
+ Annotation ann = getJavaAnnotation( PrePersist.class );
+ addIfNotNull( annotationList, ann );
+ ann = getJavaAnnotation( PreRemove.class );
+ addIfNotNull( annotationList, ann );
+ ann = getJavaAnnotation( PreUpdate.class );
+ addIfNotNull( annotationList, ann );
+ ann = getJavaAnnotation( PostPersist.class );
+ addIfNotNull( annotationList, ann );
+ ann = getJavaAnnotation( PostRemove.class );
+ addIfNotNull( annotationList, ann );
+ ann = getJavaAnnotation( PostUpdate.class );
+ addIfNotNull( annotationList, ann );
+ ann = getJavaAnnotation( PostLoad.class );
+ addIfNotNull( annotationList, ann );
+ }
+ }
+
+ private EntityListeners getEntityListeners(Element tree, XMLContext.Default defaults) {
+ Element element = tree != null ? tree.element( "entity-listeners" ) : null;
+ if ( element != null ) {
+ List<Class> entityListenerClasses = new ArrayList<Class>();
+ for (Element subelement : (List<Element>) element.elements(
"entity-listener" )) {
+ String className = subelement.attributeValue( "class" );
+ try {
+ entityListenerClasses.add(
+ ReflectHelper.classForName(
+ XMLContext.buildSafeClassName( className, defaults ),
+ this.getClass()
+ )
+ );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException(
+ "Unable to find " + element.getPath() + ".class: " +
className, e
+ );
+ }
+ }
+ AnnotationDescriptor ad = new AnnotationDescriptor( EntityListeners.class );
+ ad.setValue( "value", entityListenerClasses.toArray( new
Class[entityListenerClasses.size()] ) );
+ return AnnotationFactory.create( ad );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( EntityListeners.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private JoinTable overridesDefaultsInJoinTable(Annotation annotation, XMLContext.Default
defaults) {
+ //no element but might have some default or some annotation
+ boolean defaultToJoinTable = !( isJavaAnnotationPresent( JoinColumn.class )
+ || isJavaAnnotationPresent( JoinColumns.class ) );
+ final Class<? extends Annotation> annotationClass = annotation.annotationType();
+ defaultToJoinTable = defaultToJoinTable &&
+ ( ( annotationClass == ManyToMany.class && StringHelper.isEmpty( (
(ManyToMany) annotation ).mappedBy() ) )
+ || ( annotationClass == OneToMany.class && StringHelper.isEmpty( (
(OneToMany) annotation ).mappedBy() ) )
+ || ( annotationClass == CollectionOfElements.class )
+ );
+ final Class<JoinTable> annotationType = JoinTable.class;
+ if ( defaultToJoinTable
+ && ( StringHelper.isNotEmpty( defaults.getCatalog() )
+ || StringHelper.isNotEmpty( defaults.getSchema() ) ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( annotationType );
+ if ( defaults.canUseJavaAnnotations() ) {
+ JoinTable table = getJavaAnnotation( annotationType );
+ if ( table != null ) {
+ ad.setValue( "name", table.name() );
+ ad.setValue( "schema", table.schema() );
+ ad.setValue( "catalog", table.catalog() );
+ ad.setValue( "uniqueConstraints", table.uniqueConstraints() );
+ ad.setValue( "joinColumns", table.joinColumns() );
+ ad.setValue( "inverseJoinColumns", table.inverseJoinColumns() );
+ }
+ }
+ if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) )
+ && StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ ad.setValue( "schema", defaults.getSchema() );
+ }
+ if ( StringHelper.isEmpty( (String) ad.valueOf( "catalog" ) )
+ && StringHelper.isNotEmpty( defaults.getCatalog() ) ) {
+ ad.setValue( "catalog", defaults.getCatalog() );
+ }
+ return AnnotationFactory.create( ad );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( annotationType );
+ }
+ else {
+ return null;
+ }
+ }
+
+ /*
+ * no partial overriding possible
+ */
+ private void getJoinTable(List<Annotation> annotationList, Element tree,
XMLContext.Default defaults) {
+ Element subelement = tree == null ? null : tree.element( "join-table" );
+ final Class<JoinTable> annotationType = JoinTable.class;
+ if ( subelement != null ) {
+ //ignore java annotation, an element is defined
+ AnnotationDescriptor annotation = new AnnotationDescriptor( annotationType );
+ copyStringAttribute( annotation, subelement, "name", false );
+ copyStringAttribute( annotation, subelement, "catalog", false );
+ if ( StringHelper.isNotEmpty( defaults.getCatalog() )
+ && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" )
) ) {
+ annotation.setValue( "catalog", defaults.getCatalog() );
+ }
+ copyStringAttribute( annotation, subelement, "schema", false );
+ if ( StringHelper.isNotEmpty( defaults.getSchema() )
+ && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) )
) {
+ annotation.setValue( "schema", defaults.getSchema() );
+ }
+ buildUniqueConstraints( annotation, subelement );
+ annotation.setValue( "joinColumns", getJoinColumns( subelement, false ) );
+ annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement, true
) );
+ annotationList.add( AnnotationFactory.create( annotation ) );
+ }
+ }
+
+ private void getAssociation(
+ Class<? extends Annotation> annotationType, List<Annotation>
annotationList, XMLContext.Default defaults
+ ) {
+ String xmlName = annotationToXml.get( annotationType );
+ for (Element element : elementsForProperty) {
+ if ( xmlName.equals( element.getName() ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( annotationType );
+ String className = element.attributeValue( "target-entity" );
+ if ( className != null ) {
+ Class clazz;
+ try {
+ clazz = ReflectHelper.classForName(
+ XMLContext.buildSafeClassName( className, defaults ),
+ this.getClass()
+ );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException(
+ "Unable to find " + element.getPath() + "target-entity: " +
className, e
+ );
+ }
+ ad.setValue( "targetEntity", clazz );
+ }
+ getFetchType( ad, element );
+ getCascades( ad, element, defaults );
+ getJoinTable( annotationList, element, defaults );
+ buildJoinColumns( annotationList, element, defaults );
+ Annotation annotation = getPrimaryKeyJoinColumns( element, defaults );
+ addIfNotNull( annotationList, annotation );
+ copyBooleanAttribute( ad, element, "optional" );
+ copyStringAttribute( ad, element, "mapped-by", false );
+ getOrderBy( annotationList, element, defaults );
+ getMapKey( annotationList, element, defaults );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ Annotation annotation = getJavaAnnotation( annotationType );
+ if ( annotation != null ) {
+ annotationList.add( annotation );
+ annotation = overridesDefaultsInJoinTable( annotation, defaults );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( JoinColumn.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( JoinColumns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( PrimaryKeyJoinColumn.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( PrimaryKeyJoinColumns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( MapKey.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( OrderBy.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Lob.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Enumerated.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Temporal.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Column.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Columns.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ else if ( isJavaAnnotationPresent( CollectionOfElements.class ) ) {
+ annotation = overridesDefaultsInJoinTable( getJavaAnnotation(
CollectionOfElements.class ), defaults );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( JoinColumn.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( JoinColumns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( PrimaryKeyJoinColumn.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( PrimaryKeyJoinColumns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( MapKey.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( OrderBy.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Lob.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Enumerated.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Temporal.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Column.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Columns.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ }
+ }
+
+ private void getOrderBy(List<Annotation> annotationList, Element element,
XMLContext.Default defaults) {
+ Element subelement = element != null ? element.element( "order-by" ) : null;
+ if ( subelement != null ) {
+ String orderByString = subelement.getTextTrim();
+ AnnotationDescriptor ad = new AnnotationDescriptor( OrderBy.class );
+ if ( StringHelper.isNotEmpty( orderByString ) ) ad.setValue( "value",
orderByString );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+
+ private void getMapKey(List<Annotation> annotationList, Element element,
XMLContext.Default defaults) {
+ Element subelement = element != null ? element.element( "map-key" ) : null;
+ if ( subelement != null ) {
+ String mapKeyString = subelement.attributeValue( "name" );
+ AnnotationDescriptor ad = new AnnotationDescriptor( MapKey.class );
+ if ( StringHelper.isNotEmpty( mapKeyString ) ) ad.setValue( "name",
mapKeyString );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+
+ private void buildJoinColumns(List<Annotation> annotationList, Element element,
XMLContext.Default defaults) {
+ JoinColumn[] joinColumns = getJoinColumns( element, false );
+ if ( joinColumns.length > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( JoinColumns.class );
+ ad.setValue( "value", joinColumns );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+
+ private void getCascades(AnnotationDescriptor ad, Element element, XMLContext.Default
defaults) {
+ List<Element> elements = element != null ? element.elements( "cascade"
) : new ArrayList<Element>( 0 );
+ List<CascadeType> cascades = new ArrayList<CascadeType>();
+ for (Element subelement : elements) {
+ if ( subelement.element( "cascade-all" ) != null ) cascades.add(
CascadeType.ALL );
+ if ( subelement.element( "cascade-persist" ) != null ) cascades.add(
CascadeType.PERSIST );
+ if ( subelement.element( "cascade-merge" ) != null ) cascades.add(
CascadeType.MERGE );
+ if ( subelement.element( "cascade-remove" ) != null ) cascades.add(
CascadeType.REMOVE );
+ if ( subelement.element( "cascade-refresh" ) != null ) cascades.add(
CascadeType.REFRESH );
+ }
+ if ( Boolean.TRUE.equals( defaults.getCascadePersist() )
+ && !cascades.contains( CascadeType.ALL ) && !cascades.contains(
CascadeType.PERSIST ) ) {
+ cascades.add( CascadeType.PERSIST );
+ }
+ if ( cascades.size() > 0 ) {
+ ad.setValue( "cascade", cascades.toArray( new CascadeType[cascades.size()] )
);
+ }
+ }
+
+ private void getEmbedded(List<Annotation> annotationList, XMLContext.Default
defaults) {
+ for (Element element : elementsForProperty) {
+ if ( "embedded".equals( element.getName() ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( Embedded.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ Annotation annotation = getJavaAnnotation( Embedded.class );
+ if ( annotation != null ) {
+ annotationList.add( annotation );
+ annotation = getJavaAnnotation( AttributeOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ }
+ }
+
+ private Transient getTransient(XMLContext.Default defaults) {
+ for (Element element : elementsForProperty) {
+ if ( "transient".equals( element.getName() ) ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( Transient.class );
+ return AnnotationFactory.create( ad );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( Transient.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void getVersion(List<Annotation> annotationList, XMLContext.Default
defaults) {
+ for (Element element : elementsForProperty) {
+ if ( "version".equals( element.getName() ) ) {
+ Annotation annotation = buildColumns( element );
+ addIfNotNull( annotationList, annotation );
+ getTemporal( annotationList, element );
+ AnnotationDescriptor basic = new AnnotationDescriptor( Version.class );
+ annotationList.add( AnnotationFactory.create( basic ) );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ //we have nothing, so Java annotations might occurs
+ Annotation annotation = getJavaAnnotation( Version.class );
+ if ( annotation != null ) {
+ annotationList.add( annotation );
+ annotation = getJavaAnnotation( Column.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Columns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Temporal.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ }
+ }
+
+ private void getBasic(List<Annotation> annotationList, XMLContext.Default
defaults) {
+ for (Element element : elementsForProperty) {
+ if ( "basic".equals( element.getName() ) ) {
+ Annotation annotation = buildColumns( element );
+ addIfNotNull( annotationList, annotation );
+ getTemporal( annotationList, element );
+ getLob( annotationList, element );
+ getEnumerated( annotationList, element );
+ AnnotationDescriptor basic = new AnnotationDescriptor( Basic.class );
+ getFetchType( basic, element );
+ copyBooleanAttribute( basic, element, "optional" );
+ annotationList.add( AnnotationFactory.create( basic ) );
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ //no annotation presence constraint, basic is the default
+ Annotation annotation = getJavaAnnotation( Basic.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Lob.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Enumerated.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Temporal.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Column.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Columns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ }
+
+ private void getEnumerated(List<Annotation> annotationList, Element element) {
+ Element subElement = element != null ? element.element( "enumerated" ) :
null;
+ if ( subElement != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( Enumerated.class );
+ String enumerated = subElement.getTextTrim();
+ if ( "ORDINAL".equalsIgnoreCase( enumerated ) ) {
+ ad.setValue( "value", EnumType.ORDINAL );
+ }
+ else if ( "STRING".equalsIgnoreCase( enumerated ) ) {
+ ad.setValue( "value", EnumType.STRING );
+ }
+ else if ( StringHelper.isNotEmpty( enumerated ) ) {
+ throw new AnnotationException( "Unknown EnumType: " + enumerated + ".
" + SCHEMA_VALIDATION );
+ }
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+
+ private void getLob(List<Annotation> annotationList, Element element) {
+ Element subElement = element != null ? element.element( "lob" ) : null;
+ if ( subElement != null ) {
+ annotationList.add( AnnotationFactory.create( new AnnotationDescriptor( Lob.class ) )
);
+ }
+ }
+
+ private void getFetchType(AnnotationDescriptor descriptor, Element element) {
+ String fetchString = element != null ? element.attributeValue( "fetch" ) :
null;
+ if ( fetchString != null ) {
+ if ( "eager".equalsIgnoreCase( fetchString ) ) {
+ descriptor.setValue( "fetch", FetchType.EAGER );
+ }
+ else if ( "lazy".equalsIgnoreCase( fetchString ) ) {
+ descriptor.setValue( "fetch", FetchType.LAZY );
+ }
+ }
+ }
+
+ private void getEmbeddedId(List<Annotation> annotationList, XMLContext.Default
defaults) {
+ for (Element element : elementsForProperty) {
+ if ( "embedded-id".equals( element.getName() ) ) {
+ if ( isProcessingId( defaults ) ) {
+ Annotation annotation = getAttributeOverrides( element, defaults );
+ addIfNotNull( annotationList, annotation );
+ annotation = getAssociationOverrides( element, defaults );
+ addIfNotNull( annotationList, annotation );
+ AnnotationDescriptor ad = new AnnotationDescriptor( EmbeddedId.class );
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+// else {
+// if ( defaults.canUseJavaAnnotations() ) {
+// if ( ! properOverridingOnMetadataNonComplete ) {
+// //check that id exists on the other attribute
+// //TODO Id too?
+// if ( mirroredAttribute == null || ! mirroredAttribute.isAnnotationPresent(
+// EmbeddedId.class
+// ) ) {
+// throw new AnnotationException(
+// "Cannot override an property with <embedded-id> not having an
@EmbeddedId already"
+// );
+// }
+// }
+// }
+// }
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ Annotation annotation = getJavaAnnotation( EmbeddedId.class );
+ if ( annotation != null ) {
+ annotationList.add( annotation );
+ annotation = getJavaAnnotation( Column.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Columns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( GeneratedValue.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Temporal.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( TableGenerator.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( SequenceGenerator.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ }
+ }
+
+ private void preCalculateElementsForProperty(Element tree) {
+ elementsForProperty = new ArrayList<Element>();
+ Element element = tree != null ? tree.element( "attributes" ) : null;
+ //put entity.attributes elements
+ if ( element != null ) {
+ for (Element subelement : (List<Element>) element.elements()) {
+ if ( propertyName.equals( subelement.attributeValue( "name" ) ) ) {
+ elementsForProperty.add( subelement );
+ }
+ }
+ }
+ //add pre-* etc from entity and pure entity listener classes
+ if ( tree != null ) {
+ for (Element subelement : (List<Element>) tree.elements()) {
+ if ( propertyName.equals( subelement.attributeValue( "method-name" ) ) ) {
+ elementsForProperty.add( subelement );
+ }
+ }
+ }
+ }
+
+ private void getId(List<Annotation> annotationList, XMLContext.Default defaults)
{
+ for (Element element : elementsForProperty) {
+ if ( "id".equals( element.getName() ) ) {
+ boolean processId = isProcessingId( defaults );
+ if ( processId ) {
+ Annotation annotation = buildColumns( element );
+ addIfNotNull( annotationList, annotation );
+ annotation = buildGeneratedValue( element );
+ addIfNotNull( annotationList, annotation );
+ getTemporal( annotationList, element );
+ //FIXME: fix the priority of xml over java for generator names
+ annotation = getTableGenerator( element, defaults );
+ addIfNotNull( annotationList, annotation );
+ annotation = getSequenceGenerator( element, defaults );
+ addIfNotNull( annotationList, annotation );
+ AnnotationDescriptor id = new AnnotationDescriptor( Id.class );
+ annotationList.add( AnnotationFactory.create( id ) );
+ }
+// else {
+// if ( defaults.canUseJavaAnnotations() ) {
+// if ( ! properOverridingOnMetadataNonComplete ) {
+// //check that id exists on the other attribute
+// //TODO EmbeddedId too?
+// if ( mirroredAttribute == null || ! mirroredAttribute.isAnnotationPresent(
Id.class ) ) {
+// throw new AnnotationException(
+// "Cannot override a property with <id> it does not have an @Id
already"
+// );
+// }
+// }
+// }
+// }
+ }
+ }
+ if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ Annotation annotation = getJavaAnnotation( Id.class );
+ if ( annotation != null ) {
+ annotationList.add( annotation );
+ annotation = getJavaAnnotation( Column.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Columns.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( GeneratedValue.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( Temporal.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( TableGenerator.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( SequenceGenerator.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AttributeOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverride.class );
+ addIfNotNull( annotationList, annotation );
+ annotation = getJavaAnnotation( AssociationOverrides.class );
+ addIfNotNull( annotationList, annotation );
+ }
+ }
+ }
+
+ private boolean isProcessingId(XMLContext.Default defaults) {
+ boolean isExplicit = defaults.getAccess() != null;
+ boolean correctAccess =
+ ( PropertyType.PROPERTY.equals( propertyType ) &&
"property".equals( defaults.getAccess() ) )
+ || ( PropertyType.FIELD.equals( propertyType ) && "field".equals(
defaults.getAccess() ) );
+ boolean hasId = defaults.canUseJavaAnnotations()
+ && ( isJavaAnnotationPresent( Id.class ) || isJavaAnnotationPresent(
EmbeddedId.class ) );
+ //if ( properAccessOnMetadataComplete || properOverridingOnMetadataNonComplete ) {
+ boolean mirrorAttributeIsId = defaults.canUseJavaAnnotations() &&
+ ( mirroredAttribute != null &&
+ ( mirroredAttribute.isAnnotationPresent( Id.class )
+ || mirroredAttribute.isAnnotationPresent( EmbeddedId.class ) ) );
+ boolean propertyIsDefault = PropertyType.PROPERTY.equals( propertyType )
+ && !mirrorAttributeIsId;
+ return correctAccess || ( !isExplicit && hasId ) || ( !isExplicit &&
propertyIsDefault );
+ }
+
+ private Columns buildColumns(Element element) {
+ List<Element> subelements = element.elements( "column" );
+ List<Column> columns = new ArrayList<Column>( subelements.size() );
+ for (Element subelement : subelements) {
+ columns.add( getColumn( subelement, false, element ) );
+ }
+ if ( columns.size() > 0 ) {
+ AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class );
+ columnsDescr.setValue( "columns", columns.toArray( new
Column[columns.size()] ) );
+ return AnnotationFactory.create( columnsDescr );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private GeneratedValue buildGeneratedValue(Element element) {
+ Element subElement = element != null ? element.element( "generated-value" ) :
null;
+ if ( subElement != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( GeneratedValue.class );
+ String strategy = subElement.attributeValue( "strategy" );
+ if ( "TABLE".equalsIgnoreCase( strategy ) ) {
+ ad.setValue( "strategy", GenerationType.TABLE );
+ }
+ else if ( "SEQUENCE".equalsIgnoreCase( strategy ) ) {
+ ad.setValue( "strategy", GenerationType.SEQUENCE );
+ }
+ else if ( "IDENTITY".equalsIgnoreCase( strategy ) ) {
+ ad.setValue( "strategy", GenerationType.IDENTITY );
+ }
+ else if ( "AUTO".equalsIgnoreCase( strategy ) ) {
+ ad.setValue( "strategy", GenerationType.AUTO );
+ }
+ else if ( StringHelper.isNotEmpty( strategy ) ) {
+ throw new AnnotationException( "Unknown GenerationType: " + strategy +
". " + SCHEMA_VALIDATION );
+ }
+ copyStringAttribute( ad, subElement, "generator", false );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void getTemporal(List<Annotation> annotationList, Element element) {
+ Element subElement = element != null ? element.element( "temporal" ) : null;
+ if ( subElement != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( Temporal.class );
+ String temporal = subElement.getTextTrim();
+ if ( "DATE".equalsIgnoreCase( temporal ) ) {
+ ad.setValue( "value", TemporalType.DATE );
+ }
+ else if ( "TIME".equalsIgnoreCase( temporal ) ) {
+ ad.setValue( "value", TemporalType.TIME );
+ }
+ else if ( "TIMESTAMP".equalsIgnoreCase( temporal ) ) {
+ ad.setValue( "value", TemporalType.TIMESTAMP );
+ }
+ else if ( StringHelper.isNotEmpty( temporal ) ) {
+ throw new AnnotationException( "Unknown TemporalType: " + temporal +
". " + SCHEMA_VALIDATION );
+ }
+ annotationList.add( AnnotationFactory.create( ad ) );
+ }
+ }
+
+ private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.Default
defaults) {
+ List<AssociationOverride> attributes = (List<AssociationOverride>)
buildAssociationOverrides( tree );
+ if ( defaults.canUseJavaAnnotations() ) {
+ AssociationOverride annotation = getJavaAnnotation( AssociationOverride.class );
+ addAssociationOverrideIfNeeded( annotation, attributes );
+ AssociationOverrides annotations = getJavaAnnotation( AssociationOverrides.class );
+ if ( annotations != null ) {
+ for (AssociationOverride current : annotations.value()) {
+ addAssociationOverrideIfNeeded( current, attributes );
+ }
+ }
+ }
+ if ( attributes.size() > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( AssociationOverrides.class );
+ ad.setValue( "value", attributes.toArray( new
AssociationOverride[attributes.size()] ) );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private List<AssociationOverride> buildAssociationOverrides(Element element) {
+ List<Element> subelements = element == null ? null : element.elements(
"association-override" );
+ List<AssociationOverride> overrides = new
ArrayList<AssociationOverride>();
+ if ( subelements != null && subelements.size() > 0 ) {
+ for (Element current : subelements) {
+ AnnotationDescriptor override = new AnnotationDescriptor( AssociationOverride.class
);
+ copyStringAttribute( override, current, "name", true );
+ override.setValue( "joinColumns", getJoinColumns( current, false ) );
+ overrides.add( (AssociationOverride) AnnotationFactory.create( override ) );
+ }
+ }
+ return overrides;
+ }
+
+ private JoinColumn[] getJoinColumns(Element element, boolean isInverse) {
+ List<Element> subelements = element != null ?
+ element.elements( isInverse ? "inverse-join-column" :
"join-column" ) :
+ null;
+ List<JoinColumn> joinColumns = new ArrayList<JoinColumn>();
+ if ( subelements != null ) {
+ for (Element subelement : subelements) {
+ AnnotationDescriptor column = new AnnotationDescriptor( JoinColumn.class );
+ copyStringAttribute( column, subelement, "name", false );
+ copyStringAttribute( column, subelement, "referenced-column-name", false
);
+ copyBooleanAttribute( column, subelement, "unique" );
+ copyBooleanAttribute( column, subelement, "nullable" );
+ copyBooleanAttribute( column, subelement, "insertable" );
+ copyBooleanAttribute( column, subelement, "updatable" );
+ copyStringAttribute( column, subelement, "column-definition", false );
+ copyStringAttribute( column, subelement, "table", false );
+ joinColumns.add( (JoinColumn) AnnotationFactory.create( column ) );
+ }
+ }
+ return joinColumns.toArray( new JoinColumn[joinColumns.size()] );
+ }
+
+ private void addAssociationOverrideIfNeeded(AssociationOverride annotation,
List<AssociationOverride> overrides) {
+ if ( annotation != null ) {
+ String overrideName = annotation.name();
+ boolean present = false;
+ for (AssociationOverride current : overrides) {
+ if ( current.name().equals( overrideName ) ) {
+ present = true;
+ break;
+ }
+ }
+ if ( !present ) overrides.add( annotation );
+ }
+ }
+
+ private AttributeOverrides getAttributeOverrides(Element tree, XMLContext.Default
defaults) {
+ List<AttributeOverride> attributes = buildAttributeOverrides( tree );
+ return mergeAttributeOverrides( defaults, attributes );
+ }
+
+ private AttributeOverrides getAttributeOverrides(List<Element> elements,
XMLContext.Default defaults) {
+ List<AttributeOverride> attributes = new ArrayList<AttributeOverride>();
+ for (Element element : elements) {
+ attributes.addAll( buildAttributeOverrides( element ) );
+ }
+ return mergeAttributeOverrides( defaults, attributes );
+ }
+
+ private AttributeOverrides mergeAttributeOverrides(XMLContext.Default defaults,
+ List<AttributeOverride> attributes) {
+ if ( defaults.canUseJavaAnnotations() ) {
+ AttributeOverride annotation = getJavaAnnotation( AttributeOverride.class );
+ addAttributeOverrideIfNeeded( annotation, attributes );
+ AttributeOverrides annotations = getJavaAnnotation( AttributeOverrides.class );
+ if ( annotations != null ) {
+ for (AttributeOverride current : annotations.value()) {
+ addAttributeOverrideIfNeeded( current, attributes );
+ }
+ }
+ }
+ if ( attributes.size() > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( AttributeOverrides.class );
+ ad.setValue( "value", attributes.toArray( new
AttributeOverride[attributes.size()] ) );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private List<AttributeOverride> buildAttributeOverrides(Element element) {
+ List<Element> subelements = element == null ? null : element.elements(
"attribute-override" );
+ return buildAttributeOverrides( subelements );
+ }
+
+ private List<AttributeOverride> buildAttributeOverrides(List<Element>
subelements) {
+ List<AttributeOverride> overrides = new ArrayList<AttributeOverride>();
+ if ( subelements != null && subelements.size() > 0 ) {
+ for (Element current : subelements) {
+ if ( !current.getName().equals( "attribute-override" ) ) continue;
+ AnnotationDescriptor override = new AnnotationDescriptor( AttributeOverride.class );
+ copyStringAttribute( override, current, "name", true );
+ Element column = current != null ? current.element( "column" ) : null;
+ override.setValue( "column", getColumn( column, true, current ) );
+ overrides.add( (AttributeOverride) AnnotationFactory.create( override ) );
+ }
+ }
+ return overrides;
+ }
+
+ private Column getColumn(Element element, boolean isMandatory, Element current) {
+ //Element subelement = element != null ? element.element( "column" ) : null;
+ if ( element != null ) {
+ AnnotationDescriptor column = new AnnotationDescriptor( Column.class );
+ copyStringAttribute( column, element, "name", false );
+ copyBooleanAttribute( column, element, "unique" );
+ copyBooleanAttribute( column, element, "nullable" );
+ copyBooleanAttribute( column, element, "insertable" );
+ copyBooleanAttribute( column, element, "updatable" );
+ copyStringAttribute( column, element, "column-definition", false );
+ copyStringAttribute( column, element, "table", false );
+ copyIntegerAttribute( column, element, "length" );
+ copyIntegerAttribute( column, element, "precision" );
+ copyIntegerAttribute( column, element, "scale" );
+ return (Column) AnnotationFactory.create( column );
+ }
+ else {
+ if ( isMandatory ) {
+ throw new AnnotationException( current.getPath() + ".column is mandatory. "
+ SCHEMA_VALIDATION );
+ }
+ return null;
+ }
+ }
+
+ private void addAttributeOverrideIfNeeded(AttributeOverride annotation,
List<AttributeOverride> overrides) {
+ if ( annotation != null ) {
+ String overrideName = annotation.name();
+ boolean present = false;
+ for (AttributeOverride current : overrides) {
+ if ( current.name().equals( overrideName ) ) {
+ present = true;
+ break;
+ }
+ }
+ if ( !present ) overrides.add( annotation );
+ }
+ }
+
+ private AccessType getAccessType(Element tree, XMLContext.Default defaults) {
+ String access = tree == null ? null : tree.attributeValue( "access" );
+ if ( "FIELD".equals( access ) || "PROPERTY".equals( access ) ) {
+ access = access.toLowerCase();
+ }
+ if ( access != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( AccessType.class );
+ ad.setValue( "value", access );
+ return AnnotationFactory.create( ad );
+ }
+ else if ( defaults.canUseJavaAnnotations() && isJavaAnnotationPresent(
AccessType.class ) ) {
+ AccessType annotation = getJavaAnnotation( AccessType.class );
+ return annotation;
+ }
+ else if ( defaults.getAccess() != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( AccessType.class );
+ ad.setValue( "value", defaults.getAccess() );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private ExcludeSuperclassListeners getExcludeSuperclassListeners(Element tree,
XMLContext.Default defaults) {
+ return (ExcludeSuperclassListeners) getMarkerAnnotation(
ExcludeSuperclassListeners.class, tree, defaults );
+ }
+
+ private ExcludeDefaultListeners getExcludeDefaultListeners(Element tree,
XMLContext.Default defaults) {
+ return (ExcludeDefaultListeners) getMarkerAnnotation( ExcludeDefaultListeners.class,
tree, defaults );
+ }
+
+ private Annotation getMarkerAnnotation(
+ Class<? extends Annotation> clazz, Element element, XMLContext.Default defaults
+ ) {
+ Element subelement = element == null ? null : element.element( annotationToXml.get(
clazz ) );
+ if ( subelement != null ) {
+ return AnnotationFactory.create( new AnnotationDescriptor( clazz ) );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ //TODO wonder whether it should be excluded so that user can undone it
+ return getJavaAnnotation( clazz );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private SqlResultSetMappings getSqlResultSetMappings(Element tree, XMLContext.Default
defaults) {
+ List<SqlResultSetMapping> results = (List<SqlResultSetMapping>)
buildSqlResultsetMappings( tree, defaults );
+ if ( defaults.canUseJavaAnnotations() ) {
+ SqlResultSetMapping annotation = getJavaAnnotation( SqlResultSetMapping.class );
+ addSqlResultsetMappingIfNeeded( annotation, results );
+ SqlResultSetMappings annotations = getJavaAnnotation( SqlResultSetMappings.class );
+ if ( annotations != null ) {
+ for (SqlResultSetMapping current : annotations.value()) {
+ addSqlResultsetMappingIfNeeded( current, results );
+ }
+ }
+ }
+ if ( results.size() > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( SqlResultSetMappings.class );
+ ad.setValue( "value", results.toArray( new
SqlResultSetMapping[results.size()] ) );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ public static List<SqlResultSetMapping> buildSqlResultsetMappings(Element element,
XMLContext.Default defaults) {
+ if ( element == null ) return new ArrayList<SqlResultSetMapping>();
+ List resultsetElementList = element.elements( "sql-result-set-mapping" );
+ List<SqlResultSetMapping> resultsets = new
ArrayList<SqlResultSetMapping>();
+ Iterator it = resultsetElementList.listIterator();
+ while ( it.hasNext() ) {
+ Element subelement = (Element) it.next();
+ AnnotationDescriptor ann = new AnnotationDescriptor( SqlResultSetMapping.class );
+ copyStringAttribute( ann, subelement, "name", true );
+ List<Element> elements = subelement.elements( "entity-result" );
+ List<EntityResult> entityResults = new ArrayList<EntityResult>(
elements.size() );
+ for (Element entityResult : elements) {
+ AnnotationDescriptor entityResultDescriptor = new AnnotationDescriptor(
EntityResult.class );
+ String clazzName = entityResult.attributeValue( "entity-class" );
+ if ( clazzName == null ) {
+ throw new AnnotationException( "<entity-result> without entity-class.
" + SCHEMA_VALIDATION );
+ }
+ Class clazz = null;
+ try {
+ clazz = ReflectHelper.classForName(
+ XMLContext.buildSafeClassName( clazzName, defaults ),
+ EJB3OverridenAnnotationReader.class
+ );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException( "Unable to find entity-class: " +
clazzName, e );
+ }
+ entityResultDescriptor.setValue( "entityClass", clazz );
+ copyStringAttribute( entityResultDescriptor, entityResult,
"discriminator-column", false );
+ List<FieldResult> fieldResults = new ArrayList<FieldResult>();
+ for (Element fieldResult : (List<Element>) entityResult.elements(
"field-result" )) {
+ AnnotationDescriptor fieldResultDescriptor = new AnnotationDescriptor(
FieldResult.class );
+ copyStringAttribute( fieldResultDescriptor, fieldResult, "name", true );
+ copyStringAttribute( fieldResultDescriptor, fieldResult, "column", true
);
+ fieldResults.add( (FieldResult) AnnotationFactory.create( fieldResultDescriptor )
);
+ }
+ entityResultDescriptor.setValue(
+ "fields", fieldResults.toArray( new FieldResult[fieldResults.size()] )
+ );
+ entityResults.add( (EntityResult) AnnotationFactory.create( entityResultDescriptor )
);
+ }
+ ann.setValue( "entities", entityResults.toArray( new
EntityResult[entityResults.size()] ) );
+
+ elements = subelement.elements( "column-result" );
+ List<ColumnResult> columnResults = new ArrayList<ColumnResult>(
elements.size() );
+ for (Element columnResult : elements) {
+ AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor(
ColumnResult.class );
+ copyStringAttribute( columnResultDescriptor, columnResult, "name", true );
+ columnResults.add( (ColumnResult) AnnotationFactory.create( columnResultDescriptor )
);
+ }
+ ann.setValue( "columns", columnResults.toArray( new
ColumnResult[columnResults.size()] ) );
+ //FIXME there is never such a result-class, get rid of it?
+ String clazzName = subelement.attributeValue( "result-class" );
+ if ( StringHelper.isNotEmpty( clazzName ) ) {
+ Class clazz = null;
+ try {
+ clazz = ReflectHelper.classForName(
+ XMLContext.buildSafeClassName( clazzName, defaults ),
+ EJB3OverridenAnnotationReader.class
+ );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException( "Unable to find entity-class: " +
clazzName, e );
+ }
+ ann.setValue( "resultClass", clazz );
+ }
+ copyStringAttribute( ann, subelement, "result-set-mapping", false );
+ resultsets.add( (SqlResultSetMapping) AnnotationFactory.create( ann ) );
+ }
+ return resultsets;
+ }
+
+ private void addSqlResultsetMappingIfNeeded(SqlResultSetMapping annotation,
List<SqlResultSetMapping> resultsets) {
+ if ( annotation != null ) {
+ String resultsetName = annotation.name();
+ boolean present = false;
+ for (SqlResultSetMapping current : resultsets) {
+ if ( current.name().equals( resultsetName ) ) {
+ present = true;
+ break;
+ }
+ }
+ if ( !present ) resultsets.add( annotation );
+ }
+ }
+
+ private NamedQueries getNamedQueries(Element tree, XMLContext.Default defaults) {
+ //TODO avoid the Proxy Creation (@NamedQueries) when possible
+ List<NamedQuery> queries = (List<NamedQuery>) buildNamedQueries( tree,
false, defaults );
+ if ( defaults.canUseJavaAnnotations() ) {
+ NamedQuery annotation = getJavaAnnotation( NamedQuery.class );
+ addNamedQueryIfNeeded( annotation, queries );
+ NamedQueries annotations = getJavaAnnotation( NamedQueries.class );
+ if ( annotations != null ) {
+ for (NamedQuery current : annotations.value()) {
+ addNamedQueryIfNeeded( current, queries );
+ }
+ }
+ }
+ if ( queries.size() > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( NamedQueries.class );
+ ad.setValue( "value", queries.toArray( new NamedQuery[queries.size()] ) );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void addNamedQueryIfNeeded(NamedQuery annotation, List<NamedQuery>
queries) {
+ if ( annotation != null ) {
+ String queryName = annotation.name();
+ boolean present = false;
+ for (NamedQuery current : queries) {
+ if ( current.name().equals( queryName ) ) {
+ present = true;
+ break;
+ }
+ }
+ if ( !present ) queries.add( annotation );
+ }
+ }
+
+ private NamedNativeQueries getNamedNativeQueries(Element tree, XMLContext.Default
defaults) {
+ List<NamedNativeQuery> queries = (List<NamedNativeQuery>)
buildNamedQueries( tree, true, defaults );
+ if ( defaults.canUseJavaAnnotations() ) {
+ NamedNativeQuery annotation = getJavaAnnotation( NamedNativeQuery.class );
+ addNamedNativeQueryIfNeeded( annotation, queries );
+ NamedNativeQueries annotations = getJavaAnnotation( NamedNativeQueries.class );
+ if ( annotations != null ) {
+ for (NamedNativeQuery current : annotations.value()) {
+ addNamedNativeQueryIfNeeded( current, queries );
+ }
+ }
+ }
+ if ( queries.size() > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( NamedNativeQueries.class );
+ ad.setValue( "value", queries.toArray( new NamedNativeQuery[queries.size()]
) );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void addNamedNativeQueryIfNeeded(NamedNativeQuery annotation,
List<NamedNativeQuery> queries) {
+ if ( annotation != null ) {
+ String queryName = annotation.name();
+ boolean present = false;
+ for (NamedNativeQuery current : queries) {
+ if ( current.name().equals( queryName ) ) {
+ present = true;
+ break;
+ }
+ }
+ if ( !present ) queries.add( annotation );
+ }
+ }
+
+ public static List buildNamedQueries(Element element, boolean isNative,
XMLContext.Default defaults) {
+ if ( element == null ) return new ArrayList();
+ List namedQueryElementList = isNative ?
+ element.elements( "named-native-query" ) :
+ element.elements( "named-query" );
+ List namedQueries = new ArrayList();
+ Iterator it = namedQueryElementList.listIterator();
+ while ( it.hasNext() ) {
+ Element subelement = (Element) it.next();
+ AnnotationDescriptor ann = new AnnotationDescriptor(
+ isNative ? NamedNativeQuery.class : NamedQuery.class
+ );
+ copyStringAttribute( ann, subelement, "name", false );
+ Element queryElt = subelement.element( "query" );
+ if ( queryElt == null ) throw new AnnotationException( "No <query> element
found." + SCHEMA_VALIDATION );
+ ann.setValue( "query", queryElt.getTextTrim() );
+ List<Element> elements = subelement.elements( "hint" );
+ List<QueryHint> queryHints = new ArrayList<QueryHint>( elements.size() );
+ for (Element hint : elements) {
+ AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class );
+ String value = hint.attributeValue( "name" );
+ if ( value == null ) throw new AnnotationException( "<hint> without name.
" + SCHEMA_VALIDATION );
+ hintDescriptor.setValue( "name", value );
+ value = hint.attributeValue( "value" );
+ if ( value == null ) throw new AnnotationException( "<hint> without value.
" + SCHEMA_VALIDATION );
+ hintDescriptor.setValue( "value", value );
+ queryHints.add( (QueryHint) AnnotationFactory.create( hintDescriptor ) );
+ }
+ ann.setValue( "hints", queryHints.toArray( new QueryHint[queryHints.size()]
) );
+ String clazzName = subelement.attributeValue( "result-class" );
+ if ( StringHelper.isNotEmpty( clazzName ) ) {
+ Class clazz = null;
+ try {
+ clazz = ReflectHelper.classForName(
+ XMLContext.buildSafeClassName( clazzName, defaults ),
+ EJB3OverridenAnnotationReader.class
+ );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException( "Unable to find entity-class: " +
clazzName, e );
+ }
+ ann.setValue( "resultClass", clazz );
+ }
+ copyStringAttribute( ann, subelement, "result-set-mapping", false );
+ namedQueries.add( AnnotationFactory.create( ann ) );
+ }
+ return namedQueries;
+ }
+
+ private TableGenerator getTableGenerator(Element tree, XMLContext.Default defaults) {
+ Element element = tree != null ? tree.element( annotationToXml.get(
TableGenerator.class ) ) : null;
+ if ( element != null ) {
+ return buildTableGeneratorAnnotation( element, defaults );
+ }
+ else if ( defaults.canUseJavaAnnotations() && isJavaAnnotationPresent(
TableGenerator.class ) ) {
+ TableGenerator tableAnn = getJavaAnnotation( TableGenerator.class );
+ if ( StringHelper.isNotEmpty( defaults.getSchema() )
+ || StringHelper.isNotEmpty( defaults.getCatalog() ) ) {
+ AnnotationDescriptor annotation = new AnnotationDescriptor( TableGenerator.class );
+ annotation.setValue( "name", tableAnn.name() );
+ annotation.setValue( "table", tableAnn.table() );
+ annotation.setValue( "catalog", tableAnn.table() );
+ if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) )
+ && StringHelper.isNotEmpty( defaults.getCatalog() ) ) {
+ annotation.setValue( "catalog", defaults.getCatalog() );
+ }
+ annotation.setValue( "schema", tableAnn.table() );
+ if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) )
+ && StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ annotation.setValue( "catalog", defaults.getSchema() );
+ }
+ annotation.setValue( "pkColumnName", tableAnn.pkColumnName() );
+ annotation.setValue( "valueColumnName", tableAnn.valueColumnName() );
+ annotation.setValue( "pkColumnValue", tableAnn.pkColumnValue() );
+ annotation.setValue( "initialValue", tableAnn.initialValue() );
+ annotation.setValue( "allocationSize", tableAnn.allocationSize() );
+ annotation.setValue( "uniqueConstraints", tableAnn.uniqueConstraints() );
+ return AnnotationFactory.create( annotation );
+ }
+ else {
+ return tableAnn;
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ public static TableGenerator buildTableGeneratorAnnotation(Element element,
XMLContext.Default defaults) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( TableGenerator.class );
+ copyStringAttribute( ad, element, "name", false );
+ copyStringAttribute( ad, element, "table", false );
+ copyStringAttribute( ad, element, "catalog", false );
+ copyStringAttribute( ad, element, "schema", false );
+ copyStringAttribute( ad, element, "pk-column-name", false );
+ copyStringAttribute( ad, element, "value-column-name", false );
+ copyStringAttribute( ad, element, "pk-column-value", false );
+ copyIntegerAttribute( ad, element, "initial-value" );
+ copyIntegerAttribute( ad, element, "allocation-size" );
+ buildUniqueConstraints( ad, element );
+ if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) )
+ && StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ ad.setValue( "schema", defaults.getSchema() );
+ }
+ if ( StringHelper.isEmpty( (String) ad.valueOf( "catalog" ) )
+ && StringHelper.isNotEmpty( defaults.getCatalog() ) ) {
+ ad.setValue( "catalog", defaults.getCatalog() );
+ }
+ return AnnotationFactory.create( ad );
+ }
+
+ private SequenceGenerator getSequenceGenerator(Element tree, XMLContext.Default
defaults) {
+ Element element = tree != null ? tree.element( annotationToXml.get(
SequenceGenerator.class ) ) : null;
+ if ( element != null ) {
+ return buildSequenceGeneratorAnnotation( element );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( SequenceGenerator.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ public static SequenceGenerator buildSequenceGeneratorAnnotation(Element element) {
+ if ( element != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( SequenceGenerator.class );
+ copyStringAttribute( ad, element, "name", false );
+ copyStringAttribute( ad, element, "sequence-name", false );
+ copyIntegerAttribute( ad, element, "initial-value" );
+ copyIntegerAttribute( ad, element, "allocation-size" );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private DiscriminatorColumn getDiscriminatorColumn(Element tree, XMLContext.Default
defaults) {
+ Element element = tree != null ? tree.element( "discriminator-column" ) :
null;
+ if ( element != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorColumn.class );
+ copyStringAttribute( ad, element, "name", false );
+ copyStringAttribute( ad, element, "column-definition", false );
+ String value = element.attributeValue( "discriminator-type" );
+ DiscriminatorType type = DiscriminatorType.STRING;
+ if ( value != null ) {
+ if ( "STRING".equals( value ) ) {
+ type = DiscriminatorType.STRING;
+ }
+ else if ( "CHAR".equals( value ) ) {
+ type = DiscriminatorType.CHAR;
+ }
+ else if ( "INTEGER".equals( value ) ) {
+ type = DiscriminatorType.INTEGER;
+ }
+ else {
+ throw new AnnotationException(
+ "Unknown DiscrimiatorType in XML: " + value + " (" +
SCHEMA_VALIDATION + ")"
+ );
+ }
+ }
+ ad.setValue( "discriminatorType", type );
+ copyIntegerAttribute( ad, element, "length" );
+ return AnnotationFactory.create( ad );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( DiscriminatorColumn.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private DiscriminatorValue getDiscriminatorValue(Element tree, XMLContext.Default
defaults) {
+ Element element = tree != null ? tree.element( "discriminator-value" ) :
null;
+ if ( element != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorValue.class );
+ copyStringElement( element, ad, "value" );
+ return AnnotationFactory.create( ad );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( DiscriminatorValue.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private Inheritance getInheritance(Element tree, XMLContext.Default defaults) {
+ Element element = tree != null ? tree.element( "inheritance" ) : null;
+ if ( element != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( Inheritance.class );
+ Attribute attr = element.attribute( "strategy" );
+ InheritanceType strategy = InheritanceType.SINGLE_TABLE;
+ if ( attr != null ) {
+ String value = attr.getValue();
+ if ( "SINGLE_TABLE".equals( value ) ) {
+ strategy = InheritanceType.SINGLE_TABLE;
+ }
+ else if ( "JOINED".equals( value ) ) {
+ strategy = InheritanceType.JOINED;
+ }
+ else if ( "TABLE_PER_CLASS".equals( value ) ) {
+ strategy = InheritanceType.TABLE_PER_CLASS;
+ }
+ else {
+ throw new AnnotationException(
+ "Unknown InheritanceType in XML: " + value + " (" +
SCHEMA_VALIDATION + ")"
+ );
+ }
+ }
+ ad.setValue( "strategy", strategy );
+ return AnnotationFactory.create( ad );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( Inheritance.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private IdClass getIdClass(Element tree, XMLContext.Default defaults) {
+ Element element = tree == null ? null : tree.element( "id-class" );
+ if ( element != null ) {
+ Attribute attr = element.attribute( "class" );
+ if ( attr != null ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( IdClass.class );
+ Class clazz = null;
+ try {
+ clazz = ReflectHelper.classForName(
+ XMLContext.buildSafeClassName( attr.getValue(), defaults ),
+ this.getClass()
+ );
+ }
+ catch (ClassNotFoundException e) {
+ throw new AnnotationException( "Unable to find id-class: " +
attr.getValue(), e );
+ }
+ ad.setValue( "value", clazz );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ throw new AnnotationException( "id-class without class. " +
SCHEMA_VALIDATION );
+ }
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( IdClass.class );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(Element element,
XMLContext.Default defaults) {
+ PrimaryKeyJoinColumn[] columns = buildPrimaryKeyJoinColumns( element );
+ if ( columns.length == 0 && defaults.canUseJavaAnnotations() ) {
+ PrimaryKeyJoinColumn annotation = getJavaAnnotation( PrimaryKeyJoinColumn.class );
+ if ( annotation != null ) {
+ columns = new PrimaryKeyJoinColumn[] { annotation };
+ }
+ else {
+ PrimaryKeyJoinColumns annotations = getJavaAnnotation( PrimaryKeyJoinColumns.class
);
+ columns = annotations != null ? annotations.value() : columns;
+ }
+ }
+ if ( columns.length > 0 ) {
+ AnnotationDescriptor ad = new AnnotationDescriptor( PrimaryKeyJoinColumns.class );
+ ad.setValue( "value", columns );
+ return AnnotationFactory.create( ad );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private Entity getEntity(Element tree, XMLContext.Default defaults) {
+ if ( tree == null ) {
+ return defaults.canUseJavaAnnotations() ? getJavaAnnotation( Entity.class ) : null;
+ }
+ else {
+ if ( "entity".equals( tree.getName() ) ) {
+ AnnotationDescriptor entity = new AnnotationDescriptor( Entity.class );
+ copyStringAttribute( entity, tree, "name", false );
+ if ( defaults.canUseJavaAnnotations()
+ && StringHelper.isEmpty( (String) entity.valueOf( "name" ) ) ) {
+ Entity javaAnn = getJavaAnnotation( Entity.class );
+ if ( javaAnn != null ) entity.setValue( "name", javaAnn.name() );
+ }
+ return AnnotationFactory.create( entity );
+ }
+ else {
+ return null; //this is not an entity
+ }
+ }
+ }
+
+ private MappedSuperclass getMappedSuperclass(Element tree, XMLContext.Default defaults)
{
+ if ( tree == null ) {
+ return defaults.canUseJavaAnnotations() ? getJavaAnnotation( MappedSuperclass.class )
: null;
+ }
+ else {
+ if ( "mapped-superclass".equals( tree.getName() ) ) {
+ AnnotationDescriptor entity = new AnnotationDescriptor( MappedSuperclass.class );
+ return AnnotationFactory.create( entity );
+ }
+ else {
+ return null; //this is not an entity
+ }
+ }
+ }
+
+ private Embeddable getEmbeddable(Element tree, XMLContext.Default defaults) {
+ if ( tree == null ) {
+ return defaults.canUseJavaAnnotations() ? getJavaAnnotation( Embeddable.class ) :
null;
+ }
+ else {
+ if ( "embeddable".equals( tree.getName() ) ) {
+ AnnotationDescriptor entity = new AnnotationDescriptor( Embeddable.class );
+ return AnnotationFactory.create( entity );
+ }
+ else {
+ return null; //this is not an entity
+ }
+ }
+ }
+
+ private Table getTable(Element tree, XMLContext.Default defaults) {
+ Element subelement = tree == null ? null : tree.element( "table" );
+ if ( subelement == null ) {
+ //no element but might have some default or some annotation
+ if ( StringHelper.isNotEmpty( defaults.getCatalog() )
+ || StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class );
+ if ( defaults.canUseJavaAnnotations() ) {
+ Table table = getJavaAnnotation( Table.class );
+ if ( table != null ) {
+ annotation.setValue( "name", table.name() );
+ annotation.setValue( "schema", table.schema() );
+ annotation.setValue( "catalog", table.catalog() );
+ annotation.setValue( "uniqueConstraints", table.uniqueConstraints() );
+ }
+ }
+ if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) )
+ && StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ annotation.setValue( "schema", defaults.getSchema() );
+ }
+ if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) )
+ && StringHelper.isNotEmpty( defaults.getCatalog() ) ) {
+ annotation.setValue( "catalog", defaults.getCatalog() );
+ }
+ return AnnotationFactory.create( annotation );
+ }
+ else if ( defaults.canUseJavaAnnotations() ) {
+ return getJavaAnnotation( Table.class );
+ }
+ else {
+ return null;
+ }
+ }
+ else {
+ //ignore java annotation, an element is defined
+ AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class );
+ copyStringAttribute( annotation, subelement, "name", false );
+ copyStringAttribute( annotation, subelement, "catalog", false );
+ if ( StringHelper.isNotEmpty( defaults.getCatalog() )
+ && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" )
) ) {
+ annotation.setValue( "catalog", defaults.getCatalog() );
+ }
+ copyStringAttribute( annotation, subelement, "schema", false );
+ if ( StringHelper.isNotEmpty( defaults.getSchema() )
+ && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) )
) {
+ annotation.setValue( "schema", defaults.getSchema() );
+ }
+ buildUniqueConstraints( annotation, subelement );
+ return AnnotationFactory.create( annotation );
+ }
+ }
+
+ private SecondaryTables getSecondaryTables(Element tree, XMLContext.Default defaults) {
+ List<Element> elements = tree == null ?
+ new ArrayList<Element>() :
+ (List<Element>) tree.elements( "secondary-table" );
+ List<SecondaryTable> secondaryTables = new ArrayList<SecondaryTable>( 3 );
+ for (Element element : elements) {
+ AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class );
+ copyStringAttribute( annotation, element, "name", false );
+ copyStringAttribute( annotation, element, "catalog", false );
+ if ( StringHelper.isNotEmpty( defaults.getCatalog() )
+ && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" )
) ) {
+ annotation.setValue( "catalog", defaults.getCatalog() );
+ }
+ copyStringAttribute( annotation, element, "schema", false );
+ if ( StringHelper.isNotEmpty( defaults.getSchema() )
+ && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) )
) {
+ annotation.setValue( "schema", defaults.getSchema() );
+ }
+ buildUniqueConstraints( annotation, element );
+ annotation.setValue( "pkJoinColumns", buildPrimaryKeyJoinColumns( element )
);
+ secondaryTables.add( (SecondaryTable) AnnotationFactory.create( annotation ) );
+ }
+ /*
+ * You can't have both secondary table in XML and Java,
+ * since there would be no way to "remove" a secondary table
+ */
+ if ( secondaryTables.size() == 0 && defaults.canUseJavaAnnotations() ) {
+ SecondaryTable secTableAnn = getJavaAnnotation( SecondaryTable.class );
+ overridesDefaultInSecondaryTable( secTableAnn, defaults, secondaryTables );
+ SecondaryTables secTablesAnn = getJavaAnnotation( SecondaryTables.class );
+ if ( secTablesAnn != null ) {
+ for (SecondaryTable table : secTablesAnn.value()) {
+ overridesDefaultInSecondaryTable( table, defaults, secondaryTables );
+ }
+ }
+ }
+ if ( secondaryTables.size() > 0 ) {
+ AnnotationDescriptor descriptor = new AnnotationDescriptor( SecondaryTables.class );
+ descriptor.setValue( "value", secondaryTables.toArray( new
SecondaryTable[secondaryTables.size()] ) );
+ return AnnotationFactory.create( descriptor );
+ }
+ else {
+ return null;
+ }
+ }
+
+ private void overridesDefaultInSecondaryTable(
+ SecondaryTable secTableAnn, XMLContext.Default defaults, List<SecondaryTable>
secondaryTables
+ ) {
+ if ( secTableAnn != null ) {
+ //handle default values
+ if ( StringHelper.isNotEmpty( defaults.getCatalog() )
+ || StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class );
+ annotation.setValue( "name", secTableAnn.name() );
+ annotation.setValue( "schema", secTableAnn.schema() );
+ annotation.setValue( "catalog", secTableAnn.catalog() );
+ annotation.setValue( "uniqueConstraints", secTableAnn.uniqueConstraints()
);
+ annotation.setValue( "pkJoinColumns", secTableAnn.pkJoinColumns() );
+ if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) )
+ && StringHelper.isNotEmpty( defaults.getSchema() ) ) {
+ annotation.setValue( "schema", defaults.getSchema() );
+ }
+ if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) )
+ && StringHelper.isNotEmpty( defaults.getCatalog() ) ) {
+ annotation.setValue( "catalog", defaults.getCatalog() );
+ }
+ secondaryTables.add( (SecondaryTable) AnnotationFactory.create( annotation ) );
+ }
+ else {
+ secondaryTables.add( secTableAnn );
+ }
+ }
+ }
+
+ private static void buildUniqueConstraints(AnnotationDescriptor annotation, Element
element) {
+ List uniqueConstraintElementList = element.elements( "unique-constraint" );
+ UniqueConstraint[] uniqueConstraints = new
UniqueConstraint[uniqueConstraintElementList.size()];
+ int ucIndex = 0;
+ Iterator ucIt = uniqueConstraintElementList.listIterator();
+ while ( ucIt.hasNext() ) {
+ Element subelement = (Element) ucIt.next();
+ List<Element> columnNamesElements = subelement.elements( "column-name"
);
+ String[] columnNames = new String[columnNamesElements.size()];
+ int columnNameIndex = 0;
+ Iterator it = columnNamesElements.listIterator();
+ while ( it.hasNext() ) {
+ Element columnNameElt = (Element) it.next();
+ columnNames[columnNameIndex++] = columnNameElt.getTextTrim();
+ }
+ AnnotationDescriptor ucAnn = new AnnotationDescriptor( UniqueConstraint.class );
+ ucAnn.setValue( "columnNames", columnNames );
+ uniqueConstraints[ucIndex++] = AnnotationFactory.create( ucAnn );
+ }
+ annotation.setValue( "uniqueConstraints", uniqueConstraints );
+ }
+
+ private PrimaryKeyJoinColumn[] buildPrimaryKeyJoinColumns(Element element) {
+ if ( element == null ) return new PrimaryKeyJoinColumn[] { };
+ List pkJoinColumnElementList = element.elements( "primary-key-join-column"
);
+ PrimaryKeyJoinColumn[] pkJoinColumns = new
PrimaryKeyJoinColumn[pkJoinColumnElementList.size()];
+ int index = 0;
+ Iterator pkIt = pkJoinColumnElementList.listIterator();
+ while ( pkIt.hasNext() ) {
+ Element subelement = (Element) pkIt.next();
+ AnnotationDescriptor pkAnn = new AnnotationDescriptor( PrimaryKeyJoinColumn.class );
+ copyStringAttribute( pkAnn, subelement, "name", false );
+ copyStringAttribute( pkAnn, subelement, "referenced-column-name", false );
+ copyStringAttribute( pkAnn, subelement, "column-definition", false );
+ pkJoinColumns[index++] = AnnotationFactory.create( pkAnn );
+ }
+ return pkJoinColumns;
+ }
+
+ private static void copyStringAttribute(
+ AnnotationDescriptor annotation, Element element, String attributeName, boolean
mandatory
+ ) {
+ String attribute = element.attributeValue( attributeName );
+ if ( attribute != null ) {
+ String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName );
+ annotation.setValue( annotationAttributeName, attribute );
+ }
+ else {
+ if ( mandatory ) {
+ throw new AnnotationException(
+ element.getName() + "." + attributeName + " is mandatory in XML
overring. " + SCHEMA_VALIDATION
+ );
+ }
+ }
+ }
+
+ private static void copyIntegerAttribute(AnnotationDescriptor annotation, Element
element, String attributeName) {
+ String attribute = element.attributeValue( attributeName );
+ if ( attribute != null ) {
+ String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName );
+ annotation.setValue( annotationAttributeName, attribute );
+ try {
+ int length = Integer.parseInt( attribute );
+ annotation.setValue( annotationAttributeName, length );
+ }
+ catch (NumberFormatException e) {
+ throw new AnnotationException(
+ element.getPath() + attributeName + " not parseable: " + attribute +
" (" + SCHEMA_VALIDATION + ")"
+ );
+ }
+ }
+ }
+
+ private static String getJavaAttributeNameFromXMLOne(String attributeName) {
+ StringBuilder annotationAttributeName = new StringBuilder( attributeName );
+ int index = annotationAttributeName.indexOf( WORD_SEPARATOR );
+ while ( index != -1 ) {
+ annotationAttributeName.deleteCharAt( index );
+ annotationAttributeName.setCharAt(
+ index, Character.toUpperCase( annotationAttributeName.charAt( index ) )
+ );
+ index = annotationAttributeName.indexOf( WORD_SEPARATOR );
+ }
+ return annotationAttributeName.toString();
+ }
+
+ private static void copyStringElement(Element element, AnnotationDescriptor ad, String
annotationAttribute) {
+ String discr = element.getTextTrim();
+ ad.setValue( annotationAttribute, discr );
+ }
+
+ private static void copyBooleanAttribute(AnnotationDescriptor descriptor, Element
element, String attribute) {
+ String attributeValue = element.attributeValue( attribute );
+ if ( StringHelper.isNotEmpty( attributeValue ) ) {
+ String javaAttribute = getJavaAttributeNameFromXMLOne( attribute );
+ descriptor.setValue( javaAttribute, Boolean.parseBoolean( attributeValue ) );
+ }
+ }
+
+ private <T extends Annotation> T getJavaAnnotation(Class<T> annotationType)
{
+ return element.getAnnotation( annotationType );
+ }
+
+ private <T extends Annotation> boolean isJavaAnnotationPresent(Class<T>
annotationType) {
+ return element.isAnnotationPresent( annotationType );
+ }
+
+ private Annotation[] getJavaAnnotations() {
+ return element.getAnnotations();
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3ReflectionManager.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3ReflectionManager.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/EJB3ReflectionManager.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,101 @@
+package org.hibernate.cfg.annotations.reflection;
+
+import java.lang.reflect.AnnotatedElement;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.persistence.EntityListeners;
+import javax.persistence.NamedNativeQuery;
+import javax.persistence.NamedQuery;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.SqlResultSetMapping;
+import javax.persistence.TableGenerator;
+
+import org.dom4j.Element;
+import org.hibernate.annotations.common.reflection.AnnotationReader;
+import org.hibernate.annotations.common.reflection.java.JavaReflectionManager;
+import org.hibernate.util.ReflectHelper;
+
+public class EJB3ReflectionManager extends JavaReflectionManager {
+
+ private XMLContext xmlContext = new XMLContext();
+ private HashMap defaults = null;
+
+ public AnnotationReader buildAnnotationReader(AnnotatedElement annotatedElement) {
+ if ( xmlContext.hasContext() ) {
+ return new EJB3OverridenAnnotationReader( annotatedElement, xmlContext );
+ }
+ else {
+ return super.buildAnnotationReader( annotatedElement );
+ }
+ }
+
+ public Map getDefaults() {
+ if ( defaults == null ) {
+ defaults = new HashMap();
+ XMLContext.Default xmlDefaults = xmlContext.getDefault( null );
+ List<Class> entityListeners = new ArrayList<Class>();
+ for (String className : xmlContext.getDefaultEntityListeners()) {
+ try {
+ entityListeners.add( ReflectHelper.classForName( className, this.getClass() ) );
+ }
+ catch (ClassNotFoundException e) {
+ throw new IllegalStateException( "Default entity listener class not found:
" + className );
+ }
+ }
+ defaults.put( EntityListeners.class, entityListeners );
+ for (Element element : xmlContext.getAllDocuments()) {
+
+ List<Element> elements = element.elements( "sequence-generator" );
+ List<SequenceGenerator> sequenceGenerators = (List<SequenceGenerator>)
defaults.get( SequenceGenerator.class );
+ if ( sequenceGenerators == null ) {
+ sequenceGenerators = new ArrayList<SequenceGenerator>();
+ defaults.put( SequenceGenerator.class, sequenceGenerators );
+ }
+ for (Element subelement : elements) {
+ sequenceGenerators.add(
EJB3OverridenAnnotationReader.buildSequenceGeneratorAnnotation( subelement ) );
+ }
+
+ elements = element.elements( "table-generator" );
+ List<TableGenerator> tableGenerators = (List<TableGenerator>)
defaults.get( TableGenerator.class );
+ if ( tableGenerators == null ) {
+ tableGenerators = new ArrayList<TableGenerator>();
+ defaults.put( TableGenerator.class, tableGenerators );
+ }
+ for (Element subelement : elements) {
+ tableGenerators.add( EJB3OverridenAnnotationReader.buildTableGeneratorAnnotation(
subelement, xmlDefaults ) );
+ }
+
+ List<NamedQuery> namedQueries = (List<NamedQuery>) defaults.get(
NamedQuery.class );
+ if ( namedQueries == null ) {
+ namedQueries = new ArrayList<NamedQuery>();
+ defaults.put( NamedQuery.class, namedQueries );
+ }
+ List<NamedQuery> currentNamedQueries =
EJB3OverridenAnnotationReader.buildNamedQueries( element, false, xmlDefaults );
+ namedQueries.addAll( currentNamedQueries );
+
+ List<NamedNativeQuery> namedNativeQueries = (List<NamedNativeQuery>)
defaults.get( NamedNativeQuery.class );
+ if ( namedNativeQueries == null ) {
+ namedNativeQueries = new ArrayList<NamedNativeQuery>();
+ defaults.put( NamedNativeQuery.class, namedNativeQueries );
+ }
+ List<NamedNativeQuery> currentNamedNativeQueries =
EJB3OverridenAnnotationReader.buildNamedQueries( element, true, xmlDefaults );
+ namedNativeQueries.addAll( currentNamedNativeQueries );
+
+ List<SqlResultSetMapping> sqlResultSetMappings =
(List<SqlResultSetMapping>) defaults.get( SqlResultSetMapping.class );
+ if ( sqlResultSetMappings == null ) {
+ sqlResultSetMappings = new ArrayList<SqlResultSetMapping>();
+ defaults.put( SqlResultSetMapping.class, sqlResultSetMappings );
+ }
+ List<SqlResultSetMapping> currentSqlResultSetMappings =
EJB3OverridenAnnotationReader.buildSqlResultsetMappings( element, xmlDefaults );
+ sqlResultSetMappings.addAll( currentSqlResultSetMappings );
+ }
+ }
+ return defaults;
+ }
+
+ public XMLContext getXMLContext() {
+ return xmlContext;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,255 @@
+//$Id: XMLContext.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.cfg.annotations.reflection;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.hibernate.util.StringHelper;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class XMLContext {
+ private Logger log = LoggerFactory.getLogger( XMLContext.class );
+ private Default globalDefaults;
+ private Map<String, Element> classOverriding = new HashMap<String,
Element>();
+ private Map<String, Default> defaultsOverriding = new HashMap<String,
Default>();
+ private List<Element> defaultElements = new ArrayList<Element>();
+ private List<String> defaultEntityListeners = new ArrayList<String>();
+ private boolean hasContext = false;
+
+ /**
+ * Add a document and return the list of added classes names
+ */
+ public List<String> addDocument(Document doc) {
+ hasContext = true;
+ List<String> addedClasses = new ArrayList<String>();
+ Element root = doc.getRootElement();
+ //global defaults
+ Element metadata = root.element( "persistence-unit-metadata" );
+ if ( metadata != null ) {
+ if ( globalDefaults == null ) {
+ globalDefaults = new Default();
+ globalDefaults.setMetadataComplete(
+ metadata.element( "xml-mapping-metadata-complete" ) != null ?
+ Boolean.TRUE :
+ null
+ );
+ Element defaultElement = metadata.element( "persistence-unit-defaults" );
+ if ( defaultElement != null ) {
+ Element unitElement = defaultElement.element( "schema" );
+ globalDefaults.setSchema( unitElement != null ? unitElement.getTextTrim() : null );
+ unitElement = defaultElement.element( "catalog" );
+ globalDefaults.setCatalog( unitElement != null ? unitElement.getTextTrim() : null
);
+ unitElement = defaultElement.element( "access" );
+ globalDefaults.setAccess( unitElement != null ? unitElement.getTextTrim() : null );
+ unitElement = defaultElement.element( "cascade-persist" );
+ globalDefaults.setCascadePersist( unitElement != null ? Boolean.TRUE : null );
+ defaultEntityListeners.addAll( addEntityListenerClasses( defaultElement, null,
addedClasses ) );
+ }
+ }
+ else {
+ log.warn( "Found more than one <persistence-unit-metadata>, subsequent
ignored" );
+ }
+ }
+
+ //entity mapping default
+ Default entityMappingDefault = new Default();
+ Element unitElement = root.element( "package" );
+ String packageName = unitElement != null ? unitElement.getTextTrim() : null;
+ entityMappingDefault.setPackageName( packageName );
+ unitElement = root.element( "schema" );
+ entityMappingDefault.setSchema( unitElement != null ? unitElement.getTextTrim() : null
);
+ unitElement = root.element( "catalog" );
+ entityMappingDefault.setCatalog( unitElement != null ? unitElement.getTextTrim() : null
);
+ unitElement = root.element( "access" );
+ entityMappingDefault.setAccess( unitElement != null ? unitElement.getTextTrim() : null
);
+ defaultElements.add( root );
+
+ List<Element> entities = (List<Element>) root.elements( "entity"
);
+ addClass( entities, packageName, entityMappingDefault, addedClasses );
+
+ entities = (List<Element>) root.elements( "mapped-superclass" );
+ addClass( entities, packageName, entityMappingDefault, addedClasses );
+
+ entities = (List<Element>) root.elements( "embeddable" );
+ addClass( entities, packageName, entityMappingDefault, addedClasses );
+ return addedClasses;
+ }
+
+ private void addClass(List<Element> entities, String packageName, Default
defaults, List<String> addedClasses) {
+ for (Element element : entities) {
+ String className = buildSafeClassName( element.attributeValue( "class" ),
packageName );
+ if ( classOverriding.containsKey( className ) ) {
+ //maybe switch it to warn?
+ throw new IllegalStateException( "Duplicate XML entry for " + className );
+ }
+ addedClasses.add( className );
+ classOverriding.put( className, element );
+ Default localDefault = new Default();
+ localDefault.override( defaults );
+ String metadataCompleteString = element.attributeValue( "metadata-complete"
);
+ if ( metadataCompleteString != null ) {
+ localDefault.setMetadataComplete( Boolean.parseBoolean( metadataCompleteString ) );
+ }
+ String access = element.attributeValue( "access" );
+ if ( access != null ) localDefault.setAccess( access );
+ defaultsOverriding.put( className, localDefault );
+
+ log.debug( "Adding XML overriding information for {}", className );
+ addEntityListenerClasses( element, packageName, addedClasses );
+ }
+ }
+
+ private List<String> addEntityListenerClasses(Element element, String packageName,
List<String> addedClasses) {
+ List<String> localAddedClasses = new ArrayList<String>();
+ Element listeners = element.element( "entity-listeners" );
+ if ( listeners != null ) {
+ List<Element> elements = (List<Element>) listeners.elements(
"entity-listener" );
+ for (Element listener : elements) {
+ String listenerClassName = buildSafeClassName( listener.attributeValue(
"class" ), packageName );
+ if ( classOverriding.containsKey( listenerClassName ) ) {
+ //maybe switch it to warn?
+ if ( "entity-listener".equals( classOverriding.get( listenerClassName
).getName() ) ) {
+ log.info(
+ "entity-listener duplication, first event definition will be used:
{}",
+ listenerClassName
+ );
+ continue;
+ }
+ else {
+ throw new IllegalStateException( "Duplicate XML entry for " +
listenerClassName );
+ }
+ }
+ localAddedClasses.add( listenerClassName );
+ classOverriding.put( listenerClassName, listener );
+ }
+ }
+ log.debug( "Adding XML overriding information for listener: {}", listeners
);
+ addedClasses.addAll( localAddedClasses );
+ return localAddedClasses;
+ }
+
+ public static String buildSafeClassName(String className, String defaultPackageName) {
+ if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty(
defaultPackageName ) ) {
+ className = StringHelper.qualify( defaultPackageName, className );
+ }
+ return className;
+ }
+
+ public static String buildSafeClassName(String className, XMLContext.Default defaults)
{
+ return buildSafeClassName( className, defaults.getPackageName() );
+ }
+
+ public Default getDefault(String className) {
+ Default xmlDefault = new Default();
+ xmlDefault.override( globalDefaults );
+ if ( className != null ) {
+ Default entityMappingOverriding = defaultsOverriding.get( className );
+ xmlDefault.override( entityMappingOverriding );
+ }
+ return xmlDefault;
+ }
+
+ public Element getXMLTree(String className, String methodName) {
+ return classOverriding.get( className );
+ }
+
+ public List<Element> getAllDocuments() {
+ return defaultElements;
+ }
+
+ public boolean hasContext() {
+ return hasContext;
+ }
+
+ public static class Default {
+ private String access;
+ private String packageName;
+ private String schema;
+ private String catalog;
+ private Boolean metadataComplete;
+ private Boolean cascadePersist;
+
+ public String getAccess() {
+ return access;
+ }
+
+ protected void setAccess(String access) {
+ if ( "FIELD".equals( access ) || "PROPERTY".equals( access ) ) {
+ this.access = access.toLowerCase();
+ }
+ else {
+ this.access = access;
+ }
+ }
+
+ public String getCatalog() {
+ return catalog;
+ }
+
+ protected void setCatalog(String catalog) {
+ this.catalog = catalog;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ protected void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public String getSchema() {
+ return schema;
+ }
+
+ protected void setSchema(String schema) {
+ this.schema = schema;
+ }
+
+ public Boolean getMetadataComplete() {
+ return metadataComplete;
+ }
+
+ public boolean canUseJavaAnnotations() {
+ return metadataComplete == null || !metadataComplete.booleanValue();
+ }
+
+ protected void setMetadataComplete(Boolean metadataComplete) {
+ this.metadataComplete = metadataComplete;
+ }
+
+ public Boolean getCascadePersist() {
+ return cascadePersist;
+ }
+
+ void setCascadePersist(Boolean cascadePersist) {
+ this.cascadePersist = cascadePersist;
+ }
+
+ public void override(Default globalDefault) {
+ if ( globalDefault != null ) {
+ if ( globalDefault.getAccess() != null ) access = globalDefault.getAccess();
+ if ( globalDefault.getPackageName() != null ) packageName =
globalDefault.getPackageName();
+ if ( globalDefault.getSchema() != null ) schema = globalDefault.getSchema();
+ if ( globalDefault.getCatalog() != null ) catalog = globalDefault.getCatalog();
+ if ( globalDefault.getMetadataComplete() != null ) {
+ metadataComplete = globalDefault.getMetadataComplete();
+ }
+ //TODO fix that in stone if cascade-persist is set already?
+ if ( globalDefault.getCascadePersist() != null ) cascadePersist =
globalDefault.getCascadePersist();
+ }
+ }
+ }
+
+ public List<String> getDefaultEntityListeners() {
+ return defaultEntityListeners;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/search/HibernateSearchEventListenerRegister.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/search/HibernateSearchEventListenerRegister.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/cfg/search/HibernateSearchEventListenerRegister.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,224 @@
+// $Id: HibernateSearchEventListenerRegister.java 14991 2008-07-29 18:20:47Z epbernard $
+package org.hibernate.cfg.search;
+
+import java.util.Properties;
+
+import org.hibernate.AnnotationException;
+import org.hibernate.event.EventListeners;
+import org.hibernate.event.PostCollectionRecreateEventListener;
+import org.hibernate.event.PostCollectionRemoveEventListener;
+import org.hibernate.event.PostCollectionUpdateEventListener;
+import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.util.ReflectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper methods initializing Hibernate Search event listeners.
+ *
+ * @deprecated as of release 3.4.0.CR2, replaced by Hibernate Search's {@link
org.hibernate.search.cfg.EventListenerRegister}
+ * @author Emmanuel Bernard
+ * @author Hardy Ferentschik
+ */
+@Deprecated
+public class HibernateSearchEventListenerRegister {
+
+ private static final Logger log =
LoggerFactory.getLogger(HibernateSearchEventListenerRegister.class);
+
+ /**
+ * Class name of the class needed to enable Search.
+ */
+ private static final String FULL_TEXT_INDEX_EVENT_LISTENER_CLASS =
"org.hibernate.search.event.FullTextIndexEventListener";
+
+ /**
+ * @deprecated as of release 3.4.0.CR2, replaced by Hibernate Search's {@link
org.hibernate.search.cfg.EventListenerRegister#enableHibernateSearch(EventListeners,
Properties)}
+ */
+ @SuppressWarnings("unchecked")
+ @Deprecated
+ public static void enableHibernateSearch(EventListeners eventListeners, Properties
properties) {
+ // check whether search is explicitly enabled - if so there is nothing
+ // to do
+ String enableSearchListeners = properties.getProperty(
"hibernate.search.autoregister_listeners" );
+ if("false".equalsIgnoreCase(enableSearchListeners )) {
+ log.info("Property hibernate.search.autoregister_listeners is set to false."
+
+ " No attempt will be made to register Hibernate Search event
listeners.");
+ return;
+ }
+
+ // add search events if the jar is available and class can be loaded
+ Class searchEventListenerClass = attemptToLoadSearchEventListener();
+ if ( searchEventListenerClass == null ) {
+ log.info("Unable to find {} on the classpath. Hibernate Search is not
enabled.", FULL_TEXT_INDEX_EVENT_LISTENER_CLASS);
+ return;
+ }
+
+ Object searchEventListener = instantiateEventListener(searchEventListenerClass);
+
+ //TODO Generalize this. Pretty much the same code all the time. Reflecetion?
+ {
+ boolean present = false;
+ PostInsertEventListener[] listeners = eventListeners
+ .getPostInsertEventListeners();
+ if (listeners != null) {
+ for (Object eventListener : listeners) {
+ // not isAssignableFrom since the user could subclass
+ present = present
+ || searchEventListenerClass == eventListener
+ .getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PostInsertEventListener[] newListeners = new PostInsertEventListener[length];
+ System.arraycopy(listeners, 0, newListeners, 0, length - 1);
+ newListeners[length - 1] = (PostInsertEventListener) searchEventListener;
+ eventListeners.setPostInsertEventListeners(newListeners);
+ }
+ } else {
+ eventListeners
+ .setPostInsertEventListeners(new PostInsertEventListener[] {
(PostInsertEventListener) searchEventListener });
+ }
+ }
+ {
+ boolean present = false;
+ PostUpdateEventListener[] listeners = eventListeners
+ .getPostUpdateEventListeners();
+ if (listeners != null) {
+ for (Object eventListener : listeners) {
+ // not isAssignableFrom since the user could subclass
+ present = present
+ || searchEventListenerClass == eventListener
+ .getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PostUpdateEventListener[] newListeners = new PostUpdateEventListener[length];
+ System.arraycopy(listeners, 0, newListeners, 0, length - 1);
+ newListeners[length - 1] = (PostUpdateEventListener) searchEventListener;
+ eventListeners.setPostUpdateEventListeners(newListeners);
+ }
+ } else {
+ eventListeners
+ .setPostUpdateEventListeners(new PostUpdateEventListener[] {
(PostUpdateEventListener) searchEventListener });
+ }
+ }
+ {
+ boolean present = false;
+ PostDeleteEventListener[] listeners = eventListeners
+ .getPostDeleteEventListeners();
+ if (listeners != null) {
+ for (Object eventListener : listeners) {
+ // not isAssignableFrom since the user could subclass
+ present = present
+ || searchEventListenerClass == eventListener
+ .getClass();
+ }
+ if (!present) {
+ int length = listeners.length + 1;
+ PostDeleteEventListener[] newListeners = new PostDeleteEventListener[length];
+ System.arraycopy(listeners, 0, newListeners, 0, length - 1);
+ newListeners[length - 1] = (PostDeleteEventListener) searchEventListener;
+ eventListeners.setPostDeleteEventListeners(newListeners);
+ }
+ } else {
+ eventListeners
+ .setPostDeleteEventListeners(new PostDeleteEventListener[] {
(PostDeleteEventListener) searchEventListener });
+ }
+ }
+ {
+ boolean present = false;
+ PostCollectionRecreateEventListener[] listeners =
eventListeners.getPostCollectionRecreateEventListeners();
+ if ( listeners != null ) {
+ for (Object eventListener : listeners) {
+ //not isAssignableFrom since the user could subclass
+ present = present || searchEventListenerClass == eventListener.getClass();
+ }
+ if ( !present ) {
+ int length = listeners.length + 1;
+ PostCollectionRecreateEventListener[] newListeners = new
PostCollectionRecreateEventListener[length];
+ System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
+ newListeners[length - 1] = (PostCollectionRecreateEventListener)
searchEventListener;
+ eventListeners.setPostCollectionRecreateEventListeners( newListeners );
+ }
+ }
+ else {
+ eventListeners.setPostCollectionRecreateEventListeners(
+ new PostCollectionRecreateEventListener[] { (PostCollectionRecreateEventListener)
searchEventListener }
+ );
+ }
+ }
+ {
+ boolean present = false;
+ PostCollectionRemoveEventListener[] listeners =
eventListeners.getPostCollectionRemoveEventListeners();
+ if ( listeners != null ) {
+ for (Object eventListener : listeners) {
+ //not isAssignableFrom since the user could subclass
+ present = present || searchEventListenerClass == eventListener.getClass();
+ }
+ if ( !present ) {
+ int length = listeners.length + 1;
+ PostCollectionRemoveEventListener[] newListeners = new
PostCollectionRemoveEventListener[length];
+ System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
+ newListeners[length - 1] = (PostCollectionRemoveEventListener) searchEventListener;
+ eventListeners.setPostCollectionRemoveEventListeners( newListeners );
+ }
+ }
+ else {
+ eventListeners.setPostCollectionRemoveEventListeners(
+ new PostCollectionRemoveEventListener[] { (PostCollectionRemoveEventListener)
searchEventListener }
+ );
+ }
+ }
+ {
+ boolean present = false;
+ PostCollectionUpdateEventListener[] listeners =
eventListeners.getPostCollectionUpdateEventListeners();
+ if ( listeners != null ) {
+ for (Object eventListener : listeners) {
+ //not isAssignableFrom since the user could subclass
+ present = present || searchEventListenerClass == eventListener.getClass();
+ }
+ if ( !present ) {
+ int length = listeners.length + 1;
+ PostCollectionUpdateEventListener[] newListeners = new
PostCollectionUpdateEventListener[length];
+ System.arraycopy( listeners, 0, newListeners, 0, length - 1 );
+ newListeners[length - 1] = (PostCollectionUpdateEventListener) searchEventListener;
+ eventListeners.setPostCollectionUpdateEventListeners( newListeners );
+ }
+ }
+ else {
+ eventListeners.setPostCollectionUpdateEventListeners(
+ new PostCollectionUpdateEventListener[] { (PostCollectionUpdateEventListener)
searchEventListener }
+ );
+ }
+ }
+ }
+
+ /**
+ * Tries to load Hibernate Search event listener.
+ *
+ * @return An event listener instance in case the jar was available.
+ */
+ private static Class<?> attemptToLoadSearchEventListener() {
+ Class searchEventListenerClass = null;
+ try {
+ searchEventListenerClass = ReflectHelper.classForName(
+ FULL_TEXT_INDEX_EVENT_LISTENER_CLASS,
+ HibernateSearchEventListenerRegister.class);
+ } catch (ClassNotFoundException e) {
+ log.debug("Search not present in classpath, ignoring event listener
registration.");
+ }
+ return searchEventListenerClass;
+ }
+
+ private static Object instantiateEventListener(Class<?> clazz) {
+ Object searchEventListener;
+ try {
+ searchEventListener = clazz.newInstance();
+ } catch (Exception e) {
+ throw new AnnotationException(
+ "Unable to load Search event listener", e);
+ }
+ return searchEventListener;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/mapping/IdGenerator.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/mapping/IdGenerator.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/mapping/IdGenerator.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,52 @@
+//$Id: IdGenerator.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.mapping;
+
+import java.io.Serializable;
+import java.util.Properties;
+
+/**
+ * Identifier generator container,
+ * Useful to keep named generator in annotations
+ *
+ * @author Emmanuel Bernard
+ */
+public class IdGenerator implements Serializable {
+ private String name;
+ private String identifierGeneratorStrategy;
+ private Properties params = new Properties();
+
+
+ /**
+ * @return identifier generator strategy
+ */
+ public String getIdentifierGeneratorStrategy() {
+ return identifierGeneratorStrategy;
+ }
+
+ /**
+ * @return generator name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return generator configuration parameters
+ */
+ public Properties getParams() {
+ return params;
+ }
+
+ public void setIdentifierGeneratorStrategy(String string) {
+ identifierGeneratorStrategy = string;
+ }
+
+ public void setName(String string) {
+ name = string;
+ }
+
+ public void addParam(String key, String value) {
+ params.setProperty( key, value );
+ }
+
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/AbstractLobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/AbstractLobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/AbstractLobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,67 @@
+//$Id: AbstractLobType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.type;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionImplementor;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class AbstractLobType extends AbstractType implements Serializable {
+ public boolean isDirty(Object old, Object current, boolean[] checkable,
SessionImplementor session)
+ throws HibernateException {
+ return checkable[0] ? ! isEqual( old, current, session.getEntityMode() ) : false;
+ }
+
+ @Override
+ public boolean isEqual(Object x, Object y, EntityMode entityMode) {
+ return isEqual( x, y, entityMode, null );
+ }
+
+ @Override
+ public int getHashCode(Object x, EntityMode entityMode) {
+ return getHashCode( x, entityMode, null );
+ }
+
+ public String getName() {
+ return this.getClass().getName();
+ }
+
+ public int getColumnSpan(Mapping mapping) throws MappingException {
+ return 1;
+ }
+
+ protected abstract Object get(ResultSet rs, String name) throws SQLException;
+
+ public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session,
Object owner)
+ throws HibernateException, SQLException {
+ return get( rs, names[0] );
+ }
+
+ public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object
owner)
+ throws HibernateException, SQLException {
+ return get( rs, name );
+ }
+
+ public void nullSafeSet(
+ PreparedStatement st, Object value, int index, boolean[] settable, SessionImplementor
session
+ ) throws HibernateException, SQLException {
+ if ( settable[0] ) set( st, value, index, session );
+ }
+
+ protected abstract void set(PreparedStatement st, Object value, int index,
SessionImplementor session)
+ throws SQLException;
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session)
+ throws HibernateException, SQLException {
+ set( st, value, index, session );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/ByteArrayBlobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/ByteArrayBlobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/ByteArrayBlobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,195 @@
+//$Id: ByteArrayBlobType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.type;
+
+import java.io.ByteArrayInputStream;
+import java.sql.Blob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Map;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.lob.BlobImpl;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Map a Byte[] into a Blob
+ * Experimental
+ *
+ * @author Emmanuel Bernard
+ */
+public class ByteArrayBlobType extends AbstractLobType {
+
+ public int[] sqlTypes(Mapping mapping) throws MappingException {
+ return new int[]{Types.BLOB};
+ }
+
+ @Override
+ public boolean isEqual(Object x, Object y, EntityMode entityMode,
SessionFactoryImplementor factory) {
+ if ( x == y ) return true;
+ if ( x == null || y == null ) return false;
+ if ( x instanceof Byte[] ) {
+ Object[] o1 = (Object[]) x;
+ Object[] o2 = (Object[]) y;
+ return ArrayHelper.isEquals( o1, o2 );
+ }
+ else {
+ byte[] c1 = (byte[]) x;
+ byte[] c2 = (byte[]) y;
+ return ArrayHelper.isEquals( c1, c2 );
+ }
+ }
+
+ public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor
factory) {
+ if ( x instanceof Character[] ) {
+ Object[] o = (Object[]) x;
+ return ArrayHelper.hash( o );
+ }
+ else {
+ byte[] c = (byte[]) x;
+ return ArrayHelper.hash( c );
+ }
+ }
+
+ public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor
factory)
+ throws HibernateException {
+ if ( value == null ) return null;
+ if ( value instanceof Byte[] ) {
+ Byte[] array = (Byte[]) value;
+ int length = array.length;
+ Byte[] copy = new Byte[length];
+ for ( int index = 0; index < length ; index++ ) {
+ copy[index] = Byte.valueOf( array[index].byteValue() );
+ }
+ return copy;
+ }
+ else {
+ byte[] array = (byte[]) value;
+ int length = array.length;
+ byte[] copy = new byte[length];
+ System.arraycopy( array, 0, copy, 0, length );
+ return copy;
+ }
+ }
+
+ public Class getReturnedClass() {
+ return Byte[].class;
+ }
+
+ protected Object get(ResultSet rs, String name) throws SQLException {
+ Blob blob = rs.getBlob( name );
+ if ( rs.wasNull() ) return null;
+ int length = (int) blob.length();
+ byte[] primaryResult = blob.getBytes( 1, length );
+ return wrap( primaryResult );
+ }
+
+ protected void set(PreparedStatement st, Object value, int index, SessionImplementor
session) throws SQLException {
+ if ( value == null ) {
+ st.setNull( index, sqlTypes( null )[0] );
+ }
+ else {
+ byte[] toSet = unWrap( value );
+ final boolean useInputStream =
session.getFactory().getDialect().useInputStreamToInsertBlob();
+
+ if ( useInputStream ) {
+ st.setBinaryStream( index, new ByteArrayInputStream( toSet ), toSet.length );
+ }
+ else {
+ st.setBlob( index, new BlobImpl( toSet ) );
+ }
+ }
+ }
+
+ public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory)
throws HibernateException {
+ node.setText( toString( value ) );
+ }
+
+ public String toString(Object val) {
+ byte[] bytes = unWrap( val );
+ StringBuilder buf = new StringBuilder( 2 * bytes.length );
+ for ( int i = 0; i < bytes.length ; i++ ) {
+ String hexStr = Integer.toHexString( bytes[i] - Byte.MIN_VALUE );
+ if ( hexStr.length() == 1 ) buf.append( '0' );
+ buf.append( hexStr );
+ }
+ return buf.toString();
+ }
+
+ public String toLoggableString(Object value, SessionFactoryImplementor factory) {
+ return value == null ? "null" : toString( value );
+ }
+
+ public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+ String xmlText = xml.getText();
+ return xmlText == null || xmlText.length() == 0 ? null : fromString( xmlText );
+ }
+
+ private Object fromString(String xmlText) {
+ if ( xmlText == null ) {
+ return null;
+ }
+ if ( xmlText.length() % 2 != 0 ) {
+ throw new IllegalArgumentException( "The string is not a valid xml representation
of a binary content." );
+ }
+ byte[] bytes = new byte[xmlText.length() / 2];
+ for ( int i = 0; i < bytes.length ; i++ ) {
+ String hexStr = xmlText.substring( i * 2, ( i + 1 ) * 2 );
+ bytes[i] = (byte) ( Integer.parseInt( hexStr, 16 ) + Byte.MIN_VALUE );
+ }
+ return wrap( bytes );
+ }
+
+ protected Object wrap(byte[] bytes) {
+ return wrapPrimitive( bytes );
+ }
+
+ protected byte[] unWrap(Object bytes) {
+ return unwrapNonPrimitive( (Byte[]) bytes );
+ }
+
+ private byte[] unwrapNonPrimitive(Byte[] bytes) {
+ int length = bytes.length;
+ byte[] result = new byte[length];
+ for ( int i = 0; i < length ; i++ ) {
+ result[i] = bytes[i].byteValue();
+ }
+ return result;
+ }
+
+ private Byte[] wrapPrimitive(byte[] bytes) {
+ int length = bytes.length;
+ Byte[] result = new Byte[length];
+ for ( int index = 0; index < length ; index++ ) {
+ result[index] = Byte.valueOf( bytes[index] );
+ }
+ return result;
+ }
+
+ public boolean isMutable() {
+ return true;
+ }
+
+ public Object replace(
+ Object original,
+ Object target,
+ SessionImplementor session,
+ Object owner,
+ Map copyCache
+ )
+ throws HibernateException {
+ if ( isEqual( original, target, session.getEntityMode() ) ) return original;
+ return deepCopy( original, session.getEntityMode(), session.getFactory() );
+ }
+
+ public boolean[] toColumnNullness(Object value, Mapping mapping) {
+ return value == null ? ArrayHelper.FALSE : ArrayHelper.TRUE;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/CharacterArrayClobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/CharacterArrayClobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/CharacterArrayClobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,148 @@
+//$Id: CharacterArrayClobType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.type;
+
+import java.io.CharArrayReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+
+import org.hibernate.HibernateException;
+import org.hibernate.usertype.UserType;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * Map a Character[] to a Clob
+ * Experimental
+ *
+ * @author Emmanuel Bernard
+ */
+public class CharacterArrayClobType implements UserType, Serializable {
+ public static final int BUFFER_SIZE = 4096;
+
+ public int[] sqlTypes() {
+ return new int[]{Types.CLOB};
+ }
+
+ public Class returnedClass() {
+ return Character[].class;
+ }
+
+ public boolean equals(Object x, Object y) throws HibernateException {
+ if ( x == y ) return true;
+ if ( x == null || y == null ) return false;
+ if ( x instanceof Character[] ) {
+ Object[] o1 = (Object[]) x;
+ Object[] o2 = (Object[]) y;
+ return ArrayHelper.isEquals( o1, o2 );
+ }
+ else {
+ char[] c1 = (char[]) x;
+ char[] c2 = (char[]) y;
+ return ArrayHelper.isEquals( c1, c2 );
+ }
+ }
+
+ public int hashCode(Object x) throws HibernateException {
+ if ( x instanceof Character[] ) {
+ Object[] o = (Object[]) x;
+ return ArrayHelper.hash( o );
+ }
+ else {
+ char[] c = (char[]) x;
+ return ArrayHelper.hash( c );
+ }
+ }
+
+ public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws
HibernateException, SQLException {
+ Reader reader = rs.getCharacterStream( names[0] );
+ if ( reader == null ) return null;
+ ArrayList result = new ArrayList();
+ try {
+ char[] charbuf = new char[BUFFER_SIZE];
+ for ( int i = reader.read( charbuf ); i > 0 ; i = reader.read( charbuf ) ) {
+ result.ensureCapacity( result.size() + BUFFER_SIZE );
+ for ( int charIndex = 0; charIndex < i ; charIndex++ ) {
+ result.add( Character.valueOf( charbuf[charIndex] ) );
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new SQLException( e.getMessage() );
+ }
+ if ( returnedClass().equals( Character[].class ) ) {
+ return result.toArray( new Character[ result.size() ] );
+ }
+ else {
+ //very suboptimal
+ int length = result.size();
+ char[] chars = new char[length];
+ for ( int index = 0; index < length ; index++ ) {
+ chars[index] = ( (Character) result.get( index ) ).charValue();
+ }
+ return chars;
+ }
+ }
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index) throws
HibernateException, SQLException {
+ if ( value != null ) {
+ char[] chars;
+ if ( value instanceof Character[] ) {
+ Character[] character = (Character[]) value;
+ int length = character.length;
+ chars = new char[length];
+ for ( int i = 0; i < length ; i++ ) {
+ chars[i] = character[i].charValue();
+ }
+ }
+ else {
+ chars = (char[]) value;
+ }
+ CharArrayReader reader = new CharArrayReader( chars );
+ st.setCharacterStream( index, reader, chars.length );
+ }
+ else {
+ st.setNull( index, sqlTypes()[0] );
+ }
+ }
+
+ public Object deepCopy(Object value) throws HibernateException {
+ if ( value == null ) return null;
+ if ( value instanceof Character[] ) {
+ Character[] array = (Character[]) value;
+ int length = array.length;
+ Character[] copy = new Character[length];
+ for ( int index = 0; index < length ; index++ ) {
+ copy[index] = Character.valueOf( array[index].charValue() );
+ }
+ return copy;
+ }
+ else {
+ char[] array = (char[]) value;
+ int length = array.length;
+ char[] copy = new char[length];
+ System.arraycopy( array, 0, copy, 0, length );
+ return copy;
+ }
+ }
+
+ public boolean isMutable() {
+ return true;
+ }
+
+ public Serializable disassemble(Object value) throws HibernateException {
+ return (Serializable) deepCopy( value );
+ }
+
+ public Object assemble(Serializable cached, Object owner) throws HibernateException {
+ return deepCopy( cached );
+ }
+
+ public Object replace(Object original, Object target, Object owner) throws
HibernateException {
+ return deepCopy( original );
+ }
+}
Added: annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/EnumType.java
===================================================================
--- annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/EnumType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/EnumType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,269 @@
+//$Id: EnumType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.type;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+import org.hibernate.annotations.common.util.StringHelper;
+import org.hibernate.usertype.EnhancedUserType;
+import org.hibernate.usertype.ParameterizedType;
+import org.hibernate.util.ReflectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Enum type mapper
+ * Try and find the appropriate SQL type depending on column metadata
+ *
+ * @author Emmanuel Bernard
+ */
+//TODO implements readobject/writeobject to recalculate the enumclasses
+public class EnumType implements EnhancedUserType, ParameterizedType, Serializable {
+ /**
+ * This is the old scheme where logging of parameter bindings and value extractions
+ * was controlled by the trace level enablement on the 'org.hibernate.type'
package...
+ * <p/>
+ * Originally was cached such because of performance of looking up the logger each time
+ * in order to check the trace-enablement. Driving this via a central Log-specific
class
+ * would alleviate that performance hit, and yet still allow more "normal"
logging usage/config.
+ */
+ private static final boolean IS_VALUE_TRACING_ENABLED = LoggerFactory.getLogger(
StringHelper.qualifier( Type.class.getName() ) ).isTraceEnabled();
+ private transient Logger log;
+
+ private Logger log() {
+ if ( log == null ) {
+ log = LoggerFactory.getLogger( getClass() );
+ }
+ return log;
+ }
+
+ public static final String ENUM = "enumClass";
+ public static final String SCHEMA = "schema";
+ public static final String CATALOG = "catalog";
+ public static final String TABLE = "table";
+ public static final String COLUMN = "column";
+ public static final String TYPE = "type";
+
+ private static Map<Class, Object[]> enumValues = new HashMap<Class,
Object[]>();
+
+ private Class<? extends Enum> enumClass;
+ private String column;
+ private String table;
+ private String catalog;
+ private String schema;
+ private boolean guessed = false;
+ private int sqlType = Types.INTEGER; //before any guessing
+
+ public int[] sqlTypes() {
+ return new int[]{sqlType};
+ }
+
+ public Class returnedClass() {
+ return enumClass;
+ }
+
+ public boolean equals(Object x, Object y) throws HibernateException {
+ return x == y;
+ }
+
+ public int hashCode(Object x) throws HibernateException {
+ return x == null ? 0 : x.hashCode();
+ }
+
+ public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws
HibernateException, SQLException {
+ Object object = rs.getObject( names[0] );
+ if ( rs.wasNull() ) {
+ if ( IS_VALUE_TRACING_ENABLED ) {
+ log().debug( "Returning null as column {}", names[0] );
+ }
+ return null;
+ }
+ if ( object instanceof Number ) {
+ Object[] values = enumValues.get( enumClass );
+ if ( values == null ) throw new AssertionFailure( "enumValues not preprocessed:
" + enumClass );
+ int ordinal = ( (Number) object ).intValue();
+ if ( ordinal < 0 || ordinal >= values.length ) {
+ throw new IllegalArgumentException( "Unknown ordinal value for enum " +
enumClass + ": " + ordinal );
+ }
+ if ( IS_VALUE_TRACING_ENABLED ) {
+ log().debug( "Returning '{}' as column {}", ordinal, names[0] );
+ }
+ return values[ordinal];
+ }
+ else {
+ String name = (String) object;
+ if ( IS_VALUE_TRACING_ENABLED ) {
+ log().debug( "Returning '{}' as column {}", name, names[0] );
+ }
+ try {
+ return Enum.valueOf( enumClass, name );
+ }
+ catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException( "Unknown name value for enum " +
enumClass + ": " + name, iae );
+ }
+ }
+ }
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index) throws
HibernateException, SQLException {
+ //if (!guessed) guessType( st, index );
+ if ( value == null ) {
+ if ( IS_VALUE_TRACING_ENABLED ) log().debug( "Binding null to parameter:
{}", index );
+ st.setNull( index, sqlType );
+ }
+ else {
+ boolean isOrdinal = isOrdinal( sqlType );
+ if ( isOrdinal ) {
+ int ordinal = ( (Enum) value ).ordinal();
+ if ( IS_VALUE_TRACING_ENABLED ) {
+ log().debug( "Binding '{}' to parameter: {}", ordinal, index );
+ }
+ st.setObject( index, Integer.valueOf( ordinal ), sqlType );
+ }
+ else {
+ String enumString = ( (Enum) value ).name();
+ if ( IS_VALUE_TRACING_ENABLED ) {
+ log().debug( "Binding '{}' to parameter: {}", enumString, index
);
+ }
+ st.setObject( index, enumString, sqlType );
+ }
+ }
+ }
+
+ private boolean isOrdinal(int paramType) {
+ switch ( paramType ) {
+ case Types.INTEGER:
+ case Types.NUMERIC:
+ case Types.SMALLINT:
+ case Types.TINYINT:
+ case Types.BIGINT:
+ case Types.DECIMAL: //for Oracle Driver
+ case Types.DOUBLE: //for Oracle Driver
+ case Types.FLOAT: //for Oracle Driver
+ return true;
+ case Types.CHAR:
+ case Types.LONGVARCHAR:
+ case Types.VARCHAR:
+ return false;
+ default:
+ throw new HibernateException( "Unable to persist an Enum in a column of SQL
Type: " + paramType );
+ }
+ }
+
+ public Object deepCopy(Object value) throws HibernateException {
+ return value;
+ }
+
+ public boolean isMutable() {
+ return false;
+ }
+
+ public Serializable disassemble(Object value) throws HibernateException {
+ return (Serializable) value;
+ }
+
+ public Object assemble(Serializable cached, Object owner) throws HibernateException {
+ return cached;
+ }
+
+ public Object replace(Object original, Object target, Object owner) throws
HibernateException {
+ return original;
+ }
+
+ public void setParameterValues(Properties parameters) {
+ String enumClassName = parameters.getProperty( ENUM );
+ try {
+ enumClass = ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass(
Enum.class );
+ }
+ catch (ClassNotFoundException exception) {
+ throw new HibernateException( "Enum class not found", exception );
+ }
+ //this is threadsafe to do it here, setParameterValues() is called sequencially
+ initEnumValue();
+ //nullify unnullified properties yuck!
+ schema = parameters.getProperty( SCHEMA );
+ if ( "".equals( schema ) ) schema = null;
+ catalog = parameters.getProperty( CATALOG );
+ if ( "".equals( catalog ) ) catalog = null;
+ table = parameters.getProperty( TABLE );
+ column = parameters.getProperty( COLUMN );
+ String type = parameters.getProperty( TYPE );
+ if ( type != null ) {
+ sqlType = Integer.decode( type ).intValue();
+ guessed = true;
+ }
+ }
+
+ private void initEnumValue() {
+ Object[] values = enumValues.get( enumClass );
+ if ( values == null ) {
+ try {
+ Method method = null;
+ method = enumClass.getDeclaredMethod( "values", new Class[0] );
+ values = (Object[]) method.invoke( null, new Object[0] );
+ enumValues.put( enumClass, values );
+ }
+ catch (Exception e) {
+ throw new HibernateException( "Error while accessing enum.values(): " +
enumClass, e );
+ }
+ }
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException,
ClassNotFoundException {
+ //FIXME Hum, I think I break the thread safety here
+ ois.defaultReadObject();
+ initEnumValue();
+ }
+
+ public String objectToSQLString(Object value) {
+ boolean isOrdinal = isOrdinal( sqlType );
+ if ( isOrdinal ) {
+ int ordinal = ( (Enum) value ).ordinal();
+ return Integer.toString( ordinal );
+ }
+ else {
+ return '\'' + ( (Enum) value ).name() + '\'';
+ }
+ }
+
+ public String toXMLString(Object value) {
+ boolean isOrdinal = isOrdinal( sqlType );
+ if ( isOrdinal ) {
+ int ordinal = ( (Enum) value ).ordinal();
+ return Integer.toString( ordinal );
+ }
+ else {
+ return ( (Enum) value ).name();
+ }
+ }
+
+ public Object fromXMLString(String xmlValue) {
+ try {
+ int ordinal = Integer.parseInt( xmlValue );
+ Object[] values = enumValues.get( enumClass );
+ if ( values == null ) throw new AssertionFailure( "enumValues not preprocessed:
" + enumClass );
+ if ( ordinal < 0 || ordinal >= values.length ) {
+ throw new IllegalArgumentException( "Unknown ordinal value for enum " +
enumClass + ": " + ordinal );
+ }
+ return values[ordinal];
+ }
+ catch(NumberFormatException e) {
+ try {
+ return Enum.valueOf( enumClass, xmlValue );
+ }
+ catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException( "Unknown name value for enum " +
enumClass + ": " + xmlValue, iae );
+ }
+ }
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveByteArrayBlobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveByteArrayBlobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveByteArrayBlobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,21 @@
+//$Id: PrimitiveByteArrayBlobType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.type;
+
+/**
+ * Map a byte[] to a Blob
+ *
+ * @author Emmanuel Bernard
+ */
+public class PrimitiveByteArrayBlobType extends ByteArrayBlobType {
+ public Class getReturnedClass() {
+ return byte[].class;
+ }
+
+ protected Object wrap(byte[] bytes) {
+ return bytes;
+ }
+
+ protected byte[] unWrap(Object bytes) {
+ return (byte[]) bytes;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/PrimitiveCharacterArrayClobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,14 @@
+//$Id: PrimitiveCharacterArrayClobType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik
$
+package org.hibernate.type;
+
+
+/**
+ * Map a char[] to a Clob
+ *
+ * @author Emmanuel Bernard
+ */
+public class PrimitiveCharacterArrayClobType extends CharacterArrayClobType {
+ public Class returnedClass() {
+ return char[].class;
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/SerializableToBlobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/SerializableToBlobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/SerializableToBlobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,135 @@
+//$Id: SerializableToBlobType.java 17982 2009-11-14 13:18:39Z stliu $
+package org.hibernate.type;
+
+import java.io.ByteArrayInputStream;
+import java.io.Serializable;
+import java.sql.Blob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Map;
+import java.util.Properties;
+
+import org.dom4j.Node;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.lob.BlobImpl;
+import org.hibernate.usertype.ParameterizedType;
+import org.hibernate.util.ReflectHelper;
+import org.hibernate.util.SerializationHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class SerializableToBlobType extends AbstractLobType implements ParameterizedType
{
+ /**
+ * class name of the serialisable class
+ */
+ public static final String CLASS_NAME = "classname";
+ private Class serializableClass;
+ private SerializableType type;
+
+ public int[] sqlTypes(Mapping mapping) throws MappingException {
+ return new int[]{Types.BLOB};
+ }
+
+ public Class getReturnedClass() {
+ return serializableClass;
+ }
+
+ @Override
+ public boolean isEqual(Object x, Object y, EntityMode entityMode,
SessionFactoryImplementor factory) {
+ return type.isEqual( x, y );
+ }
+
+
+ @Override
+ public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor
session) {
+ return type.getHashCode( x, null );
+ }
+
+ public Object get(ResultSet rs, String name) throws SQLException {
+ Blob blob = rs.getBlob( name );
+ if ( rs.wasNull() ) return null;
+ int length = (int) blob.length();
+ byte[] primaryResult = blob.getBytes( 1, length );
+ return fromBytes( primaryResult );
+ }
+
+ private static byte[] toBytes(Object object) throws SerializationException {
+ return SerializationHelper.serialize( (Serializable) object );
+ }
+
+ private Object fromBytes(byte[] bytes) throws SerializationException {
+ return SerializationHelper.deserialize( bytes, getReturnedClass().getClassLoader() );
+ }
+
+ public void set(PreparedStatement st, Object value, int index, SessionImplementor
session) throws SQLException {
+ if ( value != null ) {
+ byte[] toSet;
+ toSet = toBytes( value );
+ if ( session.getFactory().getDialect().useInputStreamToInsertBlob() ) {
+ st.setBinaryStream( index, new ByteArrayInputStream( toSet ), toSet.length );
+ }
+ else {
+ st.setBlob( index, new BlobImpl( toSet ) );
+ }
+ }
+ else {
+ st.setNull( index, sqlTypes( null )[0] );
+ }
+ }
+
+ public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory)
throws HibernateException {
+ type.setToXMLNode( node, value, factory );
+ }
+
+ public String toLoggableString(Object value, SessionFactoryImplementor factory) throws
HibernateException {
+ return type.toLoggableString( value, factory );
+ }
+
+ public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
+ return type.fromXMLNode( xml, factory );
+ }
+
+ public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor
factory)
+ throws HibernateException {
+ return type.deepCopy( value, null, null );
+ }
+
+ public boolean isMutable() {
+ return type.isMutable();
+ }
+
+ public Object replace(Object original, Object target, SessionImplementor session, Object
owner, Map copyCache)
+ throws HibernateException {
+ return type.replace( original, target, session, owner, copyCache );
+ }
+
+ public boolean[] toColumnNullness(Object value, Mapping mapping) {
+ return type.toColumnNullness( value, mapping );
+ }
+
+ public void setParameterValues(Properties parameters) {
+ if ( parameters != null ) {
+ String className = parameters.getProperty( CLASS_NAME );
+ if ( className == null ) {
+ throw new MappingException(
+ "No class name defined for type: " +
SerializableToBlobType.class.getName()
+ );
+ }
+ try {
+ serializableClass = ReflectHelper.classForName( className );
+ }
+ catch (ClassNotFoundException e) {
+ throw new MappingException( "Unable to load class from " + CLASS_NAME +
" parameter", e );
+ }
+ }
+ type = new SerializableType( serializableClass );
+ }
+}
Added:
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/StringClobType.java
===================================================================
---
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/StringClobType.java
(rev 0)
+++
annotations/branches/v3_4_0_GA_CP/src/main/java/org/hibernate/type/StringClobType.java 2009-11-24
21:08:28 UTC (rev 18050)
@@ -0,0 +1,85 @@
+//$Id: StringClobType.java 14736 2008-06-04 14:23:42Z hardy.ferentschik $
+package org.hibernate.type;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.hibernate.HibernateException;
+import org.hibernate.usertype.UserType;
+
+/**
+ * Map a String to a Clob
+ *
+ * @author Emmanuel Bernard
+ */
+public class StringClobType implements UserType, Serializable {
+ public int[] sqlTypes() {
+ return new int[]{Types.CLOB};
+ }
+
+ public Class returnedClass() {
+ return String.class;
+ }
+
+ public boolean equals(Object x, Object y) throws HibernateException {
+ return ( x == y ) || ( x != null && x.equals( y ) );
+ }
+
+ public int hashCode(Object x) throws HibernateException {
+ return x.hashCode();
+ }
+
+ public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws
HibernateException, SQLException {
+ Reader reader = rs.getCharacterStream( names[0] );
+ if ( reader == null ) return null;
+ StringBuilder result = new StringBuilder( 4096 );
+ try {
+ char[] charbuf = new char[4096];
+ for ( int i = reader.read( charbuf ); i > 0 ; i = reader.read( charbuf ) ) {
+ result.append( charbuf, 0, i );
+ }
+ }
+ catch (IOException e) {
+ throw new SQLException( e.getMessage() );
+ }
+ return result.toString();
+ }
+
+ public void nullSafeSet(PreparedStatement st, Object value, int index) throws
HibernateException, SQLException {
+ if ( value != null ) {
+ String string = (String) value;
+ StringReader reader = new StringReader( string );
+ st.setCharacterStream( index, reader, string.length() );
+ }
+ else {
+ st.setNull( index, sqlTypes()[0] );
+ }
+ }
+
+ public Object deepCopy(Object value) throws HibernateException {
+ //returning value should be OK since String are immutable
+ return value;
+ }
+
+ public boolean isMutable() {
+ return false;
+ }
+
+ public Serializable disassemble(Object value) throws HibernateException {
+ return (Serializable) value;
+ }
+
+ public Object assemble(Serializable cached, Object owner) throws HibernateException {
+ return cached;
+ }
+
+ public Object replace(Object original, Object target, Object owner) throws
HibernateException {
+ return original;
+ }
+}