Skip to content

Commit

Permalink
Update spring and hibernate versions and apply appropriate fixes (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
itineric authored Feb 23, 2025
1 parent e7f1fb4 commit 5883376
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 34 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
<java.version>17</java.version>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>3.0.0</spring-boot.version>
<spring-data-releasetrain.version>2022.0.0</spring-data-releasetrain.version>
<spring-boot.version>3.4.1</spring-boot.version>
<spring-data-releasetrain.version>2024.1.1</spring-data-releasetrain.version>
<querydsl.version>4.1.4</querydsl.version>
<rsql-parser.version>2.3.2</rsql-parser.version>
<lombok.version>1.18.24</lombok.version>
Expand Down
4 changes: 2 additions & 2 deletions rsql-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
</dependency>
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-62</artifactId>
<version>3.5.1</version>
<artifactId>hypersistence-utils-hibernate-63</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.perplexhub.rsql;

import java.lang.reflect.*;
import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeParseException;
import java.util.*;
Expand All @@ -13,6 +14,7 @@
import jakarta.persistence.metamodel.PluralAttribute;

import lombok.Getter;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.orm.jpa.vendor.Database;
Expand Down Expand Up @@ -52,6 +54,15 @@ public static Database getDatabase(EntityManager entityManager) {
return entityManagerDatabase.get(entityManager);
}

public static <T> Attribute<? super T, ?> getAttribute(String property, ManagedType<T> classMetadata) {
// W/A found here: https://hibernate.atlassian.net/browse/HHH-18569
// breaking change on hibernate side: https://github.com/hibernate/hibernate-orm/pull/6924#discussion_r1250474422
if (classMetadata instanceof ManagedDomainType managedDomainType) {
return managedDomainType.findSubTypesAttribute(property);
}
return classMetadata.getAttribute(property);
}

protected abstract Map<String, String> getPropertyPathMapper();

public Map<Class<?>, Map<String, String>> getPropertyRemapping() {
Expand All @@ -71,6 +82,9 @@ protected Object convert(String source, Class targetType) {
object = UUID.fromString(source);
} else if (targetType.equals(Date.class) || targetType.equals(java.sql.Date.class)) {
object = java.sql.Date.valueOf(LocalDate.parse(source));
} else if (targetType.equals(Timestamp.class)) {
Date date = java.sql.Date.valueOf(LocalDate.parse(source));
return new Timestamp(date.getTime());
} else if (targetType.equals(LocalDate.class)) {
object = LocalDate.parse(source);
} else if (targetType.equals(LocalDateTime.class)) {
Expand Down Expand Up @@ -158,10 +172,10 @@ protected String mapProperty(String selector, Class<?> entityClass) {

protected <T> Class<?> findPropertyType(String property, ManagedType<T> classMetadata) {
Class<?> propertyType = null;
if (classMetadata.getAttribute(property).isCollection()) {
propertyType = ((PluralAttribute) classMetadata.getAttribute(property)).getBindableJavaType();
if (getAttribute(property, classMetadata).isCollection()) {
propertyType = ((PluralAttribute) getAttribute(property, classMetadata)).getBindableJavaType();
} else {
propertyType = classMetadata.getAttribute(property).getJavaType();
propertyType = getAttribute(property, classMetadata).getJavaType();
}
return propertyType;
}
Expand Down Expand Up @@ -217,7 +231,7 @@ protected <T> ManagedType<T> getManagedElementCollectionType(String mappedProper

protected <T> boolean hasPropertyName(String property, ManagedType<T> classMetadata) {
try {
return classMetadata.getAttribute(property) != null;
return getAttribute(property, classMetadata) != null;
} catch (IllegalArgumentException e) {
return false;
}
Expand All @@ -238,30 +252,30 @@ protected static Class getElementCollectionGenericType(Class type, Attribute att
}

protected <T> boolean isEmbeddedType(String property, ManagedType<T> classMetadata) {
return classMetadata.getAttribute(property).getPersistentAttributeType() == PersistentAttributeType.EMBEDDED;
return getAttribute(property, classMetadata).getPersistentAttributeType() == PersistentAttributeType.EMBEDDED;
}

protected <T> boolean isElementCollectionType(String property, ManagedType<T> classMetadata) {
return classMetadata.getAttribute(property).getPersistentAttributeType() == PersistentAttributeType.ELEMENT_COLLECTION;
return getAttribute(property, classMetadata).getPersistentAttributeType() == PersistentAttributeType.ELEMENT_COLLECTION;
}

protected <T> boolean isAssociationType(String property, ManagedType<T> classMetadata) {
return classMetadata.getAttribute(property).isAssociation();
return getAttribute(property, classMetadata).isAssociation();
}

protected <T> boolean isOneToOneAssociationType(String property, ManagedType<T> classMetadata) {
return classMetadata.getAttribute(property).isAssociation()
&& PersistentAttributeType.ONE_TO_ONE == classMetadata.getAttribute(property).getPersistentAttributeType();
return getAttribute(property, classMetadata).isAssociation()
&& PersistentAttributeType.ONE_TO_ONE == getAttribute(property, classMetadata).getPersistentAttributeType();
}

protected <T> boolean isOneToManyAssociationType(String property, ManagedType<T> classMetadata) {
return classMetadata.getAttribute(property).isAssociation()
&& PersistentAttributeType.ONE_TO_MANY == classMetadata.getAttribute(property).getPersistentAttributeType();
return getAttribute(property, classMetadata).isAssociation()
&& PersistentAttributeType.ONE_TO_MANY == getAttribute(property, classMetadata).getPersistentAttributeType();
}

protected <T> boolean isManyToManyAssociationType(String property, ManagedType<T> classMetadata) {
return classMetadata.getAttribute(property).isAssociation()
&& PersistentAttributeType.MANY_TO_MANY == classMetadata.getAttribute(property).getPersistentAttributeType();
return getAttribute(property, classMetadata).isAssociation()
&& PersistentAttributeType.MANY_TO_MANY == getAttribute(property, classMetadata).getPersistentAttributeType();
}

static {
Expand Down
4 changes: 2 additions & 2 deletions rsql-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
</dependency>
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-60</artifactId>
<version>3.5.2</version>
<artifactId>hypersistence-utils-hibernate-63</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import cz.jirutka.rsql.parser.ast.OrNode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.query.criteria.JpaExpression;

@Slf4j
@SuppressWarnings({ "rawtypes", "unchecked" })
Expand Down Expand Up @@ -83,7 +84,6 @@ private RSQLJPAContext findPropertyPathInternal(String propertyPath, Path startR
Attribute<?, ?> attribute = null;
String resolvedPropertyPath = firstTry? mapPropertyPath(propertyPath) : propertyPath;
String[] properties = mapPropertyPath(resolvedPropertyPath).split("\\.");

for (int i = 0, propertiesLength = properties.length; i < propertiesLength; i++) {
String property = properties[i];
String mappedProperty = mapProperty(property, classMetadata.getJavaType());
Expand Down Expand Up @@ -140,14 +140,14 @@ private RSQLJPAContext findPropertyPathInternal(String propertyPath, Path startR
}
} else if (isElementCollectionType(mappedProperty, classMetadata)) {
String previousClass = classMetadata.getJavaType().getName();
attribute = classMetadata.getAttribute(property);
attribute = RSQLVisitorBase.getAttribute(property, classMetadata);
classMetadata = getManagedElementCollectionType(mappedProperty, classMetadata);
String keyJoin = getKeyJoin(root, mappedProperty);
log.debug("Create a element collection join between [{}] and [{}] using key [{}]", previousClass, classMetadata.getJavaType().getName(), keyJoin);
root = join(keyJoin, root, mappedProperty);
} else if (JsonbSupport.isJsonType(mappedProperty, classMetadata)) {
root = root.get(mappedProperty);
attribute = classMetadata.getAttribute(mappedProperty);
attribute = RSQLVisitorBase.getAttribute(mappedProperty, classMetadata);
break;
} else {
log.debug("Create property path for type [{}] property [{}]", classMetadata.getJavaType().getName(), mappedProperty);
Expand All @@ -158,7 +158,7 @@ private RSQLJPAContext findPropertyPathInternal(String propertyPath, Path startR
type = embeddedType;
classMetadata = getManagedType(embeddedType);
} else {
attribute = classMetadata.getAttribute(property);
attribute = RSQLVisitorBase.getAttribute(property, classMetadata);
}
}
}
Expand Down Expand Up @@ -246,7 +246,13 @@ private ResolvedExpression resolveExpression(ComparisonNode node, From root, Sel
ComparisonNode jsonbNode = node.withSelector(jsonbPath);
return JsonbSupport.jsonbPathExistsExpression(builder, jsonbNode, path);
} else {
return ResolvedExpression.ofPath(path.as(String.class), String.class);
final Expression expression;
if (path instanceof JpaExpression jpaExpression) {
expression = jpaExpression.cast(String.class);
} else {
expression = path.as(String.class);
}
return ResolvedExpression.ofPath(expression, String.class);
}
} else {
if (attribute != null
Expand Down
16 changes: 11 additions & 5 deletions rsql-jpa/src/main/java/io/github/perplexhub/rsql/SortUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import jakarta.persistence.criteria.Order;
import jakarta.persistence.criteria.Root;

import org.hibernate.query.criteria.JpaExpression;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;

Expand Down Expand Up @@ -63,16 +64,16 @@ private static Order sortToJpaOrder(final String[] parts, final SortSupport sort
sortSupport.getJoinHints(), sortSupport.getProcedureWhiteList(),
sortSupport.getProcedureBlackList());

final boolean ic = parts.length > 2 && "ic".equalsIgnoreCase(parts[2]);
Expression<?> propertyExpression = selector.getExpression((string, builder) ->{
final RSQLJPAContext rsqljpaContext = converter.findPropertyPath(string, root);
final boolean isJson = JsonbSupport.isJsonType(rsqljpaContext.getAttribute());
return isJson
? sortExpressionOfJson(rsqljpaContext, string, sortSupport.getPropertyPathMapper(), builder)
? sortExpressionOfJson(rsqljpaContext, string, sortSupport.getPropertyPathMapper(), builder, ic)
: rsqljpaContext.getPath();
});

if (parts.length > 2 && "ic".equalsIgnoreCase(parts[2])
&& String.class.isAssignableFrom(propertyExpression.getJavaType())) {
if (ic && String.class.isAssignableFrom(propertyExpression.getJavaType())) {
propertyExpression = cb.lower(propertyExpression.as(String.class));
}

Expand All @@ -92,7 +93,8 @@ private static Order sortToJpaOrder(final String[] parts, final SortSupport sort
private static Expression<?> sortExpressionOfJson(RSQLJPAContext context,
String property,
Map<String, String> mapping,
CriteriaBuilder builder) {
CriteriaBuilder builder,
boolean ic) {
String path = PathUtils.expectBestMapping(property, mapping);
String jsonbSelector = JsonbSupport.jsonPathOfSelector(context.getAttribute(), path);
if(jsonbSelector.contains(".")) {
Expand All @@ -102,7 +104,11 @@ private static Expression<?> sortExpressionOfJson(RSQLJPAContext context,
.skip(1) // skip root
.map(builder::literal)
.forEach(args::add);
return builder.function("jsonb_extract_path", String.class, args.toArray(Expression[]::new));
Expression<?> expression = builder.function("jsonb_extract_path", Object.class, args.toArray(Expression[]::new));
if (ic && expression instanceof JpaExpression<?> jpaExpression) {
expression = jpaExpression.cast(String.class);
}
return expression;
} else {
return context.getPath().as(String.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ && isJsonColumn(attribute)
* @return true if the attribute is a jsonb attribute
*/
public static boolean isJsonType(String mappedProperty, ManagedType<?> classMetadata) {
return Optional.ofNullable(classMetadata.getAttribute(mappedProperty))
return Optional.ofNullable(RSQLVisitorBase.getAttribute(mappedProperty, classMetadata))
.map(JsonbSupport::isJsonType)
.orElse(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.*;
Expand Down Expand Up @@ -764,9 +766,9 @@ final void testBetweenDate() {
@Test
final void testBetweenDateTime() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
RSQLJPASupport.addConverter(Date.class, s -> {
RSQLJPASupport.addConverter(Timestamp.class, s -> {
try {
return sdf.parse(s);
return new Timestamp(sdf.parse(s).getTime());
} catch (ParseException e) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.perplexhub.rsql;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;

Expand All @@ -23,9 +24,9 @@ public static void main(String[] args) throws Exception {
@Bean
public Object rsqlConfiguration(RSQLCommonSupport rsqlCommonSupport) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
RSQLCommonSupport.addConverter(Date.class, s -> {
RSQLCommonSupport.addConverter(Timestamp.class, s -> {
try {
return sdf.parse(s);
return new Timestamp(sdf.parse(s).getTime());
} catch (Exception e) {
return null;
}
Expand Down

0 comments on commit 5883376

Please sign in to comment.