You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2009/03/05 18:30:25 UTC
svn commit: r750517 [1/4] - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/
openjpa-kernel/src/...
Author: fancy
Date: Thu Mar 5 17:30:20 2009
New Revision: 750517
URL: http://svn.apache.org/viewvc?rev=750517&view=rev
Log:
OPENJPA-879 JPA2 Query support for selecting KEY, ENTRY and VALUE of a Map value
Added:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapEntry.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapKey.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Division.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/TestMany2ManyMap.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Department.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Division.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/TestMany2ManyMapEx1.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/EmployeePK.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhonePK.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/TestMany2ManyMapEx10.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex2/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex2/Department.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex2/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex2/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex2/TestMany2ManyMapEx2.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex3/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex3/Department.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex3/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex3/FullName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex3/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex3/TestMany2ManyMapEx3.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex4/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex4/Division.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex4/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex4/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex4/TestMany2ManyMapEx4.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex5/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex5/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex5/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex5/TestMany2ManyMapEx5.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex6/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex6/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex6/FullName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex6/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex6/TestMany2ManyMapEx6.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex7/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex7/Division.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex7/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex7/FullName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex7/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex7/TestMany2ManyMapEx7.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex8/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex8/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex8/FullName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex8/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex8/TestMany2ManyMapEx8.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex9/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex9/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex9/FullName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex9/FullPhoneName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex9/PhoneNumber.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex9/TestMany2ManyMapEx9.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/Department1.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/Department2.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/Department3.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/Employee1.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/Employee2.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/Employee3.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/EmployeeName3.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/EmployeePK2.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex0/TestSpec10_1_26.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex1/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex1/Department.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex1/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex1/TestSpec10_1_26_Ex1.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex2/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex2/Department.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex2/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex2/EmployeePK.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex2/TestSpec10_1_26_Ex2.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex3/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex3/Department.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex3/Employee.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex3/EmployeeName.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/spec_10_1_26_ex3/TestSpec10_1_26_Ex3.java
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Type.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/jpql/localizer.properties
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java Thu Mar 5 17:30:20 2009
@@ -408,6 +408,14 @@
return new Type((Val) val);
}
+ public Value mapEntry(Value key, Value val) {
+ return new MapEntry((Val) key, (Val) val);
+ }
+
+ public Value mapKey(Value key, Value val) {
+ return new MapKey((Val) key, (Val) val);
+ }
+
public Value getObjectId(Value val) {
if (val instanceof Const)
return new ConstGetObjectId((Const) val);
Added: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapEntry.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapEntry.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapEntry.java (added)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapEntry.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,162 @@
+/*
+ * 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.jdbc.kernel.exps;
+
+import java.sql.SQLException;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Returns the Map.Entry<K,V> of a map value.
+ *
+ * @author Catalina Wei
+ * @since 2.0.0
+ */
+public class MapEntry
+ extends AbstractVal {
+
+ private final Val _key;
+ private final Val _val;
+ private ClassMetaData _meta = null;
+ private Class _cast = null;
+ private Class _type = null;
+
+ /**
+ * Constructor. Provide the map value to operate on.
+ */
+ public MapEntry(Val key, Val val) {
+ ((PCPath) key).getKey();
+ _key = key;
+ _val = val;
+ }
+
+ /**
+ * Expression state.
+ */
+ public static class EntryExpState
+ extends ExpState {
+ public ExpState key;
+ public ExpState val;
+
+ EntryExpState(ExpState key, ExpState val) {
+ this.key = key;
+ this.val = val;
+ }
+ }
+
+ public void appendTo(Select sel, ExpContext ctx, ExpState state,
+ SQLBuffer sql, int index) {
+ }
+
+ public void calculateValue(Select sel, ExpContext ctx, ExpState state,
+ Val other, ExpState otherState) {
+ _val.calculateValue(sel, ctx, state, other, otherState);
+ _key.calculateValue(sel, ctx, state, other, otherState);
+ }
+
+ public void groupBy(Select sel, ExpContext ctx, ExpState state) {
+ }
+
+ public ExpState initialize(Select sel, ExpContext ctx, int flags) {
+ ExpState val = _val.initialize(sel, ctx, flags);
+ ExpState key = _key.initialize(sel, ctx, flags);
+ return new EntryExpState(key, val);
+ }
+
+ public int length(Select sel, ExpContext ctx, ExpState state) {
+ return 1;
+ }
+
+ public Object load(ExpContext ctx, ExpState state, Result res)
+ throws SQLException {
+ EntryExpState estate = (EntryExpState) state;
+ Object key = _key.load(ctx, estate.key, res);
+ Object val = _val.load(ctx, estate.val, res);
+
+ return new Entry(key, val);
+ }
+
+ public void orderBy(Select sel, ExpContext ctx, ExpState state, boolean asc) {
+ }
+
+ public void select(Select sel, ExpContext ctx, ExpState state, boolean pks) {
+ EntryExpState estate = (EntryExpState) state;
+ _key.selectColumns(sel, ctx, estate.key, pks);
+ _val.selectColumns(sel, ctx, estate.val, pks);
+ }
+
+ public void selectColumns(Select sel, ExpContext ctx, ExpState state,
+ boolean pks) {
+ }
+
+ public ClassMetaData getMetaData() {
+ return _meta;
+ }
+
+ public Class getType() {
+ return Map.Entry.class;
+ }
+
+ public void setImplicitType(Class type) {
+ }
+
+ public void setMetaData(ClassMetaData meta) {
+ _meta = meta;
+ }
+
+ private class Entry<K,V> implements Map.Entry<K, V> {
+ private final K key;
+ private final V value;
+
+ public Entry(K k, V v) {
+ key = k;
+ value = v;
+ }
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public V setValue(V v) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean equals(Object other) {
+ if (other instanceof Map.Entry == false)
+ return false;
+ Map.Entry that = (Map.Entry)other;
+ return (this.key == null ?
+ that.getKey() == null : key.equals(that.getKey())) &&
+ (value == null ?
+ that.getValue() == null : value.equals(that.getValue()));
+ }
+
+ public int hashCode() {
+ return (key == null ? 0 : key.hashCode()) ^
+ (value == null ? 0 : value.hashCode());
+ }
+ }
+}
Added: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapKey.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapKey.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapKey.java (added)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/MapKey.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,122 @@
+/*
+ * 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.jdbc.kernel.exps;
+
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Returns the key of a map value.
+ *
+ * @author Catalina Wei
+ * @since 2.0.0
+ */
+public class MapKey
+ extends AbstractVal {
+
+ private final Val _key;
+ private final Val _val;
+ private ClassMetaData _meta = null;
+ private Class _cast = null;
+ private Class _type = null;
+
+ /**
+ * Constructor. Provide the map value to operate on.
+ */
+ public MapKey(Val key, Val val) {
+ ((PCPath) key).getKey();
+ _key = key;
+ _val = val;
+ }
+
+ /**
+ * Expression state.
+ */
+ public static class KeyExpState
+ extends ExpState {
+ public ExpState key;
+ public ExpState val;
+
+ KeyExpState(ExpState key, ExpState val) {
+ this.key = key;
+ this.val = val;
+ }
+ }
+
+ public void appendTo(Select sel, ExpContext ctx, ExpState state,
+ SQLBuffer sql, int index) {
+ }
+
+ public void calculateValue(Select sel, ExpContext ctx, ExpState state,
+ Val other, ExpState otherState) {
+ _val.calculateValue(sel, ctx, state, other, otherState);
+ _key.calculateValue(sel, ctx, state, other, otherState);
+ }
+
+ public void groupBy(Select sel, ExpContext ctx, ExpState state) {
+ }
+
+ public ExpState initialize(Select sel, ExpContext ctx, int flags) {
+ ExpState val = _val.initialize(sel, ctx, flags);
+ ExpState key = _key.initialize(sel, ctx, flags);
+ return new KeyExpState(key, val);
+ }
+
+ public int length(Select sel, ExpContext ctx, ExpState state) {
+ return 1;
+ }
+
+ public Object load(ExpContext ctx, ExpState state, Result res)
+ throws SQLException {
+ KeyExpState estate = (KeyExpState) state;
+ Object key = _key.load(ctx, estate.key, res);
+ return key;
+ }
+
+ public void orderBy(Select sel, ExpContext ctx, ExpState state, boolean asc) {
+ }
+
+ public void select(Select sel, ExpContext ctx, ExpState state, boolean pks) {
+ KeyExpState estate = (KeyExpState) state;
+ _key.selectColumns(sel, ctx, estate.key, pks);
+ }
+
+ public void selectColumns(Select sel, ExpContext ctx, ExpState state,
+ boolean pks) {
+ }
+
+ public ClassMetaData getMetaData() {
+ return _meta;
+ }
+
+ public Class getType() {
+ return _key.getType();
+ }
+
+ public void setImplicitType(Class type) {
+ }
+
+ public void setMetaData(ClassMetaData meta) {
+ _meta = meta;
+ }
+}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/PCPath.java Thu Mar 5 17:30:20 2009
@@ -25,11 +25,14 @@
import java.util.ListIterator;
import org.apache.commons.lang.ObjectUtils;
+import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.Discriminator;
import org.apache.openjpa.jdbc.meta.FieldMapping;
+import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
import org.apache.openjpa.jdbc.meta.ValueMapping;
+import org.apache.openjpa.jdbc.meta.strats.HandlerRelationMapTableFieldStrategy;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.schema.Schemas;
@@ -40,6 +43,7 @@
import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.StateManagerImpl;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.kernel.exps.CandidatePath;
import org.apache.openjpa.lib.util.Localizer;
@@ -240,6 +244,8 @@
if (pstate.field == null)
return _class;
if (_key) {
+ if (pstate.field.getKey().getValueMappedBy() != null)
+ return _class;
if (pstate.field.getKey().getTypeCode() == JavaTypes.PC)
return pstate.field.getKeyMapping().getTypeMapping();
return null;
@@ -363,8 +369,8 @@
public FieldMetaData last() {
Action act = lastFieldAction();
- return (act == null) ? null : isXPath() ? _xmlfield :
- (FieldMetaData) act.data;
+ return (act == null || act.op == Action.GET_KEY) ? null : isXPath() ?
+ _xmlfield : (FieldMetaData) act.data;
}
/**
@@ -395,7 +401,8 @@
if (act != null && act.op == Action.GET_XPATH)
return ((XMLMetaData) act.data).getType();
- FieldMetaData fld = (act == null) ? null : (FieldMetaData) act.data;
+ FieldMetaData fld = (act == null || act.op == Action.GET_KEY) ? null :
+ (FieldMetaData) act.data;
boolean key = act != null && act.op == Action.GET_KEY;
if (fld != null) {
switch (fld.getDeclaredTypeCode()) {
@@ -437,7 +444,7 @@
Action action;
Variable var;
Iterator itr = (_actions == null) ? null : _actions.iterator();
- FieldMapping field;
+ FieldMapping field = null;
while (itr != null && itr.hasNext()) {
action = (Action) itr.next();
@@ -459,7 +466,13 @@
} else {
// move past the previous field, if any
field = (action.op == Action.GET_XPATH) ? (FieldMapping) _xmlfield :
- (FieldMapping) action.data;
+ (action.op == Action.GET_KEY) ? field : (FieldMapping) action.data;
+
+ // mark if the next traversal should go through
+ // the key rather than value
+ key = action.op == Action.GET_KEY;
+ forceOuter |= action.op == Action.GET_OUTER;
+
if (pstate.field != null) {
// if this is the second-to-last field and the last is
// the related field this field joins to, no need to
@@ -472,11 +485,6 @@
rel = traverseField(pstate, key, forceOuter, false);
}
- // mark if the next traversal should go through
- // the key rather than value
- key = action.op == Action.GET_KEY;
- forceOuter |= action.op == Action.GET_OUTER;
-
// get mapping for the current field
pstate.field = field;
owner = pstate.field.getDefiningMapping();
@@ -515,6 +523,11 @@
if (_varName != null)
pstate.joins = pstate.joins.setVariable(_varName);
+ // if last action is key action, avoid redundant joins
+ if (key) {
+ return pstate;
+ }
+
// if we're not comparing to null or doing an isEmpty, then
// join into the data on the final field; obviously we can't do these
// joins when comparing to null b/c the whole purpose is to see
@@ -740,13 +753,29 @@
if (pks)
return mapping.getObjectId(ctx.store, res, null, true,
pstate.joins);
+ if (_key) {
+ if (pstate.field.getKey().getValueMappedBy() != null) {
+ Object obj = res.load(mapping, ctx.store, ctx.fetch,
+ pstate.joins);
+ StateManagerImpl sm = (StateManagerImpl)
+ ((PersistenceCapable) obj).pcGetStateManager();
+ obj = sm.fetch(_class.getField(pstate.field.getKey().
+ getValueMappedBy()).getIndex());
+ return obj;
+ }
+ else if (pstate.field.getKey().isEmbedded())
+ return loadEmbeddedMapKey(ctx, state, res);
+ }
+
return res.load(mapping, ctx.store, ctx.fetch, pstate.joins);
}
Object ret;
if (_key)
- ret = pstate.field.loadKeyProjection(ctx.store, ctx.fetch, res,
- pstate.joins);
+ // Map key is a java primitive type
+ // example: Map<Integer, Employee> emps
+ ret = res.getObject(pstate.cols[0],
+ JavaSQLTypes.JDBC_DEFAULT, pstate.joins);
else
ret = pstate.field.loadProjection(ctx.store, ctx.fetch, res,
pstate.joins);
@@ -755,6 +784,23 @@
return ret;
}
+ private Object loadEmbeddedMapKey(ExpContext ctx, ExpState state,
+ Result res) throws SQLException {
+ PathExpState pstate = (PathExpState) state;
+ // consume keyProjection
+ PersistenceCapable pc = (PersistenceCapable) res.load(_candidate,
+ ctx.store, ctx.fetch, pstate.joins);
+ if (pstate.field.getStrategy() == null ||
+ !(pstate.field.getStrategy() instanceof
+ HandlerRelationMapTableFieldStrategy))
+ throw new RuntimeException("Invalid map field strategy");
+ HandlerRelationMapTableFieldStrategy strategy =
+ (HandlerRelationMapTableFieldStrategy) pstate.field.getStrategy();
+ return strategy
+ .loadKey((OpenJPAStateManager) pc.pcGetStateManager(),
+ ctx.store, ctx.fetch, res, pstate.joins);
+ }
+
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
Val other, ExpState otherState) {
// we don't create the SQL b/c it forces the Select to cache aliases
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Type.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Type.java?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Type.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Type.java Thu Mar 5 17:30:20 2009
@@ -40,7 +40,8 @@
public Type(Val val) {
super(val);
setMetaData(val.getMetaData());
- _disc = ((ClassMapping) getMetaData()).getDiscriminator();
+ if (getMetaData() != null)
+ _disc = ((ClassMapping) getMetaData()).getDiscriminator();
}
public ExpState initialize(Select sel, ExpContext ctx, int flags) {
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java Thu Mar 5 17:30:20 2009
@@ -416,6 +416,18 @@
public Value type(Value target);
/**
+ * Return the map entry of the given value.
+ *
+ * @since 2.0.0
+ */
+ public Value mapEntry(Value key, Value val);
+
+ /**
+ * Return the map key of the given value
+ */
+ public Value mapKey(Value key, Value val);
+
+ /**
* Return distinct values of the given value. This is typically used
* within aggregates, for example: max(distinct(path))
*
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java Thu Mar 5 17:30:20 2009
@@ -35,6 +35,7 @@
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.util.ImplHelper;
+import org.apache.openjpa.util.UnsupportedException;
import org.apache.openjpa.util.UserException;
/**
@@ -647,6 +648,14 @@
return new Type((Val) val);
}
+ public Value mapEntry(Value key, Value val) {
+ throw new UnsupportedException("not implemented yet");
+ }
+
+ public Value mapKey(Value key, Value val) {
+ throw new UnsupportedException("not implemented yet");
+ }
+
public Value getObjectId(Value val) {
return new GetObjectId((Val) val);
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java Thu Mar 5 17:30:20 2009
@@ -49,6 +49,7 @@
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.util.InternalException;
@@ -958,6 +959,17 @@
case JJTIDENTIFICATIONVARIABLE:
return getIdentifier(node);
+ case JJTQUALIFIEDPATH:
+ // TODO: to be implemented.
+
+ case JJTQUALIFIEDIDENTIFIER:
+ // KEY(e), VALUE(e), ENTRY(e)
+ return getQualifiedIdentifier(onlyChild(node));
+
+ case JJTGENERALIDENTIFIER:
+ // KEY(e), VALUE(e)
+ return getQualifiedIdentifier(onlyChild(node));
+
case JJTNOT:
return factory.not(getExpression(onlyChild(node)));
@@ -1412,6 +1424,35 @@
new Object[]{ name }, null);
}
+ private Value getQualifiedIdentifier(JPQLNode node) {
+ JPQLNode id = onlyChild(node);
+ Path path = (Path) getValue(id);
+
+ FieldMetaData fld = path.last();
+
+ if (fld != null) {
+ // validate the field is of type java.util.Map
+ if (fld.getDeclaredTypeCode() != JavaTypes.MAP) {
+ String oper = "VALUE";
+ if (node.id == JJTENTRY)
+ oper = "ENTRY";
+ else if (node.id == JJTKEY)
+ oper = "KEY";
+ throw parseException(EX_USER, "bad-qualified-identifier",
+ new Object[]{ id.text, oper}, null);
+ }
+ }
+
+ if (node.id == JJTVALUE)
+ return path;
+
+ Value value = getValue(id);
+ if (node.id == JJTKEY)
+ return factory.mapKey(path, value);
+ else
+ return factory.mapEntry(path, value);
+ }
+
private Value getTypeLiteral(JPQLNode node) {
JPQLNode type = onlyChild(node);
final String name = type.text;
@@ -1460,7 +1501,7 @@
/**
* Process type_discriminator
* type_discriminator ::=
- * TYPE(identification_variable |
+ * TYPE(general_identification_variable |
* single_valued_object_path_expression |
* input_parameter )
*/
@@ -1475,6 +1516,9 @@
case JJTPOSITIONALINPUTPARAMETER:
return factory.type(getParameter(node.text, true, false));
+ case JJTGENERALIDENTIFIER:
+ return factory.type(getQualifiedIdentifier(onlyChild(node)));
+
default:
// TODO: enforce jpa2.0 spec rules.
// A single_valued_object_field is designated by the name of
Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/jpql/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/jpql/localizer.properties?rev=750517&r1=750516&r2=750517&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/jpql/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/jpql/localizer.properties Thu Mar 5 17:30:20 2009
@@ -73,3 +73,5 @@
jpql-parse-error: "{1}" while parsing JPQL "{0}". See nested stack trace for \
original parse error.
not-type-literal: The specified node ("{0}") is not a valid entity type literal.
+bad-qualified-identifier: The identifier "{0}" in "{1}" operator is not \
+ referring to an association field of type java.util.Map.
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Division.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Division.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Division.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Division.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,61 @@
+/*
+ * 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.jdbc.maps.m2mmapex0;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name="m2mDivision")
+public class Division {
+ @Id
+ int id;
+
+ String name;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean equals(Object o) {
+ Division d = (Division) o;
+ if (d.name.equals(name) &&
+ d.getId() == id)
+ return true;
+ return false;
+ }
+
+ public int hashCode() {
+ int ret = 0;
+ ret = ret * 31 + name.hashCode();
+ ret = ret *31 + id;
+ return ret;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Employee.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Employee.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Employee.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/Employee.java Thu Mar 5 17:30:20 2009
@@ -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.jdbc.maps.m2mmapex0;
+
+import javax.persistence.*;
+
+import java.util.*;
+
+@Entity
+@Table(name="m2mEmp")
+public class Employee {
+ @Id
+ int empId;
+
+ @ManyToMany // Bidirectional
+ Map<Division, PhoneNumber> phones =
+ new HashMap<Division, PhoneNumber>();
+
+ public Map<Division, PhoneNumber> getPhoneNumbers() {
+ return phones;
+ }
+
+ public void addPhoneNumber(Division d, PhoneNumber phoneNumber) {
+ phones.put(d, phoneNumber);
+ }
+
+ public void removePhoneNumber(Division d) {
+ phones.remove(d);
+ }
+
+ public int getEmpId() {
+ return empId;
+ }
+
+ public void setEmpId(int empId) {
+ this.empId = empId;
+ }
+
+ public boolean equals(Object o) {
+ Employee e = (Employee) o;
+ Map<Division, PhoneNumber> map = e.getPhoneNumbers();
+ if (map.size() != phones.size())
+ return false;
+ Collection<Map.Entry<Division, PhoneNumber>> entries =
+ (Collection<Map.Entry<Division, PhoneNumber>>) phones.entrySet();
+ for (Map.Entry<Division, PhoneNumber> entry : entries) {
+ Division key = entry.getKey();
+ PhoneNumber p = entry.getValue();
+ PhoneNumber p0 = map.get(key);
+ if (p.getNumber() != p0.getNumber())
+ return false;
+ }
+ return true;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/PhoneNumber.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/PhoneNumber.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/PhoneNumber.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/PhoneNumber.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,70 @@
+/*
+ * 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.jdbc.maps.m2mmapex0;
+
+import javax.persistence.*;
+
+import java.util.*;
+
+@Entity
+@Table(name="m2mPhone")
+public class PhoneNumber {
+ @Id
+ int number;
+
+ @ManyToMany(mappedBy = "phones")
+ Map<Division, Employee> emps = new HashMap<Division, Employee>();
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public Map<Division, Employee> getEmployees() {
+ return emps;
+ }
+
+ public void addEmployees(Division d, Employee employee) {
+ emps.put(d, employee);
+ }
+
+ public void removeEmployee(Division d) {
+ emps.remove(d);
+ }
+
+ public boolean equals(Object o) {
+ PhoneNumber p = (PhoneNumber) o;
+ Map<Division, Employee> map = p.getEmployees();
+ if (map.size() != emps.size())
+ return false;
+ Collection<Map.Entry<Division, Employee>> entries =
+ (Collection<Map.Entry<Division, Employee>>) emps.entrySet();
+ for (Map.Entry<Division, Employee> entry : entries) {
+ Division key = entry.getKey();
+ Employee e = entry.getValue();
+ Employee e0 = map.get(key);
+ if (e.getEmpId() != e0.getEmpId())
+ return false;
+ }
+ return true;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/TestMany2ManyMap.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/TestMany2ManyMap.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/TestMany2ManyMap.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex0/TestMany2ManyMap.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,258 @@
+/*
+ * 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.jdbc.maps.m2mmapex0;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Query;
+
+import junit.framework.Assert;
+
+import org.apache.openjpa.lib.jdbc.AbstractJDBCListener;
+import org.apache.openjpa.lib.jdbc.JDBCEvent;
+import org.apache.openjpa.lib.jdbc.JDBCListener;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+
+public class TestMany2ManyMap extends SingleEMFTestCase {
+
+ public int numEmployees = 2;
+ public int numPhoneNumbersPerEmployee = 2;
+ public Map<Integer, Employee> empMap = new HashMap<Integer, Employee>();
+ public Map<Integer, PhoneNumber> phoneMap =
+ new HashMap<Integer, PhoneNumber>();
+
+ public List<String> namedQueries = new ArrayList<String>();
+
+ public int empId = 1;
+ public int phoneId = 1;
+ public int divId = 1;
+
+ protected List<String> sql = new ArrayList<String>();
+ protected int sqlCount;
+
+ public void setUp() {
+ super.setUp(CLEAR_TABLES, Division.class,
+ Employee.class, PhoneNumber.class,
+ "openjpa.jdbc.JDBCListeners",
+ new JDBCListener[] { this.new Listener() });
+ createObj();
+ }
+
+ public void testQueryQualifiedId() throws Exception {
+ EntityManager em = emf.createEntityManager();
+
+ String query = "select KEY(e) from PhoneNumber p, " +
+ " in (p.emps) e order by e.empId";
+ List rs = em.createQuery(query).getResultList();
+ Division d = (Division) rs.get(0);
+
+ String query2 = "select KEY(p) from Employee e, " +
+ " in (e.phones) p";
+ List rs2 = em.createQuery(query2).getResultList();
+ Division d2 = (Division) rs2.get(0);
+
+ String query3 = "select VALUE(e) from PhoneNumber p, " +
+ " in (p.emps) e";
+
+ List rs3 = em.createQuery(query3).getResultList();
+ Employee e = (Employee) rs3.get(0);
+
+ em.clear();
+ String query4 = "select ENTRY(e) from PhoneNumber p, " +
+ " in (p.emps) e order by e.empId";
+ List rs4 = em.createQuery(query4).getResultList();
+ Map.Entry me = (Map.Entry) rs4.get(0);
+
+ assertTrue(d.equals(me.getKey()));
+
+ String query5 = "select TYPE(KEY(p)) from Employee e, " +
+ " in (e.phones) p";
+ List rs5 = em.createQuery(query5).getResultList();
+ assertEquals(Division.class, rs5.get(0));
+
+ em.close();
+ }
+
+ public void testQueryObject() throws Exception {
+ queryObj();
+ findObj();
+ }
+
+ public List<String> getSql() {
+ return sql;
+ }
+
+ public int getSqlCount() {
+ return sqlCount;
+ }
+
+ public void createObj() {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ for (int i = 0; i < numEmployees; i++) {
+ Employee e = createEmployee(em, empId++);
+ empMap.put(e.getEmpId(), e);
+ }
+ tran.begin();
+ em.flush();
+ tran.commit();
+ em.close();
+ }
+
+ public Employee createEmployee(EntityManager em, int id) {
+ Employee e = new Employee();
+ e.setEmpId(id);
+ for (int i = 0; i < numPhoneNumbersPerEmployee; i++) {
+ PhoneNumber phoneNumber = new PhoneNumber();
+ phoneNumber.setNumber(phoneId++);
+ Division d1 = createDivision(em, divId++);
+ Division d2 = createDivision(em, divId++);
+ phoneNumber.addEmployees(d1, e);
+ e.addPhoneNumber(d2, phoneNumber);
+ em.persist(phoneNumber);
+ phoneMap.put(phoneNumber.getNumber(), phoneNumber);
+ em.persist(d1);
+ em.persist(d2);
+ }
+ em.persist(e);
+ return e;
+ }
+
+ public Division createDivision(EntityManager em, int id) {
+ Division d = new Division();
+ d.setId(id);
+ d.setName("d" + id);
+ return d;
+ }
+
+ public void removeAll() {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ tran.begin();
+ Query q = em.createNativeQuery("delete from department");
+ q.executeUpdate();
+ q = em.createNativeQuery("delete from employee");
+ q.executeUpdate();
+ System.out.println("committing removes");
+ tran.commit();
+ em.close();
+ }
+
+ public void findObj() throws Exception {
+ EntityManager em = emf.createEntityManager();
+ Employee e = em.find(Employee.class, 1);
+ assertEmployee(e);
+
+ PhoneNumber p = em.find(PhoneNumber.class, 1);
+ assertPhoneNumber(p);
+ em.close();
+ }
+
+ public void queryObj() throws Exception {
+ queryEmployee();
+ queryPhoneNumber();
+ }
+
+ public void queryPhoneNumber() throws Exception {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ tran.begin();
+ Query q = em.createQuery("select p from PhoneNumber p");
+ List<PhoneNumber> ps = q.getResultList();
+ for (PhoneNumber p : ps) {
+ assertPhoneNumber(p);
+ }
+ tran.commit();
+ em.close();
+ }
+
+ public void queryEmployee() throws Exception {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ tran.begin();
+ Query q = em.createQuery("select e from Employee e");
+ List<Employee> es = q.getResultList();
+ for (Employee e : es) {
+ assertEmployee(e);
+ }
+ tran.commit();
+ em.close();
+ }
+
+ public void assertEmployee(Employee e) throws Exception {
+ int id = e.getEmpId();
+ Employee e0 = empMap.get(id);
+ Map<Division, PhoneNumber> phones0 = e0.getPhoneNumbers();
+ Map<Division, PhoneNumber> phones = e.getPhoneNumbers();
+ Assert.assertEquals(phones0.size(), phones.size());
+ checkPhoneMap(phones0, phones);
+ }
+
+ public void assertPhoneNumber(PhoneNumber p) throws Exception {
+ int number = p.getNumber();
+ PhoneNumber p0 = phoneMap.get(number);
+ Map<Division, Employee> es0 = p0.getEmployees();
+ Map<Division, Employee> es = p.getEmployees();
+ Assert.assertEquals(es0.size(), es.size());
+ checkEmpMap(es0, es);
+ }
+
+ public void checkPhoneMap(Map<Division, PhoneNumber> es0,
+ Map<Division, PhoneNumber> es) throws Exception {
+ Collection<Map.Entry<Division, PhoneNumber>> entrySets0 =
+ es0.entrySet();
+ for (Map.Entry<Division, PhoneNumber> entry0 : entrySets0) {
+ Division d0 = entry0.getKey();
+ PhoneNumber p0 = entry0.getValue();
+ PhoneNumber p = es.get(d0);
+ if (!p0.equals(p))
+ throw new Exception("Assertion failure");
+ }
+ }
+
+ public void checkEmpMap(Map<Division, Employee> es0,
+ Map<Division, Employee> es) throws Exception {
+ Collection<Map.Entry<Division, Employee>> entrySets0 =
+ es0.entrySet();
+ for (Map.Entry<Division, Employee> entry0 : entrySets0) {
+ Division d0 = entry0.getKey();
+ Employee e0 = entry0.getValue();
+ Employee e = es.get(d0);
+ if (!e0.equals(e))
+ throw new Exception("Assertion failure");
+ }
+ }
+
+ public class Listener extends AbstractJDBCListener {
+ @Override
+ public void beforeExecuteStatement(JDBCEvent event) {
+ if (event.getSQL() != null && sql != null) {
+ sql.add(event.getSQL());
+ sqlCount++;
+ }
+ }
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Department.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Department.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Department.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Department.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,65 @@
+/*
+ * 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.jdbc.maps.m2mmapex1;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="MEx1Dept")
+public class Department {
+ @Id
+ int id;
+
+ String name;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof Department))
+ return false;
+ Department other = (Department) o;
+ if (name.equals(other.name) &&
+ id == other.id)
+ return true;
+ return false;
+ }
+
+ public int hashCode() {
+ int ret = 0;
+ ret = ret * 31 + name.hashCode();
+ ret = ret *31 + id;
+ return ret;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Division.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Division.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Division.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Division.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,65 @@
+/*
+ * 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.jdbc.maps.m2mmapex1;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="MEx1Division")
+public class Division {
+ @Id
+ int id;
+
+ String name;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean equals(Object o) {
+ if (!(o instanceof Division))
+ return false;
+ Division other = (Division) o;
+ if (name.equals(other.name) &&
+ id == other.id)
+ return true;
+ return false;
+ }
+
+ public int hashCode() {
+ int ret = 0;
+ ret = ret * 31 + name.hashCode();
+ ret = ret *31 + id;
+ return ret;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Employee.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Employee.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Employee.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/Employee.java Thu Mar 5 17:30:20 2009
@@ -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.jdbc.maps.m2mmapex1;
+
+import javax.persistence.*;
+
+import java.util.*;
+
+@Entity
+@Table(name="MEx1Emp")
+public class Employee {
+ @Id
+ int empId;
+
+ @ManyToMany
+ Map<Department, PhoneNumber> phones =
+ new HashMap<Department, PhoneNumber>();
+
+ public Map<Department, PhoneNumber> getPhoneNumbers() {
+ return phones;
+ }
+
+ public void addPhoneNumber(Department d, PhoneNumber phoneNumber) {
+ phones.put(d, phoneNumber);
+ }
+
+ public void removePhoneNumber(Department d) {
+ phones.remove(d);
+ }
+
+ public int getEmpId() {
+ return empId;
+ }
+
+ public void setEmpId(int empId) {
+ this.empId = empId;
+ }
+
+ public boolean equals(Object o) {
+ Employee e = (Employee) o;
+ Map<Department, PhoneNumber> map = e.getPhoneNumbers();
+ if (map.size() != phones.size())
+ return false;
+ Collection<Map.Entry<Department, PhoneNumber>> entries =
+ (Collection<Map.Entry<Department, PhoneNumber>>) phones.entrySet();
+ for (Map.Entry<Department, PhoneNumber> entry : entries) {
+ Department key = entry.getKey();
+ PhoneNumber p = entry.getValue();
+ PhoneNumber p0 = map.get(key);
+ if (p.getNumber() != p0.getNumber())
+ return false;
+ }
+ return true;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/PhoneNumber.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/PhoneNumber.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/PhoneNumber.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/PhoneNumber.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,69 @@
+/*
+ * 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.jdbc.maps.m2mmapex1;
+
+import javax.persistence.*;
+
+import java.util.*;
+
+@Entity
+@Table(name="MEx1Phone")
+public class PhoneNumber {
+ @Id int number;
+
+ @ManyToMany(mappedBy="phones")
+ Map<Division, Employee> emps = new HashMap<Division, Employee>();
+
+ public int getNumber() {
+ return number;
+ }
+
+ public void setNumber(int number) {
+ this.number = number;
+ }
+
+ public Map<Division, Employee> getEmployees() {
+ return emps;
+ }
+
+ public void addEmployees(Division d, Employee employee) {
+ emps.put(d, employee);
+ }
+
+ public void removeEmployee(Division d) {
+ emps.remove(d);
+ }
+
+ public boolean equals(Object o) {
+ PhoneNumber p = (PhoneNumber) o;
+ Map<Division, Employee> map = p.getEmployees();
+ if (map.size() != emps.size())
+ return false;
+ Collection<Map.Entry<Division, Employee>> entries =
+ (Collection<Map.Entry<Division, Employee>>) emps.entrySet();
+ for (Map.Entry<Division, Employee> entry : entries) {
+ Division key = entry.getKey();
+ Employee e = entry.getValue();
+ Employee e0 = map.get(key);
+ if (e.getEmpId() != e0.getEmpId())
+ return false;
+ }
+ return true;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/TestMany2ManyMapEx1.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/TestMany2ManyMapEx1.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/TestMany2ManyMapEx1.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex1/TestMany2ManyMapEx1.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,248 @@
+/*
+ * 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.jdbc.maps.m2mmapex1;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Query;
+
+import junit.framework.Assert;
+
+import org.apache.openjpa.lib.jdbc.AbstractJDBCListener;
+import org.apache.openjpa.lib.jdbc.JDBCEvent;
+import org.apache.openjpa.lib.jdbc.JDBCListener;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+public class TestMany2ManyMapEx1 extends SingleEMFTestCase {
+
+ public int numEmployees = 2;
+ public int numPhoneNumbersPerEmployee = 2;
+
+ public Map<Integer, Employee> empMap = new HashMap<Integer, Employee>();
+ public Map<Integer, PhoneNumber> phoneMap =
+ new HashMap<Integer, PhoneNumber>();
+
+ public List<String> namedQueries = new ArrayList<String>();
+
+ public int empId = 1;
+ public int phoneId = 1;
+ public int divId = 1;
+ public int deptId = 10;
+
+ protected List<String> sql = new ArrayList<String>();
+ protected int sqlCount;
+
+ public void setUp() {
+ super.setUp(CLEAR_TABLES,
+ Department.class,
+ Division.class,
+ Employee.class,
+ PhoneNumber.class,
+ "openjpa.jdbc.JDBCListeners",
+ new JDBCListener[] {
+ this.new Listener()
+ });
+
+ createObj(emf);
+ }
+
+ public void testQueryQualifiedId() throws Exception {
+ EntityManager em = emf.createEntityManager();
+ String query = "select KEY(e), p from PhoneNumber p, " +
+ " in (p.emps) e order by e.empId";
+ List rs = em.createQuery(query).getResultList();
+ Division d = (Division) ((Object[]) rs.get(0))[0];
+ PhoneNumber p = (PhoneNumber) ((Object[]) rs.get(0))[1];
+
+ String query2 = "select KEY(p) from Employee e, " +
+ " in (e.phones) p";
+ List rs2 = em.createQuery(query2).getResultList();
+ Department d2 = (Department) rs2.get(0);
+
+ em.clear();
+ String query4 = "select ENTRY(e) from PhoneNumber p, " +
+ " in (p.emps) e order by e.empId";
+ List rs4 = em.createQuery(query4).getResultList();
+ Map.Entry me = (Map.Entry) rs4.get(0);
+
+ assertTrue(d.equals(me.getKey()));
+
+ em.close();
+ }
+
+ public void testQueryObject() throws Exception {
+ queryObj(emf);
+ findObj(emf);
+ }
+
+ public List<String> getSql() {
+ return sql;
+ }
+
+ public int getSqlCount() {
+ return sqlCount;
+ }
+
+ public void createObj(EntityManagerFactory emf) {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ for (int i = 0; i < numEmployees; i++) {
+ Employee e = createEmployee(em, empId++);
+ empMap.put(e.getEmpId(), e);
+ }
+ tran.begin();
+ em.flush();
+ tran.commit();
+ em.close();
+ }
+
+ public Employee createEmployee(EntityManager em, int id) {
+ Employee e = new Employee();
+ e.setEmpId(id);
+ for (int i = 0; i < numPhoneNumbersPerEmployee; i++) {
+ PhoneNumber phoneNumber = new PhoneNumber();
+ phoneNumber.setNumber(phoneId++);
+ Division div = createDivision(em, divId++);
+ Department dept = createDepartment(em, deptId++);
+ phoneNumber.addEmployees(div, e);
+ e.addPhoneNumber(dept, phoneNumber);
+ phoneMap.put(phoneNumber.getNumber(), phoneNumber);
+ em.persist(phoneNumber);
+ em.persist(dept);
+ em.persist(div);
+ }
+ em.persist(e);
+ return e;
+ }
+
+ public Division createDivision(EntityManager em, int id) {
+ Division d = new Division();
+ d.setId(id);
+ d.setName("d" + id);
+ return d;
+ }
+
+ public Department createDepartment(EntityManager em, int id) {
+ Department d = new Department();
+ d.setId(id);
+ d.setName("dept" + id);
+ return d;
+ }
+
+ public void findObj(EntityManagerFactory emf) throws Exception {
+ EntityManager em = emf.createEntityManager();
+ Employee e = em.find(Employee.class, 1);
+ assertEmployee(e);
+
+ PhoneNumber p = em.find(PhoneNumber.class, 1);
+ assertPhoneNumber(p);
+ em.close();
+ }
+
+ public void queryObj(EntityManagerFactory emf) throws Exception {
+ queryEmployee(emf);
+ queryPhoneNumber(emf);
+ }
+
+ public void queryPhoneNumber(EntityManagerFactory emf) throws Exception {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ tran.begin();
+ Query q = em.createQuery("select p from PhoneNumber p");
+ List<PhoneNumber> ps = q.getResultList();
+ for (PhoneNumber p : ps) {
+ assertPhoneNumber(p);
+ }
+ tran.commit();
+ em.close();
+ }
+
+ public void queryEmployee(EntityManagerFactory emf) throws Exception {
+ EntityManager em = emf.createEntityManager();
+ EntityTransaction tran = em.getTransaction();
+ tran.begin();
+ Query q = em.createQuery("select e from Employee e");
+ List<Employee> es = q.getResultList();
+ for (Employee e : es) {
+ assertEmployee(e);
+ }
+ tran.commit();
+ em.close();
+ }
+
+ public void assertEmployee(Employee e) throws Exception {
+ int id = e.getEmpId();
+ Employee e0 = empMap.get(id);
+ Map<Department, PhoneNumber> phones0 = e0.getPhoneNumbers();
+ Map<Department, PhoneNumber> phones = e.getPhoneNumbers();
+ Assert.assertEquals(phones0.size(), phones.size());
+ checkPhoneMap(phones0, phones);
+ }
+
+ public void assertPhoneNumber(PhoneNumber p) throws Exception {
+ int number = p.getNumber();
+ PhoneNumber p0 = phoneMap.get(number);
+ Map<Division, Employee> es0 = p0.getEmployees();
+ Map<Division, Employee> es = p.getEmployees();
+ Assert.assertEquals(es0.size(), es.size());
+ checkEmpMap(es0, es);
+ }
+
+ public void checkPhoneMap(Map<Department, PhoneNumber> es0,
+ Map<Department, PhoneNumber> es) throws Exception {
+ Collection<Map.Entry<Department, PhoneNumber>> entrySets0 =
+ es0.entrySet();
+ for (Map.Entry<Department, PhoneNumber> entry0 : entrySets0) {
+ Department d0 = entry0.getKey();
+ PhoneNumber p0 = entry0.getValue();
+ PhoneNumber p = es.get(d0);
+ if (!p0.equals(p))
+ throw new Exception("Assertion failure");
+ }
+ }
+
+ public void checkEmpMap(Map<Division, Employee> es0,
+ Map<Division, Employee> es) throws Exception {
+ Collection<Map.Entry<Division, Employee>> entrySets0 = es0.entrySet();
+ for (Map.Entry<Division, Employee> entry0 : entrySets0) {
+ Division d0 = entry0.getKey();
+ Employee e0 = entry0.getValue();
+ Employee e = es.get(d0);
+ if (!e0.equals(e))
+ throw new Exception("Assertion failure");
+ }
+ }
+
+ public class Listener extends AbstractJDBCListener {
+ @Override
+ public void beforeExecuteStatement(JDBCEvent event) {
+ if (event.getSQL() != null && sql != null) {
+ sql.add(event.getSQL());
+ sqlCount++;
+ }
+ }
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/Employee.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/Employee.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/Employee.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/Employee.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,81 @@
+/*
+ * 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.jdbc.maps.m2mmapex10;
+
+import javax.persistence.*;
+
+import java.util.*;
+
+@Entity
+@Table(name="MEx10Emp")
+public class Employee {
+ @EmbeddedId
+ EmployeePK empPK;
+
+ @ManyToMany // Bidirectional
+ Map<PhonePK, PhoneNumber> phones = new HashMap<PhonePK, PhoneNumber>();
+
+ int salary;
+
+ public EmployeePK getEmpPK() {
+ return empPK;
+ }
+
+ public void setEmpPK(EmployeePK empPK) {
+ this.empPK = empPK;
+ }
+
+
+ public Map<PhonePK, PhoneNumber> getPhoneNumbers() {
+ return phones;
+ }
+
+ public void addPhoneNumber(PhonePK d, PhoneNumber phoneNumber) {
+ phones.put(d, phoneNumber);
+ }
+
+ public void removePhoneNumber(PhonePK d) {
+ phones.remove(d);
+ }
+
+ public int getSalary() {
+ return salary;
+ }
+
+ public void setSalary(int salary) {
+ this.salary = salary;
+ }
+
+ public boolean equals(Object o) {
+ Employee e = (Employee) o;
+ Map<PhonePK, PhoneNumber> map = e.getPhoneNumbers();
+ if (map.size() != phones.size())
+ return false;
+ Collection<Map.Entry<PhonePK, PhoneNumber>> entries =
+ (Collection<Map.Entry<PhonePK, PhoneNumber>>) phones.entrySet();
+ for (Map.Entry<PhonePK, PhoneNumber> entry : entries) {
+ PhonePK key = entry.getKey();
+ PhoneNumber p = entry.getValue();
+ PhoneNumber p0 = map.get(key);
+ if (!p.getPhonePK().equals(p0.getPhonePK()))
+ return false;
+ }
+ return true;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/EmployeePK.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/EmployeePK.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/EmployeePK.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/EmployeePK.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,55 @@
+/*
+ * 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.jdbc.maps.m2mmapex10;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.*;
+
+@Embeddable
+public class EmployeePK implements Serializable {
+ String name;
+ Date bDay;
+
+ public EmployeePK() {}
+ public EmployeePK(String name, Date bDay) {
+ this.name = name;
+ this.bDay = bDay;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof EmployeePK))
+ return false;
+ EmployeePK pk = (EmployeePK) o;
+ if (pk.name.equals(name) &&
+ pk.bDay.equals(bDay))
+ return true;
+ return false;
+ }
+
+ public int hashCode() {
+ int code = 0;
+ code += name.hashCode();
+ code += bDay.hashCode();
+ return code;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhoneNumber.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhoneNumber.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhoneNumber.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhoneNumber.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,80 @@
+/*
+ * 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.jdbc.maps.m2mmapex10;
+
+import javax.persistence.*;
+
+import java.util.*;
+
+@Entity
+@Table(name="MEx10Phone")
+public class PhoneNumber {
+ @EmbeddedId
+ PhonePK phonePK;
+
+ @ManyToMany(mappedBy="phones")
+ Map<EmployeePK, Employee> emps = new HashMap<EmployeePK, Employee>();
+
+ int room;
+
+ public PhonePK getPhonePK() {
+ return phonePK;
+ }
+
+ public void setPhonePK(PhonePK phonePK) {
+ this.phonePK = phonePK;
+ }
+
+ public Map<EmployeePK, Employee> getEmployees() {
+ return emps;
+ }
+
+ public void addEmployees(EmployeePK d, Employee employee) {
+ emps.put(d, employee);
+ }
+
+ public void removeEmployee(EmployeePK d) {
+ emps.remove(d);
+ }
+
+ public int getRoom() {
+ return room;
+ }
+
+ public void setRoom(int room) {
+ this.room = room;
+ }
+
+ public boolean equals(Object o) {
+ PhoneNumber p = (PhoneNumber) o;
+ Map<EmployeePK, Employee> map = p.getEmployees();
+ if (map.size() != emps.size())
+ return false;
+ Collection<Map.Entry<EmployeePK, Employee>> entries =
+ (Collection<Map.Entry<EmployeePK, Employee>>) emps.entrySet();
+ for (Map.Entry<EmployeePK, Employee> entry : entries) {
+ EmployeePK key = entry.getKey();
+ Employee e0 = map.get(key);
+ Employee e = emps.get(key);
+ if (!e.getEmpPK().equals(e0.getEmpPK()))
+ return false;
+ }
+ return true;
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhonePK.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhonePK.java?rev=750517&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhonePK.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/maps/m2mmapex10/PhonePK.java Thu Mar 5 17:30:20 2009
@@ -0,0 +1,54 @@
+/*
+ * 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.jdbc.maps.m2mmapex10;
+
+import java.io.Serializable;
+
+import javax.persistence.*;
+
+@Embeddable
+public class PhonePK implements Serializable {
+ String areaCode;
+ String phoneNum;
+
+ public PhonePK() {}
+ public PhonePK(String areaCode, String phoneNum) {
+ this.areaCode = areaCode;
+ this.phoneNum = phoneNum;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof PhonePK))
+ return false;
+ PhonePK pk = (PhonePK) o;
+ if (pk.areaCode.equals(areaCode) &&
+ pk.phoneNum.equals(phoneNum))
+ return true;
+ return false;
+ }
+
+ public int hashCode() {
+ int code = 0;
+ code = code * 31 + areaCode.hashCode();
+ code = code * 31 + phoneNum.hashCode();
+ return code;
+ }
+}