4 Replies Latest reply on May 7, 2011 5:21 AM by piotrekde

    Persisting java.util.Map with custom class as key and value

    piotrekde

      Hi, I have the following situation:

       

       

      @Entity
      @Table(name = 'myclass_table')
      public class MyClass {
        private Map<CustomObjectOne, CustomObjectTwo> map;
        (...)
      }
      
      public class CustomObjectOne {
       int a;
       int b;
      }
      
      public class CustomObjectTwo {
        double x;
      }
      

       

       

      Could you please give me an example how to persist MyClass along with Map inside (using annotations)?

       

      I've found that I can use @ElementCollection annotation in order to do it, but as far as I know it's not available in Java1.5/EJB3.0 which I use.

      Thanks in advance!

        • 1. Persisting java.util.Map with custom class as key and value
          wdfink

          Mmmh,

          you are right, @ElementCollection is a EJB3.1 annotation (ähm a JPA2.0 which is part of EJB3.1).

          ATM I have this options:

          - store as a BLOB (MAP and its elements must be serializable)

          - write your own mapper to store (and respect the EJB3.1 structure to port later )

          - use a table with relation to store it

          • 2. Re: Persisting java.util.Map with custom class as key and value
            piotrekde

            Thanks for help!

            I think that the first one option is the easiest one (blob). Can I store object as a blob in a database, but have it defined as a Map type in class properties? What I mean is this (MyEntity class, myBlobMap property):

             

             

             @Local
                public static interface MyEntityRepository {
                    void persist(MyEntity entity);
                    MyEntity find(long id);
                }
            
            
                @Stateful
                public static class MyEntityRepositoryBean implements MyEntityRepository {
            
            
                @PersistenceContext(unitName = "mydb")
                private EntityManager entityManager;
            
            
                    public void persist(MyEntity entity) {
                        entityManager.persist(entity);
                    }
            
            
                    public MyEntity find(long id) {
                        return entityManager.find(MyEntity.class, id);
                    }
                }
            
            
                @Entity
                @Table(name = "my_entity")
                private class MyEntity {
            
            
                    @Id
                    @GeneratedValue(strategy = GenerationType.AUTO)
                    @Column(name = "id")
                    private long id;
            
            
                    @Lob
                    @Column(name="my_blob")
                    private Map<CustomClassA, CustomClassB> myBlobMap;
            
            
                    public MyEntity() {
                        this.myBlobMap = new LinkedHashMap<CustomClassA, CustomClassB>();
                    }
            
            
                    public long getId() {
                        return this.id;
                    }
            
            
                    public void putToMap(CustomClassA a, CustomClassB b) {
                        this.myBlobMap.put(a,b);
                    }
            
            
                    public Map<CustomClassA, CustomClassB> getMyBlobMap() {
                        return this.myBlobMap;
                    }
                }
            
            
                private class CustomClassA implements Serializable {
            
            
                    private double a;
                    private double b;
            
            
                    public CustomClassA(double a, double b) {
                        this.a = a;
                        this.b = b;
                    }
            
            
                    public double getA() {
                        return this.a;
                    }
            
            
                    public double getB() {
                        return this.b;
                    }
                }
            
            
                private class CustomClassB implements Serializable {
                    private String x;
            
            
                    public CustomClassB(String x) {
                        this.x = x;
                    }
            
            
                    public String getX() {
                        return this.x;
                    }
                }
            
            

             

             

            anyway, if I try to test this code, I'm getting an exception:

             

             

             @Test
                public void testBlobPersistence() throws Exception {
                    MyEntityRepository repo  = (MyEntityRepository) initialContext.lookup(
                            "MyEntityRepositoryBeanLocal");
            
                    MyEntity entity = new MyEntity();
                    //entity.putToMap(new CustomClassA(1,2), new CustomClassB("qwertyz"));
                    repo.persist(entity);
                    MyEntity persisted = repo.find(entity.getId());
            
                    //assertNotNull(persisted.getMyBlobMap());
                }
            
            

             

             

            (...)

            Caused by: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to java.sql.Blob

            (...)

             

            Do I have to store it as a blob internally? I found the similar issue here:

            http://docs.jboss.org/ejb3/app-server/tutorial/blob/src/org/jboss/tutorial/blob/bean/LobTesterBean.java

            ( #findBlob:HashMap)

            • 3. Re: Persisting java.util.Map with custom class as key and value
              wdfink

              In that case you have to write a hibernate mapper for this:

              1)

              Add annotation to your field => @org.hibernate.annotations.Type(type = "my.MapTypeBlobUserType")

               

              2)

              Write the mapper class my.MapTypeBlobUserType

              implementing  => org.hibernate.usertype.UserType

              • 4. Persisting java.util.Map with custom class as key and value
                piotrekde

                Thanks, you are right.

                However after thinking a while, I decided to split entities into couple of separate classes - it allows to map them into DB without using user types (a lot easier for me)