OPENJPA-851: xml orm support for MapKeyClass, MapKeyColumn,

MapKeyJoinColumn

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@734926 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Fay Wang 2009-01-16 06:49:30 +00:00
parent 7ce5b0dad8
commit a09954b754
10 changed files with 828 additions and 0 deletions

View File

@ -38,6 +38,7 @@ import org.apache.openjpa.jdbc.meta.ClassMappingInfo;
import org.apache.openjpa.jdbc.meta.DiscriminatorMappingInfo;
import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.FieldMappingInfo;
import org.apache.openjpa.jdbc.meta.MappingInfo;
import org.apache.openjpa.jdbc.meta.MappingRepository;
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
import org.apache.openjpa.jdbc.meta.SequenceMapping;
@ -90,6 +91,8 @@ public class XMLPersistenceMappingParser
_elems.put("join-column", JOIN_COL);
_elems.put("inverse-join-column", COL);
_elems.put("join-table", JOIN_TABLE);
_elems.put("map-key-column", MAP_KEY_COL);
_elems.put("map-key-join-column", MAP_KEY_JOIN_COL);
_elems.put("primary-key-join-column", PK_JOIN_COL);
_elems.put("secondary-table", SECONDARY_TABLE);
_elems.put("sql-result-set-mapping", SQL_RESULT_SET_MAPPING);
@ -257,6 +260,12 @@ public class XMLPersistenceMappingParser
case COLLECTION_TABLE:
ret = startCollectionTable(attrs);
break;
case MAP_KEY_COL:
ret = startMapKeyColumn(attrs);
break;
case MAP_KEY_JOIN_COL:
ret = startMapKeyJoinColumn(attrs);
break;
default:
ret = false;
}
@ -784,6 +793,39 @@ public class XMLPersistenceMappingParser
return true;
}
/**
* Parse map-key-column.
*/
private boolean startMapKeyColumn(Attributes attrs)
throws SAXException {
FieldMapping fm = (FieldMapping) peekElement();
Column col = parseColumn(attrs);
MappingInfo info = fm.getKeyMapping().getValueInfo();
List cols = new ArrayList();
cols.add(col);
info.setColumns(cols);
return true;
}
/**
* Parse map-key-join-column.
*/
private boolean startMapKeyJoinColumn(Attributes attrs)
throws SAXException {
boolean retVal = startMapKeyColumn(attrs);
// check if name is not set, set it to default: the
// concatenation of the name of the referencing property
// or field name, "-", "KEY"
FieldMapping fm = (FieldMapping) peekElement();
MappingInfo info = fm.getKeyMapping().getValueInfo();
List cols = info.getColumns();
Column col = (Column)cols.get(0);
if (col.getName() == null)
col.setName(fm.getName() + "_" + "KEY");
return retVal;
}
/**
* Create a column with the given attributes.
*/

View File

@ -0,0 +1,53 @@
/*
* 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;
import java.util.HashMap;
import java.util.Map;
public class CompanyXml {
int id;
Map<DivisionXml, VicePresidentXml> organization = new HashMap<DivisionXml, VicePresidentXml>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Map getOrganization() {
return organization;
}
public void addToOrganization(DivisionXml division, VicePresidentXml vp) {
organization.put(division, vp);
}
public void removeFromOrganization(DivisionXml d) {
organization.remove(d);
}
public VicePresidentXml getOrganization(DivisionXml d) {
return organization.get(d);
}
}

View File

@ -0,0 +1,53 @@
/*
* 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;
import java.util.HashMap;
import java.util.Map;
public class DepartmentXml {
int deptId;
Map<Integer, EmployeeXml> empMap = new HashMap<Integer, EmployeeXml>();
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public Map<Integer, EmployeeXml> getEmpMap() {
return empMap;
}
public void setEmpMap(Map<Integer, EmployeeXml> empMap) {
this.empMap = empMap;
}
public void addEmployee(EmployeeXml e) {
empMap.put(e.getEmpId(), e);
}
public void removeEmployee(Integer empId) {
empMap.remove(empId);
}
}

View File

@ -0,0 +1,42 @@
/*
* 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;
public class DivisionXml {
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;
}
}

View File

@ -0,0 +1,40 @@
/*
* 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;
public class EmployeeXml {
int empId;
DepartmentXml department;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public DepartmentXml getDepartment() {
return department;
}
public void setDepartment(DepartmentXml department) {
this.department = department;
}
}

View File

@ -0,0 +1,52 @@
/*
* 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;
import java.util.HashMap;
import java.util.Map;
public class ItemXml {
int id;
Map images = new HashMap();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Map getImages() {
return images;
}
public void addImage(String imageName, String fileName) {
images.put(imageName, fileName);
}
public void removeImage(String imageName) {
images.remove(imageName);
}
public String getImage(String imageName) {
return (String) images.get(imageName);
}
}

View File

@ -18,7 +18,9 @@
*/
package org.apache.openjpa.persistence.embed;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
@ -33,6 +35,21 @@ public class TestEmbeddableXml extends SingleEMFTestCase {
public int numEmbeddables = 1;
public int numBasicTypes = 1;
public int ID = 1;
public int deptId = 1;
public int empId = 1;
public int compId = 1;
public int divId = 1;
public int vpId = 1;
public int newDivId = 100;
public int newVpId = 100;
public int numItems = 2;
public int itemId = 1;
public int numImagesPerItem = 3;
public int numDepartments = 2;
public int numEmployeesPerDept = 2;
public int numCompany = 2;
public int numDivisionsPerCo = 2;
public void setUp() {
setUp(CLEAR_TABLES);
@ -222,4 +239,391 @@ public class TestEmbeddableXml extends SingleEMFTestCase {
tran.commit();
em.close();
}
public void testMapKeyAnnotations(){
createObj();
queryObj();
findObj();
}
public void createObj() {
createDepartments();
createCompanies();
createItems();
}
public void findObj() {
findDepartment();
findCompany();
findItem();
}
public void createDepartments() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
for (int i = 0; i < numDepartments; i++)
createDepartment(em, deptId++);
tran.begin();
em.flush();
tran.commit();
em.close();
}
public void createCompanies() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
for (int i = 0; i < numCompany; i++)
createCompany(em, compId++);
tran.begin();
em.flush();
tran.commit();
em.close();
}
public void createItems() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
for (int i = 0; i < numItems; i++)
createItem(em, itemId++);
tran.begin();
em.flush();
tran.commit();
em.close();
}
public void createItem(EntityManager em, int id) {
ItemXml item = new ItemXml();
item.setId(id);
for (int i = 0; i < numImagesPerItem; i++) {
item.addImage("image" + id + i, "file" + id + i);
}
em.persist(item);
}
public void createDepartment(EntityManager em, int id) {
DepartmentXml d = new DepartmentXml();
d.setDeptId(id);
Map emps = new HashMap();
for (int i = 0; i < numEmployeesPerDept; i++) {
EmployeeXml e = createEmployee(em, empId++);
d.addEmployee(e);
emps.put(e.getEmpId(), e);
e.setDepartment(d);
em.persist(e);
}
em.persist(d);
}
public EmployeeXml createEmployee(EntityManager em, int id) {
EmployeeXml e = new EmployeeXml();
e.setEmpId(id);
return e;
}
public void createCompany(EntityManager em, int id) {
CompanyXml c = new CompanyXml();
c.setId(id);
for (int i = 0; i < numDivisionsPerCo; i++) {
DivisionXml d = createDivision(em, divId++);
VicePresidentXml vp = createVicePresident(em, vpId++);
c.addToOrganization(d, vp);
em.persist(d);
em.persist(vp);
}
em.persist(c);
}
public DivisionXml createDivision(EntityManager em, int id) {
DivisionXml d = new DivisionXml();
d.setId(id);
d.setName("d" + id);
return d;
}
public VicePresidentXml createVicePresident(EntityManager em, int id) {
VicePresidentXml vp = new VicePresidentXml();
vp.setId(id);
vp.setName("vp" + id);
return vp;
}
public void findCompany() {
EntityManager em = emf.createEntityManager();
CompanyXml c = em.find(CompanyXml.class, 1);
assertCompany(c);
DivisionXml d = em.find(DivisionXml.class, 1);
assertDivision(d);
VicePresidentXml vp = em.find(VicePresidentXml.class, 1);
assertVicePresident(vp);
updateCompany(em, c);
em.close();
em = emf.createEntityManager();
c = em.find(CompanyXml.class, 1);
assertCompany(c);
deleteCompany(em, c);
em.close();
}
public void findDepartment() {
EntityManager em = emf.createEntityManager();
DepartmentXml d = em.find(DepartmentXml.class, 1);
assertDepartment(d);
EmployeeXml e = em.find(EmployeeXml.class, 1);
assertEmployee(e);
// updateObj by adding a new Employee
updateDepartment(em, d);
deleteDepartment(em, d);
em.close();
}
public void findItem() {
EntityManager em = emf.createEntityManager();
ItemXml item = em.find(ItemXml.class, 1);
assertItem(item);
updateItem(em, item);
deleteItem(em, item);
em.close();
}
public void updateItem(EntityManager em, ItemXml item) {
// remove an element
EntityTransaction tran = em.getTransaction();
tran.begin();
item.removeImage("image" + item.getId() + "0");
em.persist(item);
em.flush();
tran.commit();
// add an element
String key = "image" + item.getId() + "new";
tran.begin();
item.addImage(key, "file" + item.getId() + "new");
em.persist(item);
em.flush();
tran.commit();
// modify an element
tran.begin();
String fileName = item.getImage(key);
fileName = fileName + "newAgain";
item.addImage(key, fileName);
em.persist(item);
em.flush();
tran.commit();
}
public void deleteItem(EntityManager em, ItemXml item) {
EntityTransaction tran = em.getTransaction();
tran.begin();
em.remove(item);
tran.commit();
}
public void updateCompany(EntityManager em, CompanyXml c) {
EntityTransaction tran = em.getTransaction();
// remove an element
tran.begin();
Map orgs = c.getOrganization();
Set keys = orgs.keySet();
for (Object key : keys) {
DivisionXml d = (DivisionXml) key;
c.removeFromOrganization(d);
break;
}
em.persist(c);
em.flush();
tran.commit();
// add an element
tran.begin();
DivisionXml d = createDivision(em, newDivId++);
VicePresidentXml vp = createVicePresident(em, newVpId++);
c.addToOrganization(d, vp);
em.persist(d);
em.persist(vp);
em.persist(c);
em.flush();
tran.commit();
// modify an element
tran.begin();
orgs = c.getOrganization();
vp = c.getOrganization(d);
vp.setName("newNameAgain");
em.persist(c);
em.persist(vp);
em.flush();
tran.commit();
}
public void deleteCompany(EntityManager em, CompanyXml c) {
EntityTransaction tran = em.getTransaction();
tran.begin();
em.remove(c);
tran.commit();
}
public void updateDepartment(EntityManager em, DepartmentXml d) {
EntityTransaction tran = em.getTransaction();
// add an element
tran.begin();
EmployeeXml e = createEmployee(em, numDepartments * numEmployeesPerDept + 1);
d.addEmployee(e);
e.setDepartment(d);
em.persist(d);
em.persist(e);
em.flush();
tran.commit();
// remove an element
tran.begin();
d.removeEmployee(e.getEmpId());
e.setDepartment(null);
em.persist(d);
em.persist(e);
em.flush();
tran.commit();
}
public void deleteDepartment(EntityManager em, DepartmentXml d) {
EntityTransaction tran = em.getTransaction();
tran.begin();
em.remove(d);
tran.commit();
}
public void queryObj() {
queryDepartment();
queryEmployee();
queryCompany();
queryDivision();
queryVicePresident();
queryItem();
}
public void queryDepartment() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
Query q = em.createQuery("select d from DepartmentXml d");
List<DepartmentXml> ds = q.getResultList();
for (DepartmentXml d : ds) {
assertDepartment(d);
}
tran.commit();
em.close();
}
public void queryEmployee() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
Query q = em.createQuery("select e from EmployeeXml e");
List<EmployeeXml> es = q.getResultList();
for (EmployeeXml e : es) {
assertEmployee(e);
}
tran.commit();
em.close();
}
public void queryCompany() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
Query q = em.createQuery("select c from CompanyXml c");
List<CompanyXml> cs = q.getResultList();
for (CompanyXml c : cs){
assertCompany(c);
}
tran.commit();
em.close();
}
public void queryDivision() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
Query q = em.createQuery("select d from DivisionXml d");
List<DivisionXml> ds = q.getResultList();
for (DivisionXml d : ds){
assertDivision(d);
}
tran.commit();
em.close();
}
public void queryVicePresident() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
Query q = em.createQuery("select vp from VicePresidentXml vp");
List<VicePresidentXml> vps = q.getResultList();
for (VicePresidentXml vp : vps){
assertVicePresident(vp);
}
tran.commit();
em.close();
}
public void queryItem() {
EntityManager em = emf.createEntityManager();
EntityTransaction tran = em.getTransaction();
tran.begin();
Query q = em.createQuery("select i from ItemXml i");
List<ItemXml> is = q.getResultList();
for (ItemXml item : is){
assertItem(item);
}
tran.commit();
em.close();
}
public void assertDepartment(DepartmentXml d) {
int id = d.getDeptId();
Map<Integer, EmployeeXml> es = d.getEmpMap();
assertEquals(2, es.size());
Set keys = es.keySet();
for (Object obj : keys) {
Integer empId = (Integer) obj;
EmployeeXml e = es.get(empId);
assertEquals(empId.intValue(), e.getEmpId());
}
}
public void assertItem(ItemXml item) {
int id = item.getId();
Map images = item.getImages();
assertEquals(numImagesPerItem, images.size());
}
public void assertEmployee(EmployeeXml e) {
int id = e.getEmpId();
DepartmentXml d = e.getDepartment();
assertDepartment(d);
}
public void assertCompany(CompanyXml c) {
int id = c.getId();
Map organization = c.getOrganization();
assertEquals(2,organization.size());
}
public void assertDivision(DivisionXml d) {
int id = d.getId();
String name = d.getName();
}
public void assertVicePresident(VicePresidentXml vp) {
int id = vp.getId();
String name = vp.getName();
}
}

View File

@ -0,0 +1,42 @@
/*
* 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;
public class VicePresidentXml {
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;
}
}

View File

@ -52,6 +52,78 @@ version="2.0">
</attributes>
</entity>
<entity name="DepartmentXml"
class="org.apache.openjpa.persistence.embed.DepartmentXml"
access="FIELD">
<attributes>
<id name="deptId"></id>
<one-to-many name="empMap">
<map-key name="empId" />
<cascade>
<cascade-all />
</cascade>
</one-to-many>
</attributes>
</entity>
<entity name="EmployeeXml"
class="org.apache.openjpa.persistence.embed.EmployeeXml"
access="FIELD">
<attributes>
<id name="empId"></id>
<many-to-one name="department">
<join-column name="dept_id" />
</many-to-one>
</attributes>
</entity>
<entity name="ItemXml"
class="org.apache.openjpa.persistence.embed.ItemXml" access="FIELD">
<attributes>
<id name="id"></id>
<element-collection name="images"
target-entity="java.lang.String">
<column name="IMAGE_FILENAME" />
<map-key-class class="java.lang.String" />
<map-key-column name="IMAGE_NAME" />
<collection-table name="IMAGE_XML" />
</element-collection>
</attributes>
</entity>
<entity name="DivisionXml"
class="org.apache.openjpa.persistence.embed.DivisionXml"
access="FIELD">
<attributes>
<id name="id"></id>
<basic name="name" />
</attributes>
</entity>
<entity name="VicePresidentXml"
class="org.apache.openjpa.persistence.embed.VicePresidentXml"
access="FIELD">
<attributes>
<id name="id"></id>
<basic name="name" />
</attributes>
</entity>
<entity name="CompanyXml"
class="org.apache.openjpa.persistence.embed.CompanyXml"
access="FIELD">
<attributes>
<id name="id"></id>
<one-to-many name="organization">
<map-key-join-column name="DIVISION" />
<join-table name="COMPANY_ORG_XML">
<join-column name="COMPANY" />
<inverse-join-column name="VP" />
</join-table>
</one-to-many>
</attributes>
</entity>
<embeddable class="org.apache.openjpa.persistence.embed.Embed_EmbedXml"
access="FIELD">
<attributes>

View File

@ -155,6 +155,7 @@ public class XMLPersistenceMetaDataParser
_elems.put("many-to-many", MANY_MANY);
_elems.put("transient", TRANSIENT);
_elems.put("element-collection", ELEM_COLL);
_elems.put("map-key-class", MAP_KEY_CLASS);
}
private static final Localizer _loc = Localizer.forPackage
@ -655,6 +656,9 @@ public class XMLPersistenceMetaDataParser
case MAP_KEY:
ret = startMapKey(attrs);
break;
case MAP_KEY_CLASS:
ret = startMapKeyClass(attrs);
break;
case FLUSH_MODE:
ret = startFlushMode(attrs);
break;
@ -1480,6 +1484,30 @@ public class XMLPersistenceMetaDataParser
return true;
}
/**
* Parse map-key-class.
*/
private boolean startMapKeyClass(Attributes attrs)
throws SAXException {
if (!isMappingOverrideMode())
return false;
FieldMetaData fmd = (FieldMetaData) currentElement();
String mapKeyClass = attrs.getValue("class");
if (mapKeyClass != null) {
try {
fmd.getKey().setDeclaredType(Class.forName(mapKeyClass));
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Class not found");
}
} else
throw new IllegalArgumentException(
"The value of the MapKeyClass cannot be null");
return true;
}
/**
* Parse order-by.
*/