spring-boot-3-2-upgrade (#32)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #32
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-04-02 13:24:25 +02:00
parent ad04faa21d
commit 73c378b456
25 changed files with 62 additions and 198 deletions

View File

@ -1,15 +1,15 @@
plugins { plugins {
id 'java' id 'java'
id 'org.springframework.boot' version '3.1.7' id 'org.springframework.boot' version '3.2.4'
id 'io.spring.dependency-management' version '1.1.4' id 'io.spring.dependency-management' version '1.1.4'
id 'io.openapiprocessor.openapi-processor' version '2023.2' id 'io.openapiprocessor.openapi-processor' version '2023.2'
id 'com.github.jk1.dependency-license-report' version '2.5' id 'com.github.jk1.dependency-license-report' version '2.6'
id "org.owasp.dependencycheck" version "9.0.7" id "org.owasp.dependencycheck" version "9.0.10"
id "com.diffplug.spotless" version "6.23.3" id "com.diffplug.spotless" version "6.25.0"
id 'jacoco' id 'jacoco'
id 'info.solidsoft.pitest' version '1.15.0' id 'info.solidsoft.pitest' version '1.15.0'
id 'se.patrikerdes.use-latest-versions' version '0.2.18' id 'se.patrikerdes.use-latest-versions' version '0.2.18'
id 'com.github.ben-manes.versions' version '0.50.0' id 'com.github.ben-manes.versions' version '0.51.0'
} }
group = 'net.hostsharing' group = 'net.hostsharing'
@ -59,28 +59,16 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.9.1' implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.9.1'
implementation 'org.springdoc:springdoc-openapi:2.3.0' implementation 'org.springdoc:springdoc-openapi:2.4.0'
implementation 'org.postgresql:postgresql:42.7.1' implementation 'org.postgresql:postgresql:42.7.3'
implementation 'org.liquibase:liquibase-core:4.25.1' implementation 'org.liquibase:liquibase-core:4.27.0'
implementation 'com.vladmihalcea:hibernate-types-60:2.21.1' implementation 'io.hypersistence:hypersistence-utils-hibernate-63:3.7.3'
implementation 'io.hypersistence:hypersistence-utils-hibernate-62:3.7.0' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.1'
implementation 'org.openapitools:jackson-databind-nullable:0.2.6' implementation 'org.openapitools:jackson-databind-nullable:0.2.6'
implementation 'org.apache.commons:commons-text:1.11.0' implementation 'org.apache.commons:commons-text:1.11.0'
implementation 'org.modelmapper:modelmapper:3.2.0' implementation 'org.modelmapper:modelmapper:3.2.0'
implementation 'org.iban4j:iban4j:3.2.7-RELEASE' implementation 'org.iban4j:iban4j:3.2.7-RELEASE'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.4.0'
// fixes vulnerability CVE-2022-1471
// The dependency usually comes from Spring Boot, just in the wrong version.
// TODO: Remove this explicit dependency once we are on SpringBoot 3.2.x
// as well as the related exclude in settings.gradle
// and the dependency suppression in owasp-dependency-check-suppression.xml.
implementation('org.yaml:snakeyaml') {
version {
strictly('2.2')
}
}
compileOnly 'org.projectlombok:lombok' compileOnly 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok' testCompileOnly 'org.projectlombok:lombok'

View File

@ -694,7 +694,7 @@ Users can view only the roles to which are granted to them.
Grant can be `empowered`, this means that the grantee user can grant the granted role to other users Grant can be `empowered`, this means that the grantee user can grant the granted role to other users
and revoke grants to that role. and revoke grants to that role.
(TODO: access control part not yet implemented) (TODO: access control part not yet implemented, currently all accessible roles can be granted to other users)
Grants can be `managed`, which means they are created and deleted by system-defined rules. Grants can be `managed`, which means they are created and deleted by system-defined rules.
If a grant is not managed, it was created by an empowered user and can be deleted by empowered users. If a grant is not managed, it was created by an empowered user and can be deleted by empowered users.

View File

@ -1,33 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd"> <suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
<suppress>
<notes><![CDATA[
We don't use the Spring HTTP invoker which causes this vulnerability due to Java deserialization.
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.springframework/spring-web@.*$</packageUrl>
<cve>CVE-2016-1000027</cve>
</suppress>
<suppress>
<notes><![CDATA[
We don't use the UNWRAP_SINGLE_VALUE_ARRAYS feature and thus are not affected.
]]></notes>
<packageUrl regex="true">^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$</packageUrl>
<cve>CVE-2022-42003</cve>
</suppress>
<suppress>
<notes><![CDATA[
We don't parse external XML.
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.eclipse\.angus/angus\-activation@.*$</packageUrl>
<cpe>cpe:/a:eclipse:eclipse_ide</cpe>
</suppress>
<suppress>
<notes><![CDATA[
We don't parse external XML.
]]></notes>
<packageUrl regex="true">^pkg:maven/jakarta\.activation/jakarta\.activation\-api@.*$</packageUrl>
<cpe>cpe:/a:eclipse:eclipse_ide</cpe>
</suppress>
<suppress> <suppress>
<notes><![CDATA[ <notes><![CDATA[
Cyclic references are not possible if file comes in JSON text format. Cyclic references are not possible if file comes in JSON text format.
@ -35,13 +7,6 @@
<packageUrl regex="true">^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$</packageUrl> <packageUrl regex="true">^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$</packageUrl>
<cpe>cpe:/a:fasterxml:jackson-databind</cpe> <cpe>cpe:/a:fasterxml:jackson-databind</cpe>
</suppress> </suppress>
<suppress>
<notes><![CDATA[
As far as I see Criteria.parse(...) cannot be reached with external data.
]]></notes>
<packageUrl regex="true">^pkg:maven/com\.jayway\.jsonpath/json\-path@.*$</packageUrl>
<vulnerabilityName>CVE-2023-51074</vulnerabilityName>
</suppress>
<suppress> <suppress>
<notes><![CDATA[ <notes><![CDATA[
Internal tooling, not exposed to the Internet. Internal tooling, not exposed to the Internet.
@ -49,17 +14,4 @@
<packageUrl regex="true">^pkg:maven/org\.pitest/pitest\-command\-line@.*$</packageUrl> <packageUrl regex="true">^pkg:maven/org\.pitest/pitest\-command\-line@.*$</packageUrl>
<cpe>cpe:/a:line:line</cpe> <cpe>cpe:/a:line:line</cpe>
</suppress> </suppress>
<suppress>
<notes><![CDATA[
Spring Boot 3.1.x has a transient dependency to snakeyaml 1.3
which contains this vulnerability.
We've explicitly bumped to 2.2, but the vulnerability checker does not seem to notice that.
TODO: Remove this suppression once we are on SpringBoot 3.2,
as well as the explicit version bump and the transient dependency exclude.
]]></notes>
<packageUrl regex="true">^pkg:maven/org\.yaml/snakeyaml@.*$</packageUrl>
<cve>CVE-2022-1471</cve>
</suppress>
</suppressions> </suppressions>

View File

@ -11,28 +11,4 @@ plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
} }
dependencyResolutionManagement {
components {
all {
allVariants {
withDependencies {
removeAll {
// Spring Boot 3.1.x has a transient dependency to snakeyaml 1.3
// which contains a severe vulnerability.
// Here we remove this transient dependency and in build.gradle
// we add an explicit dependency to snakeyaml 2.2,
// which does not have this vulnerability anymore.
//
// TODO: Check Once we are on SpringBoot 3.2.x, check if this exclude
// is still neccessary. If not:
// Remove it // as well as the related explicit dependency in build.gradle
// and the dependency suppression in owasp-dependency-check-suppression.xml.
it.module in [ 'snakeyaml' ]
}
}
}
}
}
}
rootProject.name = 'hsadmin-ng' rootProject.name = 'hsadmin-ng'

View File

@ -15,11 +15,9 @@ import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.util.function.Predicate.not; import static java.util.function.Predicate.not;
import static net.hostsharing.hsadminng.mapper.PostgresArray.fromPostgresArray;
import static org.springframework.transaction.annotation.Propagation.MANDATORY; import static org.springframework.transaction.annotation.Propagation.MANDATORY;
@Service @Service
@ -82,14 +80,11 @@ public class Context {
} }
public String[] getAssumedRoles() { public String[] getAssumedRoles() {
final byte[] result = (byte[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult(); return (String[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
return fromPostgresArray(result, String.class, Function.identity());
} }
public UUID[] currentSubjectsUuids() { public UUID[] currentSubjectsUuids() {
final byte[] result = (byte[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class) return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult();
.getSingleResult();
return fromPostgresArray(result, UUID.class, UUID::fromString);
} }
public static String getCallerMethodNameFromStackFrame(final int skipFrames) { public static String getCallerMethodNameFromStackFrame(final int skipFrames) {

View File

@ -11,16 +11,18 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException; import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
import org.springframework.orm.jpa.JpaSystemException; import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.validation.FieldError;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
import jakarta.validation.ValidationException; import jakarta.validation.ValidationException;
import java.util.NoSuchElementException; import java.util.*;
import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.errors.CustomErrorResponse.*; import static net.hostsharing.hsadminng.errors.CustomErrorResponse.*;
@ -119,6 +121,28 @@ public class RestResponseEntityExceptionHandler
return errorResponse(request, HttpStatus.BAD_REQUEST, errorList.toString()); return errorResponse(request, HttpStatus.BAD_REQUEST, errorList.toString());
} }
@SuppressWarnings("unchecked,rawtypes")
@Override
protected ResponseEntity handleHandlerMethodValidationException(
final HandlerMethodValidationException exc,
final HttpHeaders headers,
final HttpStatusCode status,
final WebRequest request) {
final var errorList = exc
.getAllValidationResults()
.stream()
.map(ParameterValidationResult::getResolvableErrors)
.flatMap(Collection::stream)
.filter(FieldError.class::isInstance)
.map(FieldError.class::cast)
.map(fieldError -> fieldError.getField() + " " + fieldError.getDefaultMessage() + " but is \""
+ fieldError.getRejectedValue() + "\"")
.toList();
return errorResponse(request, HttpStatus.BAD_REQUEST, errorList.toString());
}
private String userReadableEntityClassName(final String exceptionMessage) { private String userReadableEntityClassName(final String exceptionMessage) {
final var regex = "(net.hostsharing.hsadminng.[a-z0-9_.]*.[A-Za-z0-9_$]*Entity) "; final var regex = "(net.hostsharing.hsadminng.[a-z0-9_.]*.[A-Za-z0-9_$]*Entity) ";
final var pattern = Pattern.compile(regex); final var pattern = Pattern.compile(regex);

View File

@ -13,7 +13,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import jakarta.validation.Valid;
import jakarta.validation.ValidationException; import jakarta.validation.ValidationException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
@ -59,7 +58,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> addCoopAssetsTransaction( public ResponseEntity<HsOfficeCoopAssetsTransactionResource> addCoopAssetsTransaction(
final String currentUser, final String currentUser,
final String assumedRoles, final String assumedRoles,
@Valid final HsOfficeCoopAssetsTransactionInsertResource requestBody) { final HsOfficeCoopAssetsTransactionInsertResource requestBody) {
context.define(currentUser, assumedRoles); context.define(currentUser, assumedRoles);
validate(requestBody); validate(requestBody);

View File

@ -10,7 +10,7 @@ import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;

View File

@ -13,7 +13,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import jakarta.validation.Valid;
import jakarta.validation.ValidationException; import jakarta.validation.ValidationException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
@ -60,7 +59,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
public ResponseEntity<HsOfficeCoopSharesTransactionResource> addCoopSharesTransaction( public ResponseEntity<HsOfficeCoopSharesTransactionResource> addCoopSharesTransaction(
final String currentUser, final String currentUser,
final String assumedRoles, final String assumedRoles,
@Valid final HsOfficeCoopSharesTransactionInsertResource requestBody) { final HsOfficeCoopSharesTransactionInsertResource requestBody) {
context.define(currentUser, assumedRoles); context.define(currentUser, assumedRoles);
validate(requestBody); validate(requestBody);

View File

@ -7,10 +7,8 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity; import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject; import net.hostsharing.hsadminng.rbac.rbacobject.RbacObject;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView;
import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL; import net.hostsharing.hsadminng.rbac.rbacdef.RbacView.SQL;
import net.hostsharing.hsadminng.stringify.Stringify; import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable; import net.hostsharing.hsadminng.stringify.Stringifyable;

View File

@ -12,7 +12,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -53,7 +52,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
public ResponseEntity<HsOfficeMembershipResource> addMembership( public ResponseEntity<HsOfficeMembershipResource> addMembership(
final String currentUser, final String currentUser,
final String assumedRoles, final String assumedRoles,
@Valid final HsOfficeMembershipInsertResource body) { final HsOfficeMembershipInsertResource body) {
context.define(currentUser, assumedRoles); context.define(currentUser, assumedRoles);

View File

@ -1,7 +1,7 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType; import io.hypersistence.utils.hibernate.type.range.PostgreSQLRangeType;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import lombok.*; import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity; import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;

View File

@ -14,7 +14,6 @@ import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBui
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext; import jakarta.persistence.PersistenceContext;
import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -57,7 +56,7 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
public ResponseEntity<HsOfficeSepaMandateResource> addSepaMandate( public ResponseEntity<HsOfficeSepaMandateResource> addSepaMandate(
final String currentUser, final String currentUser,
final String assumedRoles, final String assumedRoles,
@Valid final HsOfficeSepaMandateInsertResource body) { final HsOfficeSepaMandateInsertResource body) {
context.define(currentUser, assumedRoles); context.define(currentUser, assumedRoles);

View File

@ -1,7 +1,7 @@
package net.hostsharing.hsadminng.hs.office.sepamandate; package net.hostsharing.hsadminng.hs.office.sepamandate;
import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType; import io.hypersistence.utils.hibernate.type.range.PostgreSQLRangeType;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import lombok.*; import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName; import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;

View File

@ -1,58 +0,0 @@
package net.hostsharing.hsadminng.mapper;
import lombok.experimental.UtilityClass;
import org.postgresql.util.PGtokenizer;
import java.lang.reflect.Array;
import java.nio.charset.StandardCharsets;
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 ) {
final String token = tokenizer.getToken(n);
if ( !"NULL".equals(token) ) {
array[n] = itemParser.apply(token.trim().replace("\\\"", "\""));
}
}
return array;
}
@SuppressWarnings("unchecked")
private static <T> T[] newGenericArray(final Class<T> elementClass, final int length) {
return (T[]) Array.newInstance(elementClass, length);
}
}

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.mapper; package net.hostsharing.hsadminng.mapper;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import java.time.LocalDate; import java.time.LocalDate;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeReasonForTerminationResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeReasonForTerminationResource;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository; import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.membership; package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import java.time.LocalDate; import java.time.LocalDate;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.sepamandate; package net.hostsharing.hsadminng.hs.office.sepamandate;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import io.restassured.RestAssured; import io.restassured.RestAssured;
import io.restassured.http.ContentType; import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication; import net.hostsharing.hsadminng.HsadminNgApplication;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.sepamandate; package net.hostsharing.hsadminng.hs.office.sepamandate;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandatePatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandatePatchResource;
import net.hostsharing.test.PatchUnitTestBase; import net.hostsharing.test.PatchUnitTestBase;

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.office.sepamandate; package net.hostsharing.hsadminng.hs.office.sepamandate;
import com.vladmihalcea.hibernate.type.range.Range; import io.hypersistence.utils.hibernate.type.range.Range;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository; import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;

View File

@ -7,7 +7,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -30,9 +29,7 @@ class PostgresArrayIntegrationTest {
return emptyArray; return emptyArray;
end; $$; end; $$;
""").executeUpdate(); """).executeUpdate();
final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnEmptyArray()", String[].class).getSingleResult(); final String[] result = (String[]) em.createNativeQuery("SELECT returnEmptyArray()", String[].class).getSingleResult();
final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity());
assertThat(result).isEmpty(); assertThat(result).isEmpty();
} }
@ -53,9 +50,7 @@ class PostgresArrayIntegrationTest {
return array[text1, text2, text3, null, text4]; return array[text1, text2, text3, null, text4];
end; $$; end; $$;
""").executeUpdate(); """).executeUpdate();
final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnStringArray()", String[].class).getSingleResult(); final String[] result = (String[]) em.createNativeQuery("SELECT returnStringArray()", String[].class).getSingleResult();
final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity());
assertThat(result).containsExactly("one", "two, three", "four; five", null, "say \"Hello\" to me"); assertThat(result).containsExactly("one", "two, three", "four; five", null, "say \"Hello\" to me");
} }
@ -75,9 +70,7 @@ class PostgresArrayIntegrationTest {
return ARRAY[uuid1, uuid2, null, uuid3]; return ARRAY[uuid1, uuid2, null, uuid3];
end; $$; end; $$;
""").executeUpdate(); """).executeUpdate();
final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnUuidArray()", UUID[].class).getSingleResult(); final UUID[] result = (UUID[]) em.createNativeQuery("SELECT returnUuidArray()", UUID[].class).getSingleResult();
final UUID[] result = PostgresArray.fromPostgresArray(pgArray, UUID.class, UUID::fromString);
assertThat(result).containsExactly( assertThat(result).containsExactly(
UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"), UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"),