Possible to have immutable JPA entities?

夙愿已清 提交于 2019-12-20 11:51:17

问题


In our hibernate project, the entities are coded using the java beans pattern. There's quite a few spots in our code where someone has forgotten a to set a mutator and we get an exception due to a NOT NULL field.

Is anyone using a builder to construct their entities or making them immutable?

I'm trying to find an effective pattern that is not in the style of the java beans pattern.

Thanks


回答1:


If you make your beans immutable then you have to use field level access and this comes with its own set of problems as discussed thoroughly here. The approach we took is to have a Builder/Factory enforcing/validating the requiredness etc rules for us.




回答2:


In our project we do use vanilla builders approach (@see Effective Java). Consider the following example:

@Entity
public class Person {
   public static class Builder {
        private String firstName;
        private String lastName;
        private PhoneNumber phone;

        public Builder() {}

        public Builder withFullName(String fullName) {
            Preconditions.notNull(fullName); 
            String[] split = fullName.split(" ");
            if (split == null || split.length != 2) {
                throw new IllegalArgumentException("Full name should contain First name and Last name. Full name: " + fullName);
            }  
            this.firstName = split[0];
            this.lastName = split[1];
            return this;
        }

        public Builder withPhone(String phone) {
            // valueOf does validation
            this.phone = PhoneNumber.valueOf(phone);
            return this;
        }

        public Person build() {
            return new Person(this);
        }
   }

   //@Columns
   private long id;//@Id
   private String firstName;
   private String lastName;
   private String phoneNumber;

   // hibernate requires default constructor
   private Person() {} 

   private Person(Builder builder) {
       this.firstName = Preconditions.notNull(builder.firstName);
       this.lastName = Preconditions.notNull(builder.lastName);
       this.phoneNumber = builder.phone != null ? builder.phone : null;
   }

   //Getters
   @Nonnull
   public String getFirstName() { return firstName;}
   @Nonnull
   public String getLastName() { return lastName;}
   @Nullable
   public String getPhoneName() { return phone;}
   public long getId() { return id;}
}

In case you want to sometimes mutate the entity I would recomend to introduce new Builder(Person person) which will copy all the data back, so you can mutate it with builder. Of course it will produce new one entity, so the old one remains read only.

The usage (with mutation) is as simple as:

Person.Builder personBuilder = new Person.Builder();
Person person = personBuilder.withFullName("Vadim Kirilchuk").withPhone("12345678").build();

Person modified = new Person.Builder(person).withPhone("987654321").build();

Also it is important to note that in this example Person is not 100% immutable (and can't be) class: first of all because id will be set by jpa, also lazy associations may be fetched at runtime and lastly because you can't have fields final(due to required default constructor) :( The latter point is also a concern for multithreaded environments, i.e. it is possible that entity passed to another thread just after #build() may lead to all kind of errors as abother thread is not guaranteed to see fully constructed object.

The JPA 2.1 specification, section "2.1 The Entity Class", says:

No methods or persistent instance variables of the entity class may be final.

One more similar approach: http://vlkan.com/blog/post/2015/03/21/immutable-persistence/

In my case I would just add id to the builder instead building service on top of drafts..




回答3:


@Immutable annotation can be used on Entity. JPA Will ignore all updates made to entity.

https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/Immutable.html



来源:https://stackoverflow.com/questions/4560167/possible-to-have-immutable-jpa-entities

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!