嵌套属性忽略 Spring Boot 转换器 [英] Spring Boot converter ignored for nested property
问题描述
我有一个 TaskFilter
被用作 @RestController
中的参数:
I have a TaskFilter
being used as parameter in a @RestController
:
@GetMapping("/tasks")
public ResponseEntity<List<TaskDTO>> getAllTasks(Pageable pageable, TaskFilter filter)
如果我调用 GET/api/tasks?priority=low
那么它工作正常,构造函数被调用.但是,如果我使用嵌套属性 GET/api/tasks?priority.gte=low
调用它会失败.例如,如果嵌套属性是字符串,则没问题.但这里的弹簧靴似乎完全忽略了我的转换器.
If I call GET /api/tasks?priority=low
then it works fine, the constructor is called. But if I call with a nested property GET /api/tasks?priority.gte=low
it fails. If the nested property is a string for exemple, no problem. But here spring boots seems to completely ignore my converter.
如果映射(在另一条路由上)期望在根级别有一个 TaskPriority
,则它被转换没有问题,但是当用作对象的属性时,转换不会发生,并且异常是抛出.
If the mapping (on another route) expects a TaskPriority
at the root level it is converted without issue, but when used as a property of an object, the conversion does not happen and an exception is thrown.
@Getter
@Setter
@NoArgsConstructor
@ToString
public class TaskPriorityFilter extends OrderedEnumFilter<TaskPriority> {
@JsonCreator
public TaskPriorityFilter(String tp) {
super(TaskPriority.forValue(tp));
}
}
@Getter
@Setter
@NoArgsConstructor
@ToString
abstract public class OrderedEnumFilter<E extends OrderedEnum> extends AbstractComparableFilter<E> {
public OrderedEnumFilter(E eq) {
super(eq);
}
public Object getValue() {
if (null != eq) return eq.getOrder();
if (null != gte) return gte.getOrder();
if (null != gt) return gt.getOrder();
if (null != lte) return lte.getOrder();
if (null != lt) return lt.getOrder();
if (null != between) return between.stream().map(OrderedEnum::getOrder).collect(Collectors.toList());
return null;
}
}
@Getter
@Setter
@ToString
abstract public class AbstractComparableFilter<T> implements PolymorphicFilter {
static protected AtomicInteger identifierCount = new AtomicInteger(0);
protected T eq;
protected T gte;
protected T gt;
protected T lte;
protected T lt;
protected List<T> between;
protected final int id;
public void resetIfTooHigh() {
identifierCount.compareAndSet(Integer.MAX_VALUE - 1, 0);
}
public AbstractComparableFilter() {
this.id = identifierCount.getAndIncrement();
resetIfTooHigh();
}
@JsonCreator
public AbstractComparableFilter(T eq) {
this.eq = eq;
this.id = identifierCount.getAndIncrement();
resetIfTooHigh();
}
public String getStartKey() {
return "betweenStart" + id;
}
public String getEndKey() {
return "betweenEnd" + id;
}
public Object getValue() {
if (null != eq) return eq;
if (null != gte) return gte;
if (null != gt) return gt;
if (null != lte) return lte;
if (null != lt) return lt;
if (null != between) return between;
return null;
}
public ComparableType getFilterType() {
if (null != eq) return ComparableType.EQ;
if (null != gte) return ComparableType.GTE;
if (null != gt) return ComparableType.GT;
if (null != lte) return ComparableType.LTE;
if (null != lt) return ComparableType.LT;
if (null != between) return ComparableType.BETWEEN;
throw new InvalidOperationException("unknown filter subtype");
}
}
public enum TaskPriority {
High(75),
Medium(50),
Low(25)
;
private final Integer order;
TaskPriority(Integer order) {
this.order = order;
}
public Integer getOrder() {
return order;
}
@JsonCreator
public static TaskPriority forValue(String value) {
return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, value));
}
@JsonCreator
public static TaskPriority forValue(Integer order) {
return Stream.of(TaskPriority.values())
.filter(c -> order.equals(c.getOrder()))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
@JsonValue
public String toValue() {
return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name());
}
}
我已声明自定义转换器,转换器已正确注册,但在转换过程中未使用:
I've declared a custom converter, the converter is correctly registered, but is not used during the conversion process :
@Configuration
public class CustomConvertersConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToTaskPriorityConverter());
}
}
我也尝试添加 @Component
注释,但它没有改变任何东西:
I've also tried to add the @Component
annotation, and it doesn't change anything :
@Component
public class StringToTaskPriorityConverter implements Converter<String, TaskPriority> {
@Override
public TaskPriority convert(String source) {
return null == source ? null : TaskPriority.forValue(source);
}
}
我之前写了一个简化版本,通过这个编辑,这里显示的代码与我的代码完全相同.
EDIT : I previously wrote a simplified version, with this edit the code presented here is exactly the same as in my code.
另外,作为一个回顾:
GET/api/tasks?priority=low
结果为 200GET/api/tasks?priority.gte=low
结果是 400
GET /api/tasks?priority=low
results in a 200GET /api/tasks?priority.gte=low
results in a 400
两者的结果都应该是 200.
推荐答案
- 以下构造函数会导致
StringToTaskPriorityConverter
被忽略.(最初问题将TaskPriority
作为构造函数参数,这就是我的回购行为与您的问题相反的原因) - Following constructor causes the
StringToTaskPriorityConverter
being ignored. (Initially the question hadTaskPriority
as constructor param, it is the reason my repo had the opposite behaviour to your question)
@JsonCreator
public TaskPriorityFilter(String tp) {
super(TaskPriority.forValue(tp));
}
- 将构造函数替换为
@JsonCreator
public TaskPriorityFilter(TaskPriority tp) {
super(tp);
}
- 添加了另外一个自定义转换器,如下所示.
@Component
public class StringToTaskPriorityFilterConverter implements
Converter<String, TaskPriorityFilter> {
@Override
public TaskPriorityFilter convert(String source) {
System.out.println("StringToTaskPriorityFilterConverter
is called for " + source);
if (source == null)
return null;
try {
return new
TaskPriorityFilter(TaskPriority.forValue(Integer.parseInt(source)));
} catch (Exception e) {
return new TaskPriorityFilter(TaskPriority.forValue(source));
}
}
}
通过上述更改,
?priority=low
和?priority.gte=low
都有效.但是我不确定带有字符串参数的构造函数导致自定义转换器被忽略的原因.
However I am not sure about the reason the Constructor with string param causes the custom converter to be ignored.
参考
Github 存储库,允许以下 3 个请求.https://github.com/kavi-kanap/stackoverflow-62970847
Github repo that allows following 3 requests. https://github.com/kavi-kanap/stackoverflow-62970847
这篇关于嵌套属性忽略 Spring Boot 转换器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!