Heath, did you already commit parts of that? Is this feature now half-in or are you just working on it? If not, do you have a timeframe? Should we wait for it or can I go on with the release (and do another 2.4.2 a month later)?
txs and LieGrue, strub > Am 12.02.2016 um 05:18 schrieb Heath Thomann (JIRA) <[email protected]>: > > > [ > https://issues.apache.org/jira/browse/OPENJPA-2631?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15144007#comment-15144007 > ] > > Heath Thomann commented on OPENJPA-2631: > ---------------------------------------- > > For posterity's sake, and given this was a complex issue to debug/fix, I'd > like to document some of the steps I took to debug this....sorry, it might be > a bit awkward but better than nothing should I/we ever need to revisit this > issue. :) This debug assumes knowledge of the attached test. The issue > occurs here: > > public void appendTo(Select sel, ExpContext ctx, ExpState state, > SQLBuffer sql, int index) { > ParamExpState pstate = (ParamExpState) state; > if (pstate.otherLength > 1) > sql.appendValue(((Object[]) pstate.sqlValue)[index], <------ > line 149 > pstate.getColumn(index), this); > > Note that I added a system out in this 'if' block, then I ran the OpenJPA > JUnit bucket. I found that ONLY one test method ever hits this 'if' > statement.....so it seems this 'if' block is very rarely executed (which I > suppose explains why we have yet to see this issue). Anyway, in the debugger > I notice that 'pstate.otherLength' was 2, which is the size of the number of > columns in my PK (SubjectKey), yet 'pstate.sqlValue' contained 'Subject' (the > entity in the attacked test). So I suspected that this code expected to get > at the column values of the PK (SubjectKey), not the entity (Subject) itself. > So I walked backwards to see where 'otherLength' and 'sqlValue' where set. > I found that here in Param: > > public void calculateValue(Select sel, ExpContext ctx, ExpState state, > Val other, ExpState otherState) { > super.calculateValue(sel, ctx, state, other, otherState); > Object val = getValue(ctx.params); > ParamExpState pstate = (ParamExpState) state; > if (other != null && !_container) { > pstate.sqlValue = other.toDataStoreValue(sel, ctx, otherState, > val); > pstate.otherLength = other.length(sel, ctx, otherState); > > > other.toDataStoreValue calls to ClassMapping.toDataStoreValue....here is that > code (note the javadoc): > > /** > * Return the given column value(s) for the given object. The given > * columns will be primary key columns of this mapping, but may be in > * any order. If there is only one column, return its value. If there > * are multiple columns, return an object array of their values, in the > * same order the columns are given. > */ > public Object toDataStoreValue(Object obj, Column[] cols, JDBCStore store) > { > Object ret = (cols.length == 1) ? null : new Object[cols.length]; > > // in the past we've been lenient about being able to translate objects > // from other persistence contexts, so try to get sm directly from > // instance before asking our context > OpenJPAStateManager sm; > if (ImplHelper.isManageable(obj)) { > PersistenceCapable pc = ImplHelper.toPersistenceCapable(obj, > getRepository().getConfiguration()); > sm = (OpenJPAStateManager) pc.pcGetStateManager(); > if (sm == null) { > ret = getValueFromUnmanagedInstance(obj, cols, true); > > > In my scenario 'sm' is null so we take the block to 'ret = > getValueFromUnmanagedInstance'. Again, note that I added a system out in > this 'if' block, then I ran the OpenJPA test bucket and only one test method > ever hits this 'if' statement (again, nearly dead code). :) When I ran my > test, I notice that 'ret' is assigned 'Subject' after a call to > 'getValueFromUnmanagedInstance, not the PK values as promised by the javadoc > listed above. So I set off to figure out how to get the PKs columns from > Subject, and their values. To do this, I thought "if we execute this query > as a 'find' instead, how does that path extract the PK columns and values." > When running in a debugger, I saw that we go into this code in > SelectImpl.where: > > join = mapping.assertJoinable(toCols[i]); > val = pks[mapping.getField(join.getFieldIndex()). > getPrimaryKeyIndex()]; > val = join.getJoinValue(val, toCols[i], store); > > For a finder, this is where we get the PK of SubjectKey and get its > individual values of the SubjectKey.....this is where I took my idea for the > fix attached to this JIRA. > > Thanks, > > Heath > > >> ClassCastException occurs when an equals comparison query is executed on an >> entity with an @EmbeddedId that contains more than one field. >> ----------------------------------------------------------------------------------------------------------------------------------------- >> >> Key: OPENJPA-2631 >> URL: https://issues.apache.org/jira/browse/OPENJPA-2631 >> Project: OpenJPA >> Issue Type: Bug >> Components: criteria, query, sql >> Affects Versions: 2.1.2, 2.2.3, 2.4.1 >> Reporter: Heath Thomann >> Assignee: Heath Thomann >> Attachments: OPENJPA-2631-2.1.x.patch, OPENJPA-2631-2.1.x.test >> >> >> Take the following entity: >> @Entity >> public class Subject implements Serializable { >> @EmbeddedId >> private SubjectKey key; >> ....... >> Where SubjectKey is as follows: >> @Embeddable >> public class SubjectKey implements Serializable { >> private Integer subjectNummer; >> private String subjectTypeCode; >> ...... >> As you can see we have a composite primary key. With this, take this query: >> TypedQuery<Subject> query = em.createQuery("select s from Subject s where s >> = :subject", Subject.class); >> query.setParameter("subject", s); >> Subject s2 = query.getSingleResult(); >> This query will yield the following exception: >> java.lang.ClassCastException: >> org.apache.openjpa.persistence.embed.compositepk.SubjectKey cannot be cast >> to >> [Ljava.lang.Object;] >> at org.apache.openjpa.jdbc.kernel.exps.Param.appendTo(Param.java:149) >> If we execute a corresponding 'em.find' of Subject, this exception doesn't >> occur. Furthermore, if you execute the same query for an entity with an >> @EmbeddedId that only contains one field, all will work as expected. The >> issue here is with an equals query where the entity contains an >> @EmbeddableId with more than two fields. >> While investigating/debugging this issue, I've found further issues when >> creating the query using CriteriaBuilder; both with an @Embeddable and >> @IdClass composite PKs. I will leave it as an exercise for the reader to >> view the attached test case to see how each issue can occur. Each test >> method details what issue it recreated before the fixes to this issue. I'm >> also attaching a patch with a proposed fix for the issues. >> Thanks, >> Heath Thomann > > > > -- > This message was sent by Atlassian JIRA > (v6.3.4#6332)
