HI! No, I have not committed any portion of this at all, and do not indent to any time this week. I need to do a code review, and discuss this with team mates. I might want to commit this next week if all goes well with the code review, would that work?
Thanks, Heath On Sun, Feb 14, 2016 at 3:27 AM, Mark Struberg <[email protected]> wrote: > 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) > >
