Dynamic Inheritance
I have a situation where I want a class (which is a JPA entity) to be able to extend either class A or class B dynamically. My thought was to use Generics, but it looks like generics doesn’t support this. For example:
#Entity
public abstract class Resource() {
...
}
#Entity
public abstract class Snapshot() {
...
}
public abstract class CommonRS<R extends Resource, S extends Snapshot> {
/* This is the class that I want to dynamically assign Inheritance to. */
...
}
#Entity
public class FeedResource extends CommonRS<Resource> {
...
}
#Entity
public class FeedSnapshot extends CommonRS<Snapshot> {
...
}
The reason I want to do this is that FeedResource must Inherit from Resource and FeedSnapshot must inherit from Snapshot because both classes are using the JPA join strategy InheritanceType.JOINED and are persisted to different tables, however they both share common attributes and I would like them to be able to inherit those common attributes.
I understand that I can I could use #Embeddable on CommonRS and the Embed it in both FeedResource and FeedSnapshot.
Since Java doesn’t support multiple inheritance, I can’t see any other way to do this other than using Embeddable.
Thanks in advance.
Here is how you do it
#MappedSuperClass
public abstract class Base() {
...
// put your common attributes here
}
#Entity
public abstract class Resource() extends Base{
...
}
#Entity
public abstract class Snapshot() extends Base {
...
}
public abstract class CommonRS<R extends Base> {
...
}
#Entity
public class FeedResource extends CommonRS<Resource> {
...
}
#Entity
public class FeedSnapshot extends CommonRS<Snapshot> {
...
}
UPDATE
Another solution can be implementing same interface (if common inheritance cannot be achieved). In that case #MappedSuperClass annotation should be used on actual base classes.
#Entity
public abstract class Resource() extends BaseIntf {
...
}
#Entity
public abstract class Snapshot() extends BaseIntf {
...
}
public abstract class CommonRS<R extends BaseIntf> {
...
}
#Entity
public class FeedResource extends CommonRS<Resource> {
...
}
#Entity
public class FeedSnapshot extends CommonRS<Snapshot> {
...
}
Related
I have such classes hierarchy:
#Data
#SuperBuilder
public abstract class Parent1 {
Long id;
}
#Data
#SuperBuilder
public abstract class Parent2 extends Parent1 {
String name;
// Customized Lombok's builder
public abstract static class Parent2Builder<C extends Parent2, B extends Parent2Builder<C, B>> {...}
}
#Data
#SuperBuilder
public class Child extends Parent2 {
//some fields and methods
}
All worked fine when Parent1 and Parent2 were as one class (Parent with 2 fields) with Lombok's customized builder. But I had to separate one class in two different and got the next error while compiling:
Parent2.java: error: method does not override or implement a method from a supertype #SuperBuilder
I have no idea which method I didn't implement.
P.S. I also have the same classes hierarchy (but without customized builder) in another package and there were no errors at all.
Right now, Parent2.Parent2Builder does no longer extends Parent1.Parent1Builder. If we change
public abstract static class Parent2Builder
<C extends Parent2, B extends Parent2Builder<C, B>> {
...
}
to
public abstract static class Parent2Builder
<C extends Parent2, B extends Parent2Builder<C, B>>
extends Parent1.Parent1Builder<C, B> {
...
}
It works as expected.
What would be the best practice for the following case?
You have the following entities:
#Entity public class BaseEntity { }
#Entity public class SubEntity extends BaseEntity { }
And you have a JpaRepository for BaseEntity having multiple select-methods:
public interface BaseEntityRepository extends JpaRepository<BaseEntity, Long> {
Set<BaseEntity> findAll();
Set<BaseEntity> findSome...();
}
Now you want a JpaRepository for SubEntity inheriting all the methods from BaseEntityRepository.
Now I imagine multiple scenarios, from whom I am not sure which one is the best or which ones should work:
(a) Create a new independent JpaRepository for SubEntity with exactly the same Methods, but substituing BaseEntity with SubEntity:
public interface SubEntityRepository extends JpaRepository<SubEntity, Long> {
Set<SubEntity> findAll();
Set<SubEntity> findSome...();
}
(b) Extending BaseEntityRepository, all Methods should be inherited, but it still return BaseEntity-objects instead of SubEntity-objects
public interface SubEntity extends BaseEntityRepository {
}
I don't really like any of both solutions. How would you solve this?
Somehow I think JpaRepository is not ment for this use-case?
You could parameterize your BaseEntityRepository and operate on those parameters.
public interface BaseEntityRepository<T, I> extends JpaRepository<T, I> {
Set<T> findAll();
Set<T> findSome...();
}
Then add any additional methods in the subclass by extending the BaseEntityRepository
public interface SubEntityRepository extends BaseEntityRepository<SubEntity, Long> {
...
}
I need to know if it's possible to add some attributes and behaviours to some POJO JPA entity (using hibernate provider) by extending it, and then to make entityManager to return extended objects instead of just pojo entitys, like the following examples:
POJO JPA Entity Class
#Entity
#Table("test")
public class Test implements Serializable {
}
Extended Class
public class ExtendedTest extends Test {
...
}
Fetching Extended Class's objects
List<ExtendedTest> extendedList = entityManager.createNamedQuery("ExtendedTest.findByFoo").setParameter("foo", "bar").getResultList();
The other possible way i'm assessing is extending funcionality with a composite entity and delegating all setters and getters, but this could mean a lot of work with huge tables:
public class ExtendedTest2 {
private Test test;
public ExtendedTest2(Test test) {
this.test = test;
}
public getFoo() {
return test.getFoo();
}
public getBar() {
return test.getBar();
}
...
}
Any suggestions will be very appreciated.
Using #Inheritance
#Entity
#Table(name="TEST")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Test {
...
}
#Entity
public class ExtendedTest
extends Test {
...
}
or #MappedSuperclass
#MappedSuperclass
public class Test {
...
}
#Entity
public class ExtendedTest
extends Test {
...
}
currently I'm trying to implement a typed generic DAO.
I do not even get to compile anything, since NetBeans complains about UserDAOHibernate
interface expected here
type argument User is not within bounds of type-variable ENTITY
I'm afraid there is some obvious mistake in how I use inheritance/interfaces, since I'm rather new to Java.
Here's some stripped down code
public interface GenericEntity<ID extends Serializable> {
public abstract ID getId();
public abstract void setId(final ID id);
}
public abstract class LongEntity implements GenericEntity<Long> {
protected Long id;
public Long getId();
public void setId(final Long id);
}
public class User extends LongEntity implements Serializable {
private String name;
private String password;
private Customer customer;
}
public interface GenericDAO<ENTITY extends GenericEntity<ID>, ID extends Serializable> {
public abstract ENTITY findById(ID id);
public abstract List<ENTITY> findAll();
public abstract ENTITY makePersistent(ENTITY entity);
public abstract void makeTransient(ENTITY entity);
}
public abstract class GenericHibernateDAO<ENTITY extends GenericEntity<ID>, ID extends Serializable>
implements GenericDAO<ENTITY, ID> {
}
public class UserDAOHibernate implements GenericHibernateDAO<User, LongEntity> {
}
Is it that LongEntity should extend GenericEntity<Long>? If so, how would I do this with Java's single level or inheritance?
Is this layered approach a bad example to follow? All my entities need an id and this implementation could easily be reused lateron with different id types, so I thought I might use it.
The error comes from here:
public class UserDAOHibernate implements GenericHibernateDAO<User, LongEntity> {
}
You've specified that GenericHibernateDAO's ID parameterized type is bounded by <ID extends Serializable>.
LongEntity extends GenericEntity, and hence, why you have a type mismatch.
Also, GenericHibernateDAO is an abstract class (and not an interface), so you'll need to extends instead of implements.
The correct solution should be:
public class UserDAOHibernate extends GenericHibernateDAO<User, Long> {
}
Given a generic tree based (Java) data model. Let's say
abstract class XModel {
long id;
XModel parent;
}
class ProjectModel extends XModel {
String customer;
}
class FileModel extends XModel {
String name;
}
class FolderModel extends XModel {
String name;
String attributes;
}
My challenge is to make sure that FileModels are only used in FolderModels (or PrjectModels) and FolderModels are only used in ProjectModels.
Since the model should be extensible - is there any generic way to do this constraint validation (like XML Schema does) without hardcoding the parent-child-realtions in a validation method?
I'm not sure how useful it would be - depends on how you create the tree, but this might work:
abstract class XModel<T extends XModel> {
long id;
T parent;
}
class ProjectModel extends XModel { ... }
class FolderModel extends XModel<ProjectModel> { ... }
class FileModel extends XModel<FolderModel> { ... }
UPDATE
To separate validation logic from model itself you could use some runtime validators like Hibernate or Spring validators.
I would use generics and interfaces that describe the restrictions
interface Model {
}
abstract class AbstractModel<P extends Model> implements Model {
Long id;
P parent;
}
class ProjectModel extends AbstractModel implements HasFileModel,
HasFolderModel {
}
interface HasFileModel extends Model {
}
static class FileModel extends AbstractModel<HasFileModel> {
}
interface HasFolderModel extends Model {
}
class FolderModel extends AbstractModel<HasFolderModel> implements
HasFileModel {
}
This way the child only restricts the parent to an interface not a concrete type
If you don't want to put those constraints into code, you'd have to write a validation method that is fed by some external data yourself. AFAIK there's no such built in option (in the compiler) besides using Generics, which would require you to express the constraints in code.