How to make an Entity read-only?

JavaJpa

Java Problem Overview


What is the proper way to make an Entity read-only with JPA ? I wish my database table to never be modified at all programmatically.

I think I understand that I should lock my objects with LockModeType.READ. Is it possible to use an annotation to make my entities directly locked after retrieval from the database ? Or do I have to mess around and override my generic DAO for that specific entity ?

Java Solutions


Solution 1 - Java

In your entity add an EntityListener like this:

@Entity
@EntityListeners(PreventAnyUpdate.class)
public class YourEntity {
    // ...
}

Implement your EntityListener, to throw an exception if any update occurs:

public class PreventAnyUpdate {

	@PrePersist
	void onPrePersist(Object o) {
		throw new IllegalStateException("JPA is trying to persist an entity of type " + (o == null ? "null" : o.getClass()));
	}

	@PreUpdate
	void onPreUpdate(Object o) {
		throw new IllegalStateException("JPA is trying to update an entity of type " + (o == null ? "null" : o.getClass()));
	}

	@PreRemove
	void onPreRemove(Object o) {
		throw new IllegalStateException("JPA is trying to remove an entity of type " + (o == null ? "null" : o.getClass()));
	}
}

This will create a bullet proof safety net for your entity with JPA lifecycle listeners.

  • PRO: JPA standard - not hibernate specific
  • PRO: very safe
  • CON: only shows write attempts at runtime. If you want a compile time check, you should not implement setters.

Solution 2 - Java

A solution is to use field based annotation, to declare your fields as protected and to propose only public getter. Doing so, your objects can not be altered.

(This solution is not entity specific, it is just a way to build immutable objects)

Solution 3 - Java

Hibernate also has a org.hibernate.annotations.Immutable annotation that you can put on the type, method, or field.

Solution 4 - Java

If your JPA implementation is hibernate - you could use the hibernate Entity annotation

@org.hibernate.annotations.Entity(mutable = false)

Obviously this will tie your model to hibernate though.

Solution 5 - Java

IIRC you could set every field to insertable = false and updatable = false in your @Column annotations, but I'm sure there must be a better method... :)

I don't suppose this helps?

Solution 6 - Java

I think what you are looking for is your entity to be Immutable. Hibernate supports this; JPA(at least JPA 1.0) does not. I suppose you can only control this by providing only getters and make sure that the getters return only immutable values.

Solution 7 - Java

Eclipselink implementation also offers you the @ReadOnly annotation at the entity level

Solution 8 - Java

This is probably going to catch me a downvote because I always get downvoted for suggesting it, but you could use AspectJ in several ways to enforce this:

Either automate Mac's solution (make AspectJ inject the @Column annotation):

declare @field : (@Entity *) *.* : @Column(insertable=false);

Or declare a compiler error for all access to set methods:

declare error : execution((@Entity *) *.set*(*) );

Downside: you need to add AspectJ compilation to your build, but that's easy if you use [ant][2] or [maven][3]

[2]: http://www.eclipse.org/aspectj/doc/released/devguide/antTasks.html "AspectJ Ant Tasks" [3]: http://mojo.codehaus.org/aspectj-maven-plugin/ "AspectJ Maven plugin"

Solution 9 - Java

If you are using spring-data or are otherwise using the Repository pattern, don't include any save / update / create / insert / etc methods in the Repository for that particular entity. This can be generalized by having a base class / interface for readonly entities, and an updatable one that extends the readonly one for updatable entities. As other posters have pointed out, the setters may also be made non-public to avoid developers accidentally setting values that they are then unable to save.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionglmxndrView Question on Stackoverflow
Solution 1 - JavaslartidanView Answer on Stackoverflow
Solution 2 - JavaNicolasView Answer on Stackoverflow
Solution 3 - JavaToby ArtisanView Answer on Stackoverflow
Solution 4 - JavaAndrew BView Answer on Stackoverflow
Solution 5 - JavaMacView Answer on Stackoverflow
Solution 6 - JavaTimmoView Answer on Stackoverflow
Solution 7 - JavaPauView Answer on Stackoverflow
Solution 8 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 9 - JavaJavaManView Answer on Stackoverflow