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)

Reply via email to