I have some beans that I annotated with JPA to handle persistence mapping.
Here is an example:
import javax.persistence.Id;
public class User{
#Id
private String id;
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
}
Now I want to use this class in another project where I don't need a dependency on javax.persistence, so I'd rather not include it just for such classes.
So I was thinking of splitting this bean in two classes: one with just fields and accessors and a subclass with JPA annotations on accessors. Like:
public class User{
private String id;
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
}
and
import javax.persistence.Id;
public class UserEntity extends User{
#Override
#Id
public String getId(){
return super.getId();
}
}
Unfortunately it seems that putting JPA annotations on accessors is a discouraged practice in most cases and I second that.
Can you suggest any cleaner solutions?
This may not be helpful if you absolutely have to use the annotation-based mapping for JPA, but if you are open to it you could configure your mappings using xml and not include the xml mapping file in the jar you use to share the User class with other projects.
See example here:
Persisting Entity Classes using XML in JPA
If you insist on using annotations to define your entity mappings, then your entity classes cannot avoid being dependent on JPA. If you must present non-JPA-dependent classes representing the same data, and if you want to be able to handle the different representations polymorphically, then your options are limited:
the annotated class may extend the non-annotated one, or
the annotated and non-annotated classes may extend a common superclass, or
the annotated and non-annotated classes may implement a common interface.
In any of those cases, the entity class can provide its own, annotated, member variables for the entity properties, but in all cases, doing so means the two classes provide separate storage for the entity properties. That's a bit wasteful in the first alternative and possibly in the second, but it's the only way you can annotate the member variables without tying the whole hierarchy to JPA.
If you want to go in this general direction then I'd recommend using interfaces instead of class inheritance, whether you annotate member variables or accessor methods. Using interfaces for polymorphism better models the reality you describe (some Users are entities but others are not), it does not interfere with any inheritance hierarchy you may want, and if you annotate member variables then it avoids duplicative storage .
Related
In Hibernate, placing there #Id annotation
before the field declaration itself
#Id
private int id;
and before its getter and setter
#Id
public int getId() { return this.id; }
public int setId(..) { .. }
are two different things. This difference takes effect if there's some processing in getter/setter.
The Q is, is there such an issue for non-key fields-- those without the #Id annotation?
My key fields aren't any processed. However, among the others, I've got some fields that i am validating/changing the values before setting. For those fields, should i put the annotations before their getters-setters?
I didn't hit a brick wall as far as I could observe. however - would like to make sure.
TIA.
Note: saw the useful discussion: Where to put hibernate annotations?.
Well no issue for non-key fields, but personally I prefer fields annotation, expecially if you don't have to do some business logic on entity level: code is cleaner, all db related stuff is at the beginning of the class, you don't have strange issue with equals methods (which always use fields - it happened to me) plus, if you have other methods not strictly related to db handling you have to set them #Transient.
If I'm using JPA's annotations to specify my mapped fields, like so:
public class PersistedEmployee {
private Integer id;
#Id//Plus some #GeneratedValue cruft in the real example
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
}
Does that ID need to follow the getFoo bean naming convention? Or are the annotations sufficient for identifying how to map this POJO?
The underlying provider is Hibernate, in this case, but I'm also curious if that makes a difference or not.
JPA supports two ways to access properties. Either through getters and setters or through reflection directly accessing the field.
If you use the first, the getters and setters need to follow the proper naming convention, if you use the second, they don't have to exist, and you can use whatever accessors/mutator you like.
What access type is used is defined by the place where you put the #id annotation. If it is on a field, field access is used. If it is on a getter/setter property access is used.
JPA spec.
The persistent state of an entity is accessed by the persistence provider
runtime either via JavaBeans style property accessors (“property
access”) or via instance variables (“field access”).
It's publically available, so if using JPA you really ought to get it, or a book/documentation that presents it.
Some java classes need to have private properties with a public getter and setter in order to function properly. For example JSF beans and JPA entities need them. If it wasn't for those libraries, there are probably some properties which should not have any getters and definitely not setters. Also empty constructors are oftenly discouraged for use by custom code. For example
#Entity
public class MyEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public MyEntity() {}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
}
In this class the method setId should never be called by manual code. The method is not deprecated though, so an #Deprecated annotation would be wrong.
Is there another way than #Deprecated to tell a method should not be used?
JPA entities don't need public getters and setters. Values are set using reflection (at least when using EclipseLink or Hibernate which you're probably using).
In this particular example you could simply leave the setter out, I have made a habit out of it and never had a problem with it. Note: Stick to Java naming conventions when it comes to properties and getters/setters. Some libraries/frameworks (wrongly imo) depend on this.
As for the global concept of the question, I am surprised I didn't see a suggestion that includes documentation. Documentation has, is, and will probably always be your greatest communication to users of your code.
/**
* WARNING! DO NOT USE THIS UNLESS YOU ARE GOD!
* This will probably break stuff unless...
* ....
*/
public void doEvilHackishThings()
{
// Stuff happens here.
}
If you document your code properly, developers know when they're likely to break stuff. Make sure you don't apply voodoo code etc. Good documentation describes in some detail what it does and how it does it. No developer in his right mind will touch the example method without understanding why it is evil.
You could hide getters and setters by using an interface that is backed by that concrete class. This would also encourage Tell, don't ask, because there aren't any getters you could use on the interface. The constructor usage can also be hidden in factories.
For example, I have entity class User:
public class User
{
private long id;
private String name;
// setters and getters
}
Next, I add new entity class: Comment
public class Comment
{
private long id;
private String comment;
// setters and getters
}
Next, I can add more and more entity classes.
And, at this moment I think: I can/must bind/connect in logical structure my entity classes or no?
What I mean? I try explain:
Point 1: All this classes: User, Comment and more other - POJO.
Idea 1: Need logical binding for this classes via interface or abstract class.
Point 2: I see, that All entity classes has same methods: getId and setId().
Idea 2: Need to avoid declaration this methods in all classes.
My Solution:
Add interface BaseEntity:
public interface BaseEntity
{
public long getId();
public void setId(long id);
}
Add all entity classes must implement this interface.
In result we logical connect all entity classes. And we guarante that each entity class implement getId() and setId() methods.
But this solution doesn't resolve problem with multiple declaration getId and setId.
A solution is to create general BaseEntity class:
public class BaseEntity
{
private long id;
public long getId() {return this.id};
public void setId(long id) {this.id = id;};
}
And all entity class must extends BaseEntity class.
mmmm, sound nice :)
But, with current implementation - user can create instanse BaseEntityClass. This make sense? I can give possibility to create a class BaseEntity?
Or maybe, good solution mark this class as abstract?
What do you think?
And if you agree with all my previous steps:
I have last question:
Communication beetween classes must based on Interfaces. But I dont have interface for entities. It is can create problems for me in future?
Thank you.
Yes, make your base entity an abstract class and let other extend it.
public abstract class BaseEntity
{
private long id;
public long getId() {return this.id};
public void setId(long id) {this.id = id;};
}
As a general rule, one should always program to an interface and not to an implementation.
You could use an abstract BaseEntity class, mapped with #MappedSuperclass. But you still would have to override the mapping of the ID field to the appropriate column in every subclass.
Just because two classes have the same property doesn't necessarily mean that they should extend a common class. Your code will probably never reference any object with the type BaseEntity. Unless you have additional common methods, I would advise not to use a superclass in this case. It will just be simpler.
And entities are POJOs. Using an interface for every entity, in my experience, just adds unnecessary complexity.
Making BaseEntity abstract is perfectly good, I have used it myself this way. And I don't think there's anything else you can abstract. You could abstract if you would have multiple tables that all have some common columns, such as for auditing purposes.
And interfaces for entities? I don't think that's anything useful. Interfacing is more useful when you have to switch different implementations, now in entities, that doesn't make much sense.
Java has the transientkeyword. Why does JPA have #Transient instead of simply using the already existing java keyword?
Java's transient keyword is used to denote that a field is not to be serialized, whereas JPA's #Transient annotation is used to indicate that a field is not to be persisted in the database, i.e. their semantics are different.
Because they have different meanings. The #Transient annotation tells the JPA provider to not persist any (non-transient) attribute. The other tells the serialization framework to not serialize an attribute. You might want to have a #Transient property and still serialize it.
As others have said, #Transient is used to mark fields which shouldn't be persisted. Consider this short example:
public enum Gender { MALE, FEMALE, UNKNOWN }
#Entity
public Person {
private Gender g;
private long id;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public long getId() { return id; }
public void setId(long id) { this.id = id; }
public Gender getGender() { return g; }
public void setGender(Gender g) { this.g = g; }
#Transient
public boolean isMale() {
return Gender.MALE.equals(g);
}
#Transient
public boolean isFemale() {
return Gender.FEMALE.equals(g);
}
}
When this class is fed to the JPA, it persists the gender and id but doesn't try to persist the helper boolean methods - without #Transient the underlying system would complain that the Entity class Person is missing setMale() and setFemale() methods and thus wouldn't persist Person at all.
Purpose is different:
The transient keyword and #Transient annotation have two different purposes: one deals with serialization and one deals with persistence. As programmers, we often marry these two concepts into one, but this is not accurate in general. Persistence refers to the characteristic of state that outlives the process that created it. Serialization in Java refers to the process of encoding/decoding an object's state as a byte stream.
The transient keyword is a stronger condition than #Transient:
If a field uses the transient keyword, that field will not be serialized when the object is converted to a byte stream. Furthermore, since JPA treats fields marked with the transient keyword as having the #Transient annotation, the field will not be persisted by JPA either.
On the other hand, fields annotated #Transient alone will be converted to a byte stream when the object is serialized, but it will not be persisted by JPA. Therefore, the transient keyword is a stronger condition than the #Transient annotation.
Example
This begs the question: Why would anyone want to serialize a field that is not persisted to the application's database?
The reality is that serialization is used for more than just persistence. In an Enterprise Java application there needs to be a mechanism to exchange objects between distributed components; serialization provides a common communication protocol to handle this. Thus, a field may hold critical information for the purpose of inter-component communication; but that same field may have no value from a persistence perspective.
For example, suppose an optimization algorithm is run on a server, and suppose this algorithm takes several hours to complete. To a client, having the most up-to-date set of solutions is important. So, a client can subscribe to the server and receive periodic updates during the algorithm's execution phase. These updates are provided using the ProgressReport object:
#Entity
public class ProgressReport implements Serializable{
private static final long serialVersionUID = 1L;
#Transient
long estimatedMinutesRemaining;
String statusMessage;
Solution currentBestSolution;
}
The Solution class might look like this:
#Entity
public class Solution implements Serializable{
private static final long serialVersionUID = 1L;
double[][] dataArray;
Properties properties;
}
The server persists each ProgressReport to its database. The server does not care to persist estimatedMinutesRemaining, but the client certainly cares about this information. Therefore, the estimatedMinutesRemaining is annotated using #Transient. When the final Solution is located by the algorithm, it is persisted by JPA directly without using a ProgressReport.
If you just want a field won't get persisted, both transient and #Transient work. But the question is why #Transient since transient already exists.
Because #Transient field will still get serialized!
Suppose you create a entity, doing some CPU-consuming calculation to get a result and this result will not save in database. But you want to sent the entity to other Java applications to use by JMS, then you should use #Transient, not the JavaSE keyword transient. So the receivers running on other VMs can save their time to re-calculate again.
In laymen's terms, if you use the #Transient annotation on an attribute of an entity: this attribute will be singled out and will not be saved to the database. The rest of the attributes of the object within the entity will still be saved.
Im saving the Object to the database using the jpa repository built in save method as so:
userRoleJoinRepository.save(user2);
For Kotlin developers, remember the Java transient keyword becomes the built-in Kotlin #Transient annotation. Therefore, make sure you have the JPA import if you're using JPA #Transient in your entity:
import javax.persistence.Transient
I will try to answer the question of "why".
Imagine a situation where you have a huge database with a lot of columns in a table, and your project/system uses tools to generate entities from database. (Hibernate has those, etc...)
Now, suppose that by your business logic you need a particular field NOT to be persisted. You have to "configure" your entity in a particular way.
While Transient keyword works on an object - as it behaves within a java language, the #Transient only designed to answer the tasks that pertains only to persistence tasks.