6

I would like to create dynamic and generic superclass with JPA/hibernate that will be extended for each hierarchical structured model like: role, page, directory, department, permission, tree. I would like to create with this object dynamic tree using recursion and java reflection

it should look this way:

enter image description here

This entity should have reference to self entity.

I would like it to be completely abstract and had no db table. Only extendet enities should have db.

I've tried to achive this. But fail so long. Here is my post about it

I consider solutions:

  • @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
  • @Any and @AnyMetaDef mappings
  • @MappedSuperclass
  • @Embeddable and @Embedded

I hope someone will give some suggestions.

Community
  • 1
  • 1
masterdany88
  • 5,041
  • 11
  • 58
  • 132

1 Answers1

1

I came up with the following design. You can also check it on GitHub:

@MappedSuperclass
public abstract class GenericHierarchicalDictionary {

    public abstract GenericHierarchicalDictionary getParent();

    public abstract Set<? extends GenericHierarchicalDictionary> getChildren();

}

@Entity
@Table(name = "LocalFolder")
public class LocalFolder extends GenericHierarchicalDictionary {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private LocalFolder parent;

    @OneToMany(mappedBy = "parent")
    private Set<LocalFolder> children = new HashSet<LocalFolder>();

    @Override
    public LocalFolder getParent() {
        return parent;
    }

    @Override
    public Set<LocalFolder> getChildren() {
        return children;
    }

    public void addChild(LocalFolder localFolder) {
        localFolder.parent = this;
        children.add(localFolder);
    }
}

@Entity
@Table(name = "RemoteFolder")
public class RemoteFolder extends GenericHierarchicalDictionary {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private RemoteFolder parent;

    @OneToMany(mappedBy = "parent")
    private Set<RemoteFolder> children = new HashSet<RemoteFolder>();

    @Override
    public RemoteFolder getParent() {
        return parent;
    }

    @Override
    public Set<RemoteFolder> getChildren() {
        return children;
    }

    public void addChild(RemoteFolder localFolder) {
        localFolder.parent = this;
        children.add(localFolder);
    }
}

And this is the test:

@Test
public void testTree() {
    LOGGER.debug("testAddWebResource");
    doInTransaction(new TransactionCallable<Void>() {
        @Override
        public Void execute(Session session) {
            LocalFolder rootLocalFolder = new LocalFolder();
            session.persist(rootLocalFolder);
            LocalFolder localFolder1 = new LocalFolder();
            rootLocalFolder.addChild(localFolder1);
            session.persist(localFolder1);
            LocalFolder localFolder11 = new LocalFolder();
            localFolder1.addChild(localFolder11);
            session.persist(localFolder11);

            RemoteFolder rootRemoteFolder = new RemoteFolder();
            session.persist(rootRemoteFolder);
            RemoteFolder remoteFolder1 = new RemoteFolder();
            rootRemoteFolder.addChild(remoteFolder1);
            session.persist(remoteFolder1);
            RemoteFolder remoteFolder11 = new RemoteFolder();
            remoteFolder1.addChild(remoteFolder11);
            session.persist(remoteFolder11);
            return null;
        }
    });
}
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • I've checked Your solution. It's good. But I would like to put all common methods like (getParent(),addChild()) to be in abstract method: `GenericHierarchicalDictionary`. When I put that methods and parameters to `GenericHierarchicalDictionary` I am getting an error: `rg.hibernate.AnnotationException: @OneToOne or @ManyToOne on models.LocalFolder.parent references an unknown entity: models.GenericHierarchicalDictionary` – masterdany88 Nov 27 '14 at 12:01
  • Thanks. Well, Hibernate has its limitations and that's why you have to explicitly declare dependencies in the actual implementation classes. All in all, inheritance makes much more sense for behaviour than for reusing data structures. – Vlad Mihalcea Nov 27 '14 at 13:17
  • Ok. So lets declared data structure in concret class like LocalFolder. But can we move methods of getting parents, children, tree structure into the abstract method (with reflection?)? I was trying to make generic DAO like many other are, but never saw that data structure in GenericDao – masterdany88 Nov 27 '14 at 13:22
  • GenericHierarchicalDictionary defines both getParent and getChildren. So the base class define sthe contract, meaning you don;' have to use reflection. You can also have the addChild, setParent defines in the base class too. – Vlad Mihalcea Nov 27 '14 at 13:36
  • How can I declare body to this methods in abstract base class? – masterdany88 Nov 27 '14 at 14:12
  • I was only referring to abstract method declamations so that you can compile against the base class methods. – Vlad Mihalcea Nov 27 '14 at 14:39
  • Can we ask for such functionality to Hibernate comunity? – masterdany88 Nov 28 '14 at 09:07