【问题标题】:JPA Transient Annotation and JSONJPA 瞬态注释和 JSON
【发布时间】:2014-11-01 01:26:56
【问题描述】:

这是对以下关于 JPA 瞬态注释的问题的跟进 Why does JPA have a @Transient annotation?

我有一个不想保留的瞬态变量,它标有瞬态注释。 但是,当我想从我的 rest 控制器生成 JSON 时,输出的 JSON 中没有这个瞬态变量。

POJO PublicationVO 很简单,没有花哨的属性,只有一些私有属性(持久化),带有 getter 和 setter 以及 1 个临时变量。

@RequestMapping(value = { "{publicationId}"}, method = RequestMethod.GET, produces = "application/json")
@ResponseBody public PublicationVO getPublicationDetailsJSON(@PathVariable(value = "publicationId") Integer publicationId) {
    LOG.info("Entered getPublicationDetailsJSON - publicationId: " + publicationId);

    //Call method to get the publicationVO based on publicationId
    PublicationVO publicationVO = publicationServices.getPublicationByIdForRestCalls(publicationId);       
    LOG.info("publicationVO:{}", publicationVO);

    LOG.info("Exiting getPublicationDetailsJSON");
    return publicationVO;
}

PublicationVO如下

    package com.trinity.domain.dao;

import java.util.Calendar;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import com.fasterxml.jackson.annotation.JsonInclude;

@Entity
@Table(name = "publication")
public class PublicationVO {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;    
    @Column(name = "publicationName", unique = false, nullable = false, length = 200)
    private String publicationName;
    @Column(name = "publicationSource", unique = false, nullable = false, length = 45)
    private String publicationSource;

    @Column(name = "dateAdded", unique = false, nullable = false)
    private Calendar dateAdded;

    @Transient
    private float percentageProcessed;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getPublicationName() {
        return publicationName;
    }

    public void setPublicationName(String publicationName) {
        this.publicationName = publicationName;
    }

    public String getPublicationSource() {
        return publicationSource;
    }

    public void setPublicationSource(String publicationSource) {
        this.publicationSource = publicationSource;
    }

    public Calendar getDateAdded() {
        return dateAdded;
    }

    public void setDateAdded(Calendar dateAdded) {
        this.dateAdded = dateAdded;
    }

    public float getPercentageProcessed() {
        return percentageProcessed;
    }

    public void setPercentageProcessed(float percentageProcessed) {
        this.percentageProcessed = percentageProcessed;
    }

    @Override
    public String toString() {
        return "PublicationVO [id=" + id + ", publicationName=" + publicationName + ", publicationSource=" + publicationSource + ", dateAdded=" + dateAdded
                + ", percentageProcessed=" + percentageProcessed + "]";
    }
}

当我在日志中看到publishVO 的调试语句时,瞬态变量包含在输出中,但在我的客户端代码中,瞬态变量不包含在json 响应中。

非常感谢任何帮助。

谢谢你, 达米安

【问题讨论】:

  • 您可以编辑您的问题并发布 PublicationVO 的代码吗?您未序列化的瞬态变量是否有适当的吸气剂?
  • @m4rtin - 我刚刚包含了 publicationVo 类。是的,瞬态变量有一个 getter 方法
  • 我可以在您的问题中看到一些 Spring MVC 注释以及 Spring 标记,您能否确认 JSON 的序列化是由 Jackson 库完成的?
  • 是的,很抱歉序列化是通过杰克逊完成的。如果是这种情况,我需要使字段非瞬态,我可以尝试找出一种解决方法,但希望有一种更清洁的方法
  • 真正的 m4rtin 这是一个公平的观点。我会尝试手动添加数据库列,删除瞬态注释,看看它有什么不同并回复你

标签: java json spring rest jackson


【解决方案1】:

在我的情况下只适用于此:

@Transient
@JsonGetter(value = "transientProperty")
public String getSomething() {
    return something;
}

我希望这对某人有用。 问候。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题。以下解决方案对我有用:

    @Bean
    public Module hibernate5Module() {
        Hibernate5Module hnetModule = new Hibernate5Module();
        hnetModule.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
        return hnetModule;
    }
    

    感谢 m4rtin。

    【讨论】:

      【解决方案3】:

      它对我有用:

      @Transient
      @JsonProperty
      

      在 GETTER 中(不在私有字段定义中)

      @JsonAutoDetect(fieldVisibility = Visibility.ANY) 
      

      注释类

      【讨论】:

      • 我能问一下为什么投反对票吗?
      • 这对我有用,必须在课堂级别添加@JsonAutoDetect,谢谢!
      【解决方案4】:

      由于这里没有其他解决方案对我有用,让我发布我的解决方案它是如何为我解决问题的:

      @Transient
      @JsonSerialize
      private String mapImageSrc;
      

      这对我来说似乎是最好的解决方案,因为 @JsonSerialize 注释已针对该用例进行。

      【讨论】:

      • 就我而言,我只有 getter,例如 int getCounter() ,没有 setter 或字段。我所要做的只是添加@JsonSerialize。没有瞬态或其他
      【解决方案5】:

      添加@Transient后尝试@JsonView

      【讨论】:

      • 使用 cmets 获取琐碎的答案和建议
      【解决方案6】:

      在 com.fasterxml.jackson.annotation 中使用 @JsonIgnore Date 变量还有@JsonFormat。 为我工作

      【讨论】:

        【解决方案7】:

        我同时使用@Transient 和@JsonProperty,然后就可以了!

        @Transient
        @JsonProperty
        private String mapImageSrc;
        

        【讨论】:

        • +1 是的,这也有效。 JsonSerialize 和 JsonProperty 似乎都有效。我想知道是否存在细微的差异,是否有一个优于另一个。
        • 您甚至可以使用@JsonProperty(access = Access.WRITE_ONLY) 或@JsonProperty(access = Access.READ_ONLY) 优化访问权限
        • 在我的领域使用@Transient 时,这是唯一对我有用的东西..
        【解决方案8】:

        我只是添加了JsonSerializeJsonDeserialize 注释。

        @Transient
        @JsonSerialize
        @JsonDeserialize
        private String myField;
        

        【讨论】:

        • 谢谢,它成功了。这有助于分别定义哪些应该保存在数据库中,哪些应该放入 JSON。
        • 我不知道它是否有效,但似乎我们最终在实体中混合了跨层信息。 Transient 用于 db 层(最低层),而 JsonSerialize 应位于 UI/Client 层。
        • 我必须确保为 @Json* 注解导入了正确的包。 org.springframework.cloud.cloudfoundry.com.fasterxml.jackson.databind.annotation 无效,但 com.fasterxml.jackson.databind.annotation. 有效。
        【解决方案9】:

        与我在 cmets 中告诉您的相反,由于 Jackson's Hibernate module,Jackson 在用于序列化实体类实例时似乎确实关心 JPA 注释。

        在该模块中,有一个HibernateAnnotationIntrospector,文档将其称为

        简单的 AnnotationIntrospector,增加了对使用 Transient 的支持 表示可忽略的字段(与 Jackson 和/或 JAXB 一起 注释)。

        您可以看到here,Jackson 的默认行为是检查它可以找到的任何@Transient 注释。

        所以最后,你的问题可以通过这三种方式中的任何一种来解决:

        1. 配置 Jackson(使用 HibernateAnnotationIntrospector 的 setUseTransient 方法)禁用对 @Transient 注释的检查(有关实现细节,请参阅 this answer)。
        2. 使用除PublicationVO 之外的另一个对象作为getPublicationDetailsJSON 方法的返回结果。您必须将值对象中的属性复制到某个时候返回的对象。
        3. 删除 @Transient 注释并保留该属性(但我会理解这是否不适合您,因为您可能有充分的理由首先将该属性设为 JPA 瞬态)。

        干杯

        【讨论】:

        • 优秀的答案 m4rtin。我会在早上尝试第 1 步,如果这不起作用,我认为第 2 步可能是下一个逻辑步骤
        • 非常感谢 m4rtin 提供的信息,它对我们有用。
        • Jackson 甚至关心 hibernate 的注释的选择超出了我的范围。这些家伙是不是很高?
        【解决方案10】:

        只是为了进一步补充 m4rtin 提供的答案

        我采用第一种方法 - 配置 Jackson(使用 HibernateAnnotationIntrospector 的 setUseTransient 方法)以禁用对 @Transient 注释的检查。

        在我的项目中,我必须遵循以下线程以避免对非获取的惰性对象进行杰克逊序列化 Avoid Jackson serialization on non fetched lazy objects

        为了将我的项目配置为不忽略瞬态注释,我将 Hibernate4Module 设置如下

                Hibernate4Module hm = new Hibernate4Module();
            hm.disable(Feature.USE_TRANSIENT_ANNOTATION);
        

        感谢您对此 m4rtin 的帮助

        【讨论】:

        • 很高兴您找到了有关第一种方法的实施细节,我将编辑我的答案以添加对您的答案的引用,这肯定会对寻求解决方案 1 的人们有所帮助。
        • 终于有用了!我创建了一个gist,其中包含此设置所需的各种文件。
        猜你喜欢
        • 2017-10-15
        • 2016-11-30
        • 2012-01-06
        • 1970-01-01
        • 2011-04-27
        • 2018-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多