I am implementing JPA and using Hibernate to implement ORM. I have created a class to represent a table in my database and private properties to represent the columns of the table with their getters and setters. I successfully fetched and added data to the table with and without the getters.
My question is:
Why do we need getters in this case if the data can be managed without getters?
Getters/Setters are from the Java Beans convention: https://en.wikipedia.org/wiki/JavaBeans
You don't have to use that!
According to the JPA specification fields in an Entity shouldn't be public.
The instance variables of a class must be private, protected, or
package visibility independent of whether field access or property
access is used. When property access is used, the property accessor
methods must be public or protected.
But this doesn't mean that you need getters and setters if you can access the data via other methods. Btw. Hibernate allows public fields.
Related
I am trying to persist objects in a database using hibernate JPA.
The objects already have a type hierarchy, and I'm trying to make it work with hibernate.
A CatalogPackage object has all the important properties and all the getters.
A CatalogPackageImpl (extends CatalogPackage) object has no properties, but most of the setters.
Both classes are non-abstract.
We want code to refer to CatalogPackage objects. But when initializing hibernate, it complains about the setters missing from the CatalogPackage class.
How do I suggest to hibernate that it use the subclass when building the objects?
I don't want to move all the setters to the superclass, and I don't want to use CatalogPackageImpl as the entity.
Even though I can't see the problem with defining the setter methods in your CatalogPackage since they can be marked private to avoid using them from external world.
Since you didn't paste your entities configuration and that you say Hibernate is complaining about the setter methods I can conclude you are using your getters to describe your entity mapping, right?
In such a case Hibernate will always still complaining because it assumes anything mapped to the database should be done in both directions, if it can read from the datastorage so it should be allowed to write in there.
SO you have either of below solutions:
Add the setters modifiers.
Move the mapping from getter methods to fields and set the acces type to field on top of your entity:
#Access(AccessType.Field)
class CatalogPackage {
...
}
I just want to know what is the difference between all these annotations. Why are we using these... means they have no effect especially field level and property level.
And what is the purpose of using mixed level annotation like:
#Entity
#Access(AccessType.FIELD)
class Employee {
// why their is a field level access
private int id;
// whats the purpose of transient here
#Transient
private String phnnumber;
// why its a property level access
#Access(AccessType.property)
public String getPhnnumber() {
return "1234556";
}
}
what exactly this class says?
By default the access type is defined by the place where you put your mapping annotations. If you put them on the field - it will be AccessType.FIELD, if you put them on the getters - it will be AccessType.PROPERTY.
Sometimes you might want to annotate not fields but properties (e.g. because you want to have some arbitrary logic in the getter or because you prefer it that way.) In such situation you must define a getter and annotate it as AccessType.PROPERTY.
As far as I remember, if you specify either AccessType.FIELD or AccessType.PROPERTY on any of the entity fields / methods you must specify the default behaviour for the whole class. And that's why you need to have AccessType.FIELD on the class level (despite that AccessType.FIELD is the default value.)
Now, if you wouldn't have #Transient on the phnnumber field, the JPA would provide you with a 3 columns table:
id,
phnnumber,
getphnnumber.
That's because it would use AccessType.FIELD for all of the entity fields (id and phnnumber) and, at the same time, it'd use AccessType.PROPERTY for your getter (getPhnnumber()).
You'll end with phone number mapped twice in the database.
Therefore, the #Transient annotation is required - it means that the entity won't store the value of the field in the underlying storage but the value returned by your getter.
In our application, we need to have fields that are assignable only once.
At first we thought of encapsulating the fields and making the setters private. However, some questions arouse:
Without a public setter, is Hibernate still able to map the field from the database?
Can I strip out the setter and make the field mutable only in the entity constructor?
Finally, is there any standard JPA way to make a field immutable?
Thanks in advance.
Try
#Column(updatable = false)
And make your setter private. (Leave your getter public if you want)
I think this is the best practice.
P.S.: JPA uses field access if you annotate your fields and uses getter/setter access if you annotate your getter method.
Ad. 1: I believe JPA uses plain private fields for both read and write if annotations are placed on fields and not on getters. Recently I discovered that Hibernate as an underlying JPA provider does not even need get*() and set*() methods at all. This was truly enlightening solution since from the beginning I thought Hibernate needs accessors. So the answer is: you don't need setters as far as Hibernate is concerned.
Ad. 2: However please note that Hibernate still needs no-arg constructor, otherwise it will fail to load entities with a descriptive exception. This is also a JPA requirement.
Ad. 3: No, there isn't. Remember that your collections would also had to be immutable.
Try
#Column(updatable = false)
From javadoc:
Whether the column is included in SQL UPDATE statements generated by
the persistence provider.
In JPA 2.0 you have two ways to define what attributes should be persisted:
Access(FIELD) - the fields name are persisted,
Access(PROPERTY) - the properties name are persisted.
If no Access(-) annotation is used, the decision what access will be used depends on where you put your #Id annotation. If you put it next to your field - Access(FIELD) will be used. If you put it next to your accessor - Access(PROPERTY) will be used.
Therefore, if you use Access(FIELD) you don't have to have an appropriate JavaBeans-style accessor for particular field. You can have a private field named 'myField' and a public setter for it named 'public setBlahBlah(-)'. The JPA will persist just the 'myField'.
You can mark an entity with #Entity(mutable=false) or #Immutable annotations for the framework to make use of this fact for performance gain in caching and such. (Hibernate)
Then you can use an immutable wrapper class like this:
public class ImmutableStuff {
private final FooField barValue;
public ImmutableStuff(Stuff stuff) {
barValue = stuff.barValue;
}
public FooField getBarValue(){
return barValue;
}
}
I have a base Entity class which will be derived in more than a hundred of a subclasses.
In order to be sure that persisted fields will be the ones I want (and not the users of that base class), I want to declare this JPA entity as setting all fields as transient by default.
How is it possible ?
If you don't put #MappedSuperclass on your class you are extending from, the class properties will never by persisted.
You can provide getter methods for certain properties, and place the annotations on the properties instead of the fields. The #Id annotation determines if you want the fields or the properties. In JPA 2 you can also use the #Access annotation.
I got the impression that if we use persistent fields, there is no need for getter methods since the entity manager references the instance variables directly. However, when I removed the getter and setter methods from an entity to have persistent fields, the values for the corresponding instance variable was not retrieved from the database!
Does that mean we must have getter and setter methods even though we have persistent fields?
If the entity class uses persistence, fields Persistence accesses the entity class instance variables directly at runtime.
While on persistence property, there is a getter and a setter method for each property.
What you said should have worked on hibernate.
A link about it
You don't mention what JPA implementation you are using. Hibernate certainly allows you to access fields directly. However, it is not the default setting, so you have to specify this behavior in the mapping files with access=field. (with annotation based configuration, I would imagine you just need to annotate the fields directly ...)
What provider is that? I'd expect it to work. Anyway, just create protected getter and setter methods as a workaround if your provider needs that.