Interesting. I've created a bug report and attached a reproducible test
case.
Obviously, it's a simple matter for me to change my variable name. =)
But, given the situation:
X has a public "property" getX(), and a private field "x", doesn't it
seem reasonable that cayenne should be using getX(), rather than the
private x? Otherwise, it seems, to me at least, that cayenne is
violating the contract of the "private" modifier.
Robert
Andrus Adamchik wrote:
> I see. In 1.2 Cayenne supports field-based persistence (albeit only on
> the remote client at the moment). As we move forward, this may become
> the default way to store properties (especially in light of JPA spec
> compliance). So the runtime has to work with both DataObject and POJO
> classes. The problem seems to be in the attempt to combine both
> approaches for the same entity class. Probably we shouldn't be mixing
> them when compiling ClassDescriptors.
>
> I'd appreciate a bug report - with a reproducible test case, I'll take
> another look at how the ClassDescriptors are implemented.
>
> Andrus
>
>
> On Jun 28, 2006, at 2:07 PM, Robert Zeigler wrote:
>
>> Found the issue.
>> AssignmentTransaction has a one-to-many relationship named
>> "studentResponses". It also had a private variable:
>> private List studentResponses. In certain situations (described
>> momentarily), it appears that the field accessor class is "seeing" the
>> private variable instead of the relationship. When I changed the name of
>> the private variable, the problem disappeared. I was also able to
>> duplicate the issue in an entirely unrelated (and much simpler) data
>> map. This seems like a bug to me; seems like FieldAccessor shouldn't be
>> able to grab/use my private variables. :) If you want, I can open up a
>> jira issue and attach a really simple map and bit of code that will
>> illustrate the issue.
>>
>> In any event, here is the situation where the invalid access occurs:
>> X has a to-many relationship to Y. Z also has a to-many relationship
>> to Y.
>> Y has a to-many relationship named k, and also has a private List k;
>> declaration.
>> xinstance, zinstance , and yinstance are instances of X, Z and Y,
>> respectively, and xinstance and zinstance share a yinstance.
>> X loads its list of Y via xinstance.getY(). xinstance does some
>> processing that results in
>> k's initialization in the shared yinstance. zinstance now does
>> zinstance.getY() and attempts to perform some operation on the list
>> (size(), get(0), iterator(), etc... something that forces cayenne to
>> fault the toManyList). While processing the shared yinstance, cayenne
>> will choke with a ClassCastException because it will see the private
>> variable k (now initialized, eg, to an ArrayList) rather than the
>> relationship with the same name.
>>
>> Apologies if the explanation is a bit opaque... again... I'll work up a
>> trivial data map + code example that triggers the error.
>>
>> Robert
>>
>> Robert Zeigler wrote:
>>> Didn't get back to this last night, sorry. Ok, I sat down and wrote a
>>> quick test to call the same code, external of tapestry.
>>> The code outside of tapestry didn't result in a class cast exception.
>>> Instead, it resulted in an ExpressionException (unable to evaluate
>>> assignment.name). Turns out that the assignment object doesn't have a
>>> "name" property (it's "title"). The thing that seems odd here is that
>>> the code throws no exceptions with M5 (I suspect this has to do with
>>> removing BeanUtils as a dependency?).
>>>
>>> Anyway... the lack of a ClassCastException says that something weird
>>> must be happening in tapestry or my code somewhere. I'll keep looking.
>>> I don't define collection setters in the DO; neither my code nor
>>> tapestry should be initializing the relationship, but I'll keep digging
>>> to see what I can find.
>>>
>>> Robert
>>>
>>>
>>> Andrus Adamchik wrote:
>>>
>>>>> In poking around, I saw a place where if something was
>>>>> transient, an ArrayList was returned... but I can't find it again
>>>>> at the
>>>>> moment; I'll look later tonight when I have a bit of time and see
>>>>> if I
>>>>> can find it again.
>>>>>
>>>> Let us know if you find those - this shouldn't happen in DataObjects.
>>>> The code below looks clean, so the cause is somewhere else. Is it
>>>> possible that Tapestry or the user code initializes the relationship
>>>> list on its own? Do you define collection setters in your DO's
>>>> (Cayenne does not by default)?
>>>>
>>>> Andrus
>>>>
>>>>
>>>>
>>>> On Jun 27, 2006, at 2:54 AM, Robert Zeigler wrote:
>>>>
>>>>
>>>>> Hi all,
>>>>>
>>>>> Way back when 1.2B1 was released, I reported a weird fault resolving
>>>>> exception. I didn't have time then to look into it further. I just
>>>>> tried
>>>>> out cayenne 1.2RC2 and am still seeing the same weird behavior (maybe
>>>>> I'm doing something weird. ;). I do have time now to look into it
>>>>> further, but am getting stuck before I can get started by a separate
>>>>> issue.
>>>>>
>>>>> My code:
>>>>> public List getTransactionsForCourse(Course course) {
>>>>> List ret = this.getAssignmentTransactions();
>>>>> ret =
>>>>> ExpressionFactory.matchExp("assignment.course.name",course.getName()).filterObjects(ret);
>>>>>
>>>>>
>>>>> List orderings = new ArrayList();
>>>>> orderings.add(new Ordering("assignment.name",true));
>>>>> orderings.add(new Ordering("scoreAsFloat",false));
>>>>> Ordering.orderList(ret,orderings);
>>>>> return ret;
>>>>> }
>>>>>
>>>>> assignmentTransactions is a one to many relationship.
>>>>>
>>>>> Calling said code is resulting in the following exception:
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.property.AbstractCollectionProperty.ensureCollectionValueHolderSet(AbstractCollectionProperty.java:159)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.property.AbstractCollectionProperty.injectValueHolder(AbstractCollectionProperty.java:142)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.property.BaseClassDescriptor.injectValueHolders(BaseClassDescriptor.java:218)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataContext.localObject(DataContext.java:1924)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.ObjectResolver.objectFromDataRow(ObjectResolver.java:237)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.ObjectResolver.objectsFromDataRows(ObjectResolver.java:155)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.ObjectResolver.synchronizedObjectsFromDataRows(ObjectResolver.java:134)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataDomainQueryAction.interceptObjectConversion(DataDomainQueryAction.java:373)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataDomainQueryAction.execute(DataDomainQueryAction.java:151)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataDomain.onQuery(DataDomain.java:766)
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.util.ObjectContextQueryAction.runQuery(ObjectContextQueryAction.java:253)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataContextQueryAction.execute(DataContextQueryAction.java:90)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataContext.onQuery(DataContext.java:1422)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.DataContext.performQuery(DataContext.java:1411)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.ToManyList.resolvedObjectList(ToManyList.java:343)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.objectstyle.cayenne.access.ToManyList.size(ToManyList.java:296)
>>>>> *
>>>>> org.objectstyle.cayenne.exp.Expression.filterObjects(Expression.java:458)
>>>>>
>>>>>
>>>>>
>>>>> * org.eledge.domain.User.getTransactionsForCourse(User.java:92)
>>>>> *
>>>>> org.eledge.domain.User.getGradebookGradedResponses(User.java:197)
>>>>> *
>>>>> org.eledge.domain.User.getGradedGradebookGradedResponses(User.java:192)
>>>>>
>>>>>
>>>>> *
>>>>> org.eledge.domain.User.getHasGradedGradebookGradedResponses(User.java:188)
>>>>>
>>>>>
>>>>>
>>>>> * sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>>> *
>>>>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>>>>
>>>>>
>>>>>
>>>>> * java.lang.reflect.Method.invoke(Method.java:585)
>>>>> * ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:491)
>>>>> * ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:785)
>>>>> *
>>>>> ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:61)
>>>>> * ognl.OgnlRuntime.callMethod(OgnlRuntime.java:819)
>>>>> * ognl.ASTMethod.getValueBody(ASTMethod.java:75)
>>>>> * ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
>>>>> * ognl.SimpleNode.getValue(SimpleNode.java:210)
>>>>> * ognl.ASTChain.getValueBody(ASTChain.java:109)
>>>>> * ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
>>>>> * ognl.SimpleNode.getValue(SimpleNode.java:210)
>>>>> * ognl.Ognl.getValue(Ognl.java:333)
>>>>> * ognl.Ognl.getValue(Ognl.java:310)
>>>>> *
>>>>> org.apache.tapestry.binding.ExpressionBinding.resolveProperty(ExpressionBinding.java:201)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.binding.ExpressionBinding.getObject(ExpressionBinding.java:194)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.binding.AbstractBinding.getBoolean(AbstractBinding.java:77)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.param.BooleanParameterConnector.setParameter(BooleanParameterConnector.java:51)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.param.ParameterManager.setParameters(ParameterManager.java:105)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.prepareForRender(AbstractComponent.java:898)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:853)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:624)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.components.RenderBody.renderComponent(RenderBody.java:45)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:624)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.components.RenderBody.renderComponent(RenderBody.java:45)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:624)
>>>>>
>>>>>
>>>>>
>>>>> * org.apache.tapestry.html.Body.renderComponent(Body.java:269)
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:624)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.components.RenderBody.renderComponent(RenderBody.java:45)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:624)
>>>>>
>>>>>
>>>>>
>>>>> * org.apache.tapestry.html.Shell.renderComponent(Shell.java:124)
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.BaseComponent.renderComponent(BaseComponent.java:118)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.BaseComponent.renderComponent(BaseComponent.java:118)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.renderBody(AbstractComponent.java:624)
>>>>>
>>>>>
>>>>>
>>>>> * org.mb.tapestry.base.IfBean.renderComponent(IfBean.java:83)
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.BaseComponent.renderComponent(BaseComponent.java:118)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.BaseComponent.renderComponent(BaseComponent.java:118)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractComponent.render(AbstractComponent.java:857)
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.AbstractPage.renderPage(AbstractPage.java:300)
>>>>> *
>>>>> org.apache.tapestry.engine.RequestCycle.renderPage(RequestCycle.java:368)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.engine.AbstractEngine.renderResponse(AbstractEngine.java:749)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.engine.PageService.service(PageService.java:77)
>>>>> *
>>>>> org.apache.tapestry.engine.AbstractEngine.service(AbstractEngine.java:889)
>>>>>
>>>>>
>>>>>
>>>>> * org.eledge.EledgeEngine.service(EledgeEngine.java:60)
>>>>> *
>>>>> org.apache.tapestry.ApplicationServlet.doService(ApplicationServlet.java:198)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.apache.tapestry.ApplicationServlet.doGet(ApplicationServlet.java:159)
>>>>>
>>>>>
>>>>>
>>>>> * javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
>>>>> * javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
>>>>> *
>>>>> org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428)
>>>>>
>>>>>
>>>>> *
>>>>> org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.eledge.OldEledgePagesFilter.doFilter(OldEledgePagesFilter.java:64)
>>>>>
>>>>>
>>>>> *
>>>>> org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471)
>>>>>
>>>>>
>>>>>
>>>>> *
>>>>> org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:568)
>>>>>
>>>>>
>>>>> * org.mortbay.http.HttpContext.handle(HttpContext.java:1530)
>>>>> *
>>>>> org.mortbay.jetty.servlet.WebApplicationContext.handle(WebApplicationContext.java:633)
>>>>>
>>>>>
>>>>>
>>>>> * org.mortbay.http.HttpContext.handle(HttpContext.java:1482)
>>>>> * org.mortbay.http.HttpServer.service(HttpServer.java:909)
>>>>> *
>>>>> org.mortbay.http.HttpConnection.service(HttpConnection.java:816)
>>>>> *
>>>>> org.mortbay.http.HttpConnection.handleNext(HttpConnection.java:982)
>>>>> * org.mortbay.http.HttpConnection.handle(HttpConnection.java:833)
>>>>> *
>>>>> org.mortbay.http.SocketListener.handleConnection(SocketListener.java:244)
>>>>>
>>>>>
>>>>>
>>>>> * org.mortbay.util.ThreadedServer.handle(ThreadedServer.java:357)
>>>>> * org.mortbay.util.ThreadPool$PoolThread.run(ThreadPool.java:534)
>>>>>
>>>>>
>>>>> This is a tapestry (3.0.3) webapp, running with the JettyLauncher.
>>>>> I've
>>>>> done a clean recompile, but no good. I dug into the code, and it
>>>>> looks
>>>>> like ensureCollectionValueHolderSet is trying to cast an ArrayList
>>>>> as a
>>>>> ValueHolder. In poking around, I saw a place where if something was
>>>>> transient, an ArrayList was returned... but I can't find it again
>>>>> at the
>>>>> moment; I'll look later tonight when I have a bit of time and see
>>>>> if I
>>>>> can find it again. Anyway... thoughts? Cayenne bug? Something I've
>>>>> screwed up?
>>>>>
>>>>> Robert
>>>>>
>>>>>
>>>
>>>
>>
>>
>
This archive was generated by hypermail 2.0.0 : Wed Jun 28 2006 - 10:46:56 EDT