Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Root;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.StringJoiner;
import lombok.Builder;
Expand Down Expand Up @@ -63,8 +64,22 @@ private static <T> Specification<T> newSpec(
@NonNull Class<? extends SimpleSpecification> domainClass,
@NonNull String path,
@NonNull Object value) {
return accessibleConstructor(domainClass, Context.class, String.class, Object.class)
.newInstance(context, path, value);
try {
return accessibleConstructor(domainClass, Context.class, String.class, Object.class)
.newInstance(context, path, value);
} catch (InvocationTargetException e) {
// Constructor.newInstance wraps any exception thrown inside the constructor in an
// InvocationTargetException; surface the original cause (e.g. TypeMismatchException,
// IllegalArgumentException) so it reaches SpecMapper.toSpec callers.
var cause = e.getCause();
if (cause instanceof RuntimeException runtimeException) {
throw runtimeException;
}
if (cause instanceof Error error) {
throw error;
}
throw new IllegalStateException(cause);
}
}

@SuppressWarnings({"unchecked"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@
package tw.com.softleader.data.jpa.spec.domain;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static tw.com.softleader.data.jpa.spec.IntegrationTest.TestApplication.noopContext;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import lombok.Builder;
import lombok.Data;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import tw.com.softleader.data.jpa.spec.IntegrationTest;
import tw.com.softleader.data.jpa.spec.SpecMapper;
import tw.com.softleader.data.jpa.spec.annotation.Spec;
import tw.com.softleader.data.jpa.spec.usecase.Customer;
import tw.com.softleader.data.jpa.spec.usecase.CustomerRepository;

Expand All @@ -49,4 +55,22 @@ void test() {
var actual = repository.findAll(spec);
assertThat(actual).hasSize(1).contains(matt);
}

@Test
void oneElementThroughMapper() {
var mapper = SpecMapper.builder().build();
var birthday = List.of(LocalDate.now());
var criteria = BetweenCriteria.builder().birthday(birthday).build();
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> mapper.toSpec(criteria, Customer.class))
.withMessage("@Between expected exact 2 elements, but was " + birthday);
}

@Builder
@Data
static class BetweenCriteria {

@Spec(value = Between.class)
List<LocalDate> birthday;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@
import static tw.com.softleader.data.jpa.spec.IntegrationTest.TestApplication.noopContext;

import java.util.Arrays;
import lombok.Builder;
import lombok.Data;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import tw.com.softleader.data.jpa.spec.IntegrationTest;
import tw.com.softleader.data.jpa.spec.SpecMapper;
import tw.com.softleader.data.jpa.spec.annotation.Spec;
import tw.com.softleader.data.jpa.spec.usecase.Customer;
import tw.com.softleader.data.jpa.spec.usecase.CustomerRepository;

Expand Down Expand Up @@ -56,4 +60,22 @@ void typeMismatch() {
.withMessage(
"Failed to convert value of type 'java.lang.Object' to required type 'java.lang.Iterable'");
}

@Test
void typeMismatchThroughMapper() {
var mapper = SpecMapper.builder().build();
var criteria = InCriteria.builder().name("matt").build();
assertThatExceptionOfType(TypeMismatchException.class)
.isThrownBy(() -> mapper.toSpec(criteria, Customer.class))
.withMessage(
"Failed to convert value of type 'java.lang.String' to required type 'java.lang.Iterable'");
}

@Builder
@Data
static class InCriteria {

@Spec(path = "name", value = In.class)
String name;
}
}