Fix != and =out= for maps in G2 RSQL to Specification (#2426)
+ add initial draft of Standalone RSQL test + provide option to override Hibernate / Eclipselink configuration via standard spring environment properties Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.EntityPropertyChangeListener;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.JpaExceptionTranslator;
|
||||
@@ -31,8 +32,10 @@ import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
@@ -44,18 +47,27 @@ import javax.sql.DataSource;
|
||||
* General Hibernate configuration for hawkBit's Repository.
|
||||
*/
|
||||
@Configuration
|
||||
@Import(JpaConfiguration.Properties.class)
|
||||
public class JpaConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties // predix is "/" intentionally
|
||||
protected static class Properties {
|
||||
|
||||
private final Map<String, String> hibernate = new HashMap<>();
|
||||
}
|
||||
|
||||
private final TenantIdentifier tenantIdentifier;
|
||||
private final boolean enableLazyLoadNoTrans;
|
||||
private final Map<String, String> hibernateProperties;
|
||||
|
||||
protected JpaConfiguration(
|
||||
final DataSource dataSource, final JpaProperties properties,
|
||||
final ObjectProvider<JtaTransactionManager> jtaTransactionManagerProvider,
|
||||
final TenantAware.TenantResolver tenantResolver,
|
||||
@Value("${hibernate.enable-lazy-load-no-trans:true}") final boolean enableLazyLoadNoTrans) {
|
||||
final Properties hibernateProperties) {
|
||||
super(dataSource, properties, jtaTransactionManagerProvider);
|
||||
tenantIdentifier = new TenantIdentifier(tenantResolver);
|
||||
this.enableLazyLoadNoTrans = enableLazyLoadNoTrans;
|
||||
this.hibernateProperties = hibernateProperties.getHibernate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -77,16 +89,16 @@ public class JpaConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getVendorProperties(DataSource dataSource) {
|
||||
Map<String, Object> hibernateProperties = new HashMap<>();
|
||||
hibernateProperties.put("hibernate.physical_naming_strategy", org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.class.getName());
|
||||
hibernateProperties.put(MultiTenancySettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantIdentifier);
|
||||
hibernateProperties.put("hibernate.multiTenancy", "DISCRIMINATOR");
|
||||
protected Map<String, Object> getVendorProperties(final DataSource dataSource) {
|
||||
final Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("hibernate.physical_naming_strategy", org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl.class.getName());
|
||||
properties.put(MultiTenancySettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantIdentifier);
|
||||
properties.put("hibernate.multiTenancy", "DISCRIMINATOR");
|
||||
// LAZY_LOAD - Enable lazy loading of lazy fields when session is closed - N + 1 problem occur.
|
||||
// So it would be good if in future hawkBit run without that
|
||||
// Otherwise, if false, call for the lazy field will throw LazyInitializationException
|
||||
hibernateProperties.put("hibernate.enable_lazy_load_no_trans", enableLazyLoadNoTrans);
|
||||
hibernateProperties.put("hibernate.integrator_provider", (IntegratorProvider) () -> Collections.singletonList(new Integrator() {
|
||||
properties.put("hibernate.enable_lazy_load_no_trans", "true");
|
||||
properties.put("hibernate.integrator_provider", (IntegratorProvider) () -> Collections.singletonList(new Integrator() {
|
||||
|
||||
@Override
|
||||
public void integrate(
|
||||
@@ -102,7 +114,10 @@ public class JpaConfiguration extends JpaBaseConfiguration {
|
||||
// do nothing
|
||||
}
|
||||
}));
|
||||
return hibernateProperties;
|
||||
|
||||
// override with all explicitly configured properties
|
||||
properties.putAll(hibernateProperties);
|
||||
return properties;
|
||||
}
|
||||
|
||||
static class CustomHibernateJpaDialect extends HibernateJpaDialect {
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.TypedQuery;
|
||||
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||
import org.hibernate.query.sqm.internal.QuerySqmImpl;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslation;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.MutationStatement;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||
|
||||
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
|
||||
@Slf4j
|
||||
public class Utils {
|
||||
|
||||
private static final Method getSqmTranslatorFactory;
|
||||
|
||||
static {
|
||||
Method method = null;
|
||||
try {
|
||||
method = QueryEngine.class.getMethod("getSqmTranslatorFactory");
|
||||
} catch (final NoSuchMethodException e) {
|
||||
log.warn("Can't resolve getSqmTranslatorFactory method (Utils.toString won't work)", e);
|
||||
}
|
||||
getSqmTranslatorFactory = method;
|
||||
}
|
||||
|
||||
public static String toSql(final TypedQuery<?> typedQuery) {
|
||||
if (getSqmTranslatorFactory == null) {
|
||||
throw new UnsupportedOperationException("SqmTranslatorFactory resolver is not available");
|
||||
}
|
||||
|
||||
final QuerySqmImpl<?> hqlQuery = typedQuery.unwrap(QuerySqmImpl.class);
|
||||
final SessionFactoryImplementor factory = hqlQuery.getSessionFactory();
|
||||
final SharedSessionContractImplementor session = hqlQuery.getSession();
|
||||
final SessionFactoryImplementor sessionFactory = session.getFactory();
|
||||
|
||||
final SqmTranslatorFactory sqmTranslatorFactory;
|
||||
try {
|
||||
sqmTranslatorFactory = (SqmTranslatorFactory) getSqmTranslatorFactory.invoke(factory.getQueryEngine());
|
||||
} catch (final IllegalAccessException | InvocationTargetException e) {
|
||||
throw new UnsupportedOperationException("Can't create SqmTranslatorFactory", e);
|
||||
}
|
||||
|
||||
final SqmTranslator<? extends Statement> sqmSelectTranslator =
|
||||
hqlQuery.getSqmStatement() instanceof SqmSelectStatement<?> selectStatement
|
||||
? sqmTranslatorFactory.createSelectTranslator(selectStatement,
|
||||
hqlQuery.getQueryOptions(), hqlQuery.getDomainParameterXref(), hqlQuery.getQueryParameterBindings(),
|
||||
hqlQuery.getLoadQueryInfluencers(), sessionFactory, false)
|
||||
: sqmTranslatorFactory.createMutationTranslator((SqmDmlStatement<?>) hqlQuery.getSqmStatement(),
|
||||
hqlQuery.getQueryOptions(), hqlQuery.getDomainParameterXref(), hqlQuery.getQueryParameterBindings(),
|
||||
hqlQuery.getLoadQueryInfluencers(), sessionFactory);
|
||||
|
||||
final SqmTranslation<? extends Statement> sqmTranslation = sqmSelectTranslator.translate();
|
||||
final SqlAstTranslatorFactory sqlAstTranslatorFactory = factory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory();
|
||||
final Map<QueryParameterImplementor<?>, Map<SqmParameter<?>, List<JdbcParametersList>>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref(
|
||||
hqlQuery.getDomainParameterXref(), sqmTranslation::getJdbcParamsBySqmParam);
|
||||
|
||||
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(hqlQuery.getQueryParameterBindings(),
|
||||
hqlQuery.getDomainParameterXref(), jdbcParamsXref, factory.getRuntimeMetamodels().getMappingMetamodel(),
|
||||
sqmSelectTranslator.getFromClauseAccess()::findTableGroup, new SqmParameterMappingModelResolutionAccess() {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> MappingModelExpressible<T> getResolvedMappingModelType(final SqmParameter<T> parameter) {
|
||||
return (MappingModelExpressible<T>) sqmTranslation.getSqmParameterMappingModelTypeResolutions().get(parameter);
|
||||
}
|
||||
}, hqlQuery.getSession());
|
||||
return (sqmTranslation.getSqlAst() instanceof SelectStatement selectStatement
|
||||
? sqlAstTranslatorFactory.buildSelectTranslator(factory, selectStatement)
|
||||
.translate(jdbcParameterBindings, hqlQuery.getQueryOptions())
|
||||
: sqlAstTranslatorFactory.buildMutationTranslator(factory, (MutationStatement) sqmTranslation.getSqlAst())
|
||||
.translate(jdbcParameterBindings, hqlQuery.getQueryOptions()))
|
||||
.getSqlString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user