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.ensureC ollectionValueHolderSet(AbstractCollectionProperty.java:159)


    *
org.objectstyle.cayenne.property.AbstractCollectionProperty.injectV alueHolder(AbstractCollectionProperty.java:142)


    *
org.objectstyle.cayenne.property.BaseClassDescriptor.injectValueHol ders(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.synchronizedObjectsFr omDataRows(ObjectResolver.java:134)


    *
org.objectstyle.cayenne.access.DataDomainQueryAction.interceptObjec tConversion(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







Reply via email to