spring-boot-3-2-upgrade (#32)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/32 Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
@ -15,11 +15,9 @@ 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
|
||||
@ -82,14 +80,11 @@ public class Context {
|
||||
}
|
||||
|
||||
public String[] getAssumedRoles() {
|
||||
final byte[] result = (byte[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
|
||||
return fromPostgresArray(result, String.class, Function.identity());
|
||||
return (String[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
|
||||
}
|
||||
|
||||
public UUID[] currentSubjectsUuids() {
|
||||
final byte[] result = (byte[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class)
|
||||
.getSingleResult();
|
||||
return fromPostgresArray(result, UUID.class, UUID::fromString);
|
||||
return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult();
|
||||
}
|
||||
|
||||
public static String getCallerMethodNameFromStackFrame(final int skipFrames) {
|
||||
|
@ -11,16 +11,18 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
|
||||
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.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.method.annotation.HandlerMethodValidationException;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static net.hostsharing.hsadminng.errors.CustomErrorResponse.*;
|
||||
@ -119,6 +121,28 @@ public class RestResponseEntityExceptionHandler
|
||||
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) {
|
||||
final var regex = "(net.hostsharing.hsadminng.[a-z0-9_.]*.[A-Za-z0-9_$]*Entity) ";
|
||||
final var pattern = Pattern.compile(regex);
|
||||
|
@ -13,7 +13,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
@ -59,7 +58,7 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
|
||||
public ResponseEntity<HsOfficeCoopAssetsTransactionResource> addCoopAssetsTransaction(
|
||||
final String currentUser,
|
||||
final String assumedRoles,
|
||||
@Valid final HsOfficeCoopAssetsTransactionInsertResource requestBody) {
|
||||
final HsOfficeCoopAssetsTransactionInsertResource requestBody) {
|
||||
|
||||
context.define(currentUser, assumedRoles);
|
||||
validate(requestBody);
|
||||
|
@ -10,7 +10,7 @@ import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
|
||||
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.rbacobject.RbacObject;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
@ -13,7 +13,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
@ -60,7 +59,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
|
||||
public ResponseEntity<HsOfficeCoopSharesTransactionResource> addCoopSharesTransaction(
|
||||
final String currentUser,
|
||||
final String assumedRoles,
|
||||
@Valid final HsOfficeCoopSharesTransactionInsertResource requestBody) {
|
||||
final HsOfficeCoopSharesTransactionInsertResource requestBody) {
|
||||
|
||||
context.define(currentUser, assumedRoles);
|
||||
validate(requestBody);
|
||||
|
@ -7,10 +7,8 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
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.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.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
|
@ -12,7 +12,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
@ -53,7 +52,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
||||
public ResponseEntity<HsOfficeMembershipResource> addMembership(
|
||||
final String currentUser,
|
||||
final String assumedRoles,
|
||||
@Valid final HsOfficeMembershipInsertResource body) {
|
||||
final HsOfficeMembershipInsertResource body) {
|
||||
|
||||
context.define(currentUser, assumedRoles);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.office.membership;
|
||||
|
||||
import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType;
|
||||
import com.vladmihalcea.hibernate.type.range.Range;
|
||||
import io.hypersistence.utils.hibernate.type.range.PostgreSQLRangeType;
|
||||
import io.hypersistence.utils.hibernate.type.range.Range;
|
||||
import lombok.*;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationEntity;
|
||||
|
@ -14,7 +14,6 @@ import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBui
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
@ -57,7 +56,7 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
|
||||
public ResponseEntity<HsOfficeSepaMandateResource> addSepaMandate(
|
||||
final String currentUser,
|
||||
final String assumedRoles,
|
||||
@Valid final HsOfficeSepaMandateInsertResource body) {
|
||||
final HsOfficeSepaMandateInsertResource body) {
|
||||
|
||||
context.define(currentUser, assumedRoles);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.office.sepamandate;
|
||||
|
||||
import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType;
|
||||
import com.vladmihalcea.hibernate.type.range.Range;
|
||||
import io.hypersistence.utils.hibernate.type.range.PostgreSQLRangeType;
|
||||
import io.hypersistence.utils.hibernate.type.range.Range;
|
||||
import lombok.*;
|
||||
import net.hostsharing.hsadminng.errors.DisplayName;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
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 java.time.LocalDate;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.http.ContentType;
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeReasonForTerminationResource;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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 org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.hs.office.debitor.HsOfficeDebitorRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.http.ContentType;
|
||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.generated.api.v1.model.HsOfficeSepaMandatePatchResource;
|
||||
import net.hostsharing.test.PatchUnitTestBase;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||
|
@ -7,7 +7,6 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ -30,9 +29,7 @@ class PostgresArrayIntegrationTest {
|
||||
return emptyArray;
|
||||
end; $$;
|
||||
""").executeUpdate();
|
||||
final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnEmptyArray()", String[].class).getSingleResult();
|
||||
|
||||
final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity());
|
||||
final String[] result = (String[]) em.createNativeQuery("SELECT returnEmptyArray()", String[].class).getSingleResult();
|
||||
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
@ -53,9 +50,7 @@ class PostgresArrayIntegrationTest {
|
||||
return array[text1, text2, text3, null, text4];
|
||||
end; $$;
|
||||
""").executeUpdate();
|
||||
final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnStringArray()", String[].class).getSingleResult();
|
||||
|
||||
final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity());
|
||||
final String[] result = (String[]) em.createNativeQuery("SELECT returnStringArray()", String[].class).getSingleResult();
|
||||
|
||||
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];
|
||||
end; $$;
|
||||
""").executeUpdate();
|
||||
final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnUuidArray()", UUID[].class).getSingleResult();
|
||||
|
||||
final UUID[] result = PostgresArray.fromPostgresArray(pgArray, UUID.class, UUID::fromString);
|
||||
final UUID[] result = (UUID[]) em.createNativeQuery("SELECT returnUuidArray()", UUID[].class).getSingleResult();
|
||||
|
||||
assertThat(result).containsExactly(
|
||||
UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
|
||||
|
Reference in New Issue
Block a user