【发布时间】:2020-07-18 16:16:06
【问题描述】:
我有一个TaskFilter 被用作@RestController 中的参数:
@GetMapping("/tasks")
public ResponseEntity<List<TaskDTO>> getAllTasks(Pageable pageable, TaskFilter filter)
如果我调用GET /api/tasks?priority=low 那么它工作正常,构造函数被调用。但是,如果我使用嵌套属性 GET /api/tasks?priority.gte=low 调用它会失败。如果嵌套属性是字符串,例如,没有问题。但是这里的 spring boots 似乎完全忽略了我的转换器。
如果映射(在另一条路由上)在根级别需要 TaskPriority,则它会毫无问题地转换,但当用作对象的属性时,转换不会发生并引发异常。
@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());
}
}
我已经声明了一个自定义转换器,该转换器已正确注册,但在转换过程中没有使用:
@Configuration
public class CustomConvertersConfiguration implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToTaskPriorityConverter());
}
}
我也尝试添加@Component 注释,它并没有改变任何东西:
@Component
public class StringToTaskPriorityConverter implements Converter<String, TaskPriority> {
@Override
public TaskPriority convert(String source) {
return null == source ? null : TaskPriority.forValue(source);
}
}
编辑:我之前写了一个简化版本,通过这个编辑,这里显示的代码与我的代码完全相同。
另外,作为回顾:
-
GET /api/tasks?priority=low结果为 200 -
GET /api/tasks?priority.gte=low结果为 400
两者的结果都应该是 200。
【问题讨论】:
-
GET /api/tasks?priority.gte=low工作没有任何错误。你的意思是说GET /api/tasks?priority.gte=25不工作? -
我的意思是“priority.gte=low”不起作用。 'priority=low' 工作时。
-
这很奇怪。我复制了您的代码来设置示例项目并且正在工作(我没有使用
lombok,但我认为这没有任何区别)。我将创建一个 github 存储库 -
我已经添加了 git repo。我的怀疑是你把
StringToTaskPriorityConverter放在一个完全不同的包里,没有被扫描 -
然而它正在被注册。当我使用调试器时,会触发断点。
标签: spring-boot type-conversion