-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Mapping collection with interface as generic type
PostPosted: Tue Jul 27, 2010 11:48 am 
Newbie

Joined: Tue Jul 27, 2010 9:46 am
Posts: 2
Hi everyone! (it's my first post on hibernate forum)

At the beginning I would inform that I am hibernate newbie, so your patience is very appreciated.

My question refers to mapping the following class hierarchy:
(the following code is complete and ready to run if you wish to try it in your IDE)

Code:
package pl.edu.uj.spring.hibernate.collections;

public interface Identifiable {
    Long getId();
}

Identifiable interface allows to retrieve primary key of an object (used when working with DB). Please notice that there is no setter here. I don't want to make possible changing this value from Java code. ID (key) should be set ones, and stay the same up to removing object. As far as I know in fact many DB vendors do not allow to update primary key of an entity.

Code:
package pl.edu.uj.spring.hibernate.collections;

public interface Person extends Identifiable {
    public String getName();
    public String getSurname();
    public void setName(String name);
    public void setSurname(String surname);
}


Code:
package pl.edu.uj.spring.hibernate.collections;

public class Student implements Person {

    private Long id;

    private String name;
    private String surname;
    private int classNumber;

    public Student(String name, String surname, int classNumber) {
        setName(name);
        setSurname(surname);
        setClassNumber(classNumber);
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    public int getClassNumber() {
        return classNumber;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public void setClassNumber(int classNumber) {
        this.classNumber = classNumber;
    }
}


Code:
package pl.edu.uj.spring.hibernate.collections;

public class Teacher implements Person {

    private Long id;

    private String name;
    private String surname;
    private String specializationSubject;

    public Teacher(String name, String surname, String specializationSubject) {
        setName(name);
        setSurname(surname);
        setSpecializationSubject(specializationSubject);
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    public String getSpecializationSubject() {
        return specializationSubject;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public void setSpecializationSubject(String specializationSubject) {
        this.specializationSubject = specializationSubject;
    }
}


Please notice that persons collections uses interface as a generic type! Classes Teacher and Student implements this interface:
Code:
package pl.edu.uj.spring.hibernate.collections;

import java.util.List;

public class School implements Identifiable {

    private Long id;
    private List<Person> persons;

    public Long getId() {
        return id;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }

    public List<Person> getPersons(List<Person> persons) {
        return persons;
    }

    public void addPerson(Person person) {
        persons.add(person);
    }
}


Here is how this everything is used (Spring + Hibernate):

Code:
package pl.edu.uj.spring.hibernate.collections;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class SchoolDAO extends HibernateDaoSupport {

    public void persist(School school) {
        getHibernateTemplate().save(school);
    }

    public School load(Long id) {
        return getHibernateTemplate().load(School.class, id);       
    }
}



Code:
public class HibernateCollections {
    public static void main(String[] args) {

        List<Person> persons = new ArrayList<Person>();
        persons.add(new Teacher("John","Smith","History"));
        persons.add(new Teacher("Michael","Black","Biology"));
        persons.add(new Student("Wladimir","Vodka", 3));
        persons.add(new Student("Marko","Ramirez",4));

        School school = new School();
        school.setPersons(persons);

        ApplicationContext ctx = new ClassPathXmlApplicationContext("pl/edu/uj/spring/hibernate/collections/context.xml");
        SchoolDAO dao = ctx.getBean("schoolDao", SchoolDAO.class);

        dao.persist(school);
    }
}


(I know that I can simplify this code by using inheritance but I just wanted to flash on collection persisting)

Ok so my question is how to map everything in xml file?
I've tried in this way (using inheritance - classes Teacher and Student implements interface Person):

Code:
<?xml version="1.0" ?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"  >

<hibernate-mapping>
    <class name="pl.edu.uj.spring.hibernate.collections.School" table="SCHOOLS">
        <id name="id" column="ID" access="field">
            <generator class="sequence">
                <param name="sequence">HIBERNATE_SCHOOLSEQ</param>
            </generator>
        </id>
        <!--
                        http://docs.jboss.org/hibernate/stable/core/reference/en/html/associations.html
                        one - to - many
                  -->
        <bag name="persons" table="School2Person">
            <key column="schoolId"/>
            <many-to-many column="personId" unique="true" class="pl.edu.uj.spring.hibernate.collections.Person"/>
        </bag>
    </class>

    <class name="pl.edu.uj.spring.hibernate.collections.Person" abstract="true">
        <id name="id" column="ID" access="field">
            <generator class="sequence">
                <param name="sequence">HIBERNATE_PERSONSEQ</param>
            </generator>
        </id>


        <joined-subclass name="pl.edu.uj.spring.hibernate.collections.Student" table="STUDENTS">
            <key column="ID"/>
            <!--
     <id name="id" column="ID" access="field">
         <generator class="sequence">
             <param name="sequence">HIBERNATE_STUDENTSEQ</param>
         </generator>
     </id>       -->
            <property name="name" column="NAME"/>
            <property name="surname" column="SURNAME"/>
            <property name="classNumber" column="CLASS_NUMBER"/>
        </joined-subclass>

        <joined-subclass name="pl.edu.uj.spring.hibernate.collections.Teacher" table="TEACHERS">
            <key column="id"/>
            <!--
            <id name="id" column="ID" access="field">
                <generator class="sequence">
                    <param name="sequence">HIBERNATE_TEACHERSEQ</param>
                </generator>
            </id>
            -->
            <property name="name" column="NAME"/>
            <property name="surname" column="SURNAME"/>
            <property name="specializationSubject" column="SPECIALIZATION_SUBJECT"/>
        </joined-subclass>
    </class>
</hibernate-mapping>


But it results in exception:
Quote:
org.hibernate.PropertyNotFoundException: field [id] not found on pl.edu.uj.spring.hibernate.collections.Person


... and he's right. But I do not want to add this field to interface (it would become public static final...). When working with classes I could do <id name="id" column="ID" access="field"> but it's impossible with interfaces.
Is there any way to map this?



I would also ask question to Hibernate experienced developers if it is shame using classes all the time instead interfaces? I know that in regular Java programming we should program to interfaces but I found out that it is sometimes extremely complicated to map it in hibernate (like in the preceding example). As I can see in many open source projects built on Hibernate, programmers in domain tier do not use interfaces (almost) at all - only classes - how about you? In my opinion (but as I said I am newbie) it is far more complicated to make it work with hibernate when using interfaces than using only classes and make some refactoring when needed.

Thank you in advance!
Piotr


Top
 Profile  
 
 Post subject: Re: Mapping collection with interface as generic type
PostPosted: Sat Aug 07, 2010 2:04 pm 
Newbie

Joined: Tue Jul 27, 2010 9:46 am
Posts: 2
Anyone?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.