-->
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.  [ 4 posts ] 
Author Message
 Post subject: NullPointerException with simple value object mapping
PostPosted: Sat Apr 26, 2014 1:10 am 
Newbie

Joined: Sat Apr 26, 2014 1:04 am
Posts: 1
Hello,

Here I have my Entity, which contains a simple Din value object (primitive wrapper):
Code:
@Entity(name = "DRUG")
public class Drug {
   @Id
   private Din din;
   private String name;
   private String description;
   @ElementCollection
   private List<String> interactiveDins = new ArrayList<String>();
...


Din is basically a wrapper around a String:

Code:
public final class Din implements Serializable {
   private static final long serialVersionUID = 7369022975618045987L;
   @JsonProperty
   private String din;

   public Din(String din) {
      this.din = din;
   }
}


Then If I do this:

Code:
entityManager.getTransaction().begin();
Drug drug1 = new Drug(new Din("dd"), "foin", "fsjn");
Drug drug2 = new Drug(new Din("sdfd"), "fdd", "fsjn");
drugRepository.persist(drug1);
drugRepository.persist(drug2);
entityManager.getTransaction().commit();


I get that:

Exception in thread "main" javax.persistence.RollbackException: Error while committing the transaction
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:94)
at ca.ulaval.glo4002.contexts.DemoDrugRepositoryFiller.fillDrugs(DemoDrugRepositoryFiller.java:33)
at ca.ulaval.glo4002.contexts.DemoRepositoryFiller.fillDrugRepository(DemoRepositoryFiller.java:55)
at ca.ulaval.glo4002.contexts.DemoRepositoryFiller.fillRepositories(DemoRepositoryFiller.java:46)
at ca.ulaval.glo4002.rest.DemoMain.main(DemoMain.java:16)
Caused by: java.lang.NullPointerException
at org.hibernate.type.AbstractStandardBasicType.compare(AbstractStandardBasicType.java:220)
at org.hibernate.action.internal.CollectionAction.compareTo(CollectionAction.java:172)
at org.hibernate.engine.spi.ExecutableList.add(ExecutableList.java:222)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:246)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:274)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:103)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:55)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1167)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:412)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
... 4 more

If I remove the List, it's fine. If I change the Din for a String it's fine. It crashes when both are present. What Hibernate does not like in this?
If I commit between each persist, its fine. I've tried to solve this for hours without luck...

Any ideas?

Thanks!


Top
 Profile  
 
 Post subject: Re: NullPointerException with simple value object mapping
PostPosted: Thu Sep 18, 2014 7:01 am 
Newbie

Joined: Wed Sep 17, 2014 2:55 am
Posts: 1
I've faced with similar issue during cascade update in hibernate 4.3.6.Final

There is Business entity and BusinessBank entity. One Business has many BusinessBank, and every BusinessBank belongs to certain Business. As primary keys we use byte[].

Code:
@Entity
@Table(name = "business")
public class Business {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "Generator")
    @GenericGenerator(name = "Generator", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "Business_PK", unique = true, nullable = false)
    private byte[] businessPk;

    @Column(name = "BusinessName", nullable = false, length = 100)
    private String businessName;

    @OneToMany(targetEntity = BusinessBank.class, fetch = FetchType.LAZY, mappedBy = "business", cascade = {CascadeType.ALL})
    private List<BusinessBank> businessBanks = new ArrayList<BusinessBank>(0);
    ...
}

@Entity
@Table(name = "business_bank")
public class BusinessBank {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "Generator")
    @GenericGenerator(name = "Generator", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "BusinessBank_PK", unique = true, nullable = false)
    private byte[] businessBankPk;

    @ManyToOne(targetEntity = Business.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
    @JoinColumn(name = "Business_FK", nullable = false)
    private Business business;

    @Column(name = "BankAccountNumber", length = 50)
    private String bankName;
    ...
}


When Business is saved to DB, BusinessBank entities are saved also due to cascade. When initially new Business with new BusinessBank entities are saved to DB, everything works fine.
But when we make updating of more than 1 saved BusinessBank entities there is NPE:

Caused by: java.lang.NullPointerException
at org.hibernate.type.AbstractStandardBasicType.compare(AbstractStandardBasicType.java:225)
at org.hibernate.action.internal.EntityAction.compareTo(EntityAction.java:171)
at org.hibernate.engine.spi.ExecutableList.add(ExecutableList.java:222)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:241)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.scheduleUpdate(DefaultFlushEntityEventListener.java:313)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:160)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:231)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:102)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:55)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)


Code:
            Business business = new Business();
            business.setBusinessName("Business name");

            BusinessBank businessBank1 = new BusinessBank();
            businessBank1.setBusiness(business);
            businessBank1.setBankName("bank1");

            BusinessBank businessBank2 = new BusinessBank();
            businessBank2.setBusiness(business);
            businessBank2.setBankName("bank2");

            business.setBusinessBanks(Arrays.asList(businessBank1, businessBank2));

            Session session = getSession();
            try {
                session.beginTransaction();
                session.persist(business);
                session.getTransaction().commit();
            } finally {
                session.close();
            }

            businessBank1.setBankName("Bank1 rename");
            businessBank2.setBankName("Bank2 rename");

            session = getSession();
            try {
                session.beginTransaction();
                session.merge(business);
                session.getTransaction().commit();
            } finally {
                session.close();
            }


If I update just one business banks - everything is working fine. If more then one I have NPE that mentioned above.
I've looked into the source code and find out that before committing hibernate sorts entities by id. NPE occurs in this line
Code:
javaTypeDescriptor.getComparator().compare( (T) x, (T) y );
because javaTypeDescriptor.getComparator() is NULL for PrimitiveByteArrayTypeDescriptor. Comporator is set in super AbstractTypeDescriptor class and it's always NULL for byte[]:
Code:
public class PrimitiveByteArrayTypeDescriptor extends AbstractTypeDescriptor<byte[]> {
        ...
   public PrimitiveByteArrayTypeDescriptor() {
      super( byte[].class, ArrayMutabilityPlan.INSTANCE );
   }
        ...
}

public abstract class AbstractTypeDescriptor<T> implements JavaTypeDescriptor<T>, Serializable {
   ...
   private final Comparator<T> comparator;
   ...
   protected AbstractTypeDescriptor(Class<T> type, MutabilityPlan<T> mutabilityPlan) {
      ...
      this.comparator = Comparable.class.isAssignableFrom( type )
            ? (Comparator<T>) ComparableComparator.INSTANCE
            : null;

      ...
   }
...
}


To fix this bug I've tried to add @Type annotation under BusinessBank PK with my custom type ByteArrayType for byte[] that returns not NULL comporator.
Code:

public class BusinessBank   {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "Generator")
    @GenericGenerator(name = "Generator", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(name = "BusinessBank_PK", unique = true, nullable = false)
    @Type(type="com.model.ByteArrayType")
    private byte[] businessBankPk;
    ...
}


Here is the implementation of ByteArrayType
Code:
import jdbm.helper.ByteArrayComparator;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.VersionType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor;

import java.util.Comparator;

public class ByteArrayType extends AbstractSingleColumnStandardBasicType<byte[]> implements VersionType<byte[]> {
    public ByteArrayType() {
        super( VarbinaryTypeDescriptor.INSTANCE, CustomPrimitiveByteArrayTypeDescriptor.INSTANCE );
    }

    public String getName() {
        return "hb_binary";
    }

    @Override
    public String[] getRegistrationKeys() {
        return new String[] { getName(), "byte[]", byte[].class.getName() };
    }

    @Override
    public byte[] seed(SessionImplementor session) {
        return null;
    }

    @Override
    public byte[] next(byte[] current, SessionImplementor session) {
        return current;
    }

    @Override
    public Comparator<byte[]> getComparator() {
        return CustomPrimitiveByteArrayTypeDescriptor.INSTANCE.getComparator();
    }

    private static class CustomPrimitiveByteArrayTypeDescriptor extends PrimitiveByteArrayTypeDescriptor {
        public static final CustomPrimitiveByteArrayTypeDescriptor INSTANCE =
                new CustomPrimitiveByteArrayTypeDescriptor();
        private ByteArrayComparator comparator = new ByteArrayComparator();

        @Override
        public Comparator<byte[]> getComparator() {
            return comparator;
        }
    }
}


After this business banks were updated successfully. But I don't think it's nice idea to override default BinaryType for byte[]. If someone knows better solution I would appreciate.

What about your issue, did you solve it?


Top
 Profile  
 
 Post subject: Re: NullPointerException with simple value object mapping
PostPosted: Fri Sep 30, 2016 4:36 am 
Sorry for gravedigging but this topic ranks quite high on google for this problem.

The NPE was caused by a bug. It has been fixed in 5.0.10:

https://hibernate.atlassian.net/browse/HHH-8999


Top
  
 
 Post subject: Re: NullPointerException with simple value object mapping
PostPosted: Fri Sep 30, 2016 4:37 am 
https://hibernate.atlassian.net/browse/HHH-8999


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