-->
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.  [ 6 posts ] 
Author Message
 Post subject: Accesing proxied entity instance fields.
PostPosted: Tue Oct 02, 2007 6:15 am 
Newbie

Joined: Tue Oct 02, 2007 4:48 am
Posts: 9
Hello.

I have an Entity which is loaded on demand (through proxy) and if I access a instance variable (which is a Embedded type) on the Entity directly not through a getter method the instance field is null (presumably because the field is accessed on the proxy and not on the actual instance).

For example:
Code:
@Embeddable
class EmbeddableType {
   Long valueOne;
   Long valueTwo;
   
    public Long getValueOne() {
       return valueOne;
    }
   
    public void setValueOne(Long valueOne) {
       this.valueOne = valueOne;
    }
   
    public Long getValueTwo() {
       return valueTwo;
    }
   
    public void setValueTwo(Long valueTwo) {
       this.valueTwo = valueTwo;
    }
}

@Entity
class ExampleEntity {
   @Embedded
    private EmbeddableType instanceField;
   
    public EmbeddableType getInstanceField() {
       return instanceField;
    }
    public void setInstanceField(EmbeddableType instanceField) {
       this.instanceField = instanceField;
    }
    public void accessInstanceField() {
       if (getInstanceField() != null && instanceField instanceof HibernateProxy) {
          // if this is true instanceField should not be null.. but it fails.
          assert(instanceField != null)
       }
    }
}


Is this behavior intended and expected or is this a bug ?

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 02, 2007 8:08 am 
Regular
Regular

Joined: Sun Sep 30, 2007 7:51 pm
Posts: 93
This is how proxies works. You must use the get method, hibernate can manipulate via cglib call to method, but not direct member access.

http://www.hibernate.org/hib_docs/v3/re ... ng-proxies

Regards,
Pavol


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 03, 2007 5:11 am 
Newbie

Joined: Tue Oct 02, 2007 4:48 am
Posts: 9
Thanks for the reply, but it still doesn't make sense to me. If you look closely to the example there is a method accessInstanceField() which should be forwarded to the concrete instance. The actually problem I have is similar to the one described by the example.

Here is the real stack trace and code snippet:

Code:
Thread [main] (Suspended (breakpoint at line 126 in WorkLog))   
   TechnicalContractWorkLog$$EnhancerByCGLIB$$cf97265e(WorkLog<T,WL,VS,PS>).isValidFor(ITwoDimensionalValidity) line: 126   
   TechnicalContractValidState(ObjectState<RHO,WL>).workLogValidOn(ITwoDimensionalValidity) line: 203   
   TechnicalContractValidState(ObjectState<RHO,WL>).currentReadWorkLog() line: 81   
   TechnicalContract(HistorizedObject<VT,WLT>).currentReadVersion() line: 131   
   TechnicalContract.getSomeValue() line: 48   
   TwoLifeCyclesTest.changeNonTechnicalContract(Long, TwoDimensionalValidity, long) line: 49   
   TwoLifeCyclesTest.testAcceptance() line: 69   
   NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]   
   NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39   
   DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25   
   Method.invoke(Object, Object...) line: 585   
   TwoLifeCyclesTest(TestCase).runTest() line: 154   
   TwoLifeCyclesTest(TestCase).runBare() line: 127   
   TwoLifeCyclesTest(ConditionalTestCase).runBare() line: 69   
   TwoLifeCyclesTest(SpringAcceptanceTest).runBare() line: 109   
   TestResult$1.protect() line: 106   
   TestResult.runProtected(Test, Protectable) line: 124   
   TestResult.run(TestCase) line: 109   
   TwoLifeCyclesTest(TestCase).run(TestResult) line: 118   
   TestSuite.runTest(Test, TestResult) line: 208   
   TestSuite.run(TestResult) line: 203   
   JUnit3TestReference.run(TestExecution) line: 128   
   TestExecution.run(ITestReference[]) line: 38   
   RemoteTestRunner.runTests(String[], String, TestExecution) line: 460   
   RemoteTestRunner.runTests(TestExecution) line: 673   
   RemoteTestRunner.run() line: 386   
   RemoteTestRunner.main(String[]) line: 196


Snippet that does not work:
Code:
   boolean isValidFor(ITwoDimensionalValidity validity) {
//      if (getTwoDimensionalValidity() != null && this instanceof HibernateProxy) {
//         System.out.println("Proxy");
//         assert(twoDimensionalValidity != null);
//      }

      return twoDimensionalValidity.isLessOrEqual(validity);
   }


Snippet that does work:
Code:
   boolean isValidFor(ITwoDimensionalValidity validity) {
//      if (getTwoDimensionalValidity() != null && this instanceof HibernateProxy) {
//         System.out.println("Proxy");
//         assert(twoDimensionalValidity != null);
//      }

      return getTwoDimensionalValidity().isLessOrEqual(validity);
   }


"Sender" of the method isValidFor() which is on another class:
Code:
   WL workLogValidOn(ITwoDimensionalValidity twoDimensionalValidity) {
      assert (twoDimensionalValidity != null);

      WL eachWorkLog = null;
      ListIterator<WL> iterator = getWorkLogs().listIterator(getWorkLogs().size());
      while (iterator.hasPrevious()) {
         eachWorkLog = iterator.previous();
         if (eachWorkLog.isValidFor(twoDimensionalValidity)) {
            return eachWorkLog;
         }
      }
      return null;
   }



The question now is when the workLogValidOn() method calls the isValidFor() which is on a proxied "WorkLog" class, shouldn't the isValidFor() method be forwarded to the concrete instance and not be executed on the proxy? In my case this is not true because the isValidFor() method throws a NullPointerException because twoDimensionalValidity field accessed in isValidFor() method is null.

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 03, 2007 6:04 am 
Regular
Regular

Joined: Sun Sep 30, 2007 7:51 pm
Posts: 93
I would say, hibernate will load the instance on first get/set method call, no other calls to the class. Therefor, you have to encapsulate the field also in the class itself.

So, the proxy will not need to load the instance, if invoked methods don't use the persistent fields.

Why is it so implemented, I don't know.

Regards,
Pavol


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 03, 2007 7:32 am 
Newbie

Joined: Tue Oct 02, 2007 4:48 am
Posts: 9
Thanks.

This would explain this behavior but it still can be very unpleasant. Why should one encapsulate instance field access in the class itself? Usually all the methods implemented on an entity should manipulate with entity data itself (if designed properly). It is irritating that one should need to think about how to access fields inside a class and that unexpected errors emerge once one declares associations as lazy.

Can anyone explain in more detail why this is implemented in such a way? Can it be prevented and still retain lazy loading?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 05, 2007 8:55 am 
Newbie

Joined: Tue Oct 02, 2007 4:48 am
Posts: 9
Is there really no one who knows this?


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