matrei commented on code in PR #15568:
URL: https://github.com/apache/grails-core/pull/15568#discussion_r3466326516
##########
grails-data-hibernate7/core/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java:
##########
@@ -68,226 +75,1274 @@
* }
* maxResults(10)
* order("holderLastName", "desc")
+ * cache(true)
+ * readOnly(true)
* }
* </pre>
- * <p>The builder can also be instantiated standalone with a SessionFactory
and persistent Class instance:
+ *
+ * <h2>Advanced Features</h2>
+ *
+ * <p>The builder supports several advanced Hibernate features:
+ *
+ * <ul>
+ * <li><b>Pessimistic Locking:</b> Use {@code lock(true)} to obtain a
pessimistic write lock.
+ * <li><b>Query Caching:</b> Use {@code cache(true)} to enable query caching
for the results.
+ * <li><b>Read-Only Mode:</b> Use {@code readOnly(true)} to disable dirty
checking for loaded
+ * entities.
+ * <li><b>Fetch Mode:</b> Use {@code fetchMode("association",
FetchMode.JOIN)} to specify Eager/Lazy
+ * fetching strategies.
+ * </ul>
+ *
+ * <h2>Programmatic instantiation</h2>
+ *
+ * <p>The builder requires a {@link SessionFactory}, the target persistent
class, and the {@link
+ * org.grails.orm.hibernate.HibernateDatastore} that owns the session:
+ *
* <pre>
- * new HibernateCriteriaBuilder(clazz, sessionFactory).list {
+ * new HibernateCriteriaBuilder(Account, sessionFactory, datastore).list {
* eq("firstName", "Fred")
* }
* </pre>
*
+ * <h2>Architecture</h2>
+ *
+ * <p>Closure method calls in the DSL are dispatched through {@code
invokeMethod} → {@code
+ * CriteriaMethodInvoker} → {@link HibernateQuery}, which translates each GORM
constraint into the
+ * equivalent JPA Criteria predicate. {@link grails.gorm.DetachedCriteria} can
also be passed in
+ * place of a closure to support multi-tenant and reusable query fragments.
+ *
+ * To adjust the methods to be handled you have to extend this class, extend
CriteriaMethodInvoker
Review Comment:
This sentence does not make sense to me.
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
Review Comment:
Align on JSpecify?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.mapping.PersistentClass;
+
+import org.grails.orm.hibernate.cfg.Mapping;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity;
+
+import static org.grails.orm.hibernate.cfg.GrailsHibernateUtil.unqualify;
+
+/** The class binder class. */
+public class ClassBinder {
+
+ private final InFlightMetadataCollector collector;
+
+ public ClassBinder(@Nonnull InFlightMetadataCollector collector) {
+ this.collector = collector;
+ }
+
+ /**
+ * Binds the specified persistant class to the runtime model based on the
properties defined in
+ * the domain class
+ *
+ * @param persistentEntity The Grails domain class
+ * @param persistentClass The persistant class
+ */
Review Comment:
I'm not a native english speaker, but shouldn't `persistant` be `persistent`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionForPropertyConfigBinder.java:
##########
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
Review Comment:
Align on JSpecify?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java:
##########
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.grails.orm.hibernate.cfg.ColumnConfig;
+import org.grails.orm.hibernate.cfg.Mapping;
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateAssociation;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.CreateKeyForProps;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+
+@SuppressWarnings({"PMD.NullAssignment", "PMD.DataflowAnomalyAnalysis"})
+public class ColumnBinder {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(ColumnBinder.class);
+
+ private final ColumnNameForPropertyAndPathFetcher
columnNameForPropertyAndPathFetcher;
+ private final StringColumnConstraintsBinder stringColumnConstraintsBinder;
+ private final NumericColumnConstraintsBinder
numericColumnConstraintsBinder;
+ private final CreateKeyForProps createKeyForProps;
+ private final IndexBinder indexBinder;
+
+ /** Public constructor that accepts all collaborators. */
+ public ColumnBinder(
+ ColumnNameForPropertyAndPathFetcher
columnNameForPropertyAndPathFetcher,
+ StringColumnConstraintsBinder stringColumnConstraintsBinder,
+ NumericColumnConstraintsBinder numericColumnConstraintsBinder,
+ CreateKeyForProps createKeyForProps,
+ IndexBinder indexBinder) {
+ this.columnNameForPropertyAndPathFetcher =
columnNameForPropertyAndPathFetcher;
+ this.stringColumnConstraintsBinder = stringColumnConstraintsBinder;
+ this.numericColumnConstraintsBinder = numericColumnConstraintsBinder;
+ this.createKeyForProps = createKeyForProps;
+ this.indexBinder = indexBinder;
+ }
+
+ /** Convenience constructor for backward compatibility. */
+ public ColumnBinder(PersistentEntityNamingStrategy namingStrategy) {
+ this(
+ new ColumnNameForPropertyAndPathFetcher(
+ namingStrategy, new
DefaultColumnNameFetcher(namingStrategy), new BackticksRemover()),
+ new StringColumnConstraintsBinder(),
+ new NumericColumnConstraintsBinder(),
+ new CreateKeyForProps(new ColumnNameForPropertyAndPathFetcher(
+ namingStrategy, new
DefaultColumnNameFetcher(namingStrategy), new BackticksRemover())),
+ new IndexBinder());
+ }
+
+ /**
+ * Binds a Column instance to the Hibernate meta model
+ *
+ * @param property The Grails domain class property
+ * @param parentProperty parent property
+ * @param column The column to bind
+ * @param path the path
+ * @param table The table name
+ */
+ public void bindColumn(
+ HibernatePersistentProperty property,
+ HibernatePersistentProperty parentProperty,
+ Column column,
+ ColumnConfig cc,
+ String path,
+ Table table) {
+
+ if (cc != null) {
+ column.setComment(cc.getComment());
+ column.setDefaultValue(cc.getDefaultValue());
+ column.setCustomRead(cc.getRead());
+ column.setCustomWrite(cc.getWrite());
+ }
+
+ Class<?> userType = property.getUserType();
+ String columnName =
columnNameForPropertyAndPathFetcher.getColumnNameForPropertyAndPath(property,
path, cc);
+ if ((property instanceof HibernateAssociation assoc) && userType ==
null) {
+ // Only use conventional naming when the column has not been
explicitly mapped.
+ if (column.getName() == null) {
+ column.setName(columnName);
+ }
+ column.setNullable(assoc.isAssociationColumnNullable());
+ } else {
+ column.setName(columnName);
+ column.setNullable(property.isNullable() || (parentProperty !=
null && parentProperty.isNullable()));
+ // Use the constraints for this property to more accurately define
+ // the column's length, precision, and scale
+ Class<?> type = property.getType();
+ if (type != null && (String.class.isAssignableFrom(type) ||
byte[].class.isAssignableFrom(type))) {
+ PropertyConfig mappedForm = property.getHibernateMappedForm();
+
stringColumnConstraintsBinder.bindStringColumnConstraints(column, mappedForm);
+ } else if (type != null && Number.class.isAssignableFrom(type)) {
+ PropertyConfig mappedForm = property.getHibernateMappedForm();
+
numericColumnConstraintsBinder.bindNumericColumnConstraints(column, cc,
mappedForm);
+ }
+ }
+
+ createKeyForProps.createKeyForProps(property, path, table, columnName);
+ indexBinder.bindIndex(columnName, column, cc, table);
+
+ var owner = property.getHibernateOwner();
+ if (!owner.isRoot()) {
+ Mapping mapping = owner.getHibernateMappedForm();
+ if (mapping != null && mapping.getTablePerHierarchy()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("[GrailsDomainBinder] Sub class property [{}]
for column name [{}] set to nullable", property.getName(), column.getName());
Review Comment:
Why are we logging the class name `GrailsDomainBinder` here?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java:
##########
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.boot.spi.MetadataBuildingContext;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.OneToMany;
+
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+import
org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyEntityProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BasicCollectionElementBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalMapElementBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalOneToManyLinker;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyColumnUpdater;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionWithJoinTableBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.DependentKeyValueBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.HibernateToManyEntityOrderByBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ManyToOneElementBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.PrimaryKeyValueCreator;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.SetSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ToManyEntityMultiTenantFilterBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyInverseValuesBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.GrailsPropertyResolver;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.TableForManyCalculator;
+
+
+/** Handles the binding of collections to the Hibernate runtime meta model. */
+@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
+public class CollectionBinder {
+
+ private final MetadataBuildingContext metadataBuildingContext;
+ private final CollectionHolder collectionHolder;
+ private final ListSecondPassBinder listSecondPassBinder;
+ private final CollectionSecondPassBinder collectionSecondPassBinder;
+ final MapSecondPassBinder mapSecondPassBinder;
+ private final InFlightMetadataCollector mappings;
+ private final TableForManyCalculator tableForManyCalculator;
+
+ public void setComponentBinder(ComponentBinder componentBinder) {
+ this.collectionSecondPassBinder.setComponentBinder(componentBinder);
+ }
+
+ /** Creates a new {@link CollectionBinder} instance. */
Review Comment:
Do we need this description on a constructor?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.boot.spi.MetadataBuildingContext;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Component;
+import org.hibernate.mapping.PersistentClass;
+
+import org.grails.orm.hibernate.cfg.GrailsHibernateUtil;
+import org.grails.orm.hibernate.cfg.MappingCacheHolder;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedCollectionProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateEmbeddedProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+
+// TODO (Hibernate 8 refactor): ComponentBinder holds a GrailsPropertyBinder
reference set post-construction
+// via setGrailsPropertyBinder() to break a circular dependency
(ComponentBinder ↔ GrailsPropertyBinder ↔
+// CollectionBinder ↔ ComponentBinder). This mutual dependency should be
resolved by introducing a shared
+// binding context or factory object that all binders receive at construction
time.
+@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
+public class ComponentBinder {
Review Comment:
`@since`?
##########
grails-data-hibernate7/core/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java:
##########
@@ -68,226 +75,1274 @@
* }
* maxResults(10)
* order("holderLastName", "desc")
+ * cache(true)
+ * readOnly(true)
* }
* </pre>
- * <p>The builder can also be instantiated standalone with a SessionFactory
and persistent Class instance:
+ *
+ * <h2>Advanced Features</h2>
+ *
+ * <p>The builder supports several advanced Hibernate features:
+ *
+ * <ul>
+ * <li><b>Pessimistic Locking:</b> Use {@code lock(true)} to obtain a
pessimistic write lock.
+ * <li><b>Query Caching:</b> Use {@code cache(true)} to enable query caching
for the results.
+ * <li><b>Read-Only Mode:</b> Use {@code readOnly(true)} to disable dirty
checking for loaded
+ * entities.
+ * <li><b>Fetch Mode:</b> Use {@code fetchMode("association",
FetchMode.JOIN)} to specify Eager/Lazy
+ * fetching strategies.
+ * </ul>
+ *
+ * <h2>Programmatic instantiation</h2>
+ *
+ * <p>The builder requires a {@link SessionFactory}, the target persistent
class, and the {@link
+ * org.grails.orm.hibernate.HibernateDatastore} that owns the session:
+ *
* <pre>
- * new HibernateCriteriaBuilder(clazz, sessionFactory).list {
+ * new HibernateCriteriaBuilder(Account, sessionFactory, datastore).list {
* eq("firstName", "Fred")
* }
* </pre>
*
+ * <h2>Architecture</h2>
+ *
+ * <p>Closure method calls in the DSL are dispatched through {@code
invokeMethod} → {@code
+ * CriteriaMethodInvoker} → {@link HibernateQuery}, which translates each GORM
constraint into the
+ * equivalent JPA Criteria predicate. {@link grails.gorm.DetachedCriteria} can
also be passed in
+ * place of a closure to support multi-tenant and reusable query fragments.
+ *
+ * To adjust the methods to be handled you have to extend this class, extend
CriteriaMethodInvoker
+ *
* @author Graeme Rocher
+ * @author walterduquedeestrada
+ * @see HibernateQuery
+ * @see grails.gorm.DetachedCriteria
*/
-public class HibernateCriteriaBuilder extends AbstractHibernateCriteriaBuilder
{
- /*
- * Define constants which may be used inside of criteria queries
- * to refer to standard Hibernate Type instances.
- */
- public static final Type BOOLEAN = StandardBasicTypes.BOOLEAN;
- public static final Type YES_NO = StandardBasicTypes.YES_NO;
- public static final Type BYTE = StandardBasicTypes.BYTE;
- public static final Type CHARACTER = StandardBasicTypes.CHARACTER;
- public static final Type SHORT = StandardBasicTypes.SHORT;
- public static final Type INTEGER = StandardBasicTypes.INTEGER;
- public static final Type LONG = StandardBasicTypes.LONG;
- public static final Type FLOAT = StandardBasicTypes.FLOAT;
- public static final Type DOUBLE = StandardBasicTypes.DOUBLE;
- public static final Type BIG_DECIMAL = StandardBasicTypes.BIG_DECIMAL;
- public static final Type BIG_INTEGER = StandardBasicTypes.BIG_INTEGER;
- public static final Type STRING = StandardBasicTypes.STRING;
- public static final Type NUMERIC_BOOLEAN =
StandardBasicTypes.NUMERIC_BOOLEAN;
- public static final Type TRUE_FALSE = StandardBasicTypes.TRUE_FALSE;
- public static final Type URL = StandardBasicTypes.URL;
- public static final Type TIME = StandardBasicTypes.TIME;
- public static final Type DATE = StandardBasicTypes.DATE;
- public static final Type TIMESTAMP = StandardBasicTypes.TIMESTAMP;
- public static final Type CALENDAR = StandardBasicTypes.CALENDAR;
- public static final Type CALENDAR_DATE = StandardBasicTypes.CALENDAR_DATE;
- public static final Type CLASS = StandardBasicTypes.CLASS;
- public static final Type LOCALE = StandardBasicTypes.LOCALE;
- public static final Type CURRENCY = StandardBasicTypes.CURRENCY;
- public static final Type TIMEZONE = StandardBasicTypes.TIMEZONE;
- public static final Type UUID_BINARY = StandardBasicTypes.UUID_BINARY;
- public static final Type UUID_CHAR = StandardBasicTypes.UUID_CHAR;
- public static final Type BINARY = StandardBasicTypes.BINARY;
- public static final Type WRAPPER_BINARY =
StandardBasicTypes.WRAPPER_BINARY;
- public static final Type IMAGE = StandardBasicTypes.IMAGE;
- public static final Type BLOB = StandardBasicTypes.BLOB;
- public static final Type MATERIALIZED_BLOB =
StandardBasicTypes.MATERIALIZED_BLOB;
- public static final Type CHAR_ARRAY = StandardBasicTypes.CHAR_ARRAY;
- public static final Type CHARACTER_ARRAY =
StandardBasicTypes.CHARACTER_ARRAY;
- public static final Type TEXT = StandardBasicTypes.TEXT;
- public static final Type CLOB = StandardBasicTypes.CLOB;
- public static final Type MATERIALIZED_CLOB =
StandardBasicTypes.MATERIALIZED_CLOB;
- public static final Type SERIALIZABLE = StandardBasicTypes.SERIALIZABLE;
+@Slf4j
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
+public class HibernateCriteriaBuilder extends GroovyObjectSupport implements
BuildableCriteria, ProjectionList {
+ private final SessionFactory sessionFactory;
+ private final boolean participate;
+ private final org.hibernate.query.criteria.HibernateCriteriaBuilder cb;
+ private final HibernateQuery hibernateQuery;
+ private Class<?> targetClass;
+ private CriteriaQuery<?> criteriaQuery;
+ private boolean uniqueResult = false;
- @SuppressWarnings("rawtypes")
- public HibernateCriteriaBuilder(Class targetClass, SessionFactory
sessionFactory) {
- super(targetClass, sessionFactory);
+ @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
+ private boolean scroll;
+
+ @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
+ private boolean count;
+
+ private boolean paginationEnabledList = false;
+ private int defaultFlushMode;
+
+ @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
+ private boolean distinct = false;
+ private CriteriaMethodInvoker criteriaMethodInvoker;
+
+ @SuppressWarnings({"rawtypes", "PMD.CloseResource"})
+ public HibernateCriteriaBuilder(Class targetClass, SessionFactory
sessionFactory, HibernateDatastore datastore) {
+ this.targetClass = targetClass;
+ setDatastore(datastore);
+ this.sessionFactory = sessionFactory;
+ this.cb = sessionFactory.getCriteriaBuilder();
+ if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
+ this.participate = true;
+ } else {
+ this.participate = false;
+ org.hibernate.Session session = sessionFactory.openSession();
Review Comment:
Why fully qualified, or event better: `var`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
Review Comment:
Align on JSpecify?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.MappingException;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.Value;
+
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator;
+
+/**
+ * Binds the properties of a Grails domain class to the Hibernate meta-model.
+ *
+ * @author Graeme Rocher
+ * @since 7.0
+ */
+@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
+public class ClassPropertiesBinder {
+
+ private final GrailsPropertyBinder grailsPropertyBinder;
+ private final PropertyFromValueCreator propertyFromValueCreator;
+ private final NaturalIdentifierBinder naturalIdentifierBinder;
+
+ /** Creates a new {@link ClassPropertiesBinder} instance. */
Review Comment:
Do we need this description on a constructor?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.MappingException;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.Value;
+
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator;
+
+/**
+ * Binds the properties of a Grails domain class to the Hibernate meta-model.
+ *
+ * @author Graeme Rocher
+ * @since 7.0
+ */
+@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
+public class ClassPropertiesBinder {
+
+ private final GrailsPropertyBinder grailsPropertyBinder;
+ private final PropertyFromValueCreator propertyFromValueCreator;
+ private final NaturalIdentifierBinder naturalIdentifierBinder;
+
+ /** Creates a new {@link ClassPropertiesBinder} instance. */
+ public ClassPropertiesBinder(
+ GrailsPropertyBinder grailsPropertyBinder,
+ PropertyFromValueCreator propertyFromValueCreator,
+ NaturalIdentifierBinder naturalIdentifierBinder) {
+ this.grailsPropertyBinder = grailsPropertyBinder;
+ this.propertyFromValueCreator = propertyFromValueCreator;
+ this.naturalIdentifierBinder = naturalIdentifierBinder;
+ }
+
+ /** Creates a new {@link ClassPropertiesBinder} instance. */
Review Comment:
Do we need this description on a constructor?
##########
grails-data-hibernate7/core/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java:
##########
@@ -68,226 +75,1274 @@
* }
* maxResults(10)
* order("holderLastName", "desc")
+ * cache(true)
+ * readOnly(true)
* }
* </pre>
- * <p>The builder can also be instantiated standalone with a SessionFactory
and persistent Class instance:
+ *
+ * <h2>Advanced Features</h2>
+ *
+ * <p>The builder supports several advanced Hibernate features:
+ *
+ * <ul>
+ * <li><b>Pessimistic Locking:</b> Use {@code lock(true)} to obtain a
pessimistic write lock.
+ * <li><b>Query Caching:</b> Use {@code cache(true)} to enable query caching
for the results.
+ * <li><b>Read-Only Mode:</b> Use {@code readOnly(true)} to disable dirty
checking for loaded
+ * entities.
+ * <li><b>Fetch Mode:</b> Use {@code fetchMode("association",
FetchMode.JOIN)} to specify Eager/Lazy
+ * fetching strategies.
+ * </ul>
+ *
+ * <h2>Programmatic instantiation</h2>
+ *
+ * <p>The builder requires a {@link SessionFactory}, the target persistent
class, and the {@link
+ * org.grails.orm.hibernate.HibernateDatastore} that owns the session:
+ *
* <pre>
- * new HibernateCriteriaBuilder(clazz, sessionFactory).list {
+ * new HibernateCriteriaBuilder(Account, sessionFactory, datastore).list {
* eq("firstName", "Fred")
* }
* </pre>
*
+ * <h2>Architecture</h2>
+ *
+ * <p>Closure method calls in the DSL are dispatched through {@code
invokeMethod} → {@code
+ * CriteriaMethodInvoker} → {@link HibernateQuery}, which translates each GORM
constraint into the
+ * equivalent JPA Criteria predicate. {@link grails.gorm.DetachedCriteria} can
also be passed in
+ * place of a closure to support multi-tenant and reusable query fragments.
+ *
+ * To adjust the methods to be handled you have to extend this class, extend
CriteriaMethodInvoker
+ *
* @author Graeme Rocher
+ * @author walterduquedeestrada
Review Comment:
Do not add `@author` tags?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassPropertiesBinder.java:
##########
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.MappingException;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Table;
+import org.hibernate.mapping.Value;
+
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentEntity;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.PropertyFromValueCreator;
+
+/**
+ * Binds the properties of a Grails domain class to the Hibernate meta-model.
+ *
+ * @author Graeme Rocher
+ * @since 7.0
Review Comment:
Is this correct?
##########
grails-data-hibernate7/core/src/main/groovy/grails/orm/HibernateCriteriaBuilder.java:
##########
@@ -68,226 +75,1274 @@
* }
* maxResults(10)
* order("holderLastName", "desc")
+ * cache(true)
+ * readOnly(true)
* }
* </pre>
- * <p>The builder can also be instantiated standalone with a SessionFactory
and persistent Class instance:
+ *
+ * <h2>Advanced Features</h2>
+ *
+ * <p>The builder supports several advanced Hibernate features:
+ *
+ * <ul>
+ * <li><b>Pessimistic Locking:</b> Use {@code lock(true)} to obtain a
pessimistic write lock.
+ * <li><b>Query Caching:</b> Use {@code cache(true)} to enable query caching
for the results.
+ * <li><b>Read-Only Mode:</b> Use {@code readOnly(true)} to disable dirty
checking for loaded
+ * entities.
+ * <li><b>Fetch Mode:</b> Use {@code fetchMode("association",
FetchMode.JOIN)} to specify Eager/Lazy
+ * fetching strategies.
+ * </ul>
+ *
+ * <h2>Programmatic instantiation</h2>
+ *
+ * <p>The builder requires a {@link SessionFactory}, the target persistent
class, and the {@link
+ * org.grails.orm.hibernate.HibernateDatastore} that owns the session:
+ *
* <pre>
- * new HibernateCriteriaBuilder(clazz, sessionFactory).list {
+ * new HibernateCriteriaBuilder(Account, sessionFactory, datastore).list {
* eq("firstName", "Fred")
* }
* </pre>
*
+ * <h2>Architecture</h2>
+ *
+ * <p>Closure method calls in the DSL are dispatched through {@code
invokeMethod} → {@code
+ * CriteriaMethodInvoker} → {@link HibernateQuery}, which translates each GORM
constraint into the
+ * equivalent JPA Criteria predicate. {@link grails.gorm.DetachedCriteria} can
also be passed in
+ * place of a closure to support multi-tenant and reusable query fragments.
+ *
+ * To adjust the methods to be handled you have to extend this class, extend
CriteriaMethodInvoker
+ *
* @author Graeme Rocher
+ * @author walterduquedeestrada
+ * @see HibernateQuery
+ * @see grails.gorm.DetachedCriteria
*/
-public class HibernateCriteriaBuilder extends AbstractHibernateCriteriaBuilder
{
- /*
- * Define constants which may be used inside of criteria queries
- * to refer to standard Hibernate Type instances.
- */
- public static final Type BOOLEAN = StandardBasicTypes.BOOLEAN;
- public static final Type YES_NO = StandardBasicTypes.YES_NO;
- public static final Type BYTE = StandardBasicTypes.BYTE;
- public static final Type CHARACTER = StandardBasicTypes.CHARACTER;
- public static final Type SHORT = StandardBasicTypes.SHORT;
- public static final Type INTEGER = StandardBasicTypes.INTEGER;
- public static final Type LONG = StandardBasicTypes.LONG;
- public static final Type FLOAT = StandardBasicTypes.FLOAT;
- public static final Type DOUBLE = StandardBasicTypes.DOUBLE;
- public static final Type BIG_DECIMAL = StandardBasicTypes.BIG_DECIMAL;
- public static final Type BIG_INTEGER = StandardBasicTypes.BIG_INTEGER;
- public static final Type STRING = StandardBasicTypes.STRING;
- public static final Type NUMERIC_BOOLEAN =
StandardBasicTypes.NUMERIC_BOOLEAN;
- public static final Type TRUE_FALSE = StandardBasicTypes.TRUE_FALSE;
- public static final Type URL = StandardBasicTypes.URL;
- public static final Type TIME = StandardBasicTypes.TIME;
- public static final Type DATE = StandardBasicTypes.DATE;
- public static final Type TIMESTAMP = StandardBasicTypes.TIMESTAMP;
- public static final Type CALENDAR = StandardBasicTypes.CALENDAR;
- public static final Type CALENDAR_DATE = StandardBasicTypes.CALENDAR_DATE;
- public static final Type CLASS = StandardBasicTypes.CLASS;
- public static final Type LOCALE = StandardBasicTypes.LOCALE;
- public static final Type CURRENCY = StandardBasicTypes.CURRENCY;
- public static final Type TIMEZONE = StandardBasicTypes.TIMEZONE;
- public static final Type UUID_BINARY = StandardBasicTypes.UUID_BINARY;
- public static final Type UUID_CHAR = StandardBasicTypes.UUID_CHAR;
- public static final Type BINARY = StandardBasicTypes.BINARY;
- public static final Type WRAPPER_BINARY =
StandardBasicTypes.WRAPPER_BINARY;
- public static final Type IMAGE = StandardBasicTypes.IMAGE;
- public static final Type BLOB = StandardBasicTypes.BLOB;
- public static final Type MATERIALIZED_BLOB =
StandardBasicTypes.MATERIALIZED_BLOB;
- public static final Type CHAR_ARRAY = StandardBasicTypes.CHAR_ARRAY;
- public static final Type CHARACTER_ARRAY =
StandardBasicTypes.CHARACTER_ARRAY;
- public static final Type TEXT = StandardBasicTypes.TEXT;
- public static final Type CLOB = StandardBasicTypes.CLOB;
- public static final Type MATERIALIZED_CLOB =
StandardBasicTypes.MATERIALIZED_CLOB;
- public static final Type SERIALIZABLE = StandardBasicTypes.SERIALIZABLE;
+@Slf4j
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
+public class HibernateCriteriaBuilder extends GroovyObjectSupport implements
BuildableCriteria, ProjectionList {
+ private final SessionFactory sessionFactory;
+ private final boolean participate;
+ private final org.hibernate.query.criteria.HibernateCriteriaBuilder cb;
+ private final HibernateQuery hibernateQuery;
+ private Class<?> targetClass;
+ private CriteriaQuery<?> criteriaQuery;
+ private boolean uniqueResult = false;
- @SuppressWarnings("rawtypes")
- public HibernateCriteriaBuilder(Class targetClass, SessionFactory
sessionFactory) {
- super(targetClass, sessionFactory);
+ @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
+ private boolean scroll;
+
+ @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
+ private boolean count;
+
+ private boolean paginationEnabledList = false;
+ private int defaultFlushMode;
+
+ @SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
+ private boolean distinct = false;
+ private CriteriaMethodInvoker criteriaMethodInvoker;
+
+ @SuppressWarnings({"rawtypes", "PMD.CloseResource"})
+ public HibernateCriteriaBuilder(Class targetClass, SessionFactory
sessionFactory, HibernateDatastore datastore) {
+ this.targetClass = targetClass;
+ setDatastore(datastore);
+ this.sessionFactory = sessionFactory;
+ this.cb = sessionFactory.getCriteriaBuilder();
+ if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
+ this.participate = true;
+ } else {
+ this.participate = false;
+ org.hibernate.Session session = sessionFactory.openSession();
+ TransactionSynchronizationManager.bindResource(sessionFactory, new
SessionHolder(session));
+ }
+ HibernateSession session = (HibernateSession) datastore.connect();
+ hibernateQuery = new HibernateQuery(
+ session, (GrailsHibernatePersistentEntity)
datastore.getMappingContext().getPersistentEntity(targetClass.getName()));
setDefaultFlushMode(GrailsHibernateTemplate.FLUSH_AUTO);
+ criteriaMethodInvoker = new CriteriaMethodInvoker(this);
}
- @SuppressWarnings("rawtypes")
- public HibernateCriteriaBuilder(Class targetClass, SessionFactory
sessionFactory, boolean uniqueResult) {
- super(targetClass, sessionFactory, uniqueResult);
- setDefaultFlushMode(GrailsHibernateTemplate.FLUSH_AUTO);
+ public static final String ALIAS_SEPARATOR = ":";
+
+ private static String getFullyQualifiedColumn(String propertyName, String
alias) {
+ return (Objects.nonNull(alias) ? alias + ALIAS_SEPARATOR : "") +
propertyName;
+ }
+
+ public org.grails.datastore.mapping.query.api.Criteria exists(Closure
subquery) {
+ return exists(new
grails.gorm.DetachedCriteria(targetClass).build(subquery));
Review Comment:
- Why fully qualified class names?
- The issue with fully qualified class names are repeated many times in this
class. The same comment applies for each occurrence.
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ComponentBinder.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
Review Comment:
Align on JSpecify?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java:
##########
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.boot.spi.MetadataBuildingContext;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.OneToMany;
+
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+import
org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyEntityProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BasicCollectionElementBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalMapElementBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalOneToManyLinker;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyColumnUpdater;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionWithJoinTableBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.DependentKeyValueBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.HibernateToManyEntityOrderByBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ManyToOneElementBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.PrimaryKeyValueCreator;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.SetSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ToManyEntityMultiTenantFilterBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyInverseValuesBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.GrailsPropertyResolver;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.TableForManyCalculator;
+
+
+/** Handles the binding of collections to the Hibernate runtime meta model. */
+@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
+public class CollectionBinder {
+
+ private final MetadataBuildingContext metadataBuildingContext;
+ private final CollectionHolder collectionHolder;
+ private final ListSecondPassBinder listSecondPassBinder;
+ private final CollectionSecondPassBinder collectionSecondPassBinder;
+ final MapSecondPassBinder mapSecondPassBinder;
+ private final InFlightMetadataCollector mappings;
+ private final TableForManyCalculator tableForManyCalculator;
+
+ public void setComponentBinder(ComponentBinder componentBinder) {
+ this.collectionSecondPassBinder.setComponentBinder(componentBinder);
+ }
+
+ /** Creates a new {@link CollectionBinder} instance. */
+ public CollectionBinder(
+ MetadataBuildingContext metadataBuildingContext,
+ PersistentEntityNamingStrategy namingStrategy,
+ SimpleValueBinder simpleValueBinder,
+ EnumTypeBinder enumTypeBinder,
+ ManyToOneBinder manyToOneBinder,
+ CompositeIdentifierToManyToOneBinder
compositeIdentifierToManyToOneBinder,
+ SimpleValueColumnFetcher simpleValueColumnFetcher,
+ CollectionHolder collectionHolder,
+ InFlightMetadataCollector mappings,
+ TableForManyCalculator tableForManyCalculator) {
+ this.metadataBuildingContext = metadataBuildingContext;
+ this.collectionHolder = collectionHolder;
+ this.mappings = mappings;
+ this.tableForManyCalculator = tableForManyCalculator;
+ GrailsPropertyResolver grailsPropertyResolver = new
GrailsPropertyResolver();
+ CollectionForPropertyConfigBinder collectionForPropertyConfigBinder =
new CollectionForPropertyConfigBinder();
+ UnidirectionalOneToManyInverseValuesBinder
unidirectionalOneToManyInverseValuesBinder =
+ new
UnidirectionalOneToManyInverseValuesBinder(metadataBuildingContext);
+ SimpleValueColumnBinder simpleValueColumnBinder = new
SimpleValueColumnBinder();
+ CollectionWithJoinTableBinder collectionWithJoinTableBinder = new
CollectionWithJoinTableBinder(
Review Comment:
`var`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnConfigToColumnBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.mapping.Column;
+
+import org.grails.orm.hibernate.cfg.ColumnConfig;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+
+public class ColumnConfigToColumnBinder {
+
+ private final Dialect dialect;
+
+ public ColumnConfigToColumnBinder() {
+ this(new H2Dialect());
+ }
+
+ public ColumnConfigToColumnBinder(Dialect dialect) {
+ this.dialect = dialect;
+ }
+
+ public void bindColumnConfigToColumn(@Nonnull Column column, ColumnConfig
columnConfig, PropertyConfig mappedForm) {
+ Optional.ofNullable(columnConfig).ifPresent(config -> {
+ Optional.of(config.getLength()).filter(l -> l !=
-1).ifPresent(column::setLength);
+
+ int precision = getPrecision(config);
+
+ column.setPrecision(precision);
+
+ Optional.of(config.getScale()).filter(s -> s !=
-1).ifPresent(column::setScale);
+
+ Optional.ofNullable(config.getSqlType()).filter(s ->
!s.isEmpty()).ifPresent(column::setSqlType);
+
+ Optional.ofNullable(mappedForm)
+ .filter(mf -> !mf.isUniqueWithinGroup())
+ .ifPresent(mf -> column.setUnique(config.isUnique()));
+ });
+ }
+
+ private int getPrecision(ColumnConfig config) {
+ int precision = config.getPrecision();
+ if (precision == -1) {
Review Comment:
Won't this set precision for all column types?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnConfigToColumnBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
Review Comment:
Align on JSpecify?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionBinder.java:
##########
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.boot.spi.MetadataBuildingContext;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.OneToMany;
+
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+import
org.grails.orm.hibernate.cfg.domainbinding.collectionType.CollectionHolder;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyEntityProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BasicCollectionElementBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalMapElementBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.BidirectionalOneToManyLinker;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionKeyColumnUpdater;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.CollectionWithJoinTableBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.DependentKeyValueBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.HibernateToManyEntityOrderByBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ListSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ManyToOneElementBinder;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.MapSecondPassBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.PrimaryKeyValueCreator;
+import org.grails.orm.hibernate.cfg.domainbinding.secondpass.SetSecondPass;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.ToManyEntityMultiTenantFilterBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.secondpass.UnidirectionalOneToManyInverseValuesBinder;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.GrailsPropertyResolver;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.SimpleValueColumnFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.TableForManyCalculator;
+
+
+/** Handles the binding of collections to the Hibernate runtime meta model. */
Review Comment:
`@since`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java:
##########
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.grails.orm.hibernate.cfg.ColumnConfig;
+import org.grails.orm.hibernate.cfg.Mapping;
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateAssociation;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.CreateKeyForProps;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+
+@SuppressWarnings({"PMD.NullAssignment", "PMD.DataflowAnomalyAnalysis"})
+public class ColumnBinder {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(ColumnBinder.class);
+
+ private final ColumnNameForPropertyAndPathFetcher
columnNameForPropertyAndPathFetcher;
+ private final StringColumnConstraintsBinder stringColumnConstraintsBinder;
+ private final NumericColumnConstraintsBinder
numericColumnConstraintsBinder;
+ private final CreateKeyForProps createKeyForProps;
+ private final IndexBinder indexBinder;
+
+ /** Public constructor that accepts all collaborators. */
+ public ColumnBinder(
+ ColumnNameForPropertyAndPathFetcher
columnNameForPropertyAndPathFetcher,
+ StringColumnConstraintsBinder stringColumnConstraintsBinder,
+ NumericColumnConstraintsBinder numericColumnConstraintsBinder,
+ CreateKeyForProps createKeyForProps,
+ IndexBinder indexBinder) {
+ this.columnNameForPropertyAndPathFetcher =
columnNameForPropertyAndPathFetcher;
+ this.stringColumnConstraintsBinder = stringColumnConstraintsBinder;
+ this.numericColumnConstraintsBinder = numericColumnConstraintsBinder;
+ this.createKeyForProps = createKeyForProps;
+ this.indexBinder = indexBinder;
+ }
+
+ /** Convenience constructor for backward compatibility. */
+ public ColumnBinder(PersistentEntityNamingStrategy namingStrategy) {
+ this(
+ new ColumnNameForPropertyAndPathFetcher(
+ namingStrategy, new
DefaultColumnNameFetcher(namingStrategy), new BackticksRemover()),
+ new StringColumnConstraintsBinder(),
+ new NumericColumnConstraintsBinder(),
+ new CreateKeyForProps(new ColumnNameForPropertyAndPathFetcher(
+ namingStrategy, new
DefaultColumnNameFetcher(namingStrategy), new BackticksRemover())),
+ new IndexBinder());
+ }
+
+ /**
+ * Binds a Column instance to the Hibernate meta model
+ *
+ * @param property The Grails domain class property
+ * @param parentProperty parent property
+ * @param column The column to bind
+ * @param path the path
+ * @param table The table name
+ */
+ public void bindColumn(
+ HibernatePersistentProperty property,
+ HibernatePersistentProperty parentProperty,
+ Column column,
+ ColumnConfig cc,
+ String path,
+ Table table) {
+
+ if (cc != null) {
+ column.setComment(cc.getComment());
+ column.setDefaultValue(cc.getDefaultValue());
+ column.setCustomRead(cc.getRead());
+ column.setCustomWrite(cc.getWrite());
+ }
+
+ Class<?> userType = property.getUserType();
+ String columnName =
columnNameForPropertyAndPathFetcher.getColumnNameForPropertyAndPath(property,
path, cc);
+ if ((property instanceof HibernateAssociation assoc) && userType ==
null) {
+ // Only use conventional naming when the column has not been
explicitly mapped.
+ if (column.getName() == null) {
+ column.setName(columnName);
+ }
+ column.setNullable(assoc.isAssociationColumnNullable());
+ } else {
+ column.setName(columnName);
+ column.setNullable(property.isNullable() || (parentProperty !=
null && parentProperty.isNullable()));
+ // Use the constraints for this property to more accurately define
+ // the column's length, precision, and scale
+ Class<?> type = property.getType();
+ if (type != null && (String.class.isAssignableFrom(type) ||
byte[].class.isAssignableFrom(type))) {
+ PropertyConfig mappedForm = property.getHibernateMappedForm();
+
stringColumnConstraintsBinder.bindStringColumnConstraints(column, mappedForm);
+ } else if (type != null && Number.class.isAssignableFrom(type)) {
+ PropertyConfig mappedForm = property.getHibernateMappedForm();
+
numericColumnConstraintsBinder.bindNumericColumnConstraints(column, cc,
mappedForm);
+ }
+ }
+
+ createKeyForProps.createKeyForProps(property, path, table, columnName);
+ indexBinder.bindIndex(columnName, column, cc, table);
+
+ var owner = property.getHibernateOwner();
+ if (!owner.isRoot()) {
+ Mapping mapping = owner.getHibernateMappedForm();
+ if (mapping != null && mapping.getTablePerHierarchy()) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("[GrailsDomainBinder] Sub class property [{}]
for column name [{}] set to nullable", property.getName(), column.getName());
+ }
+ column.setNullable(true);
+ } else {
+ column.setNullable(property.isNullable());
+ }
+ }
+
+ // Apply uniqueness last to ensure it isn't overridden by downstream
binders
+ PropertyConfig mappedFormFinal = property.getHibernateMappedForm();
+ column.setUnique(mappedFormFinal.isUnique() &&
!mappedFormFinal.isUniqueWithinGroup());
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("[GrailsDomainBinder] bound property [{}] to column name
[{}] in table [{}]", property.getName(), column.getName(), table.getName());
Review Comment:
Why are we logging the class name `GrailsDomainBinder` here?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnConfigToColumnBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.mapping.Column;
+
+import org.grails.orm.hibernate.cfg.ColumnConfig;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+
+public class ColumnConfigToColumnBinder {
+
+ private final Dialect dialect;
+
+ public ColumnConfigToColumnBinder() {
+ this(new H2Dialect());
+ }
+
+ public ColumnConfigToColumnBinder(Dialect dialect) {
+ this.dialect = dialect;
+ }
+
+ public void bindColumnConfigToColumn(@Nonnull Column column, ColumnConfig
columnConfig, PropertyConfig mappedForm) {
+ Optional.ofNullable(columnConfig).ifPresent(config -> {
+ Optional.of(config.getLength()).filter(l -> l !=
-1).ifPresent(column::setLength);
+
+ int precision = getPrecision(config);
+
+ column.setPrecision(precision);
+
+ Optional.of(config.getScale()).filter(s -> s !=
-1).ifPresent(column::setScale);
+
+ Optional.ofNullable(config.getSqlType()).filter(s ->
!s.isEmpty()).ifPresent(column::setSqlType);
+
+ Optional.ofNullable(mappedForm)
+ .filter(mf -> !mf.isUniqueWithinGroup())
+ .ifPresent(mf -> column.setUnique(config.isUnique()));
+ });
+ }
+
+ private int getPrecision(ColumnConfig config) {
+ int precision = config.getPrecision();
+ if (precision == -1) {
+ // Apply dialect-specific defaults for Double/Float types if
precision is not set
+ if (dialect instanceof OracleDialect) {
+ // Oracle defaults to 126 bits or 64 depending on version/type
+ precision = 126;
+ } else {
+ // Most other databases (H2, PostgreSQL, MySQL) use 53 bits
for Double
+ // Hibernate 7 interprets this precision as decimal digits for
some dialects
+ // and converts to bits. 15 decimal digits maps to ~50-53 bits.
+ precision = 15;
+ }
+ }
Review Comment:
Are we sure this is correct?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java:
##########
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.grails.orm.hibernate.cfg.ColumnConfig;
+import org.grails.orm.hibernate.cfg.Mapping;
+import org.grails.orm.hibernate.cfg.PersistentEntityNamingStrategy;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateAssociation;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernatePersistentProperty;
+import org.grails.orm.hibernate.cfg.domainbinding.util.BackticksRemover;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.ColumnNameForPropertyAndPathFetcher;
+import org.grails.orm.hibernate.cfg.domainbinding.util.CreateKeyForProps;
+import
org.grails.orm.hibernate.cfg.domainbinding.util.DefaultColumnNameFetcher;
+
+@SuppressWarnings({"PMD.NullAssignment", "PMD.DataflowAnomalyAnalysis"})
+public class ColumnBinder {
Review Comment:
`@since`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CollectionForPropertyConfigBinder.java:
##########
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.mapping.Collection;
+
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.HibernateToManyProperty;
+
+/** The collection for property config binder class. */
Review Comment:
`@since`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnConfigToColumnBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import java.util.Optional;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.H2Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.mapping.Column;
+
+import org.grails.orm.hibernate.cfg.ColumnConfig;
+import org.grails.orm.hibernate.cfg.PropertyConfig;
+
+public class ColumnConfigToColumnBinder {
Review Comment:
`@since`?
##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ClassBinder.java:
##########
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.grails.orm.hibernate.cfg.domainbinding.binder;
+
+import jakarta.annotation.Nonnull;
+
+import org.hibernate.boot.spi.InFlightMetadataCollector;
+import org.hibernate.mapping.PersistentClass;
+
+import org.grails.orm.hibernate.cfg.Mapping;
+import
org.grails.orm.hibernate.cfg.domainbinding.hibernate.GrailsHibernatePersistentEntity;
+
+import static org.grails.orm.hibernate.cfg.GrailsHibernateUtil.unqualify;
+
+/** The class binder class. */
Review Comment:
- Improve javadoc?
- `@since`?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]