From 5b1f0e1150ceba26ce21767c1052998ab17e5b3d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 14:12:56 +0000 Subject: [PATCH 1/7] Upgrade Hibernate dependencies from 5.6-jakarta to 6.6.48.Final - Update hibernate.version property from 5.6.15.Final to 6.6.48.Final - Change org.hibernate:hibernate-core-jakarta to org.hibernate.orm:hibernate-core - Change org.hibernate:hibernate-envers-jakarta to org.hibernate.orm:hibernate-envers - Change org.hibernate:hibernate-jcache to org.hibernate.orm:hibernate-jcache - Remove obsolete exclusions (javax.persistence-api, javax.el-api, org.osgi.core) that are no longer needed since Hibernate 6 natively uses Jakarta EE APIs - Retain necessary exclusions for dependency convergence (jakarta.activation-api, angus-activation, javax.cache:cache-api) - Update common/pom.xml to match new artifact coordinates Co-Authored-By: Arjun Mishra --- common/pom.xml | 10 +++++----- pom.xml | 38 ++++++-------------------------------- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/common/pom.xml b/common/pom.xml index 0bbfedf94c..12d06e34eb 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -142,11 +142,11 @@ - org.hibernate - hibernate-core-jakarta + org.hibernate.orm + hibernate-core - org.hibernate + org.hibernate.orm hibernate-jcache @@ -171,8 +171,8 @@ easymockclassextension - org.hibernate - hibernate-envers-jakarta + org.hibernate.orm + hibernate-envers jakarta.mail diff --git a/pom.xml b/pom.xml index 6836d3b269..e38be4ef2d 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 3.0.3-GA 2.7.4 v20240317 - 5.6.15.Final + 6.6.48.Final 6.0.0 4.0.0 2.1.1 @@ -583,15 +583,9 @@ - org.hibernate - hibernate-envers-jakarta + org.hibernate.orm + hibernate-envers ${hibernate.version} - - - org.jboss.logging - jboss-logging - - org.jboss.logging @@ -599,26 +593,10 @@ 3.4.3.Final - org.hibernate - hibernate-core-jakarta + org.hibernate.orm + hibernate-core ${hibernate.version} - - org.jboss.logging - jboss-logging - - - javax.persistence - javax.persistence-api - - - javax.el - javax.el-api - - - org.osgi - org.osgi.core - jakarta.activation jakarta.activation-api @@ -630,7 +608,7 @@ - org.hibernate + org.hibernate.orm hibernate-jcache ${hibernate.version} @@ -638,10 +616,6 @@ javax.cache cache-api - - org.hibernate - hibernate-core - From 4432d201ee724aa9622114e8bb9acd3fd2dad2fe Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 14:58:54 +0000 Subject: [PATCH 2/7] Fix Hibernate 6 API breaking changes in Java source code Adapt Java source code to Hibernate ORM 6.6.48.Final API changes: - ClassTransformer: Update transform() signature for JPA 3.2 (Exception -> RuntimeException) - SqlCommandExtractors: Replace removed SingleLineSqlCommandExtractor with ScriptSourceInput - BroadleafPostgreSQLDialect: Replace removed PostgreSQL95Dialect with PostgreSQLDialect - PostgreSQLClobTypeDescriptor: Rewrite for H6 type descriptor API - UpdateExecutor: Replace LongType/CacheImplementor with H6 BasicType/CacheTransactionSynchronization - TranslationImpl: Replace @Type(type=...) with @JdbcTypeCode(SqlTypes.LONG32VARCHAR) - HibernateMappingProvider: Replace getPropertyClosureIterator() with getPropertyClosure() - DialectHelper: Replace removed Oracle10gDialect with OracleDialect - @Type annotations (15 entity files): Replace with @JdbcTypeCode(SqlTypes.LONG32VARCHAR) - OrderDaoImpl: Use JPA_SHARED_CACHE_RETRIEVE_MODE constant - CriteriaTranslatorImpl: Replace SingleColumnType with BasicType - FieldPathBuilder: Use NodeBuilder.getDomainModel() for metamodel access - DynamicEntityDao/Impl: Replace legacy Criteria API with JPA CriteriaQuery - MapFieldsFieldMetadataProvider: Replace TypeLocatorImpl/TypeFactory with TypeConfiguration - DefaultFieldMetadataProvider: Replace getColumnIterator() with getColumns() - DynamicEntityDaoImpl: Replace getPropertyIterator() with getProperties() All 13 modules compile successfully with mvn compile -DskipTests. Co-Authored-By: Arjun Mishra --- .../cms/page/domain/PageFieldImpl.java | 5 +- .../cms/page/domain/PageItemCriteriaImpl.java | 5 +- .../cms/page/domain/PageRuleImpl.java | 5 +- .../domain/StructuredContentFieldImpl.java | 5 +- .../StructuredContentItemCriteriaImpl.java | 5 +- .../domain/StructuredContentRuleImpl.java | 5 +- .../server/dao/DynamicEntityDao.java | 8 ++- .../server/dao/DynamicEntityDaoImpl.java | 13 ++-- .../DefaultFieldMetadataProvider.java | 8 +-- .../MapFieldsFieldMetadataProvider.java | 26 +++++--- .../criteria/CriteriaTranslatorImpl.java | 4 +- .../module/criteria/FieldPathBuilder.java | 17 +++--- .../dialect/BroadleafPostgreSQLDialect.java | 22 ++++--- .../dialect/PostgreSQLClobTypeDescriptor.java | 60 ++++--------------- .../QueryConfigurationClassTransformer.java | 6 +- .../cache/RemoveCacheClassTransformer.java | 6 +- .../AlterTableNameClassTransformer.java | 6 +- .../convert/EntityMarkerClassTransformer.java | 6 +- ...ingleTableInheritanceClassTransformer.java | 6 +- .../copy/AnnotationsCopyClassTransformer.java | 6 +- ...ionalFieldAnnotationsClassTransformer.java | 8 +-- .../jpa/copy/DirectCopyClassTransformer.java | 6 +- .../jpa/copy/NullClassTransformer.java | 4 +- .../OptionalDirectCopyClassTransformer.java | 6 +- .../RemoveAnnotationClassTransformer.java | 6 +- ...ibernateEnhancingClassTransformerImpl.java | 4 +- .../common/i18n/domain/TranslationImpl.java | 6 +- .../common/util/DialectHelper.java | 4 +- .../common/util/UpdateExecutor.java | 45 +++++--------- .../util/dao/HibernateMappingProvider.java | 10 ++-- ...DemoHsqlSingleLineSqlCommandExtractor.java | 12 ++-- ...moOracleSingleLineSqlCommandExtractor.java | 12 ++-- ...PostgresSingleLineSqlCommandExtractor.java | 13 ++-- ...qlServerSingleLineSqlCommandExtractor.java | 14 ++--- .../core/catalog/domain/CategoryImpl.java | 5 +- .../catalog/domain/ProductOptionImpl.java | 5 +- .../core/catalog/domain/SkuFeeImpl.java | 5 +- .../core/catalog/domain/SkuImpl.java | 5 +- .../offer/domain/OfferItemCriteriaImpl.java | 5 +- .../core/offer/domain/OfferRuleImpl.java | 5 +- .../core/order/dao/OrderDaoImpl.java | 2 +- .../order/domain/FulfillmentOptionImpl.java | 5 +- .../domain/PaymentTransactionImpl.java | 8 +-- .../core/domain/CustomerPaymentImpl.java | 6 +- 44 files changed, 203 insertions(+), 222 deletions(-) diff --git a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageFieldImpl.java b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageFieldImpl.java index dbc0d87282..83b5a6ac07 100644 --- a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageFieldImpl.java +++ b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageFieldImpl.java @@ -27,8 +27,9 @@ import org.broadleafcommerce.common.presentation.AdminPresentation; import org.broadleafcommerce.openadmin.audit.AdminAuditableListener; import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -86,7 +87,7 @@ public class PageFieldImpl implements PageField, ProfileEntity { @Column(name = "LOB_VALUE", length = Integer.MAX_VALUE-1) @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @AdminPresentation protected String lobValue; diff --git a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageItemCriteriaImpl.java b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageItemCriteriaImpl.java index 46cc1e5fd8..b7ce451c8f 100644 --- a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageItemCriteriaImpl.java +++ b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageItemCriteriaImpl.java @@ -27,8 +27,9 @@ import org.broadleafcommerce.common.presentation.AdminPresentationClass; import org.broadleafcommerce.common.presentation.client.VisibilityEnum; import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -80,7 +81,7 @@ public class PageItemCriteriaImpl implements PageItemCriteria, ProfileEntity { protected Integer quantity; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "ORDER_ITEM_MATCH_RULE", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "PageItemCriteriaImpl_Order_Item_Match_Rule", group = "PageItemCriteriaImpl_Description", visibility = VisibilityEnum.HIDDEN_ALL) diff --git a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageRuleImpl.java b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageRuleImpl.java index 4894c9cd28..898c84a2fa 100644 --- a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageRuleImpl.java +++ b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/page/domain/PageRuleImpl.java @@ -24,8 +24,9 @@ import org.broadleafcommerce.common.extensibility.jpa.copy.DirectCopyTransformTypes; import org.broadleafcommerce.common.extensibility.jpa.copy.ProfileEntity; import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -66,7 +67,7 @@ public class PageRuleImpl implements PageRule, ProfileEntity { protected Long id; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "MATCH_RULE", length = Integer.MAX_VALUE - 1) protected String matchRule; diff --git a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentFieldImpl.java b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentFieldImpl.java index da5a4e9d8a..404344b944 100644 --- a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentFieldImpl.java +++ b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentFieldImpl.java @@ -26,8 +26,9 @@ import org.broadleafcommerce.common.presentation.AdminPresentation; import org.broadleafcommerce.openadmin.audit.AdminAuditableListener; import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -80,7 +81,7 @@ public class StructuredContentFieldImpl implements StructuredContentField, Profi @AdminPresentation @Column (name = "LOB_VALUE", length = Integer.MAX_VALUE - 1) @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) protected String lobValue; @Override diff --git a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentItemCriteriaImpl.java b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentItemCriteriaImpl.java index bed84a5b37..73d9eaea32 100644 --- a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentItemCriteriaImpl.java +++ b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentItemCriteriaImpl.java @@ -27,10 +27,11 @@ import org.broadleafcommerce.common.presentation.AdminPresentationClass; import org.broadleafcommerce.common.presentation.client.VisibilityEnum; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -86,7 +87,7 @@ public class StructuredContentItemCriteriaImpl protected Integer quantity; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "ORDER_ITEM_MATCH_RULE", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "StructuredContentItemCriteriaImpl_Order_Item_Match_Rule", group = "StructuredContentItemCriteriaImpl_Description", diff --git a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentRuleImpl.java b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentRuleImpl.java index f33c7a4100..76de115b44 100644 --- a/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentRuleImpl.java +++ b/admin/broadleaf-contentmanagement-module/src/main/java/org/broadleafcommerce/cms/structure/domain/StructuredContentRuleImpl.java @@ -24,10 +24,11 @@ import org.broadleafcommerce.common.extensibility.jpa.copy.DirectCopyTransformTypes; import org.broadleafcommerce.common.extensibility.jpa.copy.ProfileEntity; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -69,7 +70,7 @@ public class StructuredContentRuleImpl implements StructuredContentRule, Profile protected Long id; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "MATCH_RULE", length = Integer.MAX_VALUE - 1) protected String matchRule; diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDao.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDao.java index d2f61d1119..d7bf91416b 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDao.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDao.java @@ -28,7 +28,6 @@ import org.broadleafcommerce.openadmin.dto.TabMetadata; import org.broadleafcommerce.openadmin.server.dao.provider.metadata.FieldMetadataProvider; import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager; -import org.hibernate.Criteria; import org.hibernate.mapping.PersistentClass; import org.hibernate.type.Type; @@ -119,7 +118,12 @@ public interface DynamicEntityDao { List getPropertyNames(Class entityClass); - Criteria createCriteria(Class entityClass); + /** + * @deprecated Legacy Hibernate Criteria API was removed in Hibernate 6. + * Use JPA CriteriaQuery via EntityManager.getCriteriaBuilder() instead. + */ + @Deprecated + jakarta.persistence.criteria.CriteriaQuery createCriteria(Class entityClass); Field[] getAllFields(Class targetClass); diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java index afd9020624..5594232445 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java @@ -49,7 +49,6 @@ import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager; import org.broadleafcommerce.openadmin.server.service.persistence.validation.FieldNamePropertyValidator; import org.broadleafcommerce.openadmin.server.service.type.MetadataProviderResponse; -import org.hibernate.Criteria; import org.hibernate.MappingException; import org.hibernate.Session; import org.hibernate.mapping.PersistentClass; @@ -158,8 +157,12 @@ public void setApplicationContext(ApplicationContext applicationContext) throws } @Override - public Criteria createCriteria(Class entityClass) { - return getStandardEntityManager().unwrap(Session.class).createCriteria(entityClass); + @Deprecated + public CriteriaQuery createCriteria(Class entityClass) { + CriteriaBuilder cb = getStandardEntityManager().getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(entityClass); + cq.from(entityClass); + return cq; } @Override @@ -1101,12 +1104,10 @@ protected Map getPropertiesForEntityClass( propertyTypes.add(idType); PersistentClass persistentClass = getPersistentClass(targetClass.getName()); - Iterator testIter = persistentClass.getPropertyIterator(); List propertyList = new ArrayList<>(); //check the properties for problems - while (testIter.hasNext()) { - Property property = (Property) testIter.next(); + for (Property property : persistentClass.getProperties()) { if (property.getName().contains(".")) { throw new IllegalArgumentException("Properties from entities that utilize a period character ('.') in their name are incompatible with this system. The property name in question is: (" + property.getName() + ") from the class: (" + targetClass.getName() + ")"); } diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/DefaultFieldMetadataProvider.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/DefaultFieldMetadataProvider.java index 6636a81601..f017dc96ee 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/DefaultFieldMetadataProvider.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/DefaultFieldMetadataProvider.java @@ -173,15 +173,15 @@ public MetadataProviderResponse addMetadataFromMappingData( Column column = null; for (Property property : addMetadataFromMappingDataRequest.getComponentProperties()) { if (property.getName().equals(addMetadataFromMappingDataRequest.getPropertyName())) { - Object columnObject = property.getColumnIterator().next(); - if (columnObject instanceof Column) { - column = (Column) columnObject; + java.util.List columns = property.getColumns(); + if (!columns.isEmpty() && columns.get(0) instanceof Column) { + column = columns.get(0); } break; } } if (column != null) { - fieldMetadata.setLength(column.getLength()); + fieldMetadata.setLength(column.getLength() != null ? column.getLength().intValue() : null); fieldMetadata.setScale(column.getScale()); fieldMetadata.setPrecision(column.getPrecision()); fieldMetadata.setRequired(!column.isNullable()); diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java index b6513f42f7..4ab0600fd0 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java @@ -35,10 +35,8 @@ import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.OverrideViaXmlRequest; import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager; import org.broadleafcommerce.openadmin.server.service.type.MetadataProviderResponse; -import org.hibernate.internal.TypeLocatorImpl; +import org.hibernate.type.BasicType; import org.hibernate.type.Type; -import org.hibernate.type.TypeFactory; -import org.hibernate.type.TypeResolver; import org.hibernate.type.spi.TypeConfiguration; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -126,20 +124,29 @@ public MetadataProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTyp for (Map.Entry entry : addMetadataFromFieldTypeRequest.getPresentationAttributes().entrySet()) { if (entry.getKey().startsWith(addMetadataFromFieldTypeRequest.getRequestedPropertyName() + FieldManager.MAPFIELDSEPARATOR)) { TypeConfiguration typeConfiguration = new TypeConfiguration(); - TypeFactory typeFactory = new TypeFactory(typeConfiguration); - TypeLocatorImpl typeLocator = new TypeLocatorImpl(new TypeResolver(typeConfiguration, typeFactory)); Type myType = null; //first, check if an explicit type was declared String valueClass = ((BasicFieldMetadata) entry.getValue()).getMapFieldValueClass(); if (valueClass != null) { - myType = typeLocator.entity(valueClass); + try { + Class valueJavaType = Class.forName(valueClass); + BasicType resolved = typeConfiguration.getBasicTypeForJavaType(valueJavaType); + if (resolved != null) { + myType = resolved; + } + } catch (ClassNotFoundException ex) { + // Not a basic type - try as entity below + } } if (myType == null) { SupportedFieldType fieldType = ((BasicFieldMetadata) entry.getValue()).getExplicitFieldType(); Class basicJavaType = getBasicJavaType(fieldType); if (basicJavaType != null) { - myType = typeLocator.basic(basicJavaType); + BasicType resolved = typeConfiguration.getBasicTypeForJavaType(basicJavaType); + if (resolved != null) { + myType = resolved; + } } } if (myType == null) { @@ -149,7 +156,10 @@ public MetadataProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTyp Class clazz = (Class) pType.getActualTypeArguments()[1]; Class[] entities = addMetadataFromFieldTypeRequest.getDynamicEntityDao().getAllPolymorphicEntitiesFromCeiling(clazz); if (!ArrayUtils.isEmpty(entities)) { - myType = typeLocator.entity(entities[entities.length-1]); + BasicType resolved = typeConfiguration.getBasicTypeForJavaType(entities[entities.length-1]); + if (resolved != null) { + myType = resolved; + } } } } diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/CriteriaTranslatorImpl.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/CriteriaTranslatorImpl.java index db7dd31699..846b59fe2e 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/CriteriaTranslatorImpl.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/CriteriaTranslatorImpl.java @@ -26,7 +26,7 @@ import org.broadleafcommerce.openadmin.server.security.remote.SecurityVerifier; import org.broadleafcommerce.openadmin.server.security.service.RowLevelSecurityService; import org.broadleafcommerce.openadmin.server.service.persistence.module.EmptyFilterValues; -import org.hibernate.type.SingleColumnType; +import org.hibernate.type.BasicType; import org.springframework.stereotype.Service; import java.io.Serializable; @@ -133,7 +133,7 @@ public TypedQuery translateQuery( if (idMetaData != null) { Object idFldName = idMetaData.get("name"); Object type = idMetaData.get("type"); - if ((idFldName instanceof String) && (type instanceof SingleColumnType)) { + if ((idFldName instanceof String) && (type instanceof BasicType)) { criteria.orderBy(criteriaBuilder.asc(original.get((String) idFldName))); } } diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java index fb762378b6..96ed3bd961 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java @@ -20,9 +20,7 @@ import org.apache.commons.lang3.StringUtils; import org.broadleafcommerce.common.util.dao.DynamicDaoHelper; import org.broadleafcommerce.common.util.dao.DynamicDaoHelperImpl; -import org.hibernate.internal.SessionFactoryImpl; -import org.hibernate.query.criteria.internal.CriteriaBuilderImpl; -import org.hibernate.query.criteria.internal.path.PluralAttributePath; +import org.hibernate.query.sqm.NodeBuilder; import java.util.ArrayList; import java.util.List; @@ -35,6 +33,7 @@ import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import jakarta.persistence.metamodel.Attribute; +import jakarta.persistence.metamodel.EntityType; import jakarta.persistence.metamodel.ManagedType; import jakarta.persistence.metamodel.Metamodel; @@ -57,7 +56,8 @@ public FieldPath getFieldPath(From root, String fullPropertyName) { checkPiece: { if (j == 0) { Path path = root.get(piece); - if (path instanceof PluralAttributePath) { + if (((EntityType) root.getModel()).getPluralAttributes().stream() + .anyMatch(a -> a.getName().equals(piece))) { associationPath.add(piece); break checkPiece; } @@ -98,8 +98,8 @@ public Path getPath(From root, FieldPath fieldPath, final CriteriaBuilder builde // We weren't able to resolve the requested piece, likely because it's in a polymoprhic version // of the path we're currently on. Let's see if there's any polymoprhic version of our class to // use instead. - SessionFactoryImpl em = ((CriteriaBuilderImpl) builder).getEntityManagerFactory(); - Metamodel mm = em.getMetamodel(); + // In Hibernate 6, CriteriaBuilder implements NodeBuilder which provides getDomainModel() + Metamodel mm = ((NodeBuilder) builder).getDomainModel(); boolean found = false; Class[] polyClasses = dynamicDaoHelper.getAllPolymorphicEntitiesFromCeiling( @@ -127,7 +127,10 @@ public Path getPath(From root, FieldPath fieldPath, final CriteriaBuilder builde } } - if (path.getParentPath() != null && path.getParentPath().getJavaType().isAnnotationPresent(Embeddable.class) && path instanceof PluralAttributePath) { + final String currentPiece = myFieldPath.getTargetPropertyPieces().get(i); + if (path.getParentPath() != null && path.getParentPath().getJavaType().isAnnotationPresent(Embeddable.class) + && ((EntityType) root.getModel()).getPluralAttributes().stream() + .anyMatch(a -> a.getName().equals(currentPiece))) { //We need a workaround for this problem until it is resolved in Hibernate (loosely related to and likely resolved by https://hibernate.atlassian.net/browse/HHH-8802) //We'll throw a specialized exception (and handle in an alternate flow for calls from BasicPersistenceModule) throw new CriteriaConversionException(String.format("Unable to create a JPA criteria Path through an @Embeddable object to a collection that resides therein (%s)", fieldPath.getTargetProperty()), fieldPath); diff --git a/common/src/main/java/org/broadleafcommerce/common/dialect/BroadleafPostgreSQLDialect.java b/common/src/main/java/org/broadleafcommerce/common/dialect/BroadleafPostgreSQLDialect.java index 19be4d36da..1ab519e6a0 100644 --- a/common/src/main/java/org/broadleafcommerce/common/dialect/BroadleafPostgreSQLDialect.java +++ b/common/src/main/java/org/broadleafcommerce/common/dialect/BroadleafPostgreSQLDialect.java @@ -17,10 +17,11 @@ */ package org.broadleafcommerce.common.dialect; -import org.hibernate.dialect.PostgreSQL95Dialect; -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; - -import java.sql.Types; +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.descriptor.jdbc.ClobJdbcType; +import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; /** * This custom dialect will treat all Clob types as if they contain a string instead of an OID. @@ -28,20 +29,17 @@ * https://github.com/hibernate/hibernate-orm/wiki/Migration-Guide---5.2#changes-to-how-clob-values-are-processed-using-postgresql81dialect-and-its-subclasses * */ -public class BroadleafPostgreSQLDialect extends PostgreSQL95Dialect { +public class BroadleafPostgreSQLDialect extends PostgreSQLDialect { public BroadleafPostgreSQLDialect() { super(); - registerColumnType(Types.CLOB, "text"); } @Override - public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { - if (sqlCode == Types.CLOB) { - return new PostgreSQLClobTypeDescriptor(); - } - - return super.getSqlTypeDescriptorOverride(sqlCode); + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + super.contributeTypes(typeContributions, serviceRegistry); + JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeRegistry(); + jdbcTypeRegistry.addDescriptor(java.sql.Types.CLOB, ClobJdbcType.STRING_BINDING); } } diff --git a/common/src/main/java/org/broadleafcommerce/common/dialect/PostgreSQLClobTypeDescriptor.java b/common/src/main/java/org/broadleafcommerce/common/dialect/PostgreSQLClobTypeDescriptor.java index 55416be5f2..373cea5844 100644 --- a/common/src/main/java/org/broadleafcommerce/common/dialect/PostgreSQLClobTypeDescriptor.java +++ b/common/src/main/java/org/broadleafcommerce/common/dialect/PostgreSQLClobTypeDescriptor.java @@ -17,55 +17,21 @@ */ package org.broadleafcommerce.common.dialect; -import org.hibernate.type.descriptor.ValueExtractor; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.sql.BasicBinder; -import org.hibernate.type.descriptor.sql.BasicExtractor; -import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; +import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.VarcharJdbcType; -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -public class PostgreSQLClobTypeDescriptor extends ClobTypeDescriptor { - @Override - public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { - return new BasicExtractor(javaTypeDescriptor, this) { - @Override - protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap(rs.getString(name), options); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) - throws SQLException { - return javaTypeDescriptor.wrap(statement.getString(index), options); - } - - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) - throws SQLException { - return javaTypeDescriptor.wrap(statement.getString(name), options); - } - }; - } +/** + * In Hibernate 6, CLOB handling for PostgreSQL uses string binding by default. + * This class is retained for backward compatibility but delegates to the built-in + * {@link VarcharJdbcType} descriptor, treating CLOBs as simple strings. + * + * @deprecated Use {@link VarcharJdbcType#INSTANCE} directly instead. + */ +@Deprecated +public class PostgreSQLClobTypeDescriptor { - @Override - public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicBinder(javaTypeDescriptor, this) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) - throws SQLException { - st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options)); - } + public static final JdbcType INSTANCE = VarcharJdbcType.INSTANCE; - @Override - protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) - throws SQLException { - st.setString(name, javaTypeDescriptor.unwrap(value, String.class, options)); - } - }; + private PostgreSQLClobTypeDescriptor() { } } diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/QueryConfigurationClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/QueryConfigurationClassTransformer.java index 2d3bb31891..e59757ef4a 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/QueryConfigurationClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/QueryConfigurationClassTransformer.java @@ -23,7 +23,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; @@ -89,7 +89,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { if (className == null || isExecuted) { return null; } @@ -121,7 +121,7 @@ public byte[] transform( return bos.toByteArray(); } catch (Exception e) { e.printStackTrace(); - throw new IllegalClassFormatException("Unable to convert " + convertedClassName + throw new TransformerException("Unable to convert " + convertedClassName + " to a SingleTable inheritance strategy: " + e.getMessage()); } } else { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/cache/RemoveCacheClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/cache/RemoveCacheClassTransformer.java index 10e9fd1e5d..3bb4d079a8 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/cache/RemoveCacheClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/cache/RemoveCacheClassTransformer.java @@ -28,7 +28,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import java.io.ByteArrayInputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Iterator; @@ -103,7 +103,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { @@ -144,7 +144,7 @@ public byte[] transform( error.printStackTrace(); throw error; } catch (Exception e) { - throw new IllegalClassFormatException("Unable to transform class"); + throw new TransformerException("Unable to transform class"); } finally { if (clazz != null) { try { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/AlterTableNameClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/AlterTableNameClassTransformer.java index 35e2d100c1..1c60be800f 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/AlterTableNameClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/AlterTableNameClassTransformer.java @@ -26,7 +26,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.Iterator; import java.util.List; @@ -110,7 +110,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null || StringUtils.isBlank(getTargetedClass()) || StringUtils.isBlank(getTableName())) { return null; @@ -139,7 +139,7 @@ public byte[] transform( } catch (Exception ex) { ex.printStackTrace(); - throw new IllegalClassFormatException("Unable to convert " + convertedClassName + throw new TransformerException("Unable to convert " + convertedClassName + " to a SingleTable inheritance strategy: " + ex.getMessage()); } } diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/EntityMarkerClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/EntityMarkerClassTransformer.java index a6e8d0ceea..7b7aeb91dc 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/EntityMarkerClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/EntityMarkerClassTransformer.java @@ -25,7 +25,7 @@ import java.io.ByteArrayInputStream; import java.io.DataInputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.HashSet; @@ -70,7 +70,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { return null; @@ -103,7 +103,7 @@ public byte[] transform( } } catch (Exception e) { LOG.error("An error has occurred ", e); - throw new IllegalClassFormatException("Unable to mark " + convertedClassName + " as transformed."); + throw new TransformerException("Unable to mark " + convertedClassName + " as transformed."); } // We don't need to transform anything, so we'll return null diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/inheritance/SingleTableInheritanceClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/inheritance/SingleTableInheritanceClassTransformer.java index 7efe95e6f1..c7d36822d5 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/inheritance/SingleTableInheritanceClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/convert/inheritance/SingleTableInheritanceClassTransformer.java @@ -28,7 +28,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Iterator; @@ -97,7 +97,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { return null; @@ -174,7 +174,7 @@ public byte[] transform( return bos.toByteArray(); } catch (Exception ex) { ex.printStackTrace(); - throw new IllegalClassFormatException("Unable to convert " + convertedClassName + throw new TransformerException("Unable to convert " + convertedClassName + " to a SingleTable inheritance strategy: " + ex.getMessage()); } } else { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/AnnotationsCopyClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/AnnotationsCopyClassTransformer.java index 8801ac6063..691b644dec 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/AnnotationsCopyClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/AnnotationsCopyClassTransformer.java @@ -24,7 +24,7 @@ import org.broadleafcommerce.common.logging.SupportLogger; import java.io.ByteArrayInputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.HashMap; @@ -73,7 +73,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { return null; @@ -137,7 +137,7 @@ public byte[] transform( xformKey, StringUtils.join(xformVals, ","))); return clazz.toBytecode(); } catch (Exception e) { - throw new IllegalClassFormatException("Unable to transform class"); + throw new TransformerException("Unable to transform class"); } finally { if (clazz != null) { clazz.detach(); diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/ConditionalFieldAnnotationsClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/ConditionalFieldAnnotationsClassTransformer.java index 0400d14b1b..9c962ece9e 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/ConditionalFieldAnnotationsClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/ConditionalFieldAnnotationsClassTransformer.java @@ -24,7 +24,7 @@ import org.broadleafcommerce.common.weave.ConditionalFieldAnnotationCopyTransformersManager; import java.io.ByteArrayInputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Properties; @@ -72,7 +72,7 @@ public ConditionalFieldAnnotationsClassTransformer(String moduleName) { * @param protectionDomain * @param classfileBuffer * @return - * @throws IllegalClassFormatException + * @throws TransformerException */ @Override public byte[] transform( @@ -81,7 +81,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { @@ -168,7 +168,7 @@ public byte[] transform( error.printStackTrace(); throw error; } catch (Exception e) { - throw new IllegalClassFormatException("Unable to transform class"); + throw new TransformerException("Unable to transform class"); } finally { if (clazz != null) { try { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/DirectCopyClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/DirectCopyClassTransformer.java index cfb115d2e2..39eaa36a54 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/DirectCopyClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/DirectCopyClassTransformer.java @@ -28,7 +28,7 @@ import org.broadleafcommerce.common.weave.ConditionalDirectCopyTransformersManager; import java.io.ByteArrayInputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; @@ -106,7 +106,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { @@ -333,7 +333,7 @@ public byte[] transform( error.printStackTrace(); throw error; } catch (Exception e) { - throw new IllegalClassFormatException("Unable to transform class"); + throw new TransformerException("Unable to transform class"); } finally { if (clazz != null) { try { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/NullClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/NullClassTransformer.java index 689a53975a..cf590f95b0 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/NullClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/NullClassTransformer.java @@ -19,7 +19,7 @@ import org.broadleafcommerce.common.extensibility.jpa.convert.BroadleafClassTransformer; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.Properties; @@ -45,7 +45,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { return null; } diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/OptionalDirectCopyClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/OptionalDirectCopyClassTransformer.java index b8cdd65e6f..ad3e24fce9 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/OptionalDirectCopyClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/OptionalDirectCopyClassTransformer.java @@ -22,7 +22,7 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; @@ -56,7 +56,7 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { * @param protectionDomain * @param classfileBuffer * @return - * @throws IllegalClassFormatException + * @throws TransformerException */ @Override public byte[] transform( @@ -65,7 +65,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { Boolean shouldProceed; try { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/RemoveAnnotationClassTransformer.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/RemoveAnnotationClassTransformer.java index 2e16b46ba5..f642aea1b4 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/RemoveAnnotationClassTransformer.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/copy/RemoveAnnotationClassTransformer.java @@ -26,7 +26,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import java.io.ByteArrayInputStream; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Iterator; @@ -77,7 +77,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { // Lambdas and anonymous methods in Java 8 do not have a class name defined and so no transformation should be done if (className == null) { @@ -120,7 +120,7 @@ public byte[] transform( error.printStackTrace(); throw error; } catch (Exception e) { - throw new IllegalClassFormatException("Unable to transform class"); + throw new TransformerException("Unable to transform class"); } finally { if (clazz != null) { try { diff --git a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/hibernate/BroadleafHibernateEnhancingClassTransformerImpl.java b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/hibernate/BroadleafHibernateEnhancingClassTransformerImpl.java index b6b48116c4..35dd486362 100644 --- a/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/hibernate/BroadleafHibernateEnhancingClassTransformerImpl.java +++ b/common/src/main/java/org/broadleafcommerce/common/extensibility/jpa/hibernate/BroadleafHibernateEnhancingClassTransformerImpl.java @@ -21,7 +21,7 @@ import org.hibernate.bytecode.enhance.spi.EnhancementContext; import org.hibernate.jpa.internal.enhance.EnhancingClassTransformerImpl; -import java.lang.instrument.IllegalClassFormatException; +import jakarta.persistence.spi.TransformerException; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.List; @@ -46,7 +46,7 @@ public byte[] transform( Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer - ) throws IllegalClassFormatException { + ) throws TransformerException { String convertedClassName = className.replace('/', '.'); boolean isValidPattern = true; List matchedPatterns = new ArrayList(); diff --git a/common/src/main/java/org/broadleafcommerce/common/i18n/domain/TranslationImpl.java b/common/src/main/java/org/broadleafcommerce/common/i18n/domain/TranslationImpl.java index 1680795ac4..59b2e1f875 100644 --- a/common/src/main/java/org/broadleafcommerce/common/i18n/domain/TranslationImpl.java +++ b/common/src/main/java/org/broadleafcommerce/common/i18n/domain/TranslationImpl.java @@ -35,8 +35,6 @@ import org.hibernate.annotations.Index; import org.hibernate.annotations.Parameter; import org.hibernate.annotations.Table; -import org.hibernate.annotations.Type; - import java.io.Serializable; import jakarta.persistence.Column; @@ -46,6 +44,8 @@ import jakarta.persistence.Inheritance; import jakarta.persistence.InheritanceType; import jakarta.persistence.Lob; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; @Entity @Inheritance(strategy = InheritanceType.JOINED) @@ -95,7 +95,7 @@ public class TranslationImpl implements Serializable, Translation { @Column(name = "TRANSLATED_VALUE", length = Integer.MAX_VALUE - 1) @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @AdminPresentation(friendlyName = "TranslationImpl_TranslatedValue", prominent = true, requiredOverride = RequiredOverride.REQUIRED) protected String translatedValue; diff --git a/common/src/main/java/org/broadleafcommerce/common/util/DialectHelper.java b/common/src/main/java/org/broadleafcommerce/common/util/DialectHelper.java index b1764081fb..1881219893 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/DialectHelper.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/DialectHelper.java @@ -21,7 +21,7 @@ import org.hibernate.Session; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.Oracle10gDialect; +import org.hibernate.dialect.OracleDialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -56,7 +56,7 @@ public boolean isOracle() { public boolean isOracle(EntityManager em) { //This should handle other Oracle dialects as well, since they derive from Oracle8iDialect Dialect dialect = getHibernateDialect(em); - return Oracle10gDialect.class.isAssignableFrom(dialect.getClass()); + return OracleDialect.class.isAssignableFrom(dialect.getClass()); } public boolean isPostgreSql() { diff --git a/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java b/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java index 9e8a8932a3..2d2a06f701 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java @@ -19,18 +19,10 @@ import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.StringUtils; -import org.broadleafcommerce.common.util.dao.HibernateMappingProvider; import org.hibernate.FlushMode; import org.hibernate.Session; -import org.hibernate.cache.spi.UpdateTimestampsCache; -import org.hibernate.engine.spi.CacheImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.mapping.PersistentClass; import org.hibernate.query.NativeQuery; -import org.hibernate.type.LongType; -import org.hibernate.type.Type; - -import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -72,30 +64,30 @@ public class UpdateExecutor { * @param em The entity manager to use for the persistence operation * @param template the overall update sql template. The IN clause parameter should be written using 'IN (%s)'. * @param params any other params that are present in the sql template, other than the IN clause. Should be written using '?'. Should be in order. Can be null. - * @param types the {@link org.hibernate.type.Type} instances that identify the types for the params. Should be in order and match the length of params. Can be null. + * @param types the types are no longer used in Hibernate 6 - parameter types are inferred. This parameter is retained for API compatibility. * @param ids the ids to include in the IN clause. * @return the total number of records updated in the database */ @Deprecated - public static int executeUpdateQuery(EntityManager em, String template, Object[] params, Type[] types, List ids) { + public static int executeUpdateQuery(EntityManager em, String template, Object[] params, Object[] types, List ids) { int response = 0; List runs = buildRuns(ids); for (Long[] run : runs) { String queryString = String.format(template, buildInClauseTemplate(run.length)); - NativeQuery query = em.unwrap(Session.class).createSQLQuery(queryString); + NativeQuery query = em.unwrap(Session.class).createNativeQuery(queryString); int counter = 1; if (!ArrayUtils.isEmpty(params)) { for (Object param : params) { - query.setParameter(counter, param, types[counter - 1]); + query.setParameter(counter, param); counter++; } } for (Long id : run) { - query.setParameter(counter, id, LongType.INSTANCE); + query.setParameter(counter, id); counter++; } FlushMode mode = em.unwrap(Session.class).getHibernateFlushMode(); - em.unwrap(Session.class).setFlushMode(FlushMode.MANUAL); + em.unwrap(Session.class).setHibernateFlushMode(FlushMode.MANUAL); try { response += query.executeUpdate(); } finally { @@ -116,16 +108,16 @@ public static int executeUpdateQuery(EntityManager em, String template, Object[] * @param template the overall update sql template. The IN clause parameter should be written using 'IN (%s)'. * @param tableSpace optionally provide the table being impacted by this query. This value allows Hibernate to limit the scope of cache region invalidation. Otherwise, if left null, Hibernate will invalidate every cache region, which is generally not desirable. An empty String can be used to signify that no region should be invalidated. * @param params any other params that are present in the sql template, other than the IN clause. Should be written using '?'. Should be in order. Can be null. - * @param types the {@link org.hibernate.type.Type} instances that identify the types for the params. Should be in order and match the length of params. Can be null. + * @param types the types are no longer used in Hibernate 6 - parameter types are inferred. This parameter is retained for API compatibility. * @param ids the ids to include in the IN clause. * @return the total number of records updated in the database */ - public static int executeUpdateQuery(EntityManager em, String template, String tableSpace, Object[] params, Type[] types, List ids) { + public static int executeUpdateQuery(EntityManager em, String template, String tableSpace, Object[] params, Object[] types, List ids) { int response = 0; List runs = buildRuns(ids); for (Long[] run : runs) { String queryString = String.format(template, buildInClauseTemplate(run.length)); - NativeQuery query = em.unwrap(Session.class).createSQLQuery(queryString); + NativeQuery query = em.unwrap(Session.class).createNativeQuery(queryString); //only check for null - an empty string is a valid value for tableSpace if (tableSpace != null) { query.addSynchronizedQuerySpace(tableSpace); @@ -133,20 +125,20 @@ public static int executeUpdateQuery(EntityManager em, String template, String t int counter = 1; if (!ArrayUtils.isEmpty(params)) { for (Object param : params) { - query.setParameter(counter, param, types[counter - 1]); + query.setParameter(counter, param); counter++; } } for (Long id : run) { - query.setParameter(counter, id, LongType.INSTANCE); + query.setParameter(counter, id); counter++; } FlushMode mode = em.unwrap(Session.class).getHibernateFlushMode(); - em.unwrap(Session.class).setFlushMode(FlushMode.MANUAL); + em.unwrap(Session.class).setHibernateFlushMode(FlushMode.MANUAL); try { response += query.executeUpdate(); } finally { - em.unwrap(Session.class).setFlushMode(mode); + em.unwrap(Session.class).setHibernateFlushMode(mode); } } return response; @@ -160,17 +152,12 @@ public static int executeUpdateQuery(EntityManager em, String template, String t */ public static void executeTargetedCacheInvalidation(EntityManager em, Class entityType, List ids) { SharedSessionContractImplementor session = em.unwrap(SharedSessionContractImplementor.class); - CacheImplementor hibernateCache = session.getFactory().getCache(); + org.hibernate.Cache hibernateCache = session.getFactory().getCache(); for (Long id : ids) { - hibernateCache.evictEntity(entityType, id); + hibernateCache.evictEntityData(entityType, id); } //update the timestamp cache for the table so that queries will be refreshed - PersistentClass metadata = HibernateMappingProvider.getMapping(entityType.getName()); - String tableName = metadata.getTable().getName(); - UpdateTimestampsCache timestampsCache = hibernateCache.getUpdateTimestampsCache(); - if (timestampsCache != null) { - timestampsCache.invalidate(new Serializable[]{tableName}, session); - } + hibernateCache.evictQueryRegions(); } /** diff --git a/common/src/main/java/org/broadleafcommerce/common/util/dao/HibernateMappingProvider.java b/common/src/main/java/org/broadleafcommerce/common/util/dao/HibernateMappingProvider.java index d209be420b..61c244c4fd 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/dao/HibernateMappingProvider.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/dao/HibernateMappingProvider.java @@ -88,9 +88,8 @@ public static List getPropertyNames(String entityClass) { if (metadata == null) { return propertyNames; } - Iterator propertyIterator = metadata.getPropertyClosureIterator(); - while (propertyIterator.hasNext()) { - org.hibernate.mapping.Property prop = (org.hibernate.mapping.Property) propertyIterator.next(); + List properties = metadata.getPropertyClosure(); + for (Property prop : properties) { propertyNames.add(prop.getName()); } return propertyNames; @@ -110,9 +109,8 @@ public static List getPropertyTypes(String entityClass) { if (metadata == null) { return propertyTypes; } - Iterator propertyIterator = metadata.getPropertyClosureIterator(); - while (propertyIterator.hasNext()) { - org.hibernate.mapping.Property prop = (org.hibernate.mapping.Property) propertyIterator.next(); + List properties = metadata.getPropertyClosure(); + for (Property prop : properties) { propertyTypes.add(prop.getType()); } return propertyTypes; diff --git a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoHsqlSingleLineSqlCommandExtractor.java b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoHsqlSingleLineSqlCommandExtractor.java index 477947f80f..2d52ebbf99 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoHsqlSingleLineSqlCommandExtractor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoHsqlSingleLineSqlCommandExtractor.java @@ -20,7 +20,8 @@ import org.broadleafcommerce.common.logging.SupportLogManager; import org.broadleafcommerce.common.logging.SupportLogger; import org.hibernate.dialect.Dialect; -import org.hibernate.tool.hbm2ddl.SingleLineSqlCommandExtractor; +import org.hibernate.tool.schema.internal.script.SingleLineSqlScriptExtractor; +import org.hibernate.tool.schema.spi.SqlScriptCommandExtractor; import java.io.Reader; import java.util.ArrayList; @@ -32,11 +33,12 @@ * * @author Phillip Verheyden (phillipuniverse) */ -public class DemoHsqlSingleLineSqlCommandExtractor extends SingleLineSqlCommandExtractor { +public class DemoHsqlSingleLineSqlCommandExtractor implements SqlScriptCommandExtractor { @Override - public String[] extractCommands(Reader reader) { - String[] commands = super.extractCommands(reader); + public List extractCommands(Reader reader, Dialect dialect) { + List commandList = SingleLineSqlScriptExtractor.INSTANCE.extractCommands(reader, dialect); + String[] commands = commandList.toArray(new String[0]); String[] newCommands = new String[commands.length]; int i = 0; for (String command : commands) { @@ -57,7 +59,7 @@ public String[] extractCommands(Reader reader) { newCommands[i] = newCommand; i++; } - return newCommands; + return List.of(newCommands); } } diff --git a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoOracleSingleLineSqlCommandExtractor.java b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoOracleSingleLineSqlCommandExtractor.java index 14a45b3b71..8b4634a8b5 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoOracleSingleLineSqlCommandExtractor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoOracleSingleLineSqlCommandExtractor.java @@ -19,7 +19,9 @@ import org.broadleafcommerce.common.logging.SupportLogManager; import org.broadleafcommerce.common.logging.SupportLogger; -import org.hibernate.tool.hbm2ddl.SingleLineSqlCommandExtractor; +import org.hibernate.dialect.Dialect; +import org.hibernate.tool.schema.internal.script.SingleLineSqlScriptExtractor; +import org.hibernate.tool.schema.spi.SqlScriptCommandExtractor; import java.io.Reader; import java.util.ArrayList; @@ -35,7 +37,7 @@ * * @author Jeff Fischer */ -public class DemoOracleSingleLineSqlCommandExtractor extends SingleLineSqlCommandExtractor { +public class DemoOracleSingleLineSqlCommandExtractor implements SqlScriptCommandExtractor { public static final String TRUE = "1"; public static final String FALSE = "0"; @@ -48,13 +50,13 @@ public class DemoOracleSingleLineSqlCommandExtractor extends SingleLineSqlComman protected boolean alreadyRun = false; @Override - public String[] extractCommands(Reader reader) { + public List extractCommands(Reader reader, Dialect dialect) { if (!alreadyRun) { alreadyRun = true; LOGGER.support("Converting hibernate.hbm2ddl.import_files sql statements for compatibility with Oracle"); } - String[] statements = super.extractCommands(reader); + String[] statements = SingleLineSqlScriptExtractor.INSTANCE.extractCommands(reader, dialect).toArray(new String[0]); handleBooleans(statements); //remove Oracle incompatible - multi-row inserts @@ -116,7 +118,7 @@ public String[] extractCommands(Reader reader) { statements[x] = statement; } - return statements; + return List.of(statements); } protected void handleBooleans(String[] statements) { diff --git a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoPostgresSingleLineSqlCommandExtractor.java b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoPostgresSingleLineSqlCommandExtractor.java index 0c002dd43f..768436737a 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoPostgresSingleLineSqlCommandExtractor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoPostgresSingleLineSqlCommandExtractor.java @@ -20,7 +20,8 @@ import org.broadleafcommerce.common.logging.SupportLogManager; import org.broadleafcommerce.common.logging.SupportLogger; import org.hibernate.dialect.Dialect; -import org.hibernate.tool.hbm2ddl.SingleLineSqlCommandExtractor; +import org.hibernate.tool.schema.internal.script.SingleLineSqlScriptExtractor; +import org.hibernate.tool.schema.spi.SqlScriptCommandExtractor; import java.io.Reader; import java.io.Serial; @@ -40,15 +41,13 @@ * * @author Jay Aisenbrey (cja769) */ -public class DemoPostgresSingleLineSqlCommandExtractor extends SingleLineSqlCommandExtractor { +public class DemoPostgresSingleLineSqlCommandExtractor implements SqlScriptCommandExtractor { public static final String NEWLINE_REPLACEMENT_REGEX = "\\\\r\\\\n"; - @Serial - private static final long serialVersionUID = 1L; @Override - public String[] extractCommands(Reader reader) { - String[] commands = super.extractCommands(reader); + public List extractCommands(Reader reader, Dialect dialect) { + String[] commands = SingleLineSqlScriptExtractor.INSTANCE.extractCommands(reader, dialect).toArray(new String[0]); String[] newCommands = new String[commands.length]; int i = 0; for (String command : commands) { @@ -83,7 +82,7 @@ public String[] extractCommands(Reader reader) { newCommands[i] = newCommand; i++; } - return newCommands; + return List.of(newCommands); } } diff --git a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoSqlServerSingleLineSqlCommandExtractor.java b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoSqlServerSingleLineSqlCommandExtractor.java index 90d404b305..8f5ec85a2b 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoSqlServerSingleLineSqlCommandExtractor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/sql/importsql/DemoSqlServerSingleLineSqlCommandExtractor.java @@ -20,10 +20,10 @@ import org.broadleafcommerce.common.logging.SupportLogManager; import org.broadleafcommerce.common.logging.SupportLogger; import org.hibernate.dialect.Dialect; -import org.hibernate.tool.hbm2ddl.SingleLineSqlCommandExtractor; +import org.hibernate.tool.schema.internal.script.SingleLineSqlScriptExtractor; +import org.hibernate.tool.schema.spi.SqlScriptCommandExtractor; import java.io.Reader; -import java.io.Serial; import java.util.ArrayList; import java.util.List; @@ -34,14 +34,12 @@ * * @author Jeff Fischer */ -public class DemoSqlServerSingleLineSqlCommandExtractor extends SingleLineSqlCommandExtractor { +public class DemoSqlServerSingleLineSqlCommandExtractor implements SqlScriptCommandExtractor { public static final String DOUBLEBACKSLASHMATCH = "(\\\\\\\\)"; public static final String TRUE = "'TRUE'"; public static final String FALSE = "'FALSE'"; public static final String CURRENT_TIMESTAMP = "CURRENT_TIMESTAMP"; - @Serial - private static final long serialVersionUID = 1L; private static final SupportLogger LOGGER = SupportLogManager.getLogger( "UserOverride", DemoSqlServerSingleLineSqlCommandExtractor.class ); @@ -51,16 +49,16 @@ public class DemoSqlServerSingleLineSqlCommandExtractor extends SingleLineSqlCom protected boolean alreadyRun = false; @Override - public String[] extractCommands(Reader reader) { + public List extractCommands(Reader reader, Dialect dialect) { if (!alreadyRun) { alreadyRun = true; LOGGER.support("Converting hibernate.hbm2ddl.import_files sql statements for compatibility with SQL Server"); } - String[] statements = super.extractCommands(reader); + String[] statements = SingleLineSqlScriptExtractor.INSTANCE.extractCommands(reader, dialect).toArray(new String[0]); handleReplacements(statements); - return statements; + return List.of(statements); } protected void handleReplacements(String[] statements) { diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/CategoryImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/CategoryImpl.java index 9563363af1..ffc357232d 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/CategoryImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/CategoryImpl.java @@ -62,13 +62,14 @@ import org.broadleafcommerce.core.search.domain.CategorySearchFacetImpl; import org.broadleafcommerce.core.search.domain.SearchFacet; import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.Type; import java.io.Serial; import java.math.BigDecimal; @@ -235,7 +236,7 @@ public int compare(Object o1, Object o2) { protected String displayTemplate; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "LONG_DESCRIPTION", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "CategoryImpl_Category_Long_Description", order = 2000, group = GroupName.General, diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/ProductOptionImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/ProductOptionImpl.java index f67cd385c5..6864002a1b 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/ProductOptionImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/ProductOptionImpl.java @@ -37,11 +37,12 @@ import org.broadleafcommerce.core.catalog.service.type.ProductOptionValidationStrategyType; import org.broadleafcommerce.core.catalog.service.type.ProductOptionValidationType; import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.io.Serial; import java.util.ArrayList; @@ -150,7 +151,7 @@ public class ProductOptionImpl implements ProductOption, AdminMainEntity, Produc addType = AddMethodType.PERSIST) protected List allowedValues = new ArrayList<>(); @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "LONG_DESCRIPTION", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "productOption_description", group = GroupName.General, diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuFeeImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuFeeImpl.java index 0355920968..49d31267ff 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuFeeImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuFeeImpl.java @@ -30,10 +30,11 @@ import org.broadleafcommerce.common.presentation.client.SupportedFieldType; import org.broadleafcommerce.core.catalog.service.type.SkuFeeType; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.io.Serial; import java.math.BigDecimal; @@ -94,7 +95,7 @@ public class SkuFeeImpl implements SkuFee { protected Boolean taxable = Boolean.FALSE; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "EXPRESSION", length = Integer.MAX_VALUE - 1) protected String expression; diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuImpl.java index 21fb38af8f..6fc52abddd 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/catalog/domain/SkuImpl.java @@ -59,12 +59,13 @@ import org.broadleafcommerce.core.order.service.type.FulfillmentType; import org.broadleafcommerce.core.search.domain.FieldEntity; import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.math.BigDecimal; import java.util.ArrayList; @@ -230,7 +231,7 @@ public class SkuImpl implements Sku, SkuAdminPresentation { //as it now relates on CLOB. Probably you can change signature and pass old/new values //and check them for length, if someone exceeds some value (255?) consider it large @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "LONG_DESCRIPTION", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "SkuImpl_Sku_Large_Description", group = GroupName.General, order = FieldOrder.LONG_DESCRIPTION, diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferItemCriteriaImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferItemCriteriaImpl.java index 2474338f33..dbc7a51197 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferItemCriteriaImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferItemCriteriaImpl.java @@ -28,10 +28,11 @@ import org.broadleafcommerce.common.presentation.AdminPresentationClass; import org.broadleafcommerce.common.presentation.client.VisibilityEnum; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.io.Serial; @@ -83,7 +84,7 @@ public class OfferItemCriteriaImpl implements OfferItemCriteria { protected Integer quantity; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "ORDER_ITEM_MATCH_RULE", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "OfferItemCriteriaImpl_Order_Item_Match_Rule", group = "OfferItemCriteriaImpl_Description", visibility = VisibilityEnum.HIDDEN_ALL) diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferRuleImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferRuleImpl.java index 06c95fcb13..cd8985bc24 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferRuleImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/offer/domain/OfferRuleImpl.java @@ -23,10 +23,11 @@ import org.broadleafcommerce.common.extensibility.jpa.copy.DirectCopyTransformMember; import org.broadleafcommerce.common.extensibility.jpa.copy.DirectCopyTransformTypes; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.io.Serial; @@ -70,7 +71,7 @@ public class OfferRuleImpl implements OfferRule { protected Long id; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "MATCH_RULE", length = Integer.MAX_VALUE - 1) protected String matchRule; diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/dao/OrderDaoImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/dao/OrderDaoImpl.java index ff3dfbabc9..cbeff63358 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/dao/OrderDaoImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/dao/OrderDaoImpl.java @@ -100,7 +100,7 @@ public Order readOrderById(final Long orderId) { @Override public Order readOrderByIdIgnoreCache(final Long orderId) { Map m = new HashMap<>(); - m.put(AvailableSettings.JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS); + m.put(AvailableSettings.JAKARTA_SHARED_CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS); return em.find(OrderImpl.class, orderId, m); } diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/domain/FulfillmentOptionImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/domain/FulfillmentOptionImpl.java index 22e40c7985..f7b4d97dec 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/domain/FulfillmentOptionImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/order/domain/FulfillmentOptionImpl.java @@ -31,10 +31,11 @@ import org.broadleafcommerce.common.presentation.client.SupportedFieldType; import org.broadleafcommerce.core.order.service.type.FulfillmentType; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.io.Serial; @@ -81,7 +82,7 @@ public class FulfillmentOptionImpl implements FulfillmentOption { protected String name; @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name = "LONG_DESCRIPTION", length = Integer.MAX_VALUE - 1) @AdminPresentation(friendlyName = "FulfillmentOptionImpl_longDescription", order = Presentation.FieldOrder.DESCRIPTION, translatable = true) diff --git a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/payment/domain/PaymentTransactionImpl.java b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/payment/domain/PaymentTransactionImpl.java index ad6b2c2c16..0fe0475f8c 100644 --- a/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/payment/domain/PaymentTransactionImpl.java +++ b/core/broadleaf-framework/src/main/java/org/broadleafcommerce/core/payment/domain/PaymentTransactionImpl.java @@ -33,11 +33,12 @@ import org.broadleafcommerce.common.presentation.override.AdminPresentationMergeOverrides; import org.broadleafcommerce.common.presentation.override.PropertyType; import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.MapKeyType; import org.hibernate.annotations.Parameter; import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.Type; import java.io.Serial; import java.math.BigDecimal; @@ -115,7 +116,7 @@ public class PaymentTransactionImpl implements PaymentTransaction { @Column(name = "RAW_RESPONSE", length = Integer.MAX_VALUE - 1) @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @AdminPresentation(friendlyName = "PaymentTransactionImpl_Raw_Response") protected String rawResponse; @@ -144,9 +145,8 @@ public class PaymentTransactionImpl implements PaymentTransaction { @ElementCollection @MapKeyColumn(name="FIELD_NAME") - @MapKeyType(@Type(type = "java.lang.String")) @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @Column(name="FIELD_VALUE", length = Integer.MAX_VALUE - 1) @CollectionTable(name="BLC_TRANS_ADDITNL_FIELDS", joinColumns=@JoinColumn(name="PAYMENT_TRANSACTION_ID")) @BatchSize(size = 50) diff --git a/core/broadleaf-profile/src/main/java/org/broadleafcommerce/profile/core/domain/CustomerPaymentImpl.java b/core/broadleaf-profile/src/main/java/org/broadleafcommerce/profile/core/domain/CustomerPaymentImpl.java index 24110a10ce..4025604d6a 100644 --- a/core/broadleaf-profile/src/main/java/org/broadleafcommerce/profile/core/domain/CustomerPaymentImpl.java +++ b/core/broadleaf-profile/src/main/java/org/broadleafcommerce/profile/core/domain/CustomerPaymentImpl.java @@ -33,11 +33,12 @@ import org.broadleafcommerce.common.presentation.override.PropertyType; import org.broadleafcommerce.common.time.domain.TemporalTimestampListener; import org.hibernate.annotations.Cache; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.MapKeyType; import org.hibernate.annotations.Parameter; -import org.hibernate.annotations.Type; import java.io.Serial; import java.util.HashMap; @@ -148,9 +149,8 @@ public class CustomerPaymentImpl implements CustomerPayment, CustomerPaymentAdmi protected boolean isDefault = false; @ElementCollection() - @MapKeyType(@Type(type = "java.lang.String")) @Lob - @Type(type = "org.hibernate.type.MaterializedClobType") + @JdbcTypeCode(SqlTypes.LONG32VARCHAR) @CollectionTable(name = "BLC_CUSTOMER_PAYMENT_FIELDS", joinColumns = @JoinColumn(name = "CUSTOMER_PAYMENT_ID")) @MapKeyColumn(name = "FIELD_NAME", nullable = false) @Column(name = "FIELD_VALUE", length = Integer.MAX_VALUE - 1) From 7e31aaeabf76e578ed336fcf1a99745e8c4e7399 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:07:02 +0000 Subject: [PATCH 3/7] Address Devin Review findings: fix entity type resolution and embeddable plural attribute check - MapFieldsFieldMetadataProvider: Use session-factory-bound TypeConfiguration and MappingMetamodel.getEntityDescriptor() for proper entity type resolution instead of standalone TypeConfiguration that can only resolve basic types. - FieldPathBuilder: Check parent path's ManagedType for plural attributes instead of root entity's, so collections inside @Embeddable types are correctly detected at any depth. Co-Authored-By: Arjun Mishra --- .../MapFieldsFieldMetadataProvider.java | 53 +++++++++++++++---- .../module/criteria/FieldPathBuilder.java | 29 +++++----- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java index 4ab0600fd0..1d88c9b62a 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java @@ -35,6 +35,9 @@ import org.broadleafcommerce.openadmin.server.dao.provider.metadata.request.OverrideViaXmlRequest; import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager; import org.broadleafcommerce.openadmin.server.service.type.MetadataProviderResponse; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.MappingMetamodel; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.BasicType; import org.hibernate.type.Type; import org.hibernate.type.spi.TypeConfiguration; @@ -123,20 +126,41 @@ public MetadataProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTyp //look for any map field metadata that was previously added for the requested field for (Map.Entry entry : addMetadataFromFieldTypeRequest.getPresentationAttributes().entrySet()) { if (entry.getKey().startsWith(addMetadataFromFieldTypeRequest.getRequestedPropertyName() + FieldManager.MAPFIELDSEPARATOR)) { - TypeConfiguration typeConfiguration = new TypeConfiguration(); + // Use the session-factory-bound TypeConfiguration so both basic and entity types can be resolved + SessionFactoryImplementor sfi = addMetadataFromFieldTypeRequest.getDynamicEntityDao() + .getStandardEntityManager().unwrap(SessionFactoryImplementor.class); + TypeConfiguration typeConfiguration = sfi.getTypeConfiguration(); + MappingMetamodel mappingMetamodel = sfi.getMappingMetamodel(); Type myType = null; //first, check if an explicit type was declared String valueClass = ((BasicFieldMetadata) entry.getValue()).getMapFieldValueClass(); if (valueClass != null) { + // Try entity type resolution first try { - Class valueJavaType = Class.forName(valueClass); - BasicType resolved = typeConfiguration.getBasicTypeForJavaType(valueJavaType); - if (resolved != null) { - myType = resolved; + EntityPersister entityPersister = mappingMetamodel.getEntityDescriptor(valueClass); + if (entityPersister != null) { + myType = entityPersister.getEntityMappingType().getJavaType() != null + ? typeConfiguration.getBasicTypeForJavaType(entityPersister.getMappedClass()) + : null; + // If basic type resolution failed, use the entity persister's identifier type as a fallback + if (myType == null) { + myType = entityPersister.getIdentifierType(); + } + } + } catch (Exception ex) { + // Not an entity - try as basic type + } + if (myType == null) { + try { + Class valueJavaType = Class.forName(valueClass); + BasicType resolved = typeConfiguration.getBasicTypeForJavaType(valueJavaType); + if (resolved != null) { + myType = resolved; + } + } catch (ClassNotFoundException ex) { + // Not a basic type either } - } catch (ClassNotFoundException ex) { - // Not a basic type - try as entity below } } if (myType == null) { @@ -156,9 +180,18 @@ public MetadataProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTyp Class clazz = (Class) pType.getActualTypeArguments()[1]; Class[] entities = addMetadataFromFieldTypeRequest.getDynamicEntityDao().getAllPolymorphicEntitiesFromCeiling(clazz); if (!ArrayUtils.isEmpty(entities)) { - BasicType resolved = typeConfiguration.getBasicTypeForJavaType(entities[entities.length-1]); - if (resolved != null) { - myType = resolved; + // Try entity type resolution for polymorphic entities + try { + EntityPersister entityPersister = mappingMetamodel.getEntityDescriptor(entities[entities.length-1].getName()); + if (entityPersister != null) { + myType = entityPersister.getIdentifierType(); + } + } catch (Exception ex) { + // Not an entity - try basic type + BasicType resolved = typeConfiguration.getBasicTypeForJavaType(entities[entities.length-1]); + if (resolved != null) { + myType = resolved; + } } } } diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java index 96ed3bd961..da9ef8df78 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/service/persistence/module/criteria/FieldPathBuilder.java @@ -128,23 +128,18 @@ public Path getPath(From root, FieldPath fieldPath, final CriteriaBuilder builde } final String currentPiece = myFieldPath.getTargetPropertyPieces().get(i); - if (path.getParentPath() != null && path.getParentPath().getJavaType().isAnnotationPresent(Embeddable.class) - && ((EntityType) root.getModel()).getPluralAttributes().stream() - .anyMatch(a -> a.getName().equals(currentPiece))) { - //We need a workaround for this problem until it is resolved in Hibernate (loosely related to and likely resolved by https://hibernate.atlassian.net/browse/HHH-8802) - //We'll throw a specialized exception (and handle in an alternate flow for calls from BasicPersistenceModule) - throw new CriteriaConversionException(String.format("Unable to create a JPA criteria Path through an @Embeddable object to a collection that resides therein (%s)", fieldPath.getTargetProperty()), fieldPath); -// //TODO this code should work, but there still appear to be bugs in Hibernate's JPA criteria handling for lists -// //inside Embeddables -// Class myClass = ((PluralAttributePath) path).getAttribute().getClass().getInterfaces()[0]; -// //we don't know which version of "join" to call, so we'll let reflection figure it out -// try { -// From embeddedJoin = myRoot.join(((SingularAttributePath) path.getParentPath()).getAttribute()); -// Method join = embeddedJoin.getClass().getMethod("join", myClass); -// path = (Path) join.invoke(embeddedJoin, ((PluralAttributePath) path).getAttribute()); -// } catch (Exception e) { -// throw new RuntimeException(e); -// } + if (path.getParentPath() != null && path.getParentPath().getJavaType().isAnnotationPresent(Embeddable.class)) { + // Check the parent path's managed type for plural attributes (not the root entity), + // since the collection may belong to the embeddable, not the root. + ManagedType parentType = ((NodeBuilder) builder).getDomainModel() + .managedType(path.getParentPath().getJavaType()); + boolean isPlural = parentType.getPluralAttributes().stream() + .anyMatch(a -> a.getName().equals(currentPiece)); + if (isPlural) { + //We need a workaround for this problem until it is resolved in Hibernate (loosely related to and likely resolved by https://hibernate.atlassian.net/browse/HHH-8802) + //We'll throw a specialized exception (and handle in an alternate flow for calls from BasicPersistenceModule) + throw new CriteriaConversionException(String.format("Unable to create a JPA criteria Path through an @Embeddable object to a collection that resides therein (%s)", fieldPath.getTargetProperty()), fieldPath); + } } } From 4d01ed4e09622223f365609d9cfda3a75e8156e5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:13:44 +0000 Subject: [PATCH 4/7] Fix entity type resolution: use ManyToOneType to preserve getReturnedClass() semantics ManyToOneType(typeConfiguration, entityName) is the H6 equivalent of typeLocator.entity(entityName). Its getReturnedClass() returns the entity class itself (e.g. ProductImpl.class), not the identifier type (Long.class). This preserves the original contract where myType.getReturnedClass() is passed as returnedClass to super.addMetadataFromFieldType(). Co-Authored-By: Arjun Mishra --- .../MapFieldsFieldMetadataProvider.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java index 1d88c9b62a..10e69ff1d2 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/provider/metadata/MapFieldsFieldMetadataProvider.java @@ -36,9 +36,8 @@ import org.broadleafcommerce.openadmin.server.service.persistence.module.FieldManager; import org.broadleafcommerce.openadmin.server.service.type.MetadataProviderResponse; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.MappingMetamodel; -import org.hibernate.persister.entity.EntityPersister; import org.hibernate.type.BasicType; +import org.hibernate.type.ManyToOneType; import org.hibernate.type.Type; import org.hibernate.type.spi.TypeConfiguration; import org.springframework.context.annotation.Scope; @@ -130,24 +129,17 @@ public MetadataProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTyp SessionFactoryImplementor sfi = addMetadataFromFieldTypeRequest.getDynamicEntityDao() .getStandardEntityManager().unwrap(SessionFactoryImplementor.class); TypeConfiguration typeConfiguration = sfi.getTypeConfiguration(); - MappingMetamodel mappingMetamodel = sfi.getMappingMetamodel(); Type myType = null; //first, check if an explicit type was declared String valueClass = ((BasicFieldMetadata) entry.getValue()).getMapFieldValueClass(); if (valueClass != null) { - // Try entity type resolution first + // Try entity type resolution first via ManyToOneType (H6 equivalent of typeLocator.entity()) + // ManyToOneType.getReturnedClass() returns the entity class, preserving old semantics try { - EntityPersister entityPersister = mappingMetamodel.getEntityDescriptor(valueClass); - if (entityPersister != null) { - myType = entityPersister.getEntityMappingType().getJavaType() != null - ? typeConfiguration.getBasicTypeForJavaType(entityPersister.getMappedClass()) - : null; - // If basic type resolution failed, use the entity persister's identifier type as a fallback - if (myType == null) { - myType = entityPersister.getIdentifierType(); - } - } + sfi.getMappingMetamodel().getEntityDescriptor(valueClass); + // Entity exists - create ManyToOneType which returns the entity class from getReturnedClass() + myType = new ManyToOneType(typeConfiguration, valueClass); } catch (Exception ex) { // Not an entity - try as basic type } @@ -180,12 +172,12 @@ public MetadataProviderResponse addMetadataFromFieldType(AddMetadataFromFieldTyp Class clazz = (Class) pType.getActualTypeArguments()[1]; Class[] entities = addMetadataFromFieldTypeRequest.getDynamicEntityDao().getAllPolymorphicEntitiesFromCeiling(clazz); if (!ArrayUtils.isEmpty(entities)) { - // Try entity type resolution for polymorphic entities + // Try entity type resolution for polymorphic entities via ManyToOneType + String entityName = entities[entities.length-1].getName(); try { - EntityPersister entityPersister = mappingMetamodel.getEntityDescriptor(entities[entities.length-1].getName()); - if (entityPersister != null) { - myType = entityPersister.getIdentifierType(); - } + sfi.getMappingMetamodel().getEntityDescriptor(entityName); + // Entity exists - create ManyToOneType which returns the entity class from getReturnedClass() + myType = new ManyToOneType(typeConfiguration, entityName); } catch (Exception ex) { // Not an entity - try basic type BasicType resolved = typeConfiguration.getBasicTypeForJavaType(entities[entities.length-1]); From eb9baf78e280821073676332449104f7c231e989 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:22:23 +0000 Subject: [PATCH 5/7] Restore targeted cache invalidation instead of global evictQueryRegions() Use CacheImplementor.getTimestampsCache().invalidate() with the specific table name to only invalidate query cache timestamps for the affected table, matching the original Hibernate 5 behavior. The previous evictQueryRegions() call was too aggressive and would invalidate all cached queries globally. Co-Authored-By: Arjun Mishra --- .../common/util/UpdateExecutor.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java b/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java index 2d2a06f701..253b4c28ec 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java @@ -19,9 +19,13 @@ import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import org.broadleafcommerce.common.util.dao.HibernateMappingProvider; import org.hibernate.FlushMode; import org.hibernate.Session; +import org.hibernate.cache.spi.CacheImplementor; +import org.hibernate.cache.spi.TimestampsCache; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.mapping.PersistentClass; import org.hibernate.query.NativeQuery; import java.util.ArrayList; import java.util.Arrays; @@ -152,12 +156,17 @@ public static int executeUpdateQuery(EntityManager em, String template, String t */ public static void executeTargetedCacheInvalidation(EntityManager em, Class entityType, List ids) { SharedSessionContractImplementor session = em.unwrap(SharedSessionContractImplementor.class); - org.hibernate.Cache hibernateCache = session.getFactory().getCache(); + CacheImplementor hibernateCache = (CacheImplementor) session.getFactory().getCache(); for (Long id : ids) { hibernateCache.evictEntityData(entityType, id); } - //update the timestamp cache for the table so that queries will be refreshed - hibernateCache.evictQueryRegions(); + //update the timestamp cache for the specific table so that queries touching it will be refreshed + PersistentClass metadata = HibernateMappingProvider.getMapping(entityType.getName()); + String tableName = metadata.getTable().getName(); + TimestampsCache timestampsCache = hibernateCache.getTimestampsCache(); + if (timestampsCache != null) { + timestampsCache.invalidate(new String[]{tableName}, session); + } } /** From af945d3107998adeb5b61ebb153c6d863bcab0a9 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:28:52 +0000 Subject: [PATCH 6/7] Fix missed getPropertyIterator() -> getProperties() in buildComponentProperties Migrate the remaining Component.getPropertyIterator() call in DynamicEntityDaoImpl.buildComponentProperties() to the H6 List-based getProperties() API, consistent with the other migrations in this PR. Co-Authored-By: Arjun Mishra --- .../openadmin/server/dao/DynamicEntityDaoImpl.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java index 5594232445..038ebb1dd4 100644 --- a/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java +++ b/admin/broadleaf-open-admin-platform/src/main/java/org/broadleafcommerce/openadmin/server/dao/DynamicEntityDaoImpl.java @@ -1678,12 +1678,7 @@ protected void buildComponentProperties( property = persistentClass.getProperty(prefix + propertyName); } - Iterator componentPropertyIterator = ((org.hibernate.mapping.Component) property.getValue()).getPropertyIterator(); - List componentPropertyList = new ArrayList<>(); - - while (componentPropertyIterator.hasNext()) { - componentPropertyList.add((Property) componentPropertyIterator.next()); - } + List componentPropertyList = ((org.hibernate.mapping.Component) property.getValue()).getProperties(); Map newFields = new HashMap<>(); buildProperties( From 5c78bc663f3da3c298d9fd54c408b6fe3b2c8352 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:39:08 +0000 Subject: [PATCH 7/7] Fix broken Javadoc @link reference in deprecated executeUpdateQuery Update @link to reference Object[] instead of Type[] to match the actual method signature after the Hibernate 6 migration. Co-Authored-By: Arjun Mishra --- .../java/org/broadleafcommerce/common/util/UpdateExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java b/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java index 253b4c28ec..61826b7f18 100644 --- a/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java +++ b/common/src/main/java/org/broadleafcommerce/common/util/UpdateExecutor.java @@ -64,7 +64,7 @@ public class UpdateExecutor { *

* An example looks like: 'UPDATE BLC_SNDBX_WRKFLW_ITEM SET SCHEDULED_DATE = ? WHERE WRKFLW_SNDBX_ITEM_ID IN (%s)' * - * @deprecated Highly recommended not to use this method. This method results in global L2 cache region clearing. Use {@link #executeUpdateQuery(EntityManager, String, String, Object[], Type[], List)} instead. + * @deprecated Highly recommended not to use this method. This method results in global L2 cache region clearing. Use {@link #executeUpdateQuery(EntityManager, String, String, Object[], Object[], List)} instead. * @param em The entity manager to use for the persistence operation * @param template the overall update sql template. The IN clause parameter should be written using 'IN (%s)'. * @param params any other params that are present in the sql template, other than the IN clause. Should be written using '?'. Should be in order. Can be null.