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.
Related
I am considering moving from Hibernate to jOOQ but I can't find e.g.
how to have Pattern-Constraints on a String like this in Hibernate:
#NotEmpty(message = "Firstname cannot be empty")
#Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
How would I do that in jOOQ?
The "jOOQ way"
The "jOOQ way" to do such validation would be to create either:
A CHECK constraint in the database.
A trigger in the database.
A domain in the database.
After all, if you want to ensure data integrity, the database is where such constraints and integrity checks belong (possibly in addition to functionally equivalent client-side validation). Imagine a batch job, a Perl script, or even a JDBC statement that bypasses JSR-303 validation. You'll find yourself with corrupt data in no time.
If you do want to implement client-side validation, you can still use JSR-303 on your DTOs, which interact with your UI, for instance. But you will have to perform validation before passing the data to jOOQ for storage (as artbristol explained).
Using a Converter
You could, however, use your own custom type by declaring a Converter on individual columns and by registering such Converter with the source code generator.
Essentially, a Converter is:
public interface Converter<T, U> extends Serializable {
U from(T databaseObject);
T to(U userObject);
Class<T> fromType();
Class<U> toType();
}
In your case, you could implement your annotations as such:
public class NotEmptyAlphaNumericValidator implements Converter<String, String> {
// Validation
public String to(String userObject) {
assertNotEmpty(userObject);
assertMatches(userObject, "^[a-zA-Z0-9_]*$");
return userObject;
}
// Boilerplate
public String from(String databaseObject) { return databaseObject; }
public Class<String> fromType() { return String.class; }
public Class<String> toType() { return String.class; }
}
Note that this is more of a workaround, as Converter hasn't been designed for this use-case, even if it can perfectly implement it.
Using formal client-side validation
There's also a pending feature request #4543 to add more support for client-side validation. As of jOOQ 3.7, this is not yet implemented.
I recommend you don't try to use jOOQ in a 'hibernate/JPA' way. Leave the jOOQ generated classes as they are and map to your own domain classes manually, which you are free to annotate however you like. You can then call a JSR validator before you attempt to persist them.
For example, jOOQ might generate the following class
public class BookRecord extends UpdatableRecordImpl<BookRecord> {
private String firstname;
public void setId(Integer value) { /* ... */ }
public Integer getId() { /* ... */ }
}
You can create your own domain object
public class Book {
#NotEmpty(message = "Firstname cannot be empty")
#Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
public void setId(Integer value) { /* ... */ }
public Integer getId() { /* ... */ }
}
and map by hand once you've retrieved a BookRecord, in your DAO layer
Book book = new Book();
book.setId(bookRecord.getId());
book.setFirstname(bookRecord.getFirstname());
This seems quite tedious (and ORM tries to spare you this tedium) but actually it scales quite well to complicated domain objects, in my opinion, and it's always easy to figure out the flow of data in your application.
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).
In Java, I have access to value of Transient fields of the class. However, I do not access to the same fields on JSP. How can I make them available to JSP?
I am retrieving the values using Hibernate, I reckon a solution to this would be to Transformers.aliasToBean option but is there any other solution to it?
Is there anyway to get rid of transient annotation but have the same mapping in Hibernate? In that case, the problem will be solved.
#AssociationOverrides({
#AssociationOverride(name = "tta.names", joinColumns = #JoinColumn(name = "id"))})
public class Names implements java.io.Serializable {
private static final long serialVersionUID = -30956546435023625398L;
#EmbeddedId
private TableToAssociate tta = new TableToAssociate();
#Transient
public String getid() {
return tta.getMyIds().getId();
}
public void setid(String id) {
this.tta.getMyIds().setId(id);
}
In Java, I can access them using following code
System.out.println(mystudents.getNames().iterator().next().getId());
In JSP, I do not have access to them!
<c:forEach var="nm"items="${mystudents.names}">
${nm.id}
</c:forEach>
If I put another field of names that is not transient, JSP successfully show the value of that item.
Try renaming the methods to match the JavaBean specification.
Instead of:
#Transient
public String getid() {
return tta.getMyIds().getId();
}
public void setid(String id) {
this.tta.getMyIds().setId(id);
}
you should have:
#Transient
public String getId() {
return tta.getMyIds().getId();
}
public void setId(String id) {
this.tta.getMyIds().setId(id);
}
Get rid of #Transient on your entity. Based on your embedded id, you've chosen field annotations. You should be able to have a getter that Hibernate won't try to persist without explicitly marking it as such. And change the getter/setter to use correct JavaBean syntax. getId instead of getid.
It is happening because transient keyword stops the field to be serialized. To pass an object to JSP, it must be serialized. This field will not be there in your serialized object and hence, it is not available to JSP.
For solving your problem, you should see James' comment to use #Transient annotation. It is supplied by JPA and it should allow you to NOT save your value in DB, but serialize it so your JSP can use it.
What you are asking is not possible.. As smarter then me said before.
#Transient is just saying not to serialize/deserialize. Hibernate doesn't serialize this and the same is what jsp bean.
You can do several things:
I think the best thing here is to wrap field in getter and setter in the bean.. This way you will set the property on the bean and in case of only one field every other solution will be overhead.
public class Bean() {
private Names name;
private String id;
public Bean() {
//few action to load name
this.id = name.getid();
}
public String getId() {
return this.id;
}
Create different entity for ui(Bean) and DB(Hibernate). In many cases ui layer and entities are not the same and sometime should not be coupled
You can use inheritance and create diffrent implemenation in the hibernate entity and on ui layer(Jsp bean)
If you ask me i think the best is to do what on section 1. If this happen more oftain you should consider decouple your ui layer and business entity.
I am not sure what the best practice is for dealing with collection/lookup tables/in RequestFactory.
For example if I have following two Domain objects:
#Entity
public class Experiment {
private Long id;
private String name;
#ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE})
private UnitOfMeasure unitOfMeasure;
public Experiment() { }
public String getName() {
return name;
}
public Long getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public UnitOfMeasure getUnitOfMeasure() {
return unitOfMeasure;
}
public void setUnitOfMeasure(UnitOfMeasure unitOfMeasure) {
this.unitOfMeasure = unitOfMeasure;
}
}
#Entity
public class UnitOfMeasure {
private Long id;
private String unit_type;
public UnitOfMeasure() { }
public String getUnitType() {
return unit_type;
}
public Long getId() {
return id;
}
public void setUnitType(String unitType) {
this.unit_type = unitType;
}
}
This is a normal unidirectional 1:n realtionship between Experiment and UnitOfMeasure using a ForeignKey in the Experiment table.
I have a limited amount of different UnitOfMeasure instances which usually don't change.
The web-app provides a view where the user can change some properties of the Experiment instance. The view uses the Editor framework. For changing the UnitOfMeasure of a specific Experiment I use a ValueListBox and render the unit_type property.
Because the list of available UnitOfMeasure instances is static I use AutoBeanFactory to create a json string which I put into the HTML host page and during application start I parse it (same thing for all other collection like table values) and store them in a Singleton class instance (AppData) which I pass to `setAcceptableValues``.
Currently I derive UnitOfMeasureProxy from EntityProxy but in order to decode/encode it with AutoBeanFactory I have to annotate the Factory with EntityProxyCategory. I somehow suspect that a ValueProxy would be a better fit.
However with a ValueProxy when I change the UnitOfMeasure of a specific Experiment the entire ValueProxy instance is transmitted over the wire.
From a database point of view however only changing the value for the foreignkey in the Experiment table is required.
So what is the best practice (ValueProxy vs EntityProxy) for collection like tables and child values respectively?
In many cases, references to other entities are best modelled using their IDs rather than the EntityProxys themselves (it's debatable, but I think it's also true for server-side code, or actually any code that crosses unit-of-work boundaries –JPA EntityManager lifetime, Hibernate session, etc.–)
BTW, the proper way to serialize RequestFactory proxies is to use a ProxySerializer.
Make sure you use GWT 2.5.0-rc1 though if you have lists of ValueProxys (see issue 6961)
I'm migrating a legacy system over to use Hibernate 3. It currently generates its own identifiers. To keep with what the system currently does before I try and move it over to something a little better, how would I go about specifying (using annotations) my own class that will return the custom generated identifiers when an insert occurs?
Something like:
#Id
#CustomIdGenerator(Foo.class) // obviously this is not a real annotation
public String getId() { ... }
Where the Foo class has one method that generates the identifier.
Currently I'm just calling the setId(String id) method manually but was hoping for a better way to deal with this situation.
I don't think there is out-of-box support for generating custom Ids using custom annotations using pure JPA-2 API. But if you want to use provider specific API, then the job is pretty simple. Sample Example
To be provider independent try any of following tricks....
IdGeneratorHolder
public abstract class IdGeneratorHolder {
/* PersistentEntity is a marker interface */
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
/* sample impelementation */
if(Product.class.isAssignableFrom(entityType)) {
return new ProductIdGenerator();
}
return null;
}
}
General IdGenerator interface
public interface IdGenerator {
String generate();
}
Specific IdGenerator - Product Id Generator
public class ProductIdGenerator implements IdGenerator {
public String generate() {
/* some complicated logic goes here */
return ${generatedId};
}
}
Now set the generated id either in no-arg constructor OR in #PrePersist method.
Product.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
#PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
In above example all the ids are of the same type i.e. java.lang.String. If the persistent entities have ids of different types.....
IdGenerator.java
public interface IdGenerator {
CustomId generate();
}
CustomId.java
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
Item.java
#PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
You can also use your custom annotation...
CustomIdGenerator.java
public #interface CustomIdGenerator {
IdStrategy strategy();
}
IdStrategy.java
enum IdStrategy {
uuid, humanReadable,
}
IdGeneratorHolder.java
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
One more thing.... If we set id in #PrePersist method, the equals() method cannot rely on id field (i.e. surrogate key), we have to use business/natural key to implement equals() method. But if we set id field to some unique value (uuid or "app-uid" unique within application) in no-arg constructor, it helps us to implement the equals() method.
public boolean equals(Object obj) {
if(obj instanceof Product) {
Product that = (Product) obj;
return this.id ==that.id;
}
return false;
}
If we or someone else call (intentionally or by mistake) the #PrePersist annotated method more than one times, the "unique id will be changed!!!" So setting id in no-arg constructor is preferable. OR to address this issue put a not null check...
#PrePersist
public void generateId() {
if(id != null)
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
UPDATE
If we put the id generation in a
no-arg constructor, wouldn't that
cause a problem when loading entities
from the database? because hibernate
will call the no-arg constructor
causing existing ids to be
re-generated
Yeah you are right, I missed that part. :( Actually, I wanted to tell you that:- in my application every Entity object is associated with an Organization Entity; so I've created an abstract super class with two constructors, and every Entity (except Organization) extends this class.
protected PersistentEntityImpl() {
}
protected PersistentEntityImpl(Organization organization) {
String entityId = UUIDGenerator.generate();
String organizationId = organization.getEntityId();
identifier = new EntityIdentifier(entityId, organizationId);
}
The no-arg constructor is for JPA provider, we never invoke no-arg constructor, but the other organization based constructor. As you can see. id is assigned in Organization based constructor. (I really missed this point while writing the answer, sorry for that).
See if you can implement this or similar strategy in your application.
The second option was using the
#PrePersist annotation. I put that in
and the method never got hit and gave
me an exception stating that I needed
to set the id manually. Is there
something else I should be doing?
Ideally, JPA provider should invoke #PrePersist methods (one declared in class and also all the other methods that are declared in super-classes) before persisting the entity object. Can't tell you what is wrong, unless you show some code and console.
You can.
First, implement org.hibernate.id.IdentifierGenerator
Then you'd have to map it in a mapping xml file. I couldn't find a way to do this with annotations:
<!--
<identifier-generator.../> allows customized short-naming
of IdentifierGenerator implementations.
-->
<!ELEMENT identifier-generator EMPTY>
<!ATTLIST identifier-generator name CDATA #REQUIRED>
<!ATTLIST identifier-generator class CDATA #REQUIRED>
Finally, use #GeneratedValue(generator="identifier-name")
Note that this is hibernate-specific (not JPA)
Update: I took a look at the sources of Hibernate, and it seems at one place, after failing to resolve the short name, hibernates attempts to call Class.forName(..). The parameter there is called strategy. So Here's what you try:
try setting the class fully-qualified name as string in the generator attribute
try setting the class fqn as string in the #GenericGenerator strategy attribute (with some arbitrary name)
Let me know which (if any) worked