fix problem with Postgres function array return value in Hibernate 6
This commit is contained in:
parent
063fcf90a3
commit
ec53934f30
@ -60,9 +60,10 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.9.1'
|
||||
implementation 'org.springdoc:springdoc-openapi:2.3.0'
|
||||
implementation 'org.postgresql:postgresql:42.7.1'
|
||||
implementation 'org.liquibase:liquibase-core:4.25.1'
|
||||
implementation 'com.vladmihalcea:hibernate-types-60:2.21.1'
|
||||
implementation 'io.hypersistence:hypersistence-utils-hibernate-64:3.7.0'
|
||||
implementation 'io.hypersistence:hypersistence-utils-hibernate-62:3.7.0'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.1'
|
||||
implementation 'org.openapitools:jackson-databind-nullable:0.2.6'
|
||||
implementation 'org.apache.commons:commons-text:1.11.0'
|
||||
@ -75,7 +76,6 @@ dependencies {
|
||||
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
|
||||
runtimeOnly 'org.postgresql:postgresql:42.7.1'
|
||||
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok'
|
||||
@ -214,7 +214,7 @@ project.tasks.check.dependsOn(checkLicense)
|
||||
|
||||
// JaCoCo Test Code Coverage
|
||||
jacoco {
|
||||
toolVersion = "0.8.8"
|
||||
toolVersion = "0.8.10"
|
||||
}
|
||||
test {
|
||||
finalizedBy jacocoTestReport // generate report after tests
|
||||
|
@ -8,7 +8,7 @@ import static org.hibernate.dialect.DatabaseVersion.make;
|
||||
public class PostgresCustomDialect extends PostgreSQLDialect {
|
||||
|
||||
public PostgresCustomDialect() {
|
||||
super(make(13, 7));
|
||||
super(make(15, 5));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,9 +15,11 @@ import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresArray.fromPostgresArray;
|
||||
import static org.springframework.transaction.annotation.Propagation.MANDATORY;
|
||||
|
||||
@Service
|
||||
@ -81,11 +83,14 @@ public class Context {
|
||||
}
|
||||
|
||||
public String[] getAssumedRoles() {
|
||||
return (String[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
|
||||
final byte[] result = (byte[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
|
||||
return fromPostgresArray(result, String.class, Function.identity());
|
||||
}
|
||||
|
||||
public UUID[] currentSubjectsUuids() {
|
||||
return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult();
|
||||
final byte[] result = (byte[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class)
|
||||
.getSingleResult();
|
||||
return fromPostgresArray(result, UUID.class, UUID::fromString);
|
||||
}
|
||||
|
||||
public static String getCallerMethodNameFromStackFrame(final int skipFrames) {
|
||||
|
@ -47,7 +47,7 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable {
|
||||
|
||||
@Column(name = "transactiontype")
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Type(PostgreSQLEnumType.class)
|
||||
//@Type(PostgreSQLEnumType.class)
|
||||
private HsOfficeCoopAssetsTransactionType transactionType;
|
||||
|
||||
@Column(name = "valuedate")
|
||||
|
@ -43,7 +43,7 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable {
|
||||
|
||||
@Column(name = "transactiontype")
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Type(PostgreSQLEnumType.class)
|
||||
//@Type(PostgreSQLEnumType.class)
|
||||
private HsOfficeCoopSharesTransactionType transactionType;
|
||||
|
||||
@Column(name = "valuedate")
|
||||
|
@ -19,9 +19,9 @@ public interface HsOfficeDebitorRepository extends Repository<HsOfficeDebitorEnt
|
||||
|
||||
@Query("""
|
||||
SELECT debitor FROM HsOfficeDebitorEntity debitor
|
||||
JOIN HsOfficePartnerEntity partner ON partner.uuid = debitor.partner
|
||||
JOIN HsOfficePersonEntity person ON person.uuid = partner.person
|
||||
JOIN HsOfficeContactEntity contact ON contact.uuid = debitor.billingContact
|
||||
JOIN HsOfficePartnerEntity partner ON partner.uuid = debitor.partner.uuid
|
||||
JOIN HsOfficePersonEntity person ON person.uuid = partner.person.uuid
|
||||
JOIN HsOfficeContactEntity contact ON contact.uuid = debitor.billingContact.uuid
|
||||
WHERE :name is null
|
||||
OR partner.details.birthName like concat(:name, '%')
|
||||
OR person.tradeName like concat(:name, '%')
|
||||
|
@ -61,7 +61,7 @@ public class HsOfficeMembershipEntity implements Stringifyable {
|
||||
|
||||
@Column(name = "reasonfortermination")
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Type(PostgreSQLEnumType.class)
|
||||
//@Type(PostgreSQLEnumType.class)
|
||||
private HsOfficeReasonForTermination reasonForTermination;
|
||||
|
||||
public void setValidFrom(final LocalDate validFrom) {
|
||||
|
@ -13,8 +13,8 @@ public interface HsOfficePartnerRepository extends Repository<HsOfficePartnerEnt
|
||||
|
||||
@Query("""
|
||||
SELECT partner FROM HsOfficePartnerEntity partner
|
||||
JOIN HsOfficeContactEntity contact ON contact.uuid = partner.contact
|
||||
JOIN HsOfficePersonEntity person ON person.uuid = partner.person
|
||||
JOIN HsOfficeContactEntity contact ON contact.uuid = partner.contact.uuid
|
||||
JOIN HsOfficePersonEntity person ON person.uuid = partner.person.uuid
|
||||
WHERE :name is null
|
||||
OR partner.details.birthName like concat(:name, '%')
|
||||
OR contact.label like concat(:name, '%')
|
||||
|
@ -37,7 +37,7 @@ public class HsOfficePersonEntity implements Stringifyable {
|
||||
|
||||
@Column(name = "persontype")
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Type(PostgreSQLEnumType.class)
|
||||
//@Type(PostgreSQLEnumType.class)
|
||||
private HsOfficePersonType personType;
|
||||
|
||||
@Column(name = "tradename")
|
||||
|
@ -47,7 +47,7 @@ public class HsOfficeRelationshipEntity {
|
||||
|
||||
@Column(name = "reltype")
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Type(PostgreSQLEnumType.class)
|
||||
//@Type(PostgreSQLEnumType.class)
|
||||
private HsOfficeRelationshipType relType;
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,57 @@
|
||||
package net.hostsharing.hsadminng.mapper;
|
||||
|
||||
import com.vladmihalcea.hibernate.type.range.Range;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.postgresql.util.PGtokenizer;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDate;
|
||||
import java.util.function.Function;
|
||||
|
||||
@UtilityClass
|
||||
public class PostgresArray {
|
||||
|
||||
/**
|
||||
* Converts a byte[], as returned for a Postgres-array by native queries, to a Java array.
|
||||
*
|
||||
* <p>This example code worked with Hibernate 5 (Spring Boot 3.0.x):
|
||||
* <pre><code>
|
||||
* return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult();
|
||||
* </code></pre>
|
||||
* </p>
|
||||
*
|
||||
* <p>With Hibernate 6 (Spring Boot 3.1.x), this utility method can be used like such:
|
||||
* <pre><code>
|
||||
* final byte[] result = (byte[]) em.createNativeQuery("select * from currentSubjectsUuids() as uuids", UUID[].class)
|
||||
* .getSingleResult();
|
||||
* return fromPostgresArray(result, UUID.class, UUID::fromString);
|
||||
* </code></pre>
|
||||
* </p>
|
||||
*
|
||||
* @param pgArray the byte[] returned by a native query containing as rendered for a Postgres array
|
||||
* @param elementClass the class of a single element of the Java array to be returned
|
||||
* @param itemParser converts a string element to the specified elementClass
|
||||
* @return a Java array containing the data from pgArray
|
||||
* @param <T> type of a single element of the Java array
|
||||
*/
|
||||
public static <T> T[] fromPostgresArray(final byte[] pgArray, final Class<T> elementClass, final Function<String, T> itemParser) {
|
||||
final var pgArrayLiteral = new String(pgArray, StandardCharsets.UTF_8);
|
||||
if (pgArrayLiteral.length() == 2) {
|
||||
return newGenericArray(elementClass, 0);
|
||||
}
|
||||
final PGtokenizer tokenizer = new PGtokenizer(pgArrayLiteral.substring(1, pgArrayLiteral.length()-1), ',');
|
||||
tokenizer.remove("\"", "\"");
|
||||
final T[] array = newGenericArray(elementClass, tokenizer.getSize()); // Create a new array of the specified type and length
|
||||
for ( int n = 0; n < tokenizer.getSize(); ++n ) {
|
||||
array[n] = itemParser.apply(tokenizer.getToken(n).trim().replace("\\\"", "\""));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T[] newGenericArray(final Class<T> elementClass, final int length) {
|
||||
return (T[]) Array.newInstance(elementClass, length);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user