I am reading the Beginning Java EE6 Platform and Glassfish 3 book and I have some minor difficulties at understanding Access type on field/properties. What is the difference between the two of them?
Is it how the properties are read/set by the JPA implementation (in this case EclipseLink)? Like, if it is property access the values are read/set through possible validations etc that can be placed in the get/set method, while the field access option does not do setting/getting values through these methods but straight on the fields? And does the type get set by where I am placing the #Id annotation?
The #Access annotation type indicates how the JPA should set or get the field in your object. An AccessType.FIELD the JPA will set the field directly with reflection and will not use any provided setter method., very useful if your class tracks the "dirtyness" of a field through the setter methods. In contrast setting #Access(value=AccessType.PROPERTY) will instruct the JPA to use the setter and getter methods when it accesses fields.
You can prove this to yourself by adding logging or System.out.printlns to your setter methods and then making changes to the #Access annotation. For example:
#Id
#Access(value=AccessType.PROPERTY)
private Long Id;
public void setId(Long id) { System.out.println("SET"); this.Id = id; }
Will print SET and this:
#Id
#Access(value=AccessType.FIELD)
private Long Id;
public void setId(Long id) { System.out.println("SET"); this.Id = id; }
Will NOT!
It also does not matter where you place the annotations, at least in Hibernate ;-).
Related
I'm very new to Spring/Springboot and have seen different approaches in tutorials regarding the model classes used to represent database objects. I was just wondering when it's appropriate to use which?
Approach 1:
A basic class to model a user object
public class User {
private final UUID id;
// other fields
public User(UUID id, <other fields>) {
this.id = id;
// set other fields
}
In the repository layer, we might have a DAO which looks something like
#Repository
public interface UserDao {
public int createUser(UUID id, <other fields>);
// other CRUD operations
}
When the user doesn't input a valid UUID (or absent) a default method could insert it by calling UUID.randomUUID()
Approach 2:
Instead of using a UUID as a unique identifier, instead, with something like Hibernate/JPA we use the #Entity annotation on the User class in the model package, and have the PK field annotated with #Id
#Entity
public class User {
#Id
private final long id;
// other fields
}
#Id annotation is the most commonly used approach in Hibernate. This will map a Java String / BigDecimal / long attribute to an identifier. And using this, you can use specify four generation strategies - AUTO, IDENTITY, SEQUENCE and TABLE.
UUIDs are used when you want your primary key to be globally unique. I can think of a few scenarios where you might want this -
You have data in multiple databases and your keys needs to be unique across different databases.
You need your generated id value even before you persist your record in your database for specific business purposes.
But the downside is that, UUIDs are long and may cost more in terms of storage space.
I have confusion in using Data annotation to DTO class. Here is my sample class.
#Data
public class MyClass {
private Long id;
private String name;
}
I've read online that using Data annotation specifically on DTO class will allow the values of the fields to be changed by use of the generated setters.
Should I remove the lombok Data annotation? And implement the getters and setters manually.
Thanks :)
I would avoid #Data for DTOs since it has too many pitfalls. First of all as you mentioned it is mutable which you don't really want for a DTO. And despite it being mutable, it implements equals() and hashCode() which is only asking for trouble.
You can use #Value for an immutable DTO. For an incoming DTO you may need to add lombok.anyConstructor.addConstructorProperties to your lombok.config, which will allow libraries like jackson to deserialize to your POJO without a default constructor.
The annotation #Data comes from the Project Lombok which is designed to use reflection via annotations mostly. This annotation assures generation of all the setters, getters, a constructor with all the required arguments and overridden Object::toString, Object::equals and Object::hashCode methods.
Briefly said, this annotation "completes" a simple POJO object and generates all the boilerplate without a need to use IDE.
They named the annotation #Data because they support the idea of the understanding objects as data containers only.
As far as I understand, the generation happens only for the missing getters/setters (let's speak about them for brevity). The generated getters/setters are in their pure form as you know:
public int getId() { return this.id; }
public void setId(int id) { this.id = id; }
You can use more verbose setter/getter performing validation or anything similar which override the generated ones. You can both use #Data annotation and write your ones manually.
DTO is used to transmit data information, some information is actually we do not want users to be able to change or access, such as the user password, we do not want to pass to the front end when the user can see the encrypted password, or we do not want users to modify the password while changing their information, and what works in this serialization process is setter and getter, and data annotations that automatically generate getters and setters for all fields.
For example
#Data
class User{
private String userName;
private String pwd;
}
This class, will have all setter and getter. When you trans to web, you will see
{userName: "123", pwd: "xxx"}
This is terrible.
But if you use DTO
class User{
private String userName;
private String pwd;
public String getUserName(){
return userName;
}
}
They only see
{userName: "123"}
By default the #Data lombok annotation will generate setters and getters for all fields in the class.
If you want an immutable data transfer object, annotate it as #Value instead.
If you want a mixure of some immmutable values and some mutable values in your MyClass type, for instance you might want the id field to be immutable and the rest mutable, you would use the #Setter annotation on the field you want to be immutable, specifying an AccessLevel of NONE. For instance:
#Data
public class MyClass {
#Setter(AccessLevel.NONE)
private Long id;
private String name;
}
This will generate a getter but no setter for the id, and a getter and setter for the name.
when I use the JPA #Version annotaton in an #Embeddable I get the following exception pointing at my Updateable class:
org.hibernate.AnnotationException: Unable to define #Version on an embedded class
Here is my code:
#Embeddable
public class Updateable {
#Version
private long modcount;
private String updatedBy;
private DateTime updatedAt;
// getters & setters
}
#Entity
public class SomeEntity {
#Id
private Long id;
#Embedded
private Updateable updateAudit;
// other stuff
}
Is it not possible to have a #Version in an #Embeddable, or is this Hibernate specific?
An embeddable class is just a convinience way of declaring reusable entity elements, i.e. your Updateable could be used in other entities without having to add the fields and the mapping again.
As such, embeddables are part of the entity (as the name suggests they are embedded) and thus independent versioning doesn't make sense.
Adding the #Version annotation to the embeddable only would also not make much sense since the embeddable itself can't be versioned and you'd have to deal with cases where multiple embeddables are contained in a single entity (e.g. which version should be used in that case?). So since #Version only makes sense for entities it's easier to just allow that annotation for entities or mapped superclasses.
Actually although the JPA spec recommends that version properties are numeric, strings or timestamps Hibernate seems to provide user defined version types:
The version column may be a numeric (the recommended solution) or a timestamp. Hibernate supports any kind of type provided that you define and implement the appropriate UserVersionType.
So what you might be able to do (not tested, just derived from the docs) if you want to use Updateable as your version is to provide a custom user type for Updateable and then use it like this:
#Entity
public class SomeEntity {
#Id
private Long id;
#Type( "your.custom.UserVersionType" )
#Version
private Updateable updateAudit;
// other stuff
}
I have entities which are divided into categories. Each entity can belong to many categories, so I have one to many association.
Is it ORM-ed correctly below:
#OneToMany
#Access(AccessType.FIELD)
private Set<Category> parents = new HashSet<Category>();
public Set<Category> getParents() {
return parents;
}
public boolean addParent(Category parent) {
return parents.add(parent);
}
public boolean removeParent(Category parent) {
return parents.remove(parent);
}
My specific question is am I need to use #Access annotation or not? If I won't use it then how Hibernate will know not to map getParents getter?
I do not know whether or not you need the #Access(AccessType.FIELD) annotation, because this depends on some defaults (see below).
But if you use Field access type (by default or by #Access(AccessType.FIELD)) then
Hibernate will access the FIELD directly and not use the getter or setter!
See Hibernate Reference, chapter 5.1.4.1.2. Access type, for more details about the access type determination algorithm.
By default the access type of a class hierarchy is defined by the position of the #Id or #EmbeddedId annotations. If these annotations are on a field, then only fields are considered for persistence and the state is accessed via the field. If there annotations are on a getter, then only the getters are considered for persistence and the state is accessed via the getter/setter. That works well in practice and is the recommended approach.
I'm developing an Java-application which stores its data via Hibernate in a database.
One feature of this application is to define templates like types, etc. for reuse. For instance the type has attributes and you can create instances of an type, which has values for the attributes.
The problem is, that I don't know how to ensure that only values for attributes can assigned which the type defines. In my solution there is a redundancy which cause the problem, but I don't know how to remove it.
My current (and problematic) approach looks like this:
#Entity
class Type
{
#Id
#Generated
private Long id;
#OneToMany(mappedBy="type")
private List<Attribute> attributes;
//...
}
#Entity
class Attribute
{
#Id
#Generated
private Long id;
#ManyToOne
private Type type;
//...
}
#Entity
class Instance
{
#Id
#Generated
private Long id;
#ManyToOne
private Type type;
//...
}
#Entity
class AttributeValue
{
#Id
#Embedded
private ResourceAttributValueId id;
#Column(name="val")
private String value;
//...
}
#Embeddable
public class ResourceAttributValueId implements Serializable
{
#ManyToOne
private ResourceStateImpl resource;
#ManyToOne
private ResourceAttributeImpl attribute;
//...
}
There the definition of the type is redundant: Type can be reached via AttributeValue->Attribute->Type and AttributeValue->Instance->Type
Another idea was to use type + attribute name as id of the attribute and instance + attribute name as id of the attribute value, but that doesn't solves my problem.
The key for correctly modeling "diamond-shaped" dependencies like this is the usage of identifying relationships:
(I took a liberty of renaming your entities slightly, to what I believe is a more consistent naming scheme.)
Note how we migrate the TYPE_ID from the top of the diamond, down both sides, all the way to the bottom and then merge it there. So, since there is only one ATTRIBUTE_INSTANCE.TYPE_ID field and is involved in both FKs, we can never have an attribute instance whose attribute type's type differs from instance's type.
While this avoids "mismatched" attributes, it still doesn't ensure the presence of attribute instances (if you support the concept of "required attribute"), which is best enforced at the application level. Theoretically you could enforce it at the database level, using circular deferred FKs, but not all DBMSes support that, and I doubt it would play nicely with ORMs.
Unfortunately, I'm not experienced enough with Hibernate to answer whether this can be mapped there and how.
See also:
Choosing from multiple candidate keys
How to keep foreign key relations consistent in a “diamond-shaped” system of relationships