From 0f45f13fc297d6b73c12e3e0a0b0b155112d4457 Mon Sep 17 00:00:00 2001 From: Jeremy Bauer Date: Wed, 1 Jul 2009 12:52:56 +0000 Subject: [PATCH] OPENJPA-1135 Correct access type related issues with attribute overrides and multi-level parsing. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@790150 13f79535-47bb-0310-9956-ffa450edef68 --- .../embed/attrOverrides/AnnoOverEmbed.java | 48 +++++++++++ .../attrOverrides/TestAttrOverridesXml.java | 36 +++++++- .../embed/attrOverrides/XMLOverEntity.java | 42 +++++++++ .../inheritance/TestCallbackEntity.java | 69 +++++++++++++++ .../inheritance/entity/BaseCallback.java | 41 +++++++++ .../inheritance/entity/XMLCallback.java | 31 +++++++ .../inheritance/entity/XMLSuperCallback.java | 51 +++++++++++ .../persistence/xml/TestSimpleXmlEntity.java | 4 +- .../xml/TestXmlOverrideEntity.java | 4 +- .../test/resources/META-INF/persistence.xml | 17 +++- .../openjpa/persistence/embed/embed-orm.xml | 16 ++++ .../openjpa/persistence/inheritance/orm.xml | 37 ++++++++ .../PersistenceMetaDataDefaults.java | 12 ++- .../PersistenceMetaDataFactory.java | 42 +++++++-- .../XMLPersistenceMetaDataParser.java | 85 ++++++++++++++++++- .../openjpa/persistence/localizer.properties | 1 + 16 files changed, 523 insertions(+), 13 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/AnnoOverEmbed.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/XMLOverEntity.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/TestCallbackEntity.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/BaseCallback.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLCallback.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLSuperCallback.java create mode 100644 openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/inheritance/orm.xml diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/AnnoOverEmbed.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/AnnoOverEmbed.java new file mode 100644 index 000000000..f5e9a21ba --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/AnnoOverEmbed.java @@ -0,0 +1,48 @@ +/* + * 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.attrOverrides; + +import javax.persistence.Basic; +import javax.persistence.Embeddable; + +@Embeddable +public class AnnoOverEmbed { + + @Basic + private int intEmbed; + + @Basic + private String strEmbed; + + public void setIntEmbed(int intEmbed) { + this.intEmbed = intEmbed; + } + + public int getIntEmbed() { + return intEmbed; + } + + public void setStrEmbed(String strEmbed) { + this.strEmbed = strEmbed; + } + + public String getStrEmbed() { + return strEmbed; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/TestAttrOverridesXml.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/TestAttrOverridesXml.java index fa9bf9ab9..10fcbd600 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/TestAttrOverridesXml.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/TestAttrOverridesXml.java @@ -45,7 +45,9 @@ public class TestAttrOverridesXml extends SQLListenerTestCase { public int eId = 1; public void setUp() { - setUp(DROP_TABLES); + setUp( + org.apache.openjpa.persistence.embed.attrOverrides.AnnoOverEmbed.class, + DROP_TABLES); } @Override @@ -92,6 +94,38 @@ public class TestAttrOverridesXml extends SQLListenerTestCase { em.close(); } + /** + * This test verifies that an XML defined entity with an annotated + * only embeddable has attribute overrides applied correctly. + */ + public void testXMLEntityWithAnnotatedOverrideEmbed() { + OpenJPAEntityManagerSPI em = emf.createEntityManager(); + + XMLOverEntity xoe = new XMLOverEntity(); + xoe.setId(new Random().nextInt()); + + AnnoOverEmbed aoe = new AnnoOverEmbed(); + aoe.setIntEmbed(1); + aoe.setStrEmbed("StrVal"); + xoe.setEmbed(aoe); + + em.getTransaction().begin(); + em.persist(xoe); + em.getTransaction().commit(); + + assertTrue(verifyColumnOverride(em, "XMLOverEntity", + "intOverEmbed")); + assertFalse(verifyColumnOverride(em, "XMLOverEntity", + "intEmbed")); + + assertTrue(verifyColumnOverride(em, "XMLOverEntity", + "strOverEmbed")); + assertFalse(verifyColumnOverride(em, "XMLOverEntity", + "strEmbed")); + + em.close(); + } + public void createObj1() { EntityManager em = emf.createEntityManager(); EntityTransaction tran = em.getTransaction(); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/XMLOverEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/XMLOverEntity.java new file mode 100644 index 000000000..ff90e2ee5 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/embed/attrOverrides/XMLOverEntity.java @@ -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.attrOverrides; + +public class XMLOverEntity { + + private int id; + + private AnnoOverEmbed embed; + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setEmbed(AnnoOverEmbed embed) { + this.embed = embed; + } + + public AnnoOverEmbed getEmbed() { + return embed; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/TestCallbackEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/TestCallbackEntity.java new file mode 100644 index 000000000..fb011c9c8 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/TestCallbackEntity.java @@ -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.inheritance; + +import java.util.Random; + +import javax.persistence.EntityManager; + +import org.apache.openjpa.persistence.inheritance.entity.BaseCallback; +import org.apache.openjpa.persistence.inheritance.entity.XMLCallback; +import org.apache.openjpa.persistence.inheritance.entity.XMLSuperCallback; +import org.apache.openjpa.persistence.test.SingleEMFTestCase; + +public class TestCallbackEntity + extends SingleEMFTestCase { + + @Override + protected String getPersistenceUnitName() { + return "AbstractCallbackPU"; + } + + /* + * This test verifies that the persistence metadata factory can create + * and use separate copies of the XML metadata parser when a domain model + * contains a base class with unknown access type and multi-level + * inheritance of XML defined types. Per JPA spec, the superclass must + * be queried to determine the access type. + */ + public void testCallbackEntity() { + + EntityManager em = emf.createEntityManager(); + BaseCallback bc = new BaseCallback(); + bc.setId(new Random().nextInt()); + bc.setName("BaseCallback"); + + // Persist the entity + em.getTransaction().begin(); + em.persist(bc); + em.getTransaction().commit(); + + // Assert callbacks fire expected # of times + assertEquals(1, BaseCallback.postPersistCount); + assertEquals(1, XMLCallback.prePersistCount); + assertEquals(1, XMLSuperCallback.postPersistCount); + + // Remove the entity + em.getTransaction().begin(); + em.remove(bc); + em.getTransaction().commit(); + + em.close(); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/BaseCallback.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/BaseCallback.java new file mode 100644 index 000000000..8287add47 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/BaseCallback.java @@ -0,0 +1,41 @@ +/* + * 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.inheritance.entity; + +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.PostPersist; + +/* + * Annotated entity class with no persistent attributes or access type + * defined. This is necessary to force query of the superclass to determine + * the default access type. + */ +@Entity +@Inheritance(strategy=InheritanceType.SINGLE_TABLE) +public class BaseCallback extends XMLCallback { + + public transient static int postPersistCount = 0; + + @PostPersist + public void basePostPersist() { + postPersistCount++; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLCallback.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLCallback.java new file mode 100644 index 000000000..80ecda0b7 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLCallback.java @@ -0,0 +1,31 @@ +/* + * 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.inheritance.entity; + +/* + * XML defined class with no persistent attributes, only a callback. + */ +public class XMLCallback extends XMLSuperCallback { + + public transient static int prePersistCount = 0; + + public void prePersist() { + prePersistCount++; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLSuperCallback.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLSuperCallback.java new file mode 100644 index 000000000..8939d5a56 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/inheritance/entity/XMLSuperCallback.java @@ -0,0 +1,51 @@ +/* + * 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.inheritance.entity; + +/* + * XML defined entity superclass with no persistent attributes. + */ +public class XMLSuperCallback { + + private int id; + + private String name; + + public transient static int postPersistCount = 0; + + public void superPostPersist() { + postPersistCount++; + } + + public void setId(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestSimpleXmlEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestSimpleXmlEntity.java index 96c3baa00..f1672dd76 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestSimpleXmlEntity.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestSimpleXmlEntity.java @@ -25,7 +25,9 @@ public class TestSimpleXmlEntity extends SingleEMTestCase { public void setUp() { - setUp(CLEAR_TABLES); + setUp( + org.apache.openjpa.persistence.embed.attrOverrides.AnnoOverEmbed.class, + CLEAR_TABLES); } protected String getPersistenceUnitName() { diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestXmlOverrideEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestXmlOverrideEntity.java index da21bff14..07c7c63c2 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestXmlOverrideEntity.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/xml/TestXmlOverrideEntity.java @@ -34,7 +34,9 @@ import org.apache.openjpa.persistence.test.SingleEMFTestCase; public class TestXmlOverrideEntity extends SingleEMFTestCase { public void setUp() throws ClassNotFoundException { - setUp(CLEAR_TABLES); + setUp( + org.apache.openjpa.persistence.embed.attrOverrides.AnnoOverEmbed.class, + CLEAR_TABLES); // make sure that XmlOverrideEntity is registered for our metadata tests Class.forName(XmlOverrideEntity.class.getName(), true, diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml index 32dca1341..e3db03917 100644 --- a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml @@ -47,7 +47,8 @@ org/apache/openjpa/persistence/access/access-pudef-prop-orm.xml org/apache/openjpa/persistence/jdbc/order/order-orm.xml org/apache/openjpa/persistence/jdbc/order/order-orm-2.xml - org/apache/openjpa/persistence/jdbc/order/order-orm-3.xml + org/apache/openjpa/persistence/jdbc/order/order-orm-3.xml + org/apache/openjpa/persistence/inheritance/orm.xml @@ -120,6 +121,8 @@ org.apache.openjpa.persistence.embed.OrderXml org.apache.openjpa.persistence.embed.attrOverrides.AddressXml org.apache.openjpa.persistence.embed.attrOverrides.ZipcodeXml + org.apache.openjpa.persistence.embed.attrOverrides.XMLOverEntity + org.apache.openjpa.persistence.embed.attrOverrides.AnnoOverEmbed @@ -170,4 +173,16 @@ value="buildSchema"/> + + PU for testing with an entity with no persistent attributes + org.apache.openjpa.persistence.PersistenceProviderImpl + org/apache/openjpa/persistence/inheritance/orm.xml + org.apache.openjpa.persistence.inheritance.entity.BaseCallback + org.apache.openjpa.persistence.inheritance.entity.XMLCallback + org.apache.openjpa.persistence.inheritance.entity.XMLSuperCallback + + + + diff --git a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/embed/embed-orm.xml b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/embed/embed-orm.xml index 25eb072ab..294900f54 100644 --- a/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/embed/embed-orm.xml +++ b/openjpa-persistence-jdbc/src/test/resources/org/apache/openjpa/persistence/embed/embed-orm.xml @@ -199,6 +199,22 @@ version="2.0"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java index 19d488a81..f5625e179 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataDefaults.java @@ -279,7 +279,8 @@ public class PersistenceMetaDataDefaults return null; Class cls = meta.getDescribedType(); Class sup = cls.getSuperclass(); - if (sup == null) + if (sup == null || "java.lang.Object".equals( + sup.getName())) return null; MetaDataRepository repos = meta.getRepository(); ClassMetaData supMeta = repos.getCachedMetaData(sup); @@ -309,8 +310,13 @@ public class PersistenceMetaDataDefaults return access; ClassMetaData sup = getCachedSuperclassMetaData(meta); - while (sup != null && sup.isExplicitAccess()) - sup = getCachedSuperclassMetaData(sup); + ClassMetaData tmpSup = sup; + while (tmpSup != null && tmpSup.isExplicitAccess()) { + tmpSup = getCachedSuperclassMetaData(tmpSup); + if (tmpSup != null) { + sup = tmpSup; + } + } if (sup != null && !AccessCode.isUnknown(sup)) return sup.getAccessType(); diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java index fe6792a9f..400632b90 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceMetaDataFactory.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.security.AccessController; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -29,6 +30,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.Stack; + import javax.persistence.Embeddable; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; @@ -84,6 +87,9 @@ public class PersistenceMetaDataFactory private Set _unparsed = null; // xml rsrc private boolean _fieldOverride = true; + protected Stack _stack = + new Stack(); + /** * Whether to use field-level override or class-level override. * Defaults to true. @@ -141,11 +147,23 @@ public class PersistenceMetaDataFactory } /** - * Return XML metadata parser, creating it if it does not already exist. + * Return XML metadata parser, creating it if it does not already exist or + * if the existing parser is parsing. */ public XMLPersistenceMetaDataParser getXMLParser() { - if (_xmlParser == null) { + if (_xmlParser == null || _xmlParser.isParsing()) { + Class parseCls = null; + ArrayList> parseList = null; + // If there is an existing parser and it is parsing, push it on + // the stack and return a new one. + if (_xmlParser != null) { + _stack.push(_xmlParser); + parseCls = _xmlParser.getParseClass(); + parseList = _xmlParser.getParseList(); + } _xmlParser = newXMLParser(true); + _xmlParser.addToParseList(parseList); + _xmlParser.addToParseList(parseCls); _xmlParser.setRepository(repos); if (_fieldOverride) _xmlParser.setAnnotationParser(getAnnotationParser()); @@ -153,6 +171,15 @@ public class PersistenceMetaDataFactory return _xmlParser; } + public void resetXMLParser() { + // If a parser was pushed on the stack due to multi-level parsing, + // clear the current parser and pop the inner parser off the stack. + if (!_stack.isEmpty()) { + _xmlParser.clear(); + _xmlParser = _stack.pop(); + } + } + /** * Set the metadata parser. */ @@ -196,10 +223,12 @@ public class PersistenceMetaDataFactory boolean parsedXML = false; if (_unparsed != null && !_unparsed.isEmpty() && (mode & MODE_META) != 0) { - for (URL url : _unparsed) + Set unparsed = new HashSet(_unparsed); + for (URL url : unparsed) { parseXML(url, cls, mode, envLoader); - parsedXML = _unparsed.contains(xml); - _unparsed.clear(); + } + parsedXML = unparsed.contains(xml); + _unparsed.clear(); // XML process check meta = repos.getCachedMetaData(cls); @@ -265,6 +294,9 @@ public class PersistenceMetaDataFactory } catch (IOException ioe) { throw new GeneralException(ioe); } + finally { + resetXMLParser(); + } } /** diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java index 4fef99cf9..b58820234 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/XMLPersistenceMetaDataParser.java @@ -184,6 +184,8 @@ public class XMLPersistenceMetaDataParser private final Stack _parents = new Stack(); private Class _cls = null; + // List of classes currently being parsed + private ArrayList> _parseList = new ArrayList>(); private int _fieldPos = 0; private int _clsPos = 0; private int _access = AccessCode.UNKNOWN; @@ -490,10 +492,14 @@ public class XMLPersistenceMetaDataParser @Override protected void reset() { + // Add all remaining deferred embeddable metadata + addDeferredEmbeddableMetaData(); + super.reset(); _elements.clear(); _parents.clear(); _cls = null; + _parseList.clear(); _fieldPos = 0; _clsPos = 0; @@ -823,6 +829,12 @@ public class XMLPersistenceMetaDataParser // query mode only? _cls = classForName(currentClassName()); + + // Prevent a reentrant parse for the same class + if (parseListContains(_cls)) { + return false; + } + if (_mode == MODE_QUERY) { if (_parser != null) _parser.parse(_cls); @@ -1806,6 +1818,13 @@ public class XMLPersistenceMetaDataParser return false; boolean system = currentElement() == null; + + // If in a multi-level parse, do not add system level listeners. + // Otherwise, they will get added multiple times. + if (system && _parseList != null && _parseList.size() > 0) { + return false; + } + Class type = currentElement() == null ? null : ((ClassMetaData) currentElement()).getDescribedType(); if (type == null) @@ -1895,7 +1914,30 @@ public class XMLPersistenceMetaDataParser return PersistenceCapable.class; return super.classForName(name, isRuntime()); } - + + /** + * Process all deferred embeddables using an unknown access type. + */ + protected void addDeferredEmbeddableMetaData() { + if (_embeddables != null && _embeddables.size() > 0) { + // Reverse iterate the array of remaining deferred embeddables + // since elements will be removed as they are processed. + Class[] classes = _embeddables.keySet().toArray( + new Class[_embeddables.size()]); + for (int i = classes.length - 1 ; i >= 0; i--) { + try { + addDeferredEmbeddableMetaData(classes[i], + AccessCode.UNKNOWN); + } + catch (Exception e) { + throw new MetaDataException( + _loc.get("no-embeddable-metadata", + classes[i].getName()), e); + } + } + } + } + /** * Process all deferred embeddables and embeddable mapping overrides * for a given class. This should only happen after the access type @@ -1964,4 +2006,45 @@ public class XMLPersistenceMetaDataParser protected void applyDeferredEmbeddableOverrides(Class cls) throws SAXException { } + + /* + * Add the array of classes to the active parse list. + */ + public void addToParseList(ArrayList> parseList) { + if (parseList == null) + return; + _parseList.addAll(parseList); + } + + /* + * Add the class to the active parse list. + */ + public void addToParseList(Class parentCls) { + if (parentCls == null) + return; + _parseList.add(parentCls); + } + + /* + * Whether the active parse list contains the specified class. + */ + public boolean parseListContains(Class cls) { + if (_parseList.size() == 0) + return false; + return _parseList.contains(cls); + } + + /* + * Returns the list of classes actively being parsed. + */ + public ArrayList> getParseList() { + return _parseList; + } + + /* + * Returns class currently being parsed. + */ + public Class getParseClass() { + return _cls; + } } diff --git a/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties b/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties index da2dc56d4..7a939bd9d 100644 --- a/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties +++ b/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties @@ -197,4 +197,5 @@ dynamic-agent: OpenJPA dynamically loaded the class enhancer. Any classes \ that were not enhanced at build time will be enhanced when they are \ loaded by the JVM. vlem-creation-info: OpenJPA dynamically loaded a validation provider. +no-embeddable-metadata: Unable to load metadata for embeddable class "{0}".