【问题标题】:Jackson JPA @Version Not serializedJackson JPA @Version 未序列化
【发布时间】:2015-10-28 20:37:01
【问题描述】:

我的 JPA 实体如下

@Entity
public class OptionsEntity implements Serializable {



    @Id
    @Column(name="OptionNumber",
            nullable=false,
            insertable=true,
            updatable=true,
            length=20)
    private String optionNumber;

    @Basic
    @Column(name="OptionName",
            nullable=false,
            insertable=true,
            updatable=true,
            length=100)
    private String optionName;

    @Basic
    @Column(name="OptionStatusCode",
            nullable=true,
            insertable=true,
            updatable=true,
            length=20)
    private String optionStatusCode;

    @JsonProperty
    @Version
    @Column(name="VersionNumber",
            nullable=false,
            insertable=true,
            updatable=true)
    private Integer versionNumber;

}

我希望 versionNumber 出现在响应正文中。但是,由于某种原因,它被忽略了。

我正在使用 Spring Boot 和 Spring Data 存储库来检索数据。我不确定它是否在这里扮演任何角色。

Spring Data 谈到了 ETag。但是,让 Spring Security 与 Spring Data 一起参与似乎是一个复杂的过程(由于缓存标头),并且在使用客户端的实体集合(JavaScipt)时也是如此。因此,我想自己处理资源版本控制。

请帮忙。

谢谢!

【问题讨论】:

  • 看起来没什么问题。我认为甚至不需要@JsonProperty。您是否尝试将 Integer 更改为原始 int?我假设你有所有领域的公共 getter 和 setter。

标签: jackson spring-boot spring-data spring-data-jpa


【解决方案1】:

REST 具有处理资源状态的专用方法,显式标头可根据该资源状态有条件地触发请求。

所以 Spring Data REST 所做的就是将持久存储的方式转换为 REST 的方式来表达。这包括将人工(为了持久存储)引入的属性(标识符、版本属性)转换为 REST 等价物(self URIs、ETags)。使用 version 属性作为 ETag 然后需要将其两个删除,原因有多种:

  • 它最初是人为引入的,因此实际上不是资源表示的一部分
  • 其目的是通过不同的方式实现的,因此需要将其“转移”到这些方式
  • 将其保留在表示中会产生 ETag 中的内容与表示之间不匹配的风险。如果客户端出于某种原因混淆了它们,那么服务器应该如何确定客户端的实际意图?

@Version 属性的处理细节在reference documentation 中描述。

【讨论】:

  • 嗨奥利弗..谢谢你的回复。 ETag 似乎是个好主意。但是我们的客户不喜欢将附加标头作为他们使用的框架的想法。Telerik Kendo UI 不支持 ETag 功能。此外,当我在响应中有一组元素时,我不确定 ETAG 概念是如何工作的。最后,我需要禁用 Spring Security Cache 标头以公开 ETag,我们的安全专家不喜欢这样..因此,由于反馈意见参差不齐,我唯一的选择是自己处理版本号..有什么想法吗?
  • 要么修复客户端,要么不使用 Spring Data REST,而是自己构建服务器端。
  • :( 实际上.. 在这种情况下.. 我正在绕过 SDR.. 响应来自 REST 控制器...并且该实体/实体的保存将被发送到控制器也是如此......但看起来 SDR 配置也在启动...... SDR 在许多其他领域为我节省了很多时间......
【解决方案2】:

好吧..随着我的理解越来越好..

ETag 是一个很酷的功能。特别是因为客户端不必通过 JSON 模式来获取版本号属性。 ETag 应该是被普遍认可的。

现在,问题在于实体集合。显然,我们不能在响应上设置 ETag,除非我们将集合作为其自身的另一个实体来管理。如果存在搜索结果包含实体集合并可能将完整对象暴露给客户端的情况,则会出现问题。

根据上述 SDR 的领先优势,似乎没有直接的方法可以绕过这一点。 PersistentEntityJackson2Module 中的以下代码是跳过版本 id 属性的原因。

            for (BeanPropertyWriter writer : builder.getProperties()) {

            // Skip exported associations
            PersistentProperty<?> persistentProperty = findProperty(writer.getName(), entity, beanDesc);

            if (persistentProperty == null) {
                result.add(writer);
                continue;
            }

            if (associationLinks.isLinkableAssociation(persistentProperty)) {
                continue;
            }

            // Skip ids unless explicitly configured to expose
            if (persistentProperty.isIdProperty() && !configuration.isIdExposedFor(entity.getType())) {
                continue;
            }

            if (persistentProperty.isVersionProperty()) {
                continue; ===> This causes version number to be stripped off.. 
            }

            result.add(writer);
        }

显然我们可以编写自己的替代方案来绕过上面的代码..但这很愚蠢..所以我最终在下面做了一些事情,以便其他一切都可以顺利..

@Version
@Column(name="VersionNumber",
        nullable=false,
        insertable=true,
        updatable=true)
private Integer versionNumber;

@JsonProperty(value = "versionNumber")
@Transient
private Integer version;

public Integer getVersion(){
    return (versionNumber != null) ? versionNumber : version;
}

public void setVersion(Integer version){
    if(version != null)
        setVersionNumber(version);
}

public void setVersionNumber(Integer version){
    this.versionNumber = version;
    this.version = version;
}   

我在 SDR 项目中打开了一个功能请求来处理这种情况 DATAREST-636

编码愉快..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-19
    • 2014-07-08
    • 2012-06-11
    • 2020-09-25
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    相关资源
    最近更新 更多