You are viewing a plain text version of this content. The canonical link for it is here.
Posted to torque-dev@db.apache.org by Thomas Fischer <fi...@seitenbau.net> on 2005/03/15 19:34:17 UTC

automatically creating beans from torque objects and vice versa




Hi everyone

It has been suggested several times in the wiki that one should be able to
create beans automatically which correspond to Torque Data objects. This is
useful if one wants to transmit objects via a network and the other side
does not know about torque, or if one has a tool like apache axis which can
create xml out of an object, and one does not want to include all Torque
related metadata into the xml.

At the beginning, I tried to let the xxxBaseObject inherit from a xxxBean,
and store all persistent Data in the bean. This did not work because Torque
supports inheritance in the object hierarchy, and this would mean that a
object which is a child in a object hierarchy would have to inherit both
from its parent and from its bean, which is not possible in Java
So I resorted to a complete separation between Data Object and beans. There
are two public methods in xxxObject, namely
public xxxBean getBean()
and
public static xxxObject getXxxObject()
which are used for Object->Bean and Bean->Object conversion, respectively
(I would rather have used a Constructor for the latter, but as
xxxBaseObject is abstract, this is not an option. Also, a Constructor does
not get inherited by xxxObject)

If complexObjectModel is turned on during generation, the translation also
translates all cached related Objects to beans and vice versa. This is a
challenge because of circular references, e.g.
author.getBooks(0).getAuthor() might either reference back to the original
author, or it might point to another instance of the same Database author
object. In order not to lose this information and create infinite creation
loops in the case where the referance points back to the original object,
an identityMap is used to store the mappings which were already translated
(the identityMap is implemented in commons collection and is a map based on
the == operator, not on equals()). If an object is already found in there,
it is used, otherwise the translated object is created and stored in the
map.
This might sound pretty confusing, below is some example from the BaseBook
and BaseAuthor classes.

Some general points:
There is a switch in the generator whether to generate beans or not. The
beans are generated in a separate subpackage named bean.

Does anyone opposes to adding this functionality to Torque ? Are there any
design flaws which I have not seen yet ? Does someone disagree with some
design or implemetation decisions, such as the aforementioned relationships
between Data object and beans, or method names, or anything I did not think
about ?

The stuff is neither in its final stage nor tested. I just wanted to make
this known beforehand, so that anybody wishing to give some input can do
so.

  Eagerly awaiting some feedback,

       Thomas

from BaseAuthor.java:
    /**
     * Creates a AuthorBean with the contents of this object
       * This also creates beans for cached related objects, if they exist
       * @return a AuthorBean with the contents of this object
     */
    public AuthorBean getBean()
    {
        return getBean(new IdentityMap());
    }

    /**
     * Creates a AuthorBean with the contents of this object
     * intended for internal use only
     * @param createdBeans a IdentityMap which maps objects
     *        to already created beans
     * @return a AuthorBean with the contents of this object
     */
    AuthorBean getBean(IdentityMap createdBeans)
    {
        AuthorBean result = (AuthorBean) createdBeans.get(this);
        if (result != null ) {
            // we have already created a bean for this object, return it
            return result;
        }
        // no bean exists for this object; create a new one
        result = new AuthorBean();
        createdBeans.put(this, result);

        result.setAuthorId(getAuthorId());
        result.setName(getName());

        if (collBooks != null)
        {
            List relatedBeans = new ArrayList(collBooks.size());
            for (Iterator collBooksIt = collBooks.iterator();
collBooksIt.hasNext(); )
            {
                Book related = (Book) collBooksIt.next();
                BookBean relatedBean = related.getBean(createdBeans);
                relatedBeans.add(relatedBean);
            }
            result.setBookBeans(relatedBeans);
        }

        return result;
    }

    /**
     * Creates an instance of Author with the contents
     * of a AuthorBean.
     * This behaviour could have also been achieved using a constructor,
     * however as this class is abstract no constructors are allowed
     * @param bean the AuthorBean which contents are used to create
     *        the resulting class
     * @return an instance of Author with the contents of bean
     */
    public static Author createAuthor(AuthorBean bean)
        throws TorqueException
    {
        return createAuthor(bean, new IdentityMap());
    }

    /**
     * Creates an instance of Author with the contents
     * of a AuthorBean.
     * This behaviour could have also been achieved using a constructor,
     * however as this class is abstract no constructors are allowed
     * @param bean the AuthorBean which contents are used to create
     *        the resulting class
     * @param createdObjects a IdentityMap which maps beans
     *        to already created objects
     * @return an instance of Author with the contents of bean
     */

    static Author createAuthor(AuthorBean bean, IdentityMap createdObjects)
        throws TorqueException
    {
        Author result = (Author) createdObjects.get(bean);
        if (result != null)
        {
            // we already have an object for the bean, return it
            return result;
        }
        result = new Author();
        createdObjects.put(bean, result);
        {
            List relatedBeans = bean.getBookBeans();
            if (relatedBeans != null)
            {
                for (Iterator relatedBeansIt = relatedBeans.iterator();
relatedBeansIt.hasNext(); )
                {
                    BookBean relatedBean = (BookBean)
relatedBeansIt.next();
                    Book related = Book.createBook(relatedBean,
createdObjects);
                    result.addBook(related);
                }
            }
        }

        return result;
    }

>From BaseBook.java:

    /**
     * Creates a BookBean with the contents of this object
       * This also creates beans for cached related objects, if they exist
       * @return a BookBean with the contents of this object
     */
    public BookBean getBean()
    {
        return getBean(new IdentityMap());
    }

    /**
     * Creates a BookBean with the contents of this object
     * intended for internal use only
     * @param createdBeans a IdentityMap which maps objects
     *        to already created beans
     * @return a BookBean with the contents of this object
     */
    BookBean getBean(IdentityMap createdBeans)
    {
        BookBean result = (BookBean) createdBeans.get(this);
        if (result != null ) {
            // we have already created a bean for this object, return it
            return result;
        }
        // no bean exists for this object; create a new one
        result = new BookBean();
        createdBeans.put(this, result);

        result.setBookId(getBookId());
        result.setIsbn(getIsbn());
        result.setAuthorId(getAuthorId());
        result.setTitle(getTitle());

        if (aAuthor != null)
        {
            AuthorBean relatedBean = aAuthor.getBean(createdBeans);
            result.setAuthorBean(relatedBean);
        }
        return result;
    }

    /**
     * Creates an instance of Book with the contents
     * of a BookBean.
     * This behaviour could have also been achieved using a constructor,
     * however as this class is abstract no constructors are allowed
     * @param bean the BookBean which contents are used to create
     *        the resulting class
     * @return an instance of Book with the contents of bean
     */
    public static Book createBook(BookBean bean)
        throws TorqueException
    {
        return createBook(bean, new IdentityMap());
    }

    /**
     * Creates an instance of Book with the contents
     * of a BookBean.
     * This behaviour could have also been achieved using a constructor,
     * however as this class is abstract no constructors are allowed
     * @param bean the BookBean which contents are used to create
     *        the resulting class
     * @param createdObjects a IdentityMap which maps beans
     *        to already created objects
     * @return an instance of Book with the contents of bean
     */

    static Book createBook(BookBean bean, IdentityMap createdObjects)
        throws TorqueException
    {
        Book result = (Book) createdObjects.get(bean);
        if (result != null)
        {
            // we already have an object for the bean, return it
            return result;
        }
        result = new Book();
        createdObjects.put(bean, result);

        {
            AuthorBean relatedBean = bean.getAuthorBean();
            if (relatedBean != null)
            {
                Author relatedObject = Author.createAuthor(relatedBean,
createdObjects);
                result.setAuthor(relatedObject);
            }
        }
        return result;
    }

from BookBean.java:

public abstract class BaseBookBean
{
    /** The value for the bookId field */
    private int bookId;

    /** The value for the isbn field */
    private String isbn;

    /** The value for the authorId field */
    private int authorId;

    /** The value for the title field */
    private String title;


    /**
     * Get the BookId
     *
     * @return int
     */
    public int getBookId ()
    {
        return bookId;
    }

    /**
     * Set the value of BookId
     *
     * @param v new value
     */
    public void setBookId(int v)
    {
        this.bookId = v;
    }

    /**
     * Get the Isbn
     *
     * @return String
     */
    public String getIsbn ()
    {
        return isbn;
    }

    /**
     * Set the value of Isbn
     *
     * @param v new value
     */
    public void setIsbn(String v)
    {
        this.isbn = v;
    }

    /**
     * Get the AuthorId
     *
     * @return int
     */
    public int getAuthorId ()
    {
        return authorId;
    }

    /**
     * Set the value of AuthorId
     *
     * @param v new value
     */
    public void setAuthorId(int v)
    {
        this.authorId = v;
    }

    /**
     * Get the Title
     *
     * @return String
     */
    public String getTitle ()
    {
        return title;
    }

    /**
     * Set the value of Title
     *
     * @param v new value
     */
    public void setTitle(String v)
    {
        this.title = v;
    }

    private AuthorBean aAuthorBean;

    /**
     * sets an associated AuthorBean object
     *
     * @param v AuthorBean
     */
    public void setAuthorBean(AuthorBean v)
    {
        if (v == null)
        {
             setAuthorId( 0);
        }
        else
        {
            setAuthorId(v.getAuthorId());
        }
        aAuthorBean = v;
    }


    /**
     * Get the associated AuthorBean object
     *
     * @return the associated AuthorBean object
     */
    public AuthorBean getAuthorBean()
    {
        return aAuthorBean;
    }
}

from BaseAuthorBean.java:

public abstract class BaseAuthorBean
{
    /** The value for the authorId field */
    private int authorId;

    /** The value for the name field */
    private String name;

    /**
     * Get the AuthorId
     *
     * @return int
     */
    public int getAuthorId ()
    {
        return authorId;
    }

    /**
     * Set the value of AuthorId
     *
     * @param v new value
     */
    public void setAuthorId(int v)
    {
        this.authorId = v;
    }

    /**
     * Get the Name
     *
     * @return String
     */
    public String getName ()
    {
        return name;
    }

    /**
     * Set the value of Name
     *
     * @param v new value
     */
    public void setName(String v)
    {
        this.name = v;
    }

    /**
     * Collection to store aggregation of collBookBeans
     */
    protected List collBookBeans;

    /**
     * Returns the collection of BookBeans
     */
    public List getBookBeans()
    {
        return collBookBeans;
    }

    /**
     * Sets the collection of BookBeans to the specified value
     */
    public void setBookBeans(List list)
    {
        if (list == null)
        {
            collBookBeans = null;
        }
        else
        {
            collBookBeans = new ArrayList(list);
        }
    }
}


--------------------------------------------------------------------

Dr. Thomas Fischer
Software-Entwicklung
Tel. +49 (0) 7531 36598-22
Fax +49 (0) 7531 36598-11
E-Mail  fischer@seitenbau.com

SEITENBAU GmbH
Robert-Gerwig-Str. 10-12
D-78467 Konstanz
http://www.seitenbau.com

Amtsgericht Konstanz HRB 1528
USt-IdNr.: DE 1905 525 50

Geschäftsführer:
Florian Leinberger | Sebastian Roller | Rainer Henze
Prokuristen:
Jan Bauer | Stefan Eichenhofer


---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscribe@db.apache.org
For additional commands, e-mail: torque-dev-help@db.apache.org