This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch merge-hibernate6 in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 760d8736153f3aa281c4435af85785e87d973b5e Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sun Jul 13 13:32:17 2025 -0500 refactor StringColumnConstraintsBinder --- .../orm/hibernate/cfg/GrailsDomainBinder.java | 54 +++------- .../StringColumnConstraintsBinder.java | 39 +++++++ .../StringColumnConstraintsBinderSpec.groovy | 116 +++++++++++++++++++++ 3 files changed, 167 insertions(+), 42 deletions(-) diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java index db87d77c68..af40c7ed71 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java @@ -40,6 +40,7 @@ import org.grails.orm.hibernate.cfg.domainbinding.ConfigureDerivedPropertiesCons import org.grails.orm.hibernate.cfg.domainbinding.IndexBinder; import org.grails.orm.hibernate.cfg.domainbinding.NamingStrategyProvider; import org.grails.orm.hibernate.cfg.domainbinding.SimpleValueBinder; +import org.grails.orm.hibernate.cfg.domainbinding.StringColumnConstraintsBinder; import org.grails.orm.hibernate.cfg.domainbinding.TypeNameProvider; import org.hibernate.FetchMode; import org.hibernate.MappingException; @@ -2809,11 +2810,16 @@ public class GrailsDomainBinder implements MetadataContributor { bindSimpleValue(grailsProp, null, simpleValue, path, propertyConfig, sessionFactoryBeanName); } - private void bindSimpleValue(PersistentProperty grailsProp, - PersistentProperty parentProperty, SimpleValue simpleValue, - String path, PropertyConfig propertyConfig, String sessionFactoryBeanName) { + private void bindSimpleValue( + PersistentProperty grailsProp + , PersistentProperty parentProperty + , SimpleValue simpleValue + , String path + , PropertyConfig propertyConfig + , String sessionFactoryBeanName + ) { setTypeForPropertyConfig(grailsProp, simpleValue, propertyConfig); - final PropertyConfig mappedForm = (PropertyConfig) grailsProp.getMapping().getMappedForm(); + final PropertyConfig mappedForm = (PropertyConfig) grailsProp.getMappedForm(); if (mappedForm != null && mappedForm.isDerived() && !(grailsProp instanceof TenantId)) { Formula formula = new Formula(); formula.setFormula(propertyConfig.getFormula()); @@ -2925,7 +2931,8 @@ public class GrailsDomainBinder implements MetadataContributor { // Use the constraints for this property to more accurately define // the column's length, precision, and scale if (String.class.isAssignableFrom(property.getType()) || byte[].class.isAssignableFrom(property.getType())) { - bindStringColumnConstraints(column, property); + final org.grails.datastore.mapping.config.Property mappedForm = getPropertyConfig(property); + new StringColumnConstraintsBinder().bindStringColumnConstraints(column, mappedForm); } if (Number.class.isAssignableFrom(property.getType())) { @@ -3120,29 +3127,6 @@ public class GrailsDomainBinder implements MetadataContributor { } - - /** - * Interrogates the specified constraints looking for any constraints that would limit the - * length of the property's value. If such constraints exist, this method adjusts the length - * of the column accordingly. - * @param column the column that corresponds to the property - * @param constrainedProperty the property's constraints - */ - private void bindStringColumnConstraints(Column column, PersistentProperty constrainedProperty) { - final org.grails.datastore.mapping.config.Property mappedForm = getPropertyConfig(constrainedProperty); - Number columnLength = mappedForm.getMaxSize(); - List<?> inListValues = mappedForm.getInList(); - if (columnLength != null) { - column.setLength(columnLength.intValue()); - } else if (inListValues != null) { - column.setLength(getMaxSize(inListValues)); - } - } - - private void bindNumericColumnConstraints(Column column, PersistentProperty constrainedProperty) { - bindNumericColumnConstraints(column, constrainedProperty, null); - } - /** * Interrogates the specified constraints looking for any constraints that would limit the * precision and/or scale of the property's value. If such constraints exist, this method adjusts @@ -3214,20 +3198,6 @@ public class GrailsDomainBinder implements MetadataContributor { return numDigits; } - /** - * @return the maximum length of the strings in the specified list - */ - private int getMaxSize(List<?> inListValues) { - int maxSize = 0; - - for (Object inListValue : inListValues) { - String value = (String) inListValue; - maxSize = Math.max(value.length(), maxSize); - } - - return maxSize; - } - private void handleUniqueConstraint(PersistentProperty property, Column column, String path, Table table, String columnName, String sessionFactoryBeanName) { final PropertyConfig mappedForm = getPropertyConfig(property); if (mappedForm.isUnique()) { diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/StringColumnConstraintsBinder.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/StringColumnConstraintsBinder.java new file mode 100644 index 0000000000..ded0a91ace --- /dev/null +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/StringColumnConstraintsBinder.java @@ -0,0 +1,39 @@ +package org.grails.orm.hibernate.cfg.domainbinding; + +import org.grails.datastore.mapping.config.Property; +import org.hibernate.mapping.Column; + +import java.util.Objects; +import java.util.Optional; + +public class StringColumnConstraintsBinder { + + + public void bindStringColumnConstraints(Column column, Property mappedForm) { + Integer number = Optional.ofNullable(mappedForm.getMaxSize()) + .map(Number::intValue) + .orElse( + getMax(mappedForm).orElse(0) + ); + if (number > 0) { + column.setLength(number); + } + + } + + private Optional<Integer> getMax(Property mappedForm) { + return Optional.ofNullable(mappedForm.getInList()) + .flatMap(list -> list.stream() + .map(this::parseInt) + .filter(Objects::nonNull) + .reduce(Integer::max)); + } + + private Integer parseInt(String value) { + try{ + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return null; + } + } +} diff --git a/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/StringColumnConstraintsBinderSpec.groovy b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/StringColumnConstraintsBinderSpec.groovy new file mode 100644 index 0000000000..45877c9cc1 --- /dev/null +++ b/grails-data-hibernate6/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/StringColumnConstraintsBinderSpec.groovy @@ -0,0 +1,116 @@ +package org.grails.orm.hibernate.cfg.domainbinding + +import org.hibernate.mapping.Column +import org.grails.datastore.mapping.config.Property +import spock.lang.Specification + +class StringColumnConstraintsBinderSpec extends Specification { + + StringColumnConstraintsBinder binder + Column column + Property mappedForm + + def setup() { + binder = new StringColumnConstraintsBinder() + column = Mock(Column) + mappedForm = Mock(Property) + } + + def "should not set column length when neither is provided"() { + given: + mappedForm.getMaxSize() >> null + mappedForm.getInList() >> null + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 0 * column.setLength(_) + } + + def "should not set column length when empty list"() { + given: + mappedForm.getMaxSize() >> null + mappedForm.getInList() >> [] + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 0 * column.setLength(_) + } + + def "should set column length when maxSize is provided"() { + given: + mappedForm.getMaxSize() >> 255 + mappedForm.getInList() >> null + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 1 * column.setLength(255) + } + + def "should set column length to longest inList value when maxSize is null"() { + given: + mappedForm.getMaxSize() >> null + mappedForm.getInList() >> ["1","2","3","4"] + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 1 * column.setLength(4) // length of "very long string" + } + + def "should set column length to longest valid int inList value when maxSize is null"() { + given: + mappedForm.getMaxSize() >> null + mappedForm.getInList() >> ["4","string",Long.MAX_VALUE.toString(), null] + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 1 * column.setLength(4) // length of "very long string" + } + + + def "should prioritize maxSize over inList when both are present"() { + given: + mappedForm.getMaxSize() >> 1 + mappedForm.getInList() >> ["3"] + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 1 * column.setLength(1) + } + + def "should handle zero maxSize"() { + given: + mappedForm.getMaxSize() >> 0 + mappedForm.getInList() >> null + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 0 * column.setLength(_) + } + + + def "should handle Number subclasses for maxSize"() { + given: + mappedForm.getMaxSize() >> 50L // Long instead of Integer + mappedForm.getInList() >> null + + when: + binder.bindStringColumnConstraints(column, mappedForm) + + then: + 1 * column.setLength(50) + } +} \ No newline at end of file
