Spring打开projects+Jackson:即使@Value抛出异常也会写入JsonType注解

t8e9dugd  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(60)

项目

我使用开放投影,并带有设置类型名称的注解。Impact是一个递归接口,它将属性impacts添加到所有具有影响的对象。我只复制了相关/清理的代码以保持清晰。

@GetMapping("/{id}/impacts")
    public ImpactOverview getImpacts(@PathVariable("id") String id) {
        return repository.findImpactByLabel(id, Impacts.class);
    }
public interface Impacts extends Field,ImpactOverview {
    // repo variable is simple spring data repository with a id and projection class params.
    @JsonIgnore
    @Value("#{@repo.findTable(target.label, T(com.company.view.projections.field.impacts.Table))}")
    Table getTable();

    default Collection<? extends ImpactOverview> impacts() {
        //combine is just making a big collection of collection fields & singular fields
        return combine(getTable(), ...);
    }

}
public interface Table extends com.company.view.projections.table.Table,ImpactOverview {}
@JsonTypeName(AssetType.FIELD_TYPENAME)
public interface Field {}
@JsonTypeName(AssetType.TABLE_TYPENAME)
public interface Table {}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public interface ImpactOverview {
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
    default Collection<? extends ImpactOverview> impacts() {
        return null;
    }
}

基本上,这工作得很好,并导致嵌套的影响概述json结构如下:

{
    "type": "field",
    ...
    "impacts: [
        {
            "type": "table",
            ...
        },
        {
            "type": "...",
            ...
            impacts: [...]
        }
    ]
}


可读如下:如果这个字段发生了变化,我们会影响这个表,这个.
我们还编写了一个扩展ResponseIdentyExcepiontext的ControllerAdvice。

@ControllerAdvice
@Slf4j
@RequiredArgsConstructor
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(final Exception ex,
                                                             final Object body,
                                                             final HttpHeaders headers,
                                                             final HttpStatusCode statusCode,
                                                             final WebRequest request) {
        return toCompanyException(ex);
    }

    @ResponseBody
    ResponseEntity<Object> toCompanyException(@NonNull Exception e) {
        return ResponseEntity.status(Status.of(e)).body(Body.of(e));
    }
}

问题是

如果这个repo.findTable调用失败,AbstractJackson2HttpMessageConverter会抛出一个HttpMessageNotWritable异常,我们会收到一个如下所示的json结构:

{
    "type": "FIELD"
}{
    "exception": "http-message-not-writable",
    "message": "exception"
}


发生这种情况是因为BeanSerializerBase::serializeWithType方法执行了一个writeTypePrefix,其中写入了"type": "field"。只有在serializeFields调用中才会发生异常。
在那一刻,字段类型已经写好了。我如何克服这个问题?我们只想返回异常对象。如果我提前调用所有getImpacts,所有方法都会被调用/测试,但我会执行所有查询两次?或者在接口的代理中会有缓存。或者我应该把它存储在一些Map<String, Object>类型的对象中,让Jackson解析那个Map?

dgjrabp2

dgjrabp21#

发现这是由this issue I openend in spring framework引起的
现在可以通过删除extends ResponseEntityExceptionHandler来绕过。

相关问题