Best practice and implementation of a builder pattern when using JPA - java

I have a class that is suitable for a builder pattern, there are many params and I'd rather not use a ton of telescopic constructors.
My problem is that this class is a JPA entity and that is very new to me.
Having private final data members is throwing an error as I they are not initialized in the constructor and as far as I'm aware, JPA requires an empty protected constructor.
Can anyone help please? An example would be fantastic, I've included a basic example of the code below but it's very generic. I've omitted many of the accessors and data members to save space/time.
#Entity//(name= "TABLE_NAME") //name of the entity / table name
public class Bean implements Serializable {
private static final long serialVersionUID = 1L;
#Id //primary key
#GeneratedValue
Long id;
private final DateTime date;
private final String title;
private final String intro;
//used by jpa
protected Bean(){}
private Bean(Bean Builder beanBuilder){
this.date = beanBuilder;
this.title = beanBuilder;
this.intro = beanBuilder;
}
public DateTime getDate() {
return date;
}
public String getTitle() {
return title;
}
public static class BeanBuilder Builder{
private final DateTime date;
private final String title;
//private optional
public BeanBuilder(DateTime date, String title) {
this.date = date;
this.title = title;
}
public BeanBuilder intro(String intro){
this.intro = intro;
return this;
}
public BeanBuilder solution(String solution){
this.intro = solution;
return this;
}
public Bean buildBean(){
return new Bean(this);
}
}
}

Member fields marked as final must have a value assigned during construction and this value is final (i.e. cannot change). As a consequence, all declared constructors must assign a value to all final fields.
This explain your compiler error.
From the JLS:
A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared, or a compile-time error occurs (§8.8, §16.9).

Not sure why you want to do that. Maybe it is better to define the member variable as
#Column(name = "id", nullable = false, updatable = false)
for example

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.
..meaning that there's no way for you to build a truly immutable JPA entity. But, I don't really see how that can be such a big issue. Just don't let the entity class expose public setters?

I'm not sure what you meant for that, but having immutable objects is not a great idea when working in Hibernate (not to say you cannot do it, or you shouldn't).
Think about it, because Hibernate/JPA defines "states" for objects they are meant to be mutable; otherwise you would have a static database, or something like insert-once-and-never-modify database.
The immutable concept is a very known (nowadays) concept borrowed mainly from Functional Programming that doesn't really apply in the same way to OOP. And if you are working with Hibernate you shouldn't have immutable objects...at least till today's date.
UPDATE
If you want to have what they call read-only entities, you can use the #Immutable annotation from Hibernate itself. Pay close attention to collections as entity members.

Entities are meant to be mutable when it comes to strict Java immutability. For example, lazily loaded associations will change the object state once the association is accessed.
If you need to use entity data in a real immutable fashion (for multi-threaded purposes for example), then consider using DTOs (because entities are not meant to be accessed cuncurrently either).

Related

Persistent Model to Domain Model mapping without exposing domains object attributes

I know this is a common question, but I haven't found another that solves my doubts.
Usually, if the project is small, I've persistence annotations in the same object that represents the domain object. This allows to load the entity from database and keep all the setters private, ensuring any instance is always in a valid state. Something like:
#Entity
class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
My problem appears if I want to hava a different persistent model. Then I would have something like:
/* SomeEntity without persistent info */
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
protected SomeEntity() {}
/* Public getters */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
/* Expose some behaviour */
public void updateAttributes(String attribute1, String attribute2) {
/* do some validations before updating */
}
}
and DAO:
#Entity
class SomeEntityDAO {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
public SomeEntityDAO() {}
/* All getters and setters */
}
My question is, how can I map SomeEntityDAO to SomeEntity without exposing SomeEntity's attributes?
If I create a constructor like: public SomeEntity(String attribute1, String attribute2, ...) {}, then anyone can create an invalid instance of SomeEntity. The same occurs if I make all setters public in SomeEntity.
I also don't think is a valid solution build the object using updateAttributes() since this will execute some validations I don't whant to execute at this point (we trust the data that's persistet in database).
I'm thinking in having all the setters protected, so the DAO can extend the Entity and have access to setters... but I'm not sure if this is a good option.
Which is the best or common approach to solve this problem?
I've had the same kind of problem. And looking around I've found no solution. Believe me, if it exists is well hidden somewhere. None that suggests what to do when you have to deal with an old project where ORM entities are everywhere and there's a big step between Domain and ORM model.
Given this, I've deducted that if you really want to keep your Domain entities pure (so non get and set - the latter I would NEVER accept!) you have to do some deals. Because there's no way to share the internals without giving the entities some extra knowledge. Beware, this doesn't mean that you have to make the Domain entities aware of the ORM layer, nor that you have to use getters. Just, what I've concluded, the Domain entities should have ways to expose them as a different model.
So, in conclusion, what I would do in your situation is to build up a Visitor pattern. The Domain entity EntityA would implement the EntityAVisitable interface to accept a EntityAVisitor or something like this.
interface EntityAVisitable {
accepts(EntityAVisitor visitor);
}
The builder implements the interface required by the Visitor, EntityAVisitor.
interface EntityAVisitor<T>{
setCombinedValue1_2(String attribute1_attribute2_combinedInEntity);
<T> build();
}
The build() function of the interface EntityAVisitor uses a generic type T. In this way the Domain entity is agnostic about the return type of the concrete implementation of the EntityAVisitor.
Is it perfect? No.
Perfect solution would be to get rid of the ORM (actually I would say that I hate them, because the way are used is most of the times wrong - but this is my personal thought).
Is it nice? No.
A nice solution is not allowed due to language restrictions (I suppose you use Java).
Does it a good work in encapsulating the real content of your Domain entity? Yes.
Not only, in this way you can decide exactly what could be exposed and how. So, in my opinion, is a good deal between keeping the entity pure and having to work with an ORM under the seat.
Domain entity should be self-validating meaning it should only validate itself based on it's internal values. If update requires validation that depends on external dependencies, then I would create an updater class that is responsible for the update. From the updater class, you can use specification pattern (as an injectable dependency) to implement the validation.
Use domain entities when modifying, and DTOs for read-only projections. There are performance and simplification gains when you use straight DTOs in read-only. This is used in CQRS patterns.
class SomeEntity {
private Long id;
private String attribute1;
private String attribute2;
private String attribute3;
// ... other attributes
public SomeEntity() {}
/* Public getters/setter */
public Long getId() { ... }
public String getAttribute1() { ... }
public String getAttribute2() { ... }
public Long setId() { ... }
public String setAttribute1() { ... }
public String setAttribute2() { ... }
}
//classes/interfaces named for clarity
class EntityUpdater implements IEntityUpdater {
public EntityUpdater (ISpecification spec){
}
public updateEntity(SomeEntity entity){
//assert/execute validation
}
}
Some ORMs allow setting entity values through field access (as opposed to setter methods).
JPA uses the #Access annotation. See What is the purpose of AccessType.FIELD, AccessType.PROPERTY and #Access
I created an ORM, sormula, that can use field access. See #Row fieldAccess and test case org.sormula.tests.fieldaccess.

VARCHAR(1) vs BOOLEAN

Is it a good idea to hold a VARCHAR(1) in the db with '0' for false and '1' for true? I don't think so, but it is common practice in the company I am working at the moment. Entities look like
#Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "my_field")
private String myField;
// getter-setter
}
Wouldn't it be better to use BOOLEAN? I have never done this before, how does this work together with hibernate?
#Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "my_field")
private boolean myField;
// getter-setter
}
Is this all that is needed?
There is a simple rule of thumb: when it surprises an experienced reader, it is bad practice.
Caveat: a well-known practice within a company might not surprise the experienced users of that company. But you still have that "surprise" problem; for example when new people get into that team/company.
The real problem with this approach: it forces your code to have knowledge that would not be required otherwise! Meaning: code defines the meaning of that database entry. When the database field has boolean type, there is no interpretation whatsoever required on top of that.

Spring/JPA/persistence entity attribute field cannot be final?

I have a Spring MVC project using JPA which I have worked on for some time in the past without this issue. But now for some reason (likely an environmental issue as I have switch to a new laptop since I last worked on it) I am getting this weird error.
The project is essentially a tool for creating and performing surveys which are just a set of questions. There are multiple types of question such as "auto complete question", "multiple choice question", "integer question", etc which collect different types of data. Each of this question types is modeled by a subclass which extends an abstract class called DdmQuestion which looks something like this:
#Entity
#Table(name = "ddm_question")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING, name = "question_type")
#JsonIgnoreProperties({"dataType"})
#JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#question_type")
#JsonSubTypes(value = { #Type(DdmTextQuestion.class),#Type(DdmDateQuestion.class),#Type(DdmTimeQuestion.class),#Type(DdmNumberIntegerQuestion.class),#Type(DdmChoiceMultiQuestion.class),#Type(DdmAutoCompleteQuestion.class) })
public abstract class DdmQuestion {
#Id
#GeneratedValue
#Column(name = "question_id")
private int questionId;
#Column(name = "name")
private String name;
public int getQuestionId() {
return questionId;
}
public void setQuestionId(int questionId) {
this.questionId = questionId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#JsonIgnore
public abstract String getDataType();
}
Note the getDataType() method.
Then, for each question type, I have a subclass extending this which looks something like this:
#Entity
#DiscriminatorValue("ddm_question_date")
public class DdmDateQuestion extends DdmQuestion {
final private String DATA_TYPE = "Long"; // this is the line with the error
#Override
public String getDataType() {
return DATA_TYPE;
}
}
Now, I've never encountered this error before (that I can recall) but Eclipse is throwing up an error here that says:
"The Java field for attribute "DATA_TYPE" is final". That's all it
says.
If I remove the #Entity annotation from the class, this error disappears so evidently something in JPA doesn't like something about this but I never had this error before so I'm thinking something changed in a newer version. My POM is not particularly explicit with dependency versions so this would not be surprising.
Can anyone explain to me why this is happening and what the correct resolution is? I could just remove the "final" from the field declaration but this seems wrong to me as it is definitely a final value...
Thanks in advance.
If it is a field that should not be persisted in the database you usually should take advantage of the transient annotation which would tell the persistence provider to ommit that field in its processing.:
#Transient
final private String DATA_TYPE = "Long";
If Eclipse is smart enough, it should stop highlighting the error altogether.
in this linkshttp://docs.oracle.com/javaee/5/tutorial/doc/bnbqa.html#Entities;
An entity class must follow these requirements:
The class must be annotated with the javax.persistence.Entity annotation.
The class must have a public or protected, no-argument constructor. The class may have other constructors.
The class must not be declared final. No methods or persistent instance variables must be declared final.
If an entity instance be passed by value as a detached object, such as through a session bean’s remote business interface, the class must implement the Serializable interface.
Entities may extend both entity and non-entity classes, and non-entity classes may extend entity classes.
Persistent instance variables must be declared private, protected, or package-private, and can only be accessed directly by the entity class’s methods. Clients must access the entity’s state through accessor or business methods.

Java - How to avoid creation of setter only for a particular class needs?

I am using Hibernate and currently using the setter to set the relation to parent in children at creation time (to avoid doing this manually for both sides). How I can avoid use of setter or avoid expose it to the rest of classes and get the same behaviour. Is it ok to use reflection? This is the code:
#Entity
#Table(name = "TEST_GROUP")
#Getter
public class TestGroupEntity extends AuditedEntity{
#ManyToOne
#JoinColumn(name = "owner", nullable = false)
protected UserEntity owner;
#Column(name = "description")
#Setter
protected String description;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
protected Set<TestEntity> tests = Sets.newHashSet();
public boolean addTest(TestEntity testEntity) {
return tests.add(testEntity);
}
public boolean removeTest(TestEntity testEntity) {
return tests.remove(testEntity);
}
public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
this.owner = owner;
owner.setTestGroupEntity(this); ! how to avoid creation of setter
this.tests = tests;
tests.stream().forEach(t -> t.setTestGroupEntity(this)); ! how to avoid creation of setter
}
}
This is the children class ( I would like to keep immutability on api level):
#MappedSuperclass
#AllArgsConstructor
public class TestEntity extends AuditedEntity {
#Column(name = "name", nullable = false)
protected String name;
#Column(name = "description")
protected String description;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "test_group", nullable = false)
protected TestGroupEntity testGroupEntity;
public void setTestGroupEntity(TestGroupEntity testGroupEntity) {
this.testGroupEntity = testGroupEntity;
}
}
Edit: I think commented sections of code was not visible. Sorry.
How I can avoid use of setter or avoid expose it to the rest of
classes and get the same behaviour. Is it ok to use reflection?
Of course you can for example reduce visibility of public setters to a visibility less wide than public in order that client classes of your entities cannot use them.
Which is in your case the real problem since accessing any data from inside the object is possible in anyway
From hibernate doc :
Attributes (whether fields or getters/setters) need not be declared
public. Hibernate can deal with attributes declared with public,
protected, package or private visibility. Again, if wanting to use
runtime proxy generation for lazy loading the visibility for the
getter/setter should be at least package visibility.
So, try to use private setter for desired field. It should address your problem.
Update After comment
You have several workarounds to address your problem :
using reflection (your basic idea).
Drawback : it brings a little complexity, not a full check at compile-time and at last, someone who sees your code could wonder why you used that...
It is the same thing for any concepts which relies on reflection such as AOP.
declaring these setters with package-private level and put the 3 classes in the same package. Drawback : the used package.
creating public init methods which raises an exception if it used more than once for a same object. In this way, you guarantee the coherence of the object if bad used. Drawback : method which should not be used by clients is still provided to clients.
Unfortunately, you have not a perfect solution since Java visibility mechanisms cannot provide a ready-to-use solution for what you are looking for.
Personally, I prefer reflection or init method solutions.
Personally, I noticed that in based-class languages as Java, a good developer has often the reflex to over- protect accessibility of objects/methods. In fact, in many cases, it is not needed because it will not break the application or data integrity.
Here an example with init method :
public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
this.owner = owner;
owner.constructInit(this);
this.tests = tests;
tests.stream().forEach(t -> t.constructInit(this));
}
public class UserEntity {
private TestGroupEntity testGroupEntity;
public void constructInit(TestGroupEntity testGroupEntity) {
if (this.testGroupEntity != null) {
throw new IllegalArgumentException("forbidden");
}
this.testGroupEntity=testGroupEntity;
}
}
Make a constructor in your parent class and call it from child.
Here is the parent constructor looks like
public AuditedEntity(UserEntity owner, Set<TestEntity> tests){
this.owner = owner;
this.tests = tests;
}
And change your child constructor like
public TestGroupEntity(UserEntity owner, Set<TestEntity> tests) {
super(owner,tests);
}

How hibernate is initializing final fields using the no-arg constructor?

So, I have this class which I am trying to use with Hibernate:
#Entity
#Access(AccessType.FIELD)
public class BasicUser {
#Id
private final int userId;
private final String userName;
BasicUser(int userId, String userName) {
super();
this.userId = userId;
this.userName = userName;
}
BasicUser() {
super();
this.userId=0;
this.userName=null;
}
//getters
}
I tried pulling userId and userName from the database and make a BasicUser object and it worked fine. But, I am not getting how did it work? Hibernate required a no-arg constructor which I provided. Now since the fields are final, they had to be initialized in the constructor, so for sake of it I initialized them as shown in the code, expecting some error while running the code. But Hibernate formed the object with the field values as they were in the database. How is this happening? I need to understand because, there are a few objects in my application which are immutable. So, should I be doing the same way for them also? I saw a lot of posts telling to provide a no-arg constructor and Access type as field for immutable objects. But, when I provide no-arg constructor for a final field, the field has to be initialized. So, I am not getting whats going on here? Please help. Thanks!
Hibernate uses reflection (or some related low-level trickery) to set private instance fields. That approach can also by-pass final (i.e. reassign new values after the constructor returns).

Categories

Resources