-->
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.  [ 3 posts ] 
Author Message
 Post subject: Hibernate + Multimap
PostPosted: Sat Apr 03, 2010 12:13 pm 
Newbie

Joined: Thu Feb 04, 2010 10:10 am
Posts: 8
Hi,

I need the following result:
Code:
private Map<Long, List<FornecedorRecurso>> fornecedorRecursos;

But, Hibernate doesnt support a List value on a Map. I found out this link: http://blog.xebia.com/2007/10/05/mappin ... hibernate/

He create a class that implements the UserCollectionType from Hibernate. These are the classes:

MultiMapType.java
Code:
package sigo.utils;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.collections.MultiHashMap;
import org.apache.commons.collections.MultiMap;
import org.hibernate.HibernateException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.usertype.UserCollectionType;

public class MultiMapType implements UserCollectionType {
   
    public boolean contains(Object collection, Object entity) {
        return ((MultiMap) collection).containsValue(entity);
    }

    public Iterator getElementsIterator(Object collection) {
        return ((MultiMap) collection).values().iterator();
    }

    public Object indexOf(Object collection, Object entity) {
        for (Iterator i = ((MultiMap) collection).entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Map.Entry) i.next();
            Collection value = (Collection) entry.getValue();
            if (value.contains(entity)) {
                return entry.getKey();
            }
        }
        return null;
    }

    public Object instantiate() {
        return new MultiHashMap();
    }

    public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) throws HibernateException {
        return new PersistentMultiMap(session);
    }

    public PersistentCollection wrap(SessionImplementor session, Object collection) {
        return new PersistentMultiMap(session, (MultiMap) collection);
    }

    public Object replaceElements(Object original, Object target, CollectionPersister persister, Object owner, Map copyCache, SessionImplementor session) throws HibernateException {

        MultiMap result = (MultiMap) target;
        result.clear();

        Iterator iter = ( (java.util.Map) original ).entrySet().iterator();
        while ( iter.hasNext() ) {
            java.util.Map.Entry me = (java.util.Map.Entry) iter.next();
            Object key = persister.getIndexType().replace( me.getKey(), null, session, owner, copyCache );
            Collection collection = (Collection) me.getValue();
            for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
                Object value = persister.getElementType().replace( iterator.next(), null, session, owner, copyCache );
                result.put(key, value);
            }
        }

        return result;
    }

   @Override
   public Object instantiate(int arg0)
   {
      return new MultiHashMap();
   }
}

PersistentMultiMap.java
Code:
package sigo.utils;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.collections.DefaultMapEntry;
import org.apache.commons.collections.MultiHashMap;
import org.apache.commons.collections.MultiMap;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.collection.PersistentMap;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.Type;

@SuppressWarnings("deprecation")
public class PersistentMultiMap extends PersistentMap implements MultiMap
{
    /**
    *
    */
   private static final long serialVersionUID = 1L;

   public PersistentMultiMap(SessionImplementor session, MultiMap map)
    {
        super(session, map);
    }

    public PersistentMultiMap(SessionImplementor session)
    {
        super(session);
    }
   
    public Object remove(Object key, Object item)
    {
       Object old = isPutQueueEnabled() ? readElementByIndex(key) : UNKNOWN;
       if (old == UNKNOWN)
       {
           write();
           return ((MultiMap) map).remove(key, item);
       }
       else
       {
           queueOperation(new RemoveItem(key, item));
           return old;
       }
    }
   
    @Override
    public Iterator entries(CollectionPersister persister)
    {
        return new KeyValueCollectionIterator(super.entries(persister));
    }

    @Override
    public Serializable getSnapshot(CollectionPersister persister) throws HibernateException
    {
        EntityMode entityMode = getSession().getEntityMode();

        MultiHashMap clonedMap = new MultiHashMap(map.size());
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry e = (Map.Entry) iter.next();
            Collection collection = (Collection) e.getValue();
            for (Iterator i = collection.iterator(); i.hasNext();) {
                final Object copy = persister.getElementType().deepCopy(i.next(), entityMode, persister.getFactory());
                clonedMap.put(e.getKey(), copy);
            }
        }
        return clonedMap;
    }
   
    @Override
    public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
        Map sn = (Map) getSnapshot();
        if (sn.size() != map.size())
            return false;
        Type elemType = persister.getElementType();
        for (Iterator i = sn.entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Map.Entry) i.next();
            Map oldState = getCollectionAsIdentityMap((Collection) entry.getValue());
            Collection newState = (Collection) map.get(entry.getKey());
            for (Iterator iter = newState.iterator(); iter.hasNext();) {
                Object newValue = iter.next();
                Object oldValue = oldState.get(newValue);
                if (newValue != null && oldValue != null && elemType.isDirty(oldValue, newValue, getSession())) {
                    return false;
                }
            }
        }
        return true;
    }

    private Map getCollectionAsIdentityMap(Collection collection) {
        Map map = new HashMap();
        for (Iterator iter = collection.iterator(); iter.hasNext();) {
            Object element = iter.next();
            map.put(element, element);
        }
        return map;
    }

    @Override
    public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
        Set result = new HashSet();
        Map sn = (Map) getSnapshot();
        for (Iterator i = sn.entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Entry) i.next();
            Collection oldState = (Collection) entry.getValue();
            Collection newState = (Collection) map.get(entry.getKey());
            for (Iterator j = oldState.iterator(); j.hasNext();) {
                Object element = j.next();
                if (!(newState.contains(element))) {
                    result.add(element);
                }
            }
        }
        return result.iterator();
    }

    @Override
    public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
        Map.Entry e = (Entry) entry;
        Map sn = (Map) getSnapshot();
        Collection oldState = (Collection) sn.get(e.getKey());
        return oldState == null || !oldState.contains(e.getValue());
    }

    @Override
    public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException
    {
        Map.Entry e = (Entry) entry;
        Map sn = (Map) getSnapshot();
        Collection collection = (Collection) sn.get(e.getKey());
        if (collection == null) {
            return false;
        }
        for (Iterator iter = collection.iterator(); iter.hasNext();) {
            Object oldValue = iter.next();
            if (oldValue != null && oldValue.equals(e.getValue())) {
                return e.getValue() != null && elemType.isDirty(oldValue, e.getValue(), getSession());
            }
        }
        return false;
    }
}

class RemoveItem
{
   
    private final Object key;

    private final Object item;

    RemoveItem(Object key, Object item) {
        this.key = key;
        this.item = item;
    }

    public Object getAddedInstance() {
        return null;
    }

    public Object getOrphan() {
        return item;
    }

    public void operate() {
        //((MultiMap) map).remove(key, item);
    }

}

final class KeyValueCollectionIterator implements Iterator {
   
    private final Iterator parent;

    private Object key;

    private Iterator current;

    KeyValueCollectionIterator(Iterator parent) {
        this.parent = parent;
        move();
    }

    public boolean hasNext() {
        return key != null;
    }

    public Object next() {
        if (key == null) {
            throw new NoSuchElementException();
        } else {
            DefaultMapEntry result = new DefaultMapEntry(key, current.next());
            if (!current.hasNext()) {
                move();
            }
            return result;
        }
    }

    private void move() {
        while (this.parent.hasNext()) {
            Map.Entry entry = (Entry) this.parent.next();
            key = entry.getKey();
            current = ((Collection) entry.getValue()).iterator();
            if (current.hasNext()) {
                return;
            }
        }
        key = null;
    }

    public void remove() {
        throw new UnsupportedOperationException();
    }

}

I'm not able to use them. This is the error:
Code:
Initial SessionFactory creation failed.org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: sigo.model.Orcamento.fornecedorRecursos

Tried so:
Code:
@OneToMany(mappedBy="orcamento")
   @MapKey(columns={@Column(name="fk_fornecedorId")})
   public MultiMapType getFornecedorRecursos()
   {
      return fornecedorRecursos;
   }

   public void setFornecedorRecursos(
         MultiMapType fornecedorRecursos)
   {
      this.fornecedorRecursos = fornecedorRecursos;
   }


Somebody know what is happening?

cheers,
André Vendramini


Top
 Profile  
 
 Post subject: Re: Hibernate + Multimap
PostPosted: Sat Apr 17, 2010 10:20 am 
Newbie

Joined: Mon Apr 06, 2009 9:55 pm
Posts: 12
Hi André,

I have been using MultiMaps described in the xebia blog.
The thing is that it works with xml mappings but not with annotations.
I could find the way how to specify UserCollectionType on annotated collections as it is not supported
http://opensource.atlassian.com/project ... e/HHH-4417
In my case workaround is to specify type for such collections at configuration time.

Cheers
Anton


Top
 Profile  
 
 Post subject: Re: Hibernate + Multimap
PostPosted: Mon May 31, 2010 8:51 am 
Newbie

Joined: Sun Jan 20, 2008 6:39 pm
Posts: 4
For anybody finding this, there are a few errors. RemoveItem should be an inner class and the operate method shouldn't be commented out. In addition, you need an analagous PutItem class and put method in order to persist any puts.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.