JPA Transient Annotation and JSON

2019-01-11 03:28发布

问题:

This is a follow up to the following question on the JPA Transient annotation Why does JPA have a @Transient annotation?

I have a transient variable that I do not want to persist and it is marked with the transient annotation. However, when I want to produce JSON from my rest controller, this transient variable is not available in the outputted JSON.

The POJO PublicationVO is straight forward with no fancy attributes, just some private attributes (that are persisted) with getters and setters and 1 transient variable.

@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;
}

The PublicationVO is as follows

    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 + "]";
    }
}

When I see the debug statement for publicationVO in my logs, the transient variable is included in the output but in my client code, the transient variable is not included in the json response.

Any help is greatly appreciated.

Thank you, Damien

回答1:

Contrary to what I was telling you in comments, it seems that Jackson does care about JPA annotations when used to serialize instances of entity classes thanks to the Jackson's Hibernate module.

Within that module, there is an HibernateAnnotationIntrospector that the documentation refers to as a

simple AnnotationIntrospector that adds support for using Transient to denote ignorable fields (alongside with Jackson and/or JAXB annotations).

And as you can see here, the default behavior of Jackson is to check for any @Transient annotation it can find.

So in the end, your problem can be solved in either of those 3 ways :

  1. Configure Jackson (using HibernateAnnotationIntrospector's setUseTransient method) to disable the check for @Transient annotations (see this answer for implementation details).
  2. Use another object than PublicationVO as the returned result of your getPublicationDetailsJSON method. You'll have to copy properties from your value object to the object being returned at some point.
  3. Remove the @Transient annotation and persist the property (but I would understand if that is not an option for you since you probably have good reason to have made this property JPA-transient in the first place).

Cheers



回答2:

I simply added JsonSerialize and JsonDeserialize annotations.

@Transient
@JsonSerialize
@JsonDeserialize
private String myField;


回答3:

Just to add further to the answer provided by m4rtin

I went with the first approach - Configure Jackson (using HibernateAnnotationIntrospector's setUseTransient method) to disable the check for @Transient annotations.

In my project I follwed had to follow the following thread to avoid jackson serialization on non fetched lazy objects Avoid Jackson serialization on non fetched lazy objects

To configure my project to not ignore transient annotations, I set up the Hibernate4Module as follows

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

Thanks for your help on this m4rtin



回答4:

I use both @Transient and @JsonProperty, then it works!

@Transient
@JsonProperty
private String mapImageSrc;


回答5:

What it worked for me:

@Transient
@JsonProperty

in the GETTER (not in the private field definition)

AND

@JsonAutoDetect(fieldVisibility = Visibility.ANY) 

annotating the class



回答6:

Try @JsonView after adding @Transient



回答7:

Since no other solution here worked for me, let me post my solution how it did the trick for me:

@Transient
@JsonSerialize
private String mapImageSrc;

This seems to be the best solution to me as the @JsonSerialize annotation has been made for that use case.



回答8:

use @JsonIgnore in com.fasterxml.jackson.annotation there also is @JsonFormat for Date variable. works for me



回答9:

I had the same problem. Below solution worked for me:

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

Thanks to m4rtin.