About your quote:
But JPA specification mandates the entity bean should have public
getters and setters, inherently being an anemic data container,
antithesis to the DDD domain model.
I'm not an export on this topic, but as far as I know, JPA doesn't mandate public getters and setters, although documentation can be vague sometimes.
For example, the Hibernate 5.6 doc says:
2.5.4. Declare getters and setters for persistent attributes
The JPA specification requires this, otherwise, the model would prevent
accessing the entity persistent state fields directly from outside the
entity itself.
With "requirement quoted above", they probably mean this:
The persistent state of an entity is represented by instance
variables, which may correspond to JavaBean-style properties. An
instance variable must be directly accessed only from within the
methods of the entity by the entity instance itself. The state of the
entity is available to clients only through the entity’s accessor
methods (getter/setter methods) or other business methods.
These texts aren't very clear whether setters and setters are always required, even though the word "requires" is used. What I think what it basically says (or should say) is that if your clients wants to read and write to an attribute then you should use public getters and setters respectively. (With "your client classes", I mean a class that you have written, as opposed to Hibernate itself as a client of the entity.) But if your clients don't need to read or write to it, then you don't need accessor methods at all, as long as you use JPA field-access attribute annotations (as opposed to JPA method/property-access attribute annotations). Instead of setters, you could also use constructor parameters for non-null attributes. (I have plenty of such cases in my Hibernate code.) Although the JPA/Hibernate doc may have been written originally with a more anemic entity classes in mind, but you aren't required to have such anemic accessors.
About your quote:
So should I bundle domain logic
inside the JPA entity? Or should I maintain two distinct models and
the mapping logic when working with ORM on DDD? Where should these
model and the mapping logic live at the project level?
Making two distinct models would create a lot of boiler plate code.
The JPA spec says:
In addition to returning and setting the persistent state of the
instance, property accessor methods may contain other business logic
as well, for example, to perform validation. The persistence provider
runtime executes this logic when property-based access is used.
So having business logic in entity classes, should not be a problem.
In the ideal situation, entity classes are pure DDD domain classes, in which the ORM applied to it, is only limited to meta data (for example annotations), and the code it self is ORM agnostic.
But having a lot of ORM meta data mixed with a lot of business logic, can hurt readability. A solution to this could be extension methods in Kotlin (a Java based language). A Kotlin extension method is basically a static method in Java, that can be used as an instance method in Kotlin, that lives externally from the class to which it is logically added to.
For example, you could have the following entity class: com.stackoverflow.domain.Question.
And for whatever reason, you would like to add a persist() method to it, but you don't want to have it in the Question class because of separation of concerns, than you could accomplish this with extension method:
In the file com.stackoverflow.persistence.QuestionExt.kt:
package com.stackoverflow.persistence
import com.stackoverflow.domain.Question
fun Question.persist() {
// read "id" property of question object
val id = this.id
// persist the question
}
Then client code can do this:
package com.stackoverflow.persistence.repositories
class QuestionRepository {
fun save(question: Question) {
question.persist()
}
}