[java] What is the easiest way to ignore a JPA field during persistence?

I'm essentially looking for a "@Ignore" type annotation with which I can stop a particular field from being persisted. How can this be achieved?

This question is related to java database hibernate jpa

The answer is


To ignore a field, annotate it with @Transient so it will not be mapped by hibernate.

but then jackson will not serialize the field when converting to JSON.

If you need mix JPA with JSON(omit by JPA but still include in Jackson) use @JsonInclude :

@JsonInclude()
@Transient
private String token;

TIP:

You can also use JsonInclude.Include.NON_NULL and hide fields in JSON during deserialization when token == null:

@JsonInclude(JsonInclude.Include.NON_NULL)
@Transient
private String token;

To ignore a field, annotate it with @Transient so it will not be mapped by hibernate.
Source: Hibernate Annotations.


None of the above answers worked for me using Hibernate 5.2.10, Jersey 2.25.1 and Jackson 2.8.9. I finally found the answer (sort of, they reference hibernate4module but it works for 5 too) here. None of the Json annotations worked at all with @Transient. Apparently Jackson2 is 'smart' enough to kindly ignore stuff marked with @Transient unless you explicitly tell it not to. The key was to add the hibernate5 module (which I was using to deal with other Hibernate annotations) and disable the USE_TRANSIENT_ANNOTATION feature in my Jersey Application:

ObjectMapper jacksonObjectMapper = new ObjectMapper();
Hibernate5Module jacksonHibernateModule = new Hibernate5Module();
jacksonHibernateModule.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
jacksonObjectMapper.registerModule(jacksonHibernateModule);  

Here is the dependency for the Hibernate5Module:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-hibernate5</artifactId>
    <version>2.8.9</version>
</dependency>

Sometimes you want to:

  1. Serialize a column
  2. Ignore column from being persisted:

Use @Column(name = "columnName", insertable = false, updatable = false)

A good scenario is when a certain column is automatically calculated by using other column values


use @Transient to make JPA ignoring the field.

but! Jackson will not serialize that field as well. to solve just add @JsonProperty

an example

@Transient
@JsonProperty
private boolean locked;

Apparently, using Hibernate5Module, the @Transient will not be serialize if using ObjectMapper. Removing will make it work.

import javax.persistence.Transient;

import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TransientFieldTest {

    @Test
    public void Print_Json() throws JsonProcessingException {

        ObjectMapper objectEntityMapper = new ObjectMapper();
        //objectEntityMapper.registerModule(new Hibernate5Module());
        objectEntityMapper.setSerializationInclusion(Include.NON_NULL);

        log.info("object: {}", objectEntityMapper.writeValueAsString( //
                SampleTransient.builder()
                               .id("id")
                               .transientField("transientField")
                               .build()));

    }

    @Getter
    @Setter
    @Builder
    private static class SampleTransient {

        private String id;

        @Transient
        private String transientField;

        private String nullField;

    }
}

This answer comes a little late, but it completes the response.

In order to avoid a field from an entity to be persisted in DB one can use one of the two mechanisms:

@Transient - the JPA annotation marking a field as not persistable

transient keyword in java. Beware - using this keyword, will prevent the field to be used with any serialization mechanism from java. So, if the field must be serialized you'd better use just the @Transient annotation.


To complete the above answers, I had the case using an XML mapping file where neither the @Transient nor transient worked... I had to put the transient information in the xml file:

<attributes>
(...)
    <transient name="field" />
</attributes>

There are multiple solutions depending on the entity attribute type.

Basic attributes

Consider you have the following account table:

The account table

The account table is mapped to the Account entity like this:

@Entity(name = "Account")
public class Account {

    @Id
    private Long id;

    @ManyToOne
    private User owner;

    private String iban;

    private long cents;

    private double interestRate;

    private Timestamp createdOn;

    @Transient
    private double dollars;

    @Transient
    private long interestCents;

    @Transient
    private double interestDollars;

    @PostLoad
    private void postLoad() {
        this.dollars = cents / 100D;

        long months = createdOn.toLocalDateTime()
            .until(LocalDateTime.now(), ChronoUnit.MONTHS);
        double interestUnrounded = ( ( interestRate / 100D ) * cents * months ) / 12;
        this.interestCents = BigDecimal.valueOf(interestUnrounded)
            .setScale(0, BigDecimal.ROUND_HALF_EVEN).longValue();

        this.interestDollars = interestCents / 100D;
    }

    //Getters and setters omitted for brevity
}

The basic entity attributes are mapped to table columns, so properties like id, iban, cents are basic attributes.

But the dollars, interestCents, and interestDollars are computed properties, so you annotate them with @Transient to exclude them from SELECT, INSERT, UPDATE, and DELETE SQL statements.

So, for basic attributes, you need to use @Transient in order to exclude a given property from being persisted.

Associations

Assuming you have the following post and post_comment tables:

The post and post_comment tables

You want to map the latestComment association in the Post entity to the latest PostComment entity that was added.

To do that, you can use the @JoinFormula annotation:

@Entity(name = "Post")
@Table(name = "post")
public class Post {
 
    @Id
    private Long id;
 
    private String title;
 
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinFormula("(" +
        "SELECT pc.id " +
        "FROM post_comment pc " +
        "WHERE pc.post_id = id " +
        "ORDER BY pc.created_on DESC " +
        "LIMIT 1" +
    ")")
    private PostComment latestComment;
 
    //Getters and setters omitted for brevity
}

When fetching the Post entity, you can see that the latestComment is fetched, but if you want to modify it, the change is going to be ignored.

So, for associations, you can use @JoinFormula to ignore the write operations while still allowing reading the association.

@MapsId

Another way to ignore associations that are already mapped by the entity identifier is to use @MapsId.

For instance, consider the following one-to-one table relationship:

The post and post_details tables

The PostDetails entity is mapped like this:

@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {
 
    @Id
    private Long id;
 
    @Column(name = "created_on")
    private Date createdOn;
 
    @Column(name = "created_by")
    private String createdBy;
 
    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    private Post post;
 
    public PostDetails() {}
 
    public PostDetails(String createdBy) {
        createdOn = new Date();
        this.createdBy = createdBy;
    }
 
    //Getters and setters omitted for brevity
}

Notice that both the id attribute and the post association map the same database column, which is the post_details Primary Key column.

To exclude the id attribute, the @MapsId annotation will tell Hibernate that the post association takes care of the table Primary Key column value.

So, when the entity identifier and an association share the same column, you can use @MapsId to ignore the entity identifier attribute and use the association instead.

Using insertable = false, updatable = false

Another option is to use insertable = false, updatable = false for the association which you want to be ignored by Hibernate.

For instance, we can map the previous one-to-one association like this:

@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {

    @Id
    @Column(name = "post_id")
    private Long id;

    @Column(name = "created_on")
    private Date createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @OneToOne
    @JoinColumn(name = "post_id", insertable = false, updatable = false)
    private Post post;

    //Getters and setters omitted for brevity

    public void setPost(Post post) {
        this.post = post;
        if (post != null) {
            this.id = post.getId();
        }
    }
}

The insertable and updatable attributes of the @JoinColumn annotation will instruct Hibernate to ignore the post association since the entity identifier takes care of the post_id Primary Key column.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to database

Implement specialization in ER diagram phpMyAdmin - Error > Incorrect format parameter? Authentication plugin 'caching_sha2_password' cannot be loaded Room - Schema export directory is not provided to the annotation processor so we cannot export the schema SQL Query Where Date = Today Minus 7 Days MySQL Error: : 'Access denied for user 'root'@'localhost' SQL Server date format yyyymmdd How to create a foreign key in phpmyadmin WooCommerce: Finding the products in database TypeError: tuple indices must be integers, not str

Examples related to hibernate

Hibernate Error executing DDL via JDBC Statement How does spring.jpa.hibernate.ddl-auto property exactly work in Spring? Error creating bean with name 'entityManagerFactory' defined in class path resource : Invocation of init method failed JPA Hibernate Persistence exception [PersistenceUnit: default] Unable to build Hibernate SessionFactory Disable all Database related auto configuration in Spring Boot Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] HikariCP - connection is not available Hibernate-sequence doesn't exist How to find distinct rows with field in list using JPA and Spring? Spring Data JPA and Exists query

Examples related to jpa

No converter found capable of converting from type to type How does spring.jpa.hibernate.ddl-auto property exactly work in Spring? Deserialize Java 8 LocalDateTime with JacksonMapper Error creating bean with name 'entityManagerFactory' defined in class path resource : Invocation of init method failed How to beautifully update a JPA entity in Spring Data? JPA Hibernate Persistence exception [PersistenceUnit: default] Unable to build Hibernate SessionFactory How to return a custom object from a Spring Data JPA GROUP BY query How to find distinct rows with field in list using JPA and Spring? What is this spring.jpa.open-in-view=true property in Spring Boot? Spring Data JPA and Exists query