-->
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: Composite Identifier with associations throws NullPointers
PostPosted: Fri Aug 15, 2008 6:22 pm 
Newbie

Joined: Wed Jul 30, 2008 1:54 pm
Posts: 11
I have a seemingly insurmountable issue with a compisite identifier. I think it might be a legitimate bug, and I'd like some opinions and ideas.

I have a legacy database that I must map objects against. I cannot modify the database structure. In that database, Enterprises are associated to Addresses with a join table.

This join table, ENT_ADDR, has 3 columns: "ENT_ID", "AD_ID", and "AD_TYPE". The AD_TYPE column is not a primary key, but instead identifies the nature of the address's association with the Enterprise. For instance, "Mailing", "Billing", "Physical".

Now, I need to map this in such a way that allows me to see the type of the address association, to that end, I created the following:

Code:

@Entity
@Table(name="ENTERPRISE")
public class Enterprise
{
   @Id
   @Column(name="EID")
   private Long id = null;
   
   @Column(name="NAME")
   private String name = null;
   
   @OneToMany(cascade=CascadeType.ALL)
   @JoinColumn(name="EID")
   private Set<AddressAssociation> addresses = new HashSet<AddressAssociation>();
   
   ...
}

@Entity
@Table(name="ADDRESS")
public class Address
{
   @Id
   @Column(name="AID")
   private Long id = null;
   
   @Column(name="NAME")
   private String name = null;
   
   ...
}

@Entity
@Table(name="ENT_ADDR")
@IdClass(AddressAssociation.class)
public class Address
{
   @Id
   private Enterprise enterprise;
   
   @Id
   private Address address;
   
   @Column(name="AD_TYPE")
   private String name = null;
   
   ...
}

@Embeddable
public class AddressAssociation
implements Serializable
{
   @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
   @JoinColumn(name = "ENT_ID", nullable = false)
   private Enterprise enterprise = null;

   @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
   @JoinColumn(name = "AD_ID", nullable = false)
   private Address address = null;
   
   ...
}


Now, I realize that this isn't 100% JPA. But, the documentation for Hibernate Annotations says:
Quote:
While not supported by the EJB3 specification, Hibernate allows you to define associations inside a composite identifier. Simply use the regular annotations for that


I'm trying to store all brand new records. When I call EntityManager.persist(
I've tried this and several variations of it, but I always end up getting the Exception attached in the log.

Also, the following logging seems to show that it gets ID's from the DB for the Enterprise, but not for the Address.
Quote:
DEBUG nate.event.def.AbstractSaveEventListener - generated identifier: component[enterprise,address]{address=test.Address#null, enterprise=test.Enterprise#16475}, using strategy: org.hibernate.id.Assigned
DEBUG .event.def.AbstractFlushingEventListener - processing flush-time cascades
DEBUG nate.event.def.AbstractSaveEventListener - generated identifier: component[enterprise,address]{address=test.Address#null, enterprise=test.Enterprise#16475}, using strategy: org.hibernate.id.Assigned


Can anyone help?

For the record:

I'm using:
Hibernate Core 3.2.6.ga
Hibernate EntityManager 3.3.2
Hibernate Annotation 3.3.1

-------------------------------------------------
The Exception:

Quote:
javax.persistence.PersistenceException: java.lang.NullPointerException
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:527)
at bitronix.tm.BitronixTransaction.fireBeforeCompletionEvent(BitronixTransaction.java:288)
at bitronix.tm.BitronixTransaction.commit(BitronixTransaction.java:116)
at bitronix.tm.BitronixTransactionManager.commit(BitronixTransactionManager.java:92)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1028)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:709)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:678)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:359)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
at test.Service$$EnhancerByCGLIB$$63761de3.createSource(<generated>)
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.mule.model.resolvers.AbstractEntryPointResolver.invokeMethod(AbstractEntryPointResolver.java:147)
at org.mule.model.resolvers.MethodHeaderPropertyEntryPointResolver.invoke(MethodHeaderPropertyEntryPointResolver.java:106)
at org.mule.model.resolvers.DefaultEntryPointResolverSet.invoke(DefaultEntryPointResolverSet.java:50)
at org.mule.component.DefaultLifecycleAdapter.intercept(DefaultLifecycleAdapter.java:202)
at org.mule.component.AbstractJavaComponent.invokeComponentInstance(AbstractJavaComponent.java:82)
at org.mule.component.AbstractJavaComponent.doOnCall(AbstractJavaComponent.java:73)
at org.mule.component.AbstractComponent.onCall(AbstractComponent.java:96)
at org.mule.model.seda.SedaService.doSend(SedaService.java:237)
at org.mule.service.AbstractService.sendEvent(AbstractService.java:510)
at org.mule.DefaultMuleSession.sendEvent(DefaultMuleSession.java:354)
at org.mule.routing.inbound.DefaultInboundRouterCollection.send(DefaultInboundRouterCollection.java:221)
at org.mule.routing.inbound.DefaultInboundRouterCollection.route(DefaultInboundRouterCollection.java:181)
at org.mule.transport.AbstractMessageReceiver$DefaultInternalMessageListener.onMessage(AbstractMessageReceiver.java:604)
at org.mule.transport.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:346)
at org.mule.transport.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:269)
at org.mule.transport.vm.VMMessageReceiver.onCall(VMMessageReceiver.java:107)
at org.mule.transport.vm.VMMessageDispatcher$2.doInTransaction(VMMessageDispatcher.java:125)
at org.mule.transaction.TransactionTemplate.execute(TransactionTemplate.java:99)
at org.mule.transport.vm.VMMessageDispatcher.doSend(VMMessageDispatcher.java:128)
at org.mule.transport.AbstractMessageDispatcher.send(AbstractMessageDispatcher.java:157)
at org.mule.transport.AbstractConnector.send(AbstractConnector.java:1889)
at org.mule.endpoint.DefaultOutboundEndpoint.send(DefaultOutboundEndpoint.java:76)
at org.mule.DefaultMuleSession.sendEvent(DefaultMuleSession.java:327)
at org.mule.DefaultMuleSession.sendEvent(DefaultMuleSession.java:213)
at org.mule.DefaultMuleEventContext.sendEvent(DefaultMuleEventContext.java:220)
at org.mule.module.client.remoting.RemoteDispatcherComponent.sendAction(RemoteDispatcherComponent.java:200)
at org.mule.module.client.remoting.RemoteDispatcherComponent.onCall(RemoteDispatcherComponent.java:110)
at org.mule.component.SimpleCallableJavaComponent.invokeComponentInstance(SimpleCallableJavaComponent.java:165)
at org.mule.component.AbstractJavaComponent.doOnCall(AbstractJavaComponent.java:73)
at org.mule.component.AbstractComponent.onCall(AbstractComponent.java:96)
at org.mule.model.seda.SedaService.doSend(SedaService.java:237)
at org.mule.service.AbstractService.sendEvent(AbstractService.java:510)
at org.mule.DefaultMuleSession.sendEvent(DefaultMuleSession.java:354)
at org.mule.routing.inbound.DefaultInboundRouterCollection.send(DefaultInboundRouterCollection.java:221)
at org.mule.routing.inbound.DefaultInboundRouterCollection.route(DefaultInboundRouterCollection.java:181)
at org.mule.transport.AbstractMessageReceiver$DefaultInternalMessageListener.onMessage(AbstractMessageReceiver.java:604)
at org.mule.transport.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:346)
at org.mule.transport.AbstractMessageReceiver.routeMessage(AbstractMessageReceiver.java:287)
at org.mule.transport.http.HttpMessageReceiver$HttpWorker.doRequest(HttpMessageReceiver.java:271)
at org.mule.transport.http.HttpMessageReceiver$HttpWorker.processRequest(HttpMessageReceiver.java:229)
at org.mule.transport.http.HttpMessageReceiver$HttpWorker.run(HttpMessageReceiver.java:189)
at org.mule.work.WorkerContext.run(WorkerContext.java:310)
at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1061)
at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:575)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:112)
at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:120)
at org.hibernate.type.EntityType.getHashCode(EntityType.java:279)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:189)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:104)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:48)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:131)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:87)
at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:644)
at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:636)
at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:323)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:111)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:84)
at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:644)
at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:636)
at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:323)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:431)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:110)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:84)
at org.hibernate.impl.SessionImpl.firePersistOnFlush(SessionImpl.java:644)
at org.hibernate.impl.SessionImpl.persistOnFlush(SessionImpl.java:636)
at org.hibernate.engine.CascadingAction$9.cascade(CascadingAction.java:323)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:131)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:122)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:65)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:515)
... 60 more


Top
 Profile  
 
 Post subject: Re: Composite Identifier with associations throws NullPointe
PostPosted: Tue Aug 19, 2008 12:58 pm 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
hi,

there are basically two approaches when mapping additional columns in join tables. Either you use an intermediate entity or you use a collection of components. Both approaches are described in "Java Persistence with Hibernate". There are several threads on this forum regarding mapping with an intermediate entity. Using a collection of components the approach would look something like this (i haven;t actually tried this):


Code:

@Entity
@Table(name="ENTERPRISE")
public class Enterprise
{
   @Id
   @Column(name="EID")
   private Long id = null;
   
   @Column(name="NAME")
   private String name = null;
   
   @CollectionOfElements
   @JoinColumn(name="EID")
   private Set<AddressAssociation> addresses = new HashSet<AddressAssociation>();
   
   ...
}

@Entity
@Table(name="ADDRESS")
public class Address
{
   @Id
   @Column(name="AID")
   private Long id = null;
   
   @Column(name="NAME")
   private String name = null;
   
   ...
}


@Embeddable
public class AddressAssociation
implements Serializable
{
        @Parent // optional back pointer
        private Enterprise enterprise;

   @ManyToOne
   @JoinColumn(name = "AD_ID", nullable = false, updatable = false)
   private Address address = null;

   @Column(name="AD_TYPE")
   private String name = null;
   
   // add consructor, setters/getters and equals/hashcode
}


The downside of this approach is that there is no bidirectional navigation from Address to AddressAssociation. If you need this association as well you have to map AddressAssociation as a standalone entity.

--Hardy


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 19, 2008 4:21 pm 
Newbie

Joined: Wed Jul 30, 2008 1:54 pm
Posts: 11
I appreciate the feedback. It does solve another similar situation for me, where it's just a matter of needing the type occasionally.

However, in this case, I need to be able to modify the address association in a standalone manner. So it does need to be mapped as a separate entity, and that leads to the need for the primary key.

My hope was, with this post, that someone might have an idea as to what is causing the NullPointerException or at least acknowledge that it's a legitimate bug.

Thanks, though


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 21, 2008 8:19 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Hi,

toddjtidwell wrote:
However, in this case, I need to be able to modify the address association in a standalone manner. So it does need to be mapped as a separate entity, and that leads to the need for the primary key.


As said, there is a second way of doing this with a real intermediate entity. This post is referring to this approach http://forum.hibernate.org/viewtopic.php?t=986506. But what is your use case really - you want to change the address type without loading the enterprise?

--Hardy


Top
 Profile  
 
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.