-->
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.  [ 2 posts ] 
Author Message
 Post subject: NPE when persisting entity with embedded composite key
PostPosted: Thu Feb 11, 2010 12:54 am 
Newbie

Joined: Wed Feb 10, 2010 11:50 pm
Posts: 2
I'm going off the writeup on many-to-many associations with composite key at http://boris.kirzner.info/blog/archives ... osite-key/.

My particular legacy domain crap has a join entity with 3, not 2, foreign keys. Uniqueness is enforced on a combination of the three, but one of them is nillable; and there's some metadata on it as well.

When I tell my EntityManager to persist a new instance of this join entity, sometimes (not always) (very rarely in fact) it throws an NPE. The exception is repeatable when given the same input, and it always fails on that input. I can't detect a pattern in that input when compared to other input that doesn't generate an error, though. At first I thought of course it was because the nillable member of the composite key would be null in those cases; but some input that causes the error does not have a null value in that field (and some does).

Here is some example source code to show what I'm doing. Basically cribbed directly from the URL above. Thanks for reading this far.
Code:
// basic POJO entities
@Entity
public class Proposal {
    private Long id;
    //  ... other fields elided for length
    private List<ProposalAddon> proposalAddons;
   
    @Id
    @Column(name="proposal_id")
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
   
    @OneToMany(targetEntity=ProposalAddon.class, fetch=FetchType.LAZY, mappedBy="pk.proposal")
    public List<ProposalAddon> getProposalAddons() {
        return proposalAddons;
    }
    public void setProposalAddons(List<ProposalAddon> proposalAddons) {
        this.proposalAddons = proposalAddons;
    }
}

@Entity
public class AddonType {
    // ... basically same as Proposal, has id, other basic fields, and List<ProposalAddon>
}

@Entity
public class Access {
    // ... again, basic entity, same w.r.t. List<ProposalAddon>
}

// Join table entity
@Entity
@AssociationOverrides({
    @AssociationOverride(name="pk.proposal", joinColumns=@JoinColumn(name="proposal_id")),
    @AssociationOverride(name="pk.addonType", joinColumns=@JoinColumn(name="addon_type_lu_id")),
    @AssociationOverride(name="pk.access", joinColumns=@JoinColumn(name="access_lu_id"))
})
public class ProposalAddon implements Serializable {

    private ProposalAddonPK pk = new ProposalAddonPK();
   
    // other metadata on this join table
    private Addon addon;
   
    @EmbeddedId
    private ProposalAddonPK getPk() {
        return pk;
    }
    private void setPk(ProposalAddonPK pk) {
        this.pk = pk;
    }
   
    @Transient
    public Proposal getProposal() {
        return getPk().getProposal();
    }
    public void setProposal(Proposal proposal) {
        getPk().setProposal(proposal);
    }
   
    @Transient
    public AddonType getAddonType() {
        return getPk().getAddonType();
    }
    public void setAddonType(AddonType addonType) {
        getPk().setAddonType(addonType);
    }
   
    @Transient
    public Access getAccess() {
        return getPk().getAccess();
    }
    public void setAccess(Access access) {
        getPk().setAccess(access);
    }
   
    @ManyToOne(targetEntity=Addon.class, optional=false, fetch=FetchType.LAZY, cascade={CascadeType.REFRESH})
    @JoinColumn(name="addon_lu_id")
    public Addon getAddon() {
        return addon;
    }
    public void setAddon(Addon addon) {
        this.addon = addon;
    }
   
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
       
        ProposalAddon other = (ProposalAddon) o;
        if (getPk() != null ? !getPk().equals(other.getPk()) : other.getPk() != null) return false;
       
        return true;
    }
   
    public int hashCode() {
        return (getPk() != null ? getPk().hashCode() : 0);
    }
}

@Embeddable
public class ProposalAddonPK implements Serializable {
    private Proposal proposal;
    private AddonType addonType;
    private Access access;
   
    @ManyToOne(targetEntity=Proposal.class, fetch=FetchType.LAZY, optional=false)
    @JoinColumn(name="proposal_id")
    public Proposal getProposal() {
        return proposal;
    }
    public void setProposal(Proposal proposal) {
        this.proposal = proposal;
    }
   
    @ManyToOne(targetEntity=AddonType.class, fetch=FetchType.LAZY, optional=false)
    @JoinColumn(name="addon_type_lu_id")
    public AddonType getAddonType() {
        return addonType;
    }
    public void setAddonType(AddonType addonType) {
        this.addonType = addonType;
    }
   
    @ManyToOne(targetEntity=Access.class, fetch=FetchType.LAZY, optional=true)
    @JoinColumn(name="access_lu_id")
    public Access getAccess() {
        return access;
    }
    public void setAccess(Access access) {
        this.access = access;
    }
   
    @Override
    public boolean equals(Object obj) {
        // ... eliding for length
    }
   
    public int hashCode() {
        int result;
        result = (proposal != null ? proposal.hashCode() : 0);
        result = 31 * result + (addonType != null ? addonType.hashCode() : 0);
        result = 31 * result + (access != null ? access.hashCode() : 0);
        return result;
    }
}


Aaaand here's a stack trace.

java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:169)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:206)
at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:3619)
at org.hibernate.type.EntityType.isEqual(EntityType.java:330)
at org.hibernate.type.ComponentType.isEqual(ComponentType.java:166)
at org.hibernate.engine.EntityKey.equals(EntityKey.java:119)
at java.util.HashMap.get(Unknown Source)
at org.hibernate.engine.StatefulPersistenceContext.getEntity(StatefulPersistenceContext.java:345)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:185)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
at sun.reflect.GeneratedMethodAccessor625.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:358)
at $Proxy101.persist(Unknown Source)
at sun.reflect.GeneratedMethodAccessor624.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:197)
at $Proxy50.persist(Unknown Source)
at com.legacycrap.services.ProposalServiceImpl.setProposalAddons(ProposalServiceImpl.java:527)
at com.legacycrap.services.ProposalServiceImpl.createDefaultAddons(ProposalServiceImpl.java:452)
at com.legacycrap.services.ProposalServiceImpl$$FastClassByCGLIB$$6a8a71fc.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:160)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)

at com.legacycrap.services.ProposalServiceImpl$$EnhancerByCGLIB$$1bfe414c.createDefaultAddons(<generated>)
at otherjunk.customer.ProposalCreate.createDefaultProposalAddons(ProposalCreate.java:369)
at otherjunk.customer.ProposalCreate.handle(ProposalCreate.java:267)
at reallycrap.zoo.ZooServlet.service(ZooServlet.java:121)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:112)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at net.crapola.util.filters.ZooFilter.doFilter(ZooFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at net.crapola.util.filters.ZooFilter.doFilter(ZooFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Unknown Source)


Top
 Profile  
 
 Post subject: Re: NPE when persisting entity with embedded composite key
PostPosted: Thu Feb 11, 2010 6:23 pm 
Newbie

Joined: Wed Feb 10, 2010 11:50 pm
Posts: 2
We decided that this is due, after all, to the nillable property in the composite key; that at some point when hibernate tries to compare the current entity being persisted to the hash of the other instances of this entity, it tries to call getId() on the null member of the key. Probably at some point when it's trying to create the associations from my ProposalAddon entity to the nillable Access entity.

I have worked around this issue by removing the association to Access, and replacing it with a Long accessId. For now we do not have a need to map a list of ProposalAddon entities to an Access. Many places around the interwebs will tell you that hibernate cannot handle any nillable property of a composite key, but it appears to work fine to me. My ProposalAddon PK class now has members Proposal, AddonType, and Long.


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