web-dev-qa-db-fra.com

Annotation transitoire JPA et JSON

Ceci fait suite à la question suivante sur l'annotation transitoire JPA Pourquoi JPA a-t-elle une annotation @Transient?

J'ai une variable transitoire que je ne veux pas persister et elle est marquée avec l'annotation transitoire. Cependant, lorsque je veux produire du JSON à partir de mon contrôleur de repos, cette variable transitoire n'est pas disponible dans le JSON généré.

Le POJO PublicationVO est simple, sans attribut de fantaisie, juste quelques attributs privés (qui sont persistants) avec des getters et setters et 1 variable transitoire.

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

La PublicationVO est la suivante

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

Lorsque je vois l'instruction de débogage pour publicationVO dans mes journaux, la variable transitoire est incluse dans la sortie mais dans mon code client, la variable transitoire n'est pas incluse dans la réponse json.

Toute aide est grandement appréciée.

Merci, Damien

35
Damien Gallagher

Contrairement à ce que je vous disais dans les commentaires, il semble que Jackson se soucie des annotations JPA lorsqu'il est utilisé pour sérialiser des instances de classes d'entités grâce au module Hibernate de Jackson .

Dans ce module, il y a un HibernateAnnotationIntrospector que la documentation appelle un

annotationIntrospector simple qui ajoute la prise en charge de l'utilisation de Transient pour désigner les champs ignorables (avec les annotations Jackson et/ou JAXB).

Et comme vous pouvez le voir ici , le comportement par défaut de Jackson est de vérifier tout @Transient annotation qu'il peut trouver.

Donc, à la fin, votre problème peut être résolu de l'une des trois façons suivantes:

  1. Configurez Jackson (en utilisant la méthode setUseTransient de HibernateAnnotationIntrospector) pour désactiver la vérification de @Transient annotations (voir cette réponse pour les détails d'implémentation).
  2. Utilisez un autre objet que PublicationVO comme résultat renvoyé de votre méthode getPublicationDetailsJSON. Vous devrez copier les propriétés de votre objet de valeur vers l'objet renvoyé à un moment donné.
  3. Retirer le @Transient annoter et conserver la propriété (mais je comprendrais si ce n'est pas une option pour vous car vous avez probablement de bonnes raisons d'avoir rendu cette propriété transitoire JPA en premier lieu).

À votre santé

28
m4rtin

J'ai simplement ajouté JsonSerialize et JsonDeserialize annotations.

@Transient
@JsonSerialize
@JsonDeserialize
private String myField;
46
Fidan Hakaj

Juste pour ajouter à la réponse fournie par m4rtin

Je suis allé avec la première approche - Configurer Jackson (en utilisant la méthode setUseTransient de HibernateAnnotationIntrospector) pour désactiver la vérification des annotations @Transient.

Dans mon projet, j'ai suivi devait suivre le fil suivant pour éviter la sérialisation jackson sur les objets paresseux non récupérés Évitez la sérialisation Jackson sur les objets paresseux non récupérés

Pour configurer mon projet pour ne pas ignorer les annotations transitoires, j'ai configuré le Hibernate4Module comme suit

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

Merci pour votre aide sur ce m4rtin

21
Damien Gallagher

J'utilise à la fois @Transient et @JsonProperty, alors ça marche!

@Transient
@JsonProperty
private String mapImageSrc;
9
Clarke

Ce que cela a fonctionné pour moi:

@Transient
@JsonProperty

dans le GETTER (pas dans la définition du champ privé)

ET

@JsonAutoDetect(fieldVisibility = Visibility.ANY) 

annoter la classe

5
Vic

Puisqu'aucune autre solution ici n'a fonctionné pour moi, permettez-moi de poster ma solution comment elle a fait l'affaire pour moi:

@Transient
@JsonSerialize
private String mapImageSrc;

Cela semble être la meilleure solution pour moi car le @JsonSerialize une annotation a été faite pour ce cas d'utilisation.

2
dave0688

J'ai eu le même problème. La solution ci-dessous a fonctionné pour moi:

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

Merci à m4rtin.

2
Alok Singh

Essayez @JsonView après avoir ajouté @Transient

1
Sapna

utilisez @JsonIgnore dans com.fasterxml.jackson.annotation, il existe également @JsonFormat pour la variable Date. travaille pour moi

0
yue wang