OPENJPA-2631: Fix for CriteriaBuilder issue with an @EmbeddedId that contains more than one field.  Ported 2.1.x commit to trunk

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1750038 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java
index c03c016..657f929 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/EqualExpression.java
@@ -18,6 +18,10 @@
  */
 package org.apache.openjpa.jdbc.kernel.exps;
 
+import java.util.List;
+
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.FieldMapping;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
 import org.apache.openjpa.jdbc.sql.Select;
 
@@ -62,8 +66,31 @@
                     new FilterValueImpl(sel, ctx, bstate.state1, val1),
                     new FilterValueImpl(sel, ctx, bstate.state2, val2));
             } else {
-                int len = java.lang.Math.min(val1.length(sel, ctx, 
-                    bstate.state1), val2.length(sel, ctx, bstate.state2));
+                int lenVal1 = val1.length(sel, ctx, bstate.state1);
+                int lenVal2 = val2.length(sel, ctx, bstate.state2);
+                int len = java.lang.Math.min(lenVal1, lenVal2);
+
+                // OPENJPA-2631: Detect and handle slightly differently the
+                // case where a composite PK is in use. When an equals comparison
+                // is created by CriteriaBuilder, and the comparison is done against
+                // an entity with a composite PK, 'val2' can be either a:
+                // 1) Lit - in this case a Lit is hard coded to return a length of 1.
+                // 2) Param - in this case the metadata is null so length will return 1.
+                // Given this, first look to see if lenVal1 is greater than lenVal2.
+                if (lenVal1 > lenVal2) {
+                    // If here, lets get the metadata from val1 and see if its PK
+                    // is an embeddable. If so, the length (val1Len) will be the
+                    // size of the number of colunns in the PK. Use this length
+                    // in order to create an equal expression with the right number
+                    // of 'AND' statementes.
+                    ClassMapping cm = (ClassMapping) val1.getMetaData();
+                    FieldMapping[] fmsPK = cm.getPrimaryKeyFieldMappings();
+
+                    if (fmsPK[0].isEmbedded()) {
+                        len = lenVal1;
+                    }
+                }
+
                 for (int i = 0; i < len; i++) {
                     if (i > 0)
                         buf.append(" AND ");
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java
index db33046..4444ad2 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Lit.java
@@ -116,10 +116,11 @@
     public void appendTo(Select sel, ExpContext ctx, ExpState state, 
         SQLBuffer sql, int index) {
         LitExpState lstate = (LitExpState) state;
-        if (lstate.otherLength > 1)
-            sql.appendValue(((Object[]) lstate.sqlValue)[index], 
-                lstate.getColumn(index));
-        else if (_isRaw) {
+        if (lstate.otherLength > 1) {
+            sql.appendValue(((Object[]) lstate.sqlValue)[index], lstate.getColumn(index));
+            // OPENJPA-2631:  Return so as not to go into sql.appendValue a second time below.
+            return;
+        } else if (_isRaw) {
             int parseType = getParseType();
             if (parseType == Literal.TYPE_ENUM) { 
                 StringBuilder value = new StringBuilder();
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
index f565fab..fcecda2 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
@@ -253,6 +253,32 @@
             sm = (OpenJPAStateManager) pc.pcGetStateManager();
             if (sm == null) {
             	ret = getValueFromUnmanagedInstance(obj, cols, true);
+
+                // OPENJPA-2631 start
+                // Check to see if we are dealing with a Embeddable pk. If the PK is an Embeddable, AND IFF the
+                // columns in the Embeddable are greater than 1, we are dealing with a composite primary
+                // key, and as such 'ret' will be an instance of the embeddable, NOT the individual PK values.
+                // Given this, we need to dig deeper and get the individual values of the embeddable key.
+            	// On the other hand, if the embeddable only contains one column, 'ret' will be the value of 
+            	// that column and as such no further digging is necessary.
+                FieldMapping[] fmsPK = this.getPrimaryKeyFieldMappings();
+                List<FieldMapping> fms = getFieldMappings(cols, true);
+
+                // Note that if we are dealing with an embeddable that is an EmbeddableId, the fms.size will 
+                // always be 1 (since an EmbeddableId is slightly opaque, we don't have an fms for each field).
+                // If on the other hand we are dealing with an embeddable that is an @IdClass, fms.size will be the 
+                // number columns in the @IdClass.  Furthermore, when dealing with @IdClass, 'ret' will already  
+                // properly contain the column values, therefore no further processing is needed.
+                if (fmsPK[0].isEmbedded() && cols.length > 1 && fms.size() == 1) {
+                    // OK, we know this PK is an embeddable. So get the individual field values.
+                    Object[] tmpRet = new Object[cols.length];
+                    for (int i = 0; i < cols.length; i++) {
+                        Joinable join = this.assertJoinable(cols[i]);
+                        tmpRet[i] = join.getJoinValue(ret, cols[i], store);
+                    }
+                    ret = tmpRet;
+                }
+                // OPENJPA-2631 end
             } else if (sm.isDetached()) {
             	obj = store.getContext().find(sm.getObjectId(), false, null);
             	sm = store.getContext().getStateManager(obj);
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Subject.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Subject.java
new file mode 100644
index 0000000..1337dea
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Subject.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import java.io.Serializable;
+
+import javax.persistence.EmbeddedId;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "SUBJECT")
+public class Subject implements Serializable {
+
+	private static final long serialVersionUID = -2529380440548731281L;
+
+    @EmbeddedId
+	private SubjectKey key;
+
+	public Subject() {
+	}
+
+	public SubjectKey getKey() {
+		return key;
+	}
+
+	public void setKey(SubjectKey key) {
+		this.key = key;
+	}
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((key == null) ? 0 : key.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Subject other = (Subject) obj;
+        if (key == null) {
+            if (other.key != null)
+                return false;
+        } else if (!key.equals(other.key))
+            return false;
+        return true;
+    }
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectIdClass.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectIdClass.java
new file mode 100644
index 0000000..3c1dea0
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectIdClass.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import java.io.Serializable;
+
+public class SubjectIdClass implements Serializable {
+    
+    private Integer subjectNummer;
+
+    private String subjectTypeCode;
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((subjectNummer == null) ? 0 : subjectNummer.hashCode());
+        result = prime * result + ((subjectTypeCode == null) ? 0 : subjectTypeCode.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        SubjectIdClass other = (SubjectIdClass) obj;
+        if (subjectNummer == null) {
+            if (other.subjectNummer != null)
+                return false;
+        } else if (!subjectNummer.equals(other.subjectNummer))
+            return false;
+        if (subjectTypeCode == null) {
+            if (other.subjectTypeCode != null)
+                return false;
+        } else if (!subjectTypeCode.equals(other.subjectTypeCode))
+            return false;
+        return true;
+    }    
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectKey.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectKey.java
new file mode 100644
index 0000000..ebd78db
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectKey.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class SubjectKey implements Serializable {
+	private static final long serialVersionUID = 3714506425307136262L;
+
+	@Column(name = "SUBJECTNUMMER")
+	private Integer subjectNummer;
+
+	@Column(name = "CODE_SUBJECTTYPE")
+	private String subjectTypeCode;
+
+	public SubjectKey() {
+		super();
+	}
+
+	public SubjectKey(Integer subjectNummer, String subjectTypeCode) {
+		this.subjectNummer = subjectNummer;
+		this.subjectTypeCode = subjectTypeCode;
+	}
+
+	public Integer getSubjectNummer() {
+		return subjectNummer;
+	}
+
+	public void setSubjectNummer(Integer subjectNummer) {
+		this.subjectNummer = subjectNummer;
+	}
+
+	public String getSubjectTypeCode() {
+		return subjectTypeCode;
+	}
+
+	public void setSubjectType(String subjectType) {
+		this.subjectTypeCode = subjectType;
+	}
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((subjectNummer == null) ? 0 : subjectNummer.hashCode());
+        result = prime * result + ((subjectTypeCode == null) ? 0 : subjectTypeCode.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        SubjectKey other = (SubjectKey) obj;
+        if (subjectNummer == null) {
+            if (other.subjectNummer != null)
+                return false;
+        } else if (!subjectNummer.equals(other.subjectNummer))
+            return false;
+        if (subjectTypeCode == null) {
+            if (other.subjectTypeCode != null)
+                return false;
+        } else if (!subjectTypeCode.equals(other.subjectTypeCode))
+            return false;
+        return true;
+    }
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectKey_.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectKey_.java
new file mode 100644
index 0000000..ca3128c
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectKey_.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import javax.persistence.metamodel.SingularAttribute;
+
+@javax.persistence.metamodel.StaticMetamodel
+(value=org.apache.openjpa.persistence.embed.compositepk.SubjectKey.class)
+@javax.annotation.Generated
+(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Fri Feb 05 14:31:20 MST 2016")
+public class SubjectKey_ {
+    public static volatile SingularAttribute<SubjectKey,Integer> subjectNummer;
+    public static volatile SingularAttribute<SubjectKey,String> subjectTypeCode;
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectWithIdClass.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectWithIdClass.java
new file mode 100644
index 0000000..6c52f6a
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectWithIdClass.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "SUBJECT2")
+@IdClass(SubjectIdClass.class)
+public class SubjectWithIdClass implements Serializable {
+
+    private static final long serialVersionUID = 8038887700493762410L;
+
+    @Id
+    @Column(name = "SUBJECTNUMMER")
+    private Integer subjectNummer;
+
+    @Id
+    @Column(name = "CODE_SUBJECTTYPE")
+    private String subjectTypeCode;
+    
+	public SubjectWithIdClass() {
+	}
+
+    public void setSubjectNummer(Integer subjectNummer) {
+        this.subjectNummer = subjectNummer;
+        
+    }
+
+    public Integer getSubjectNummer() {
+        return subjectNummer;
+    }
+
+    public void setSubjectTypeCode(String subjectTypeCode) {
+        this.subjectTypeCode = subjectTypeCode;
+        
+    }
+
+    public String getSubjectTypeCode() {
+        return subjectTypeCode;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((subjectNummer == null) ? 0 : subjectNummer.hashCode());
+        result = prime * result + ((subjectTypeCode == null) ? 0 : subjectTypeCode.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        SubjectWithIdClass other = (SubjectWithIdClass) obj;
+        if (subjectNummer == null) {
+            if (other.subjectNummer != null)
+                return false;
+        } else if (!subjectNummer.equals(other.subjectNummer))
+            return false;
+        if (subjectTypeCode == null) {
+            if (other.subjectTypeCode != null)
+                return false;
+        } else if (!subjectTypeCode.equals(other.subjectTypeCode))
+            return false;
+        return true;
+    }
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectWithIdClass_.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectWithIdClass_.java
new file mode 100644
index 0000000..9b3ba4c
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/SubjectWithIdClass_.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import javax.persistence.metamodel.SingularAttribute;
+
+@javax.persistence.metamodel.StaticMetamodel
+(value=org.apache.openjpa.persistence.embed.compositepk.SubjectWithIdClass.class)
+@javax.annotation.Generated
+(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Fri Feb 05 14:31:20 MST 2016")
+public class SubjectWithIdClass_ {
+    public static volatile SingularAttribute<SubjectWithIdClass,Integer> subjectNummer;
+    public static volatile SingularAttribute<SubjectWithIdClass,String> subjectTypeCode;
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Subject_.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Subject_.java
new file mode 100644
index 0000000..6fcf76b
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Subject_.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import javax.persistence.metamodel.SingularAttribute;
+
+@javax.persistence.metamodel.StaticMetamodel
+(value=org.apache.openjpa.persistence.embed.compositepk.Subject.class)
+@javax.annotation.Generated
+(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Fri Feb 05 14:31:20 MST 2016")
+public class Subject_ {
+    public static volatile SingularAttribute<Subject,SubjectKey> key;
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/TestCompositePrimaryKeys.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/TestCompositePrimaryKeys.java
new file mode 100644
index 0000000..d6e7e7b
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/TestCompositePrimaryKeys.java
@@ -0,0 +1,538 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ParameterExpression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+
+import junit.framework.Assert;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+public class TestCompositePrimaryKeys extends SingleEMFTestCase {
+
+    // NOTE: There are 3 aspects to the fix to OPENJPA-2631, each being tested in some manner in the test
+    // methods below. The 3 aspects of the fix are:
+    //
+    // 1) Fix in ClassMapping which resolves the reported ClassCastEx.
+    // 2) After #1, things progressed further, but for some CriteriaBuilder tests incorrect SQL was created as follows:
+    // 2.1) An equals expression was created for only one of the columns in the composite PK. To
+    // resolve this a fix was made to class EqualExpression.
+    // 2.2) An extra parameter marker (?) was added to the SQL. To resolve this a fix was made to class Lit.
+
+    protected EntityManager em;
+    private EntityTransaction tx;
+
+    public void setUp() {
+        super.setUp(DROP_TABLES, Subject.class, SubjectKey.class, SubjectWithIdClass.class, Topic.class);
+        
+            em = emf.createEntityManager();
+            tx = em.getTransaction();
+            tx.begin();
+            createData();
+    }
+
+    /*
+     * OpenJPA handles this test just fine with or without the fixes of OPENJPA-2631.
+     */
+    public void testFindUsingFindOnSubjectKey() {
+
+        Subject s = createSubject();
+
+        Subject s2 = em.find(Subject.class, s.getKey());
+
+        verifySubject(s, s2);
+    }
+
+    /*
+     * OpenJPA handles this test just fine with or without the fixes of OPENJPA-2631.  This works, 
+     * compared to other tests, because a select is performed on the key class' fields.
+     */
+    public void testFindUsingEqualsOnObjectJPQL() {
+        Subject s = createSubject();
+        
+        TypedQuery<Subject> query = em.createQuery("select distinct s from Subject s where " +
+        		"s.key.subjectNummer = :subjectNummer AND s.key.subjectTypeCode = " +
+        		":subjectTypeCode", Subject.class);
+        query.setParameter("subjectNummer", s.getKey().getSubjectNummer());
+        query.setParameter("subjectTypeCode", s.getKey().getSubjectTypeCode());
+        
+        Subject s2 = query.getSingleResult();
+        
+        verifySubject(s, s2);
+    }
+
+    /*
+     * Just like the previous test, OpenJPA handles this test just fine with or without the 
+     * fixes of OPENJPA-2631.  This works, compared to other tests, because a select is 
+     * performed on the key class' fields.  This slight difference in this test compared to the
+     * previous test is that it traverses from Topic to the SubjectKey fields. 
+     */
+    public void testFindUsingJPQLEqualsOnSubjectKeyAttributes() {
+
+        Subject s = createSubject();
+
+        TypedQuery<Topic> query = em.createQuery("select distinct t from Topic t where t.subject.key.subjectNummer = " +
+                ":subjectNummer AND t.subject.key.subjectTypeCode = :subjectTypeCode", Topic.class);
+        query.setParameter("subjectNummer", s.getKey().getSubjectNummer());
+        query.setParameter("subjectTypeCode", s.getKey().getSubjectTypeCode());
+        Topic topic = query.getSingleResult();
+
+        verifyResults(topic, s);
+    }
+    
+    /*
+     * This test results in an EXPECTED exception:
+     * 
+     * ArgumentException: An error occurred while parsing the query filter 'select distinct g from Topic g where
+     * t.subject.key = :subjectKey'. Error message: JPQL query does not support conditional expression over embeddable
+     * class. JPQL string: "key".
+     * 
+     * The message in the exception tells it all. Per the spec, you can not do a compare on embeddables.
+     */
+    public void testFindUsingJPQLEqualsOnSubjectKey() {
+        try {
+            em.createQuery("select distinct t from Topic t where t.subject.key = :subjectKey");
+        } catch (Throwable t) {
+            // An exception is EXPECTED!
+            Assert.assertTrue(t.getMessage().contains("does not support conditional expression"));
+        }
+    }
+    
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * 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)
+     * 
+     * With fix #1, this test works fine.
+     */
+    public void testFindSubjectUsingJPQLEqualsOnSubject() {
+
+        Subject s = createSubject();
+
+        TypedQuery<Subject> query = em.createQuery("select s from Subject s where s = :subject", Subject.class);
+        query.setParameter("subject", s);
+        Subject s2 = query.getSingleResult();
+
+        verifySubject(s, s2);
+    }
+
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * 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)
+     * 
+     * With fix #1, this test works fine.
+     */
+    public void testFindUsingNamedQuery() {
+
+        Subject s = createSubject();
+
+        TypedQuery<Topic> q = em.createNamedQuery("bySubject", Topic.class);
+
+        q.setParameter("subject", s);
+
+        Topic topic = q.getSingleResult();
+
+        verifyResults(topic, s);
+    }
+
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * 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)
+     * 
+     * With fix #1, this test works fine.
+     */
+    public void testFindUsingJPQLEqualsOnSubject() {
+
+        Subject s = createSubject();
+
+        TypedQuery<Topic> query =
+            em.createQuery("select distinct t from Topic t where t.subject = :subject", Topic.class);
+        query.setParameter("subject", s);
+        Topic topic = query.getSingleResult();
+
+        verifyResults(topic, s);
+    }
+
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * 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)
+     * 
+     * With fix #1, the CCEx is avoided/resolved. However, we then got an incorrectly generated SQL as follows:
+     * 
+     * SELECT t0.SUBJECTNUMMER, t0.CODE_SUBJECTTYPE FROM SUBJECT t0 WHERE (t0.SUBJECTNUMMER = ?)
+     *   optimize for 1 row [params=(int) 1]
+     * 
+     * Notice that 't0.CODE_SUBJECTTYPE' is missing.  With fix #2.1 this issue is resolved.
+     * 
+     * The thing to note (which is different than the test 'findSubjectUsingCriteriaBuilderEquals' below) is that
+     * the Subject is treated as an OpenJPA 'Parameter' (see changes in EqualExpression). The test 
+     * 'findSubjectUsingCriteriaBuilderEquals' below causes the Subject to be treated as a Lit. There is 
+     * a bug in both cases, with an additional bug for the 'Lit' case.
+     */
+    public void testFindSubjectUsingCriteriaBuilderEqualsAndParameter() {
+
+        Subject s = createSubject();
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+        CriteriaQuery<Subject> cq = builder.createQuery(Subject.class);
+
+        Root<Subject> subjectRoot = cq.from(Subject.class);
+        cq.select(subjectRoot);
+
+        ParameterExpression<Subject> param1 = builder.parameter(Subject.class, "subject");
+        Predicate subjectPredicate = builder.equal(subjectRoot, param1);
+
+        cq.where(subjectPredicate);
+
+        TypedQuery<Subject> query = em.createQuery(cq);
+        query.setParameter("subject", s);
+
+        Subject s2 = query.getSingleResult();
+
+        verifySubject(s, s2);
+    }
+
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * Caused by: java.lang.ClassCastException: org.apache.openjpa.persistence.embed.compositepk.SubjectKey 
+     * cannot be cast to [Ljava.lang.Object;
+     *   at org.apache.openjpa.jdbc.kernel.exps.Lit.appendTo(Lit.java:120)
+     * 
+     * Notice the exception this time is in 'Lit'.  Previous CCEx for the other tests have been in Param.
+     * With fix #1, the CCEx is avoided/resolved. However, we then got an incorrectly generated SQL as follows:
+     * 
+     * SELECT t0.SUBJECTNUMMER, t0.CODE_SUBJECTTYPE FROM SUBJECT t0 WHERE (t0.SUBJECTNUMMER = ??)  
+     * optimize for 1 row [params=(int) 1, (String) Type]
+     * 
+     * Notice that 't0.CODE_SUBJECTTYPE' is missing, and there are two parameter markers.  With fix #2.1 and
+     * #2.2, this issue is resolved.
+     * 
+     * The other thing to note (which is different than the test 'findSubjectUsingCriteriaBuilderEqualsAndParameter'
+     * above) is that the Subject is treated as an OpenJPA 'Lit' (see changes in EqualExpression). The test
+     * 'findSubjectUsingCriteriaBuilderEqualsAndParameter' above treats the Subject as a Parameter. There is a bug in
+     * both cases, with an additional bug for the 'Lit' case.
+     */
+    public void testFindSubjectUsingCriteriaBuilderEquals() {
+
+        Subject s = createSubject();
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+        CriteriaQuery<Subject> cq = builder.createQuery(Subject.class);
+
+        Root<Subject> subjectRoot = cq.from(Subject.class);
+        cq.select(subjectRoot);
+
+        Predicate subjectPredicate = builder.equal(subjectRoot, s);
+
+        // Before the fix of JIRA OPENJPA-2631, the following was a way to fix/work around the issue, in
+        // other words, selecting the individual fields of the PK worked fine....I'll leave this here but
+        // commented out for history sake:
+        // Predicate subjectPredicate1 = builder.equal(subjectRoot.get(Subject_.key).get(SubjectKey_.subjectNummer),
+        // subject.getKey().getSubjectNummer());
+        // Predicate subjectPredicate2 = builder.equal(subjectRoot.get(Subject_.key).get(SubjectKey_.subjectTypeCode),
+        // subject.getKey().getSubjectTypeCode());
+        // Predicate subjectPredicate = builder.and(subjectPredicate1,subjectPredicate2);
+
+        cq.where(subjectPredicate);
+
+        TypedQuery<Subject> query = em.createQuery(cq);
+
+        Subject s2 = query.getSingleResult();
+
+        verifySubject(s, s2);
+    }
+
+    /*
+     * For comparison, this test does the same CriteriaBuilder code on Topic (an entity 
+     * with a single PK) as was done in the previous test to make sure it works.
+     */
+    public void testFindTopicUsingCriteriaBuilderEquals() {
+
+        Topic t = new Topic();
+        t.setId(5);
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+        CriteriaQuery<Topic> cq = builder.createQuery(Topic.class);
+
+        Root<Topic> topicRoot = cq.from(Topic.class);
+        cq.select(topicRoot);
+
+        Predicate topicPredicate = builder.equal(topicRoot, t);
+        cq.where(topicPredicate);
+
+        TypedQuery<Topic> query = em.createQuery(cq);
+
+        Topic topic = query.getSingleResult();
+
+        verifyResults(topic, createSubject());
+    }
+
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * Caused by: java.lang.ClassCastException: org.apache.openjpa.persistence.embed.compositepk.SubjectKey 
+     * cannot be cast to [Ljava.lang.Object;
+     *   at org.apache.openjpa.jdbc.kernel.exps.Lit.appendTo(Lit.java:120)
+     * 
+     * Notice the exception this time is in 'Lit'.  Previous CCEx for the other tests have been in Param.
+     * With fix #1, the CCEx is avoided/resolved. However, we then got an incorrectly generated SQL as follows:
+     * 
+     * SELECT t0.ID, t1.SUBJECTNUMMER, t1.CODE_SUBJECTTYPE FROM TOPIC t0 LEFT OUTER JOIN SUBJECT t1 ON 
+     * t0.SUBJECT_SUBJECTNUMMER = 
+     * t1.SUBJECTNUMMER AND t0.SUBJECT_CODE_SUBJECTTYPE = t1.CODE_SUBJECTTYPE WHERE (t0.SUBJECT_SUBJECTNUMMER = ??)  
+     * optimize for 1 row [params=(int) 1, (String) Type]
+     * 
+     * Notice that 't0.CODE_SUBJECTTYPE' is missing, and there are two parameter markers.  With fix #2.1 and
+     * #2.2, this issue is resolved.
+     */
+    public void testFindUsingCriteriaBuilderEquals() {
+
+        Subject s = createSubject();
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+        CriteriaQuery<Topic> cq = builder.createQuery(Topic.class);
+
+        Root<Topic> topic = cq.from(Topic.class);
+        cq.select(topic).distinct(true);
+
+        Predicate topicPredicate = builder.equal(topic.get("subject"), s);
+        cq.where(topicPredicate);
+
+        TypedQuery<Topic> query = em.createQuery(cq);
+        Topic t = query.getSingleResult();
+
+        verifyResults(t, s);
+    }
+
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * Caused by: java.lang.ClassCastException: org.apache.openjpa.persistence.embed.compositepk.SubjectKey 
+     * cannot be cast to [Ljava.lang.Object;
+     *   at org.apache.openjpa.jdbc.kernel.exps.InExpression.orContains(InExpression.java:178)
+     *   
+     * Notice this time the CCEx occurs in InExpression.  With fix #1 the issue is resolved.
+     */
+    public void testFindUsingJPQLInClauseOnSubject() {
+        Subject s = createSubject();
+        SubjectKey key = new SubjectKey(999, "Bla");
+        Subject s2 = new Subject();
+        s2.setKey(key);
+
+        List<Subject> subjectList = new ArrayList<Subject>();
+        subjectList.add(s);
+        subjectList.add(s2);
+        
+        TypedQuery<Topic> query = em.createQuery(
+                "select distinct t from Topic t where t.subject in :subjectList", Topic.class);
+        query.setParameter("subjectList", subjectList);
+        Topic t = query.getSingleResult();
+        
+        verifyResults(t, s);
+    }
+    
+    /*
+     * Prior to the fix #1 (see notes above), this fails on OJ with:
+     * 
+     * Caused by: java.lang.ClassCastException: org.apache.openjpa.persistence.embed.compositepk.SubjectKey 
+     * cannot be cast to [Ljava.lang.Object;
+     *   at org.apache.openjpa.jdbc.kernel.exps.Lit.appendTo(Lit.java:120)
+     * 
+     * Notice the exception this time is in 'Lit'.  Previous CCEx for the other tests have been in Param.
+     * 
+     * With fix #1, the CCEx is avoided/resolved. However, we then got an incorrectly generated SQL as follows:
+     * 
+     * SELECT t0.ID, t1.SUBJECTNUMMER, t1.CODE_SUBJECTTYPE FROM TOPIC t0 LEFT OUTER JOIN SUBJECT t1 ON 
+     * t0.SUBJECT_SUBJECTNUMMER = 
+     * t1.SUBJECTNUMMER AND t0.SUBJECT_CODE_SUBJECTTYPE = t1.CODE_SUBJECTTYPE WHERE (t0.SUBJECT_SUBJECTNUMMER = ??)  
+     * optimize for 1 row [params=(int) 1, (String) Type]
+     * 
+     * Notice that 't0.CODE_SUBJECTTYPE' is missing, and there are two parameter markers.  With fix #2.1 and
+     * #2.2, this issue is resolved.
+     */
+    public void testFindUsingCriteriaBuilderInClauseOnSubject() {
+
+        Subject s = createSubject();
+        SubjectKey key = new SubjectKey(999, "Bla");
+        Subject s2 = new Subject();
+        s2.setKey(key);
+
+        List<Subject> subjectList = new ArrayList<Subject>();
+        subjectList.add(s);
+        subjectList.add(s2);
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+        CriteriaQuery<Topic> cq = builder.createQuery(Topic.class);
+
+        Root<Topic> topic = cq.from(Topic.class);
+        cq.select(topic).distinct(true);
+
+        Predicate subjectInSubjectList = topic.get(Topic_.subject).in(subjectList);
+        cq.where(subjectInSubjectList);
+
+        TypedQuery<Topic> query = em.createQuery(cq);
+        Topic t = query.getSingleResult();
+
+        verifyResults(t, s);
+    }
+
+    /*
+     * This test works fine with or without the fixes.  This was added as a comparison to the case
+     * where an @EmbeddedId is used.  In other words, this query selects a Subject which uses
+     * a @IdClass (still considered an embeddable in OpenJPA).
+     */
+    public void testFindUsingJPQLEqualsOnSubjectWithIdClass() {
+        SubjectWithIdClass s = new SubjectWithIdClass();
+        s.setSubjectNummer(1);
+        s.setSubjectTypeCode("Type");
+
+            TypedQuery<SubjectWithIdClass> query =
+                em.createQuery("select s from SubjectWithIdClass s where s = :subject", SubjectWithIdClass.class);
+            
+            query.setParameter("subject", s);
+            SubjectWithIdClass s2 = query.getSingleResult();
+       
+
+        Assert.assertNotNull(s2);
+        Assert.assertEquals(s.getSubjectNummer(), s2.getSubjectNummer());
+        Assert.assertEquals(s.getSubjectTypeCode(), s2.getSubjectTypeCode());
+    }
+
+    /*
+     * For this test, the CCEx is actually never hit with or without the fixes.  However, incorrect
+     * SQL was generated as follows:
+     * 
+     * SELECT t0.SUBJECTNUMMER, t0.CODE_SUBJECTTYPE FROM SUBJECT2 t0 WHERE 
+     * (t0.SUBJECTNUMMER = ??)  optimize for 1 row [params=(int) 1, (String) Type]}
+     * 
+     * Notice that 't0.CODE_SUBJECTTYPE' is missing, and there is an extra parameter marker.  With 
+     * fix #2.1 and #2.2 this issue is resolved.
+     */
+    public void testFindUsingCriteriaBuilderOnSubjectWithIdClass() {
+        SubjectWithIdClass s = new SubjectWithIdClass();
+        s.setSubjectNummer(1);
+        s.setSubjectTypeCode("Type");
+
+        CriteriaBuilder builder = em.getCriteriaBuilder();
+        CriteriaQuery<SubjectWithIdClass> cq = builder.createQuery(SubjectWithIdClass.class);
+
+        Root<SubjectWithIdClass> subjectRoot = cq.from(SubjectWithIdClass.class);
+        cq.select(subjectRoot);
+
+        Predicate subjectPredicate = builder.equal(subjectRoot, s);
+
+        cq.where(subjectPredicate);
+
+        TypedQuery<SubjectWithIdClass> query = em.createQuery(cq);
+
+        SubjectWithIdClass s2 = query.getSingleResult();
+
+        Assert.assertNotNull(s2);
+        Assert.assertEquals(s.getSubjectNummer(), s2.getSubjectNummer());
+        Assert.assertEquals(s.getSubjectTypeCode(), s2.getSubjectTypeCode());
+    }
+    
+
+    private void createData(){
+        Subject s = new Subject();
+        SubjectKey sk = new SubjectKey();
+        sk.setSubjectNummer(1);
+        sk.setSubjectType("Type2");
+        s.setKey(sk);            
+        em.persist(s);
+        
+        s = new Subject();
+        sk = new SubjectKey();
+        sk.setSubjectNummer(1);
+        sk.setSubjectType("Type");
+        s.setKey(sk);            
+        em.persist(s);
+        
+        Topic t = new Topic();
+        t.setId(5);
+        t.setSubject(s);
+        em.persist(t);
+
+        SubjectWithIdClass swic = new SubjectWithIdClass();
+        swic.setSubjectNummer(1);
+        swic.setSubjectTypeCode("Type");
+        em.persist(swic);
+        
+        swic = new SubjectWithIdClass();
+        swic.setSubjectNummer(1);
+        swic.setSubjectTypeCode("Type2");
+        em.persist(swic);
+        
+        em.flush();
+    }
+
+    private Subject createSubject() {
+        SubjectKey key = new SubjectKey(1, "Type");
+        Subject result = new Subject();
+        result.setKey(key);
+
+        return result;
+    }
+
+    public void verifyResults(Topic topic, Subject s) {
+        Assert.assertNotNull(topic);
+        Assert.assertEquals(new Integer(5), topic.getId());
+        Subject s2 = topic.getSubject();
+        verifySubject(s, s2);
+    }
+
+    public void verifySubject(Subject expected, Subject actual) {
+        Assert.assertNotNull(expected);
+        Assert.assertEquals(expected.getKey().getSubjectNummer(), actual.getKey().getSubjectNummer());
+        Assert.assertEquals(expected.getKey().getSubjectTypeCode(), actual.getKey().getSubjectTypeCode());
+    }
+    
+    public void tearDown() {
+        if (tx != null && tx.isActive()) {
+            tx.rollback();
+            tx = null;
+        }
+
+        if (em != null && em.isOpen()) {
+            em.close();
+            em = null;
+        }
+    }    
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Topic.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Topic.java
new file mode 100644
index 0000000..1d39a33
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Topic.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "TOPIC")
+@NamedQuery(name = "bySubject", query = "SELECT t FROM Topic t WHERE t.subject = :subject")
+public class Topic {
+    @Id
+	@Column(name = "ID")
+	private Integer id;
+
+	@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
+//    @JoinColumns({ @JoinColumn(table = "TOPIC", name = "SUBJECTNUMMER", referencedColumnName = "SUBJECTNUMMER"),
+  //          @JoinColumn(table = "TOPIC", name = "CODE_SUBJECTTYPE", referencedColumnName = "CODE_SUBJECTTYPE") })
+	private Subject subject;
+
+	public Topic() {
+	}
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Subject getSubject() {
+        return subject;
+    }
+
+    public void setSubject(Subject subject) {
+        this.subject = subject;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result + ((subject == null) ? 0 : subject.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Topic other = (Topic) obj;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (subject == null) {
+            if (other.subject != null)
+                return false;
+        } else if (!subject.equals(other.subject))
+            return false;
+        return true;
+    }
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Topic_.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Topic_.java
new file mode 100644
index 0000000..564bb03
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/compositepk/Topic_.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.embed.compositepk;
+
+import javax.persistence.metamodel.SingularAttribute;
+
+@javax.persistence.metamodel.StaticMetamodel
+(value=org.apache.openjpa.persistence.embed.compositepk.Topic.class)
+@javax.annotation.Generated
+(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Fri Feb 05 14:31:20 MST 2016")
+public class Topic_ {
+    public static volatile SingularAttribute<Topic,Integer> id;
+    public static volatile SingularAttribute<Topic,Subject> subject;
+}