There are some specs supporting date fields that are also LocaleAware. When providing a config with a custom date format string (e.g. @Spec(config = {"dd.MM.yyyy"}), these specs cannot be initialized for incoming requests running into this error:
jakarta.servlet.ServletException: Request processing failed: java.lang.IllegalArgumentException: Invalid locale format: dd.MM.yyyy
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:892)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:633)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:874)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:160)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:127)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:199)
at net.kaczmarzyk.EqualIgnoreCaseE2eTest.findsByFormattedDateValueIgnoringCase(EqualIgnoreCaseE2eTest.java:122)
Caused by: java.lang.IllegalArgumentException: Invalid locale format: dd.MM.yyyy
at org.apache.commons.lang3.LocaleUtils.parseLocale(LocaleUtils.java:294)
at org.apache.commons.lang3.LocaleUtils.toLocale(LocaleUtils.java:376)
at net.kaczmarzyk.spring.data.jpa.web.SimpleSpecificationResolver.resolveConverter(SimpleSpecificationResolver.java:157)
at net.kaczmarzyk.spring.data.jpa.web.SimpleSpecificationResolver.newSpecification(SimpleSpecificationResolver.java:102)
at net.kaczmarzyk.spring.data.jpa.web.SimpleSpecificationResolver.buildSpecification(SimpleSpecificationResolver.java:77)
at net.kaczmarzyk.spring.data.jpa.web.SimpleSpecificationResolver.buildSpecification(SimpleSpecificationResolver.java:47)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationFactory.buildSpecification(SpecificationFactory.java:139)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationFactory.lambda$resolveSpecFromParameterAnnotations$1(SpecificationFactory.java:105)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationFactory.forEachSupportedSpecificationDefinition(SpecificationFactory.java:146)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationFactory.resolveSpecFromParameterAnnotations(SpecificationFactory.java:102)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationFactory.resolveSpec(SpecificationFactory.java:95)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationFactory.createSpecificationDependingOn(SpecificationFactory.java:76)
at net.kaczmarzyk.spring.data.jpa.web.SpecificationArgumentResolver.resolveArgument(SpecificationArgumentResolver.java:105)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:230)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:180)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:934)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:853)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:86)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:866)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003)
... 9 more
|
if (def.config().length == 1) { |
|
if (LocaleAware.class.isAssignableFrom(def.spec())) { // if specification is locale-aware, then we assume that config contains locale |
|
String localeConfig = def.config()[0]; |
|
Locale customlocale = LocaleUtils.toLocale(localeConfig); |
|
return Converter.withTypeMismatchBehaviour(def.onTypeMismatch(), conversionService, customlocale); |
|
} else { // otherwise we assume that config contains date format |
|
String dateFormat = def.config()[0]; |
|
return Converter.withDateFormat(dateFormat, def.onTypeMismatch(), conversionService); |
|
} |
|
} |
|
throw new IllegalStateException("config should contain only one value -- a date format"); // TODO support other config values as well |
SimpleSpecificationResolver.resolveConverter always evaluates the config value as Locale for LocaleAware Specs. I'm unsure how this could be properly resolved. Maybe the config evaluation as Locale should move somewhere near CaseConversionHelper.applyCaseConversion, since it is only relevant when using IgnoreCaseStrategy.APPLICATION.
|
if (effectiveStrategy == IgnoreCaseStrategy.APPLICATION) { |
|
Locale effectiveLocale = locale != null ? locale : Locale.getDefault(); |
|
String convertedValue = value.toUpperCase(effectiveLocale); |
|
return new ConvertedExpressions( |
|
cb.upper(columnExpression), |
|
cb.literal(convertedValue) |
|
); |
|
} |
|
|
|
return new ConvertedExpressions( |
|
applyDatabaseCaseConversion(cb, columnExpression, effectiveStrategy), |
|
applyDatabaseCaseConversion(cb, cb.literal(value), effectiveStrategy) |
|
); |
|
} |
|
|
|
/** |
|
* Applies case conversion to both column expression and value according to the strategy. |
|
*/ |
|
@SuppressWarnings("deprecation") |
|
public static ConvertedExpressionsList applyCaseConversion( |
|
CriteriaBuilder cb, |
|
Expression<String> columnExpression, |
|
String[] values, |
|
IgnoreCaseStrategy strategy, |
|
Locale locale) { |
|
|
|
IgnoreCaseStrategy effectiveStrategy = strategy != null ? strategy : IgnoreCaseStrategy.DATABASE_UPPER; |
|
|
|
if (effectiveStrategy == IgnoreCaseStrategy.APPLICATION) { |
I added some test cases in my fork at cschierle@fab944b showcasing the IgnoreCase Specs supporting date fields running into this issue, while their exact match counterparts work just fine.
Any ideas how this issue could be resolved?
There are some specs supporting date fields that are also
LocaleAware. When providing a config with a custom date format string (e.g.@Spec(config = {"dd.MM.yyyy"}), these specs cannot be initialized for incoming requests running into this error:specification-arg-resolver/src/main/java/net/kaczmarzyk/spring/data/jpa/web/SimpleSpecificationResolver.java
Lines 154 to 164 in 77bc7d0
SimpleSpecificationResolver.resolveConverteralways evaluates the config value as Locale for LocaleAware Specs. I'm unsure how this could be properly resolved. Maybe the config evaluation as Locale should move somewhere nearCaseConversionHelper.applyCaseConversion, since it is only relevant when usingIgnoreCaseStrategy.APPLICATION.specification-arg-resolver/src/main/java/net/kaczmarzyk/spring/data/jpa/utils/CaseConversionHelper.java
Lines 48 to 76 in 77bc7d0
I added some test cases in my fork at cschierle@fab944b showcasing the IgnoreCase Specs supporting date fields running into this issue, while their exact match counterparts work just fine.
Any ideas how this issue could be resolved?