-->
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.  [ 11 posts ] 
Author Message
 Post subject: Maps and UserTypes
PostPosted: Fri Jul 27, 2007 7:10 pm 
Newbie

Joined: Fri Jul 27, 2007 6:58 pm
Posts: 5
Can the type of a map-key be a UserType? I have a pretty basic map whose key type is a usertype. And when I try to access my parameters collection, even though the map's entryset is loading fine it's keyset is loading as null.

My map looks like this.....

<map name="parameters"
table="tm_parm"
lazy="true">
<key>
<column name="parm_set_def" />
<column name="parm_set_nam" />
</key>
<map-key formula = "parm_nam" type ="com.redprairie.tm.core.ParameterNameUserType"/>
<element column ="value" type = "string"/>
</map>

Any ideas or suggestions?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 11:43 am 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Yes. I just created a simple test case where the map key is a user type and I get my values back correctly.

Why do you have a formula instead of a column in map-key?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 1:07 pm 
Newbie

Joined: Fri Jul 27, 2007 6:58 pm
Posts: 5
It is interesting that it works for you. I tried the map-key using a column and it didnt work so i tried using a formula (along with a 100 other things). Could you show me how your mapping looks like, and also what version of hibernate are you using? Thanks ....


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 1:51 pm 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
hibernate 3.2.4sp1

Perhaps there's a problem with your UserType implementation?? I've included everything from my test below.

Parent.hbm.xml
Code:
<class name="Parent" table="mwutk_parent">
   
      <id name="id">
         <generator class="native" />
      </id>

   <map name="values" table="values_map">
      <key column="parent_id"/>
      <map-key column="map_key" type="test.mapwithusertypekey.MapKeyUserType"/>
      <element column="map_value" type="string"/>
   </map>       
     
</class>
</hibernate-mapping>


Parent.java
Code:
package test.mapwithusertypekey;

import java.util.Map;

public class Parent {
   private Long id;
   private Map<MapKey, String> values;
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public Map<MapKey, String> getValues() {
      return values;
   }
   public void setValues(Map<MapKey, String> values) {
      this.values = values;
   }
}


MapKey.java
Code:
package test.mapwithusertypekey;

public class MapKey {

   private int key;

   public MapKey(int v) {
      key = v;
   }
   
   public int getKey() {
      return key;
   }

   public void setKey(int key) {
      this.key = key;
   }
   
   @Override
   public boolean equals(Object obj) {
      MapKey k = (MapKey)obj;
      return k.key == key;
   }
   
   @Override
   public int hashCode() {
      return 29*(key+7);
   }
}


MapKeyUserType.java
Code:
package test.mapwithusertypekey;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;

public class MapKeyUserType implements UserType {

   private static final int[] SQL_TYPES = { Types.INTEGER };
   
   public int[] sqlTypes() {
      return SQL_TYPES;
   }
   
   public Class<MapKey> returnedClass() {
      return MapKey.class;
   }
   
   private Object createMapKey(int keyValue) {
      return new MapKey(keyValue);
   }
   
   private int getMapKeyValue(Object mapKey) {
      return ((MapKey)mapKey).getKey();
   }
   
   public boolean equals(Object x, Object y) {
      return x == y;
   }
   
   public Object deepCopy(Object value) {
      return value;
   }
   
   public boolean isMutable() {
      return false;
   }
   
   public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
      int instanceId = rs.getInt(names[0]);
      return (rs.wasNull() ? null : createMapKey(instanceId));
   }
   
   public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException {
      if (value == null) {
         statement.setNull(index, Types.INTEGER);
      } else {
         statement.setInt(index, getMapKeyValue(value));
      }
   }

   public Serializable disassemble(Object value) throws HibernateException {
      return (Serializable) value;
   }

   public Object assemble(Serializable cached, Object owner) throws HibernateException {
      return cached;
   }

   public Object replace(Object original, Object target, Object owner) throws HibernateException {
      return original;
   }

   public int hashCode(Object x) throws HibernateException {
      return x.hashCode();
   }
}


TestIt.java
Code:
package test.mapwithusertypekey;

import java.util.HashMap;
import java.util.Map;

import junit.framework.TestCase;

import org.hibernate.Session;

public class TestIt extends TestCase {

   public void testIt() {
      
      Long parentId = createParent();
      
      Session s = HibernateUtil.getSession();
      
      Parent p = (Parent)s.load(Parent.class, parentId);
      Map<MapKey, String> map = p.getValues();
      
      MapKey mk1 = new MapKey(1);
      MapKey mk2 = new MapKey(2);
      
      assertEquals("one", map.get(mk1));
      assertEquals("two", map.get(mk2));
      
      s.close();
   }

   private Long createParent() {
      Session s = HibernateUtil.getSession();
      s.beginTransaction();
      
      Parent p = new Parent();
      MapKey mk1 = new MapKey(1);
      MapKey mk2 = new MapKey(2);
      Map<MapKey, String> map = new HashMap<MapKey, String>();
      map.put(mk1, "one");
      map.put(mk2, "two");
      
      p.setValues(map);
      Long id = (Long)s.save(p);
      
      s.getTransaction().commit();
      s.close();
      
      return id;
   }
}


HibernateUtil.java
Code:
package test.mapwithusertypekey;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class HibernateUtil {

    private static SessionFactory factory;

    static {
       Configuration config = new Configuration()
          .addClass(Parent.class)
// HSQLDB Config
//          .setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
//         .setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver")
//         .setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test")
//          .setProperty("hibernate.connection.username", "sa")
//          .setProperty("hibernate.connection.password", "")
//          .setProperty("hibernate.hbm2ddl.auto", "create-drop")
          
// MYSQL Config
          .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
         .setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver")
         .setProperty("hibernate.connection.url", "jdbc:mysql://localhost/test")
         .setProperty("hibernate.connection.username", "root")
         .setProperty("hibernate.connection.password", "password")
         .setProperty("hibernate.hbm2ddl.auto", "create-drop")
                  
         .setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider")
         .setProperty("hibernate.show_sql", "true");
        HibernateUtil.setSessionFactory(config.buildSessionFactory());
    }

    public static synchronized Session getSession() {
        if (factory == null) {
            factory = new Configuration().configure().buildSessionFactory();
        }
        return factory.openSession();
    }

    public static void setSessionFactory(SessionFactory factory) {
        HibernateUtil.factory = factory;
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 3:53 pm 
Newbie

Joined: Fri Jul 27, 2007 6:58 pm
Posts: 5
So I compared my user type implementation with what you had. Couldn't find anything obviously different. However when I tried "index" instead of "map-key" the map worked! I am not exactly sure what the difference is between index and map-key and also the fact that map-key worked for you also makes no sense to me. The only difference I found between your test and mine was that my user type is a string whereas yours is an integer.

Thanks for your help, if it weren't for your unit test I probably would have given up much sooner :)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 4:53 pm 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Glad it was useful. If you post your UserType and Key up I'd be happy to take a look.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 5:01 pm 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Ok, I switched my MapKey to use a String instead of an int and it still works.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 5:58 pm 
Newbie

Joined: Fri Jul 27, 2007 6:58 pm
Posts: 5
I got excited too soon. It doesnt work even with index. I had a bug in the test case that tests my map. :(

Anyway here are my classes

/************* Parameter Set class*********************/
package com.test.core;

public class TmParameterSetImpl {

public TmParameterSetImpl() {
_pk = new ParameterSetPK();
}

public TmParameterSetImpl(String parameterSetDefinition, String parameterSetName) {
_pk = new ParameterSetPK(parameterSetDefinition,parameterSetName);
}

// @see java.lang.Object#equals(java.lang.Object)
@Override
public boolean equals(Object obj) {

if (this == obj) {
return true;
}

if (obj == null) {
return false;
}

if (!(obj instanceof TmParameterSetImpl)) {
return false;
}

if (this.getParameterSetDefinitionName().equals("") ||
this.getParameterSetName().equals("")) {
return false;
}

final TmParameterSetImpl other = (TmParameterSetImpl)obj;

if (other.getParameterSetDefinitionName().equals("") ||
other.getParameterSetName().equals("")) {
return false;
}

if (!this.getParameterSetDefinitionName().equals(other.getParameterSetDefinitionName()) ||
!this.getParameterSetName().equals(other.getParameterSetName())) {
return false;
}

return true;
}

// @see java.lang.Object#hashCode()
@Override
public int hashCode() {
return getPK().hashCode();
}

/*
* PK Property Getters
*/

public String getParameterSetDefinitionName() {
return _pk.getParameterSetDefinitionName();
}

public String getParameterSetName() {
return _pk.getParameterSetName();
}

/*
* Non-key Property getters/Setters
*/

public Map<ParameterName,String> getParameters() {
return _parameters;
}
public void setParameters(Map<ParameterName,String> a) {
_parameters = a;
}

//PK Object Getter/Getter
private ParameterSetPK getPK() {
return _pk;
}
@SuppressWarnings("unused") //for persistance
private void setPK(ParameterSetPK pk) {
_pk = pk;
}


protected ParameterSetPK _pk;
protected Map<ParameterName,String> _parameters;
}

/****ParameterSet PK *****/
package com.test.core;

import java.io.Serializable;

public final class ParameterSetPK implements Serializable {

public ParameterSetPK() {
}

public ParameterSetPK(String parameterSetDefinitionName,
String parameterSetName) {

_parameterSetDefinitionName = parameterSetDefinitionName;
_parameterSetName = parameterSetName;
}

public boolean equals (Object other) {

if (this == other) {
return true;
}
if (other == null) {
return false;
}
if (!(other instanceof ParameterSetPK)) {
return false;
}
if (_parameterSetDefinitionName.equals("") || _parameterSetName.equals("")) {
return false;
}

final ParameterSetPK otherPK = (ParameterSetPK)other;

if (otherPK._parameterSetDefinitionName.equals("") ||
otherPK._parameterSetName.equals("")) {
return false;
}

return _parameterSetDefinitionName.equals(otherPK._parameterSetDefinitionName) &&
_parameterSetName.equals(otherPK._parameterSetName);
}

public int hashCode() {

int hashVal = _parameterSetDefinitionName.hashCode();
hashVal = (hashVal * 37) + _parameterSetName.hashCode();

return hashVal;
}


public String getParameterSetDefinitionName() {
return _parameterSetDefinitionName;
}
public void setParameterSetDefinitionName(String parameterSetDefinitionName) {
_parameterSetDefinitionName = parameterSetDefinitionName;
}

public String getParameterSetName() {
return _parameterSetName;
}
public void setParameterSetName(String parameterSetName) {
_parameterSetName = parameterSetName;
}


private static final long serialVersionUID = 1L;

private String _parameterSetDefinitionName = "";
private String _parameterSetName = "";

}


/**********ParameterName class ****************/

package com.test.core;

public class ParameterName {

public ParameterName(String parameterName) {
_parameterName = parameterName;
}

public String getParameterName() {
return _parameterName;
}
public void setParameterName(String parameterName) {
_parameterName = parameterName;
}

public boolean equals(Object obj) {
ParameterName k = (ParameterName)obj;
return (k._parameterName == _parameterName);
}

public int hashCode() {
return _parameterName.hashCode();
}

public String toString() {
return _parameterName;
}

private String _parameterName;
}

/**********ParameterName UserType class**************/

package com.test.core;

public class ParameterNameUserType implements UserType {

private static final int[] SQL_TYPES = { Types.NUMERIC };

public int[] sqlTypes() {
return SQL_TYPES;
}

public Class returnedClass() {
return ParameterName.class;
}

public boolean equals(Object x, Object y)
throws HibernateException {
if (x == y) {
return true;
}
else if (x == null || y == null) {
return false;
}
else {
return x.equals(y);
}
}

public Object nullSafeGet(ResultSet resultSet,
String[] names, Object owner)
throws HibernateException, SQLException {
if(resultSet.wasNull()) {
return null;
}
return new ParameterName(resultSet.getString(names[0]));
}

public void nullSafeSet(PreparedStatement statement,
Object value, int index)
throws HibernateException, SQLException {
if (value == null) {
statement.setNull(index, Types.NUMERIC);
}
else {
String name = ((ParameterName) value).toString();
statement.setString(index, name);
}
}

public Object deepCopy(Object value) throws HibernateException {
return value;
}

public boolean isMutable() {
return false;
}

public Object assemble(Serializable cached, Object owner) {
return cached;
}

public Serializable disassemble(Object value) {
return (Serializable) value;
}

public Object replace(Object original, Object target, Object owner) {
return original;
}

public int hashCode(Object x) {
return x.hashCode();
}
}


/******* Parameter Set hibernate mapping*****************/
<hibernate-mapping package="">

<class name="com.test.core.TmParameterSetImpl" table="tm_parm_set" >

<composite-id name="PK" class="com.test.core.ParameterSetPK" >
<key-property name="parameterSetDefinitionName" column="parm_set_def" />
<key-property name="parameterSetName" column="parm_set_nam" />
</composite-id>

<map name="parameters"
table="tm_parm"
lazy="true">
<key>
<column name="parm_set_def" />
<column name="parm_set_nam" />
</key>
<index column = "parm_nam" type = "com.test.core.ParameterNameUserType"/>
<element column = "value" type = "string"/>
</map>

</class>

</hibernate-mapping>

/*************Test****************/

package com.test.core;
public class TU_TmParameterSetImpl extends AbstractMocaTestCase {

public void mocaSetUp() {
}


public void testReadParameters() {
/*
* you can assume that the parameter set I am reading here and its parameters
* exist in the database..i took some code out to reduce some clutter
*/
TmParameterSetDAO dao = TmFactoryServer.getTmDAOFactory().getTmParameterSetDAO();
TmParameterSet zs = dao.read("ZONE_SKIP","SET_2");

Map<ParameterName,String> parms = zs.getParameters();
ParameterName parm1 = new ParameterName("PARM1");

String abc = parms.get(parm1);
assertEquals(abc,"VALUE1");
}
}


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 6:43 pm 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
I think your ParameterNameUserType class is at fault. Your map key (ParameterName) is a String but your UserType implementation declares:
private static final int[] SQL_TYPES = { Types.NUMERIC };
rather than
private static final int[] SQL_TYPES = { Types.VARCHAR };

and, though probably not affecting your test, in nullSafeSet:
statement.setNull(index, Types.NUMERIC);
rather than
statement.setNull(index, Types.VARCHAR);

When I substitute VARCHAR in my working test case for NUMERIC from your UserType my test case fails with "ComparisonFailure: expected <one> but was: <null>"

Give it a go and let me know.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 7:40 pm 
Newbie

Joined: Fri Jul 27, 2007 6:58 pm
Posts: 5
I tried changing it to VARCHAR and it still didn't work. Then I realized that my implementation of the equals() method on the ParameterName class had a bug!! I was doing
(_parameterName == parameterName) instead of _parameterName.equals(parameterName).

I fixed this and it works! Then I changed the user type to use NUMERIC (cause I thought you'd be interested :)) to see if that made a difference and it still worked with NUMERIC...I am not exactly sure why...

Thanks for all your help....


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 28, 2007 7:55 pm 
Expert
Expert

Joined: Fri Jul 13, 2007 8:18 am
Posts: 370
Location: london
Well spotted!! Good result and an interesting one too.
Best of luck.
Mike


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