Parse JPA <exclude-unlisted-classes> correctly
Fix PersistenceUnitReader to correctly read <exclude-unlisted-classes> in both JPA 1.0 and 2.0 persistence.xml files. Prior to this commit PersistenceUnitReader would set the value of excludeUnlistedClasses to true when a <exclude-unlisted-classes> element was present, regardless of its value. The following rules are now used when parsing: - If the <exclude-unlisted-classes> element is missing the appropriate default value is set (based on the JPA version). - If an empty <exclude-unlisted-classes/> element is found the excludeUnlistedClasses property is set to true. - Otherwise the value of the <exclude-unlisted-classes> element is used to set the excludeUnlistedClasses property. Issue: SPR-10767
This commit is contained in:
		
							parent
							
								
									66cfe9f0e6
								
							
						
					
					
						commit
						7ad540d97b
					
				| 
						 | 
				
			
			@ -21,6 +21,7 @@ import java.io.InputStream;
 | 
			
		|||
import java.net.URL;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.SharedCacheMode;
 | 
			
		||||
import javax.persistence.ValidationMode;
 | 
			
		||||
import javax.persistence.spi.PersistenceUnitTransactionType;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +35,6 @@ import org.w3c.dom.Document;
 | 
			
		|||
import org.w3c.dom.Element;
 | 
			
		||||
import org.xml.sax.ErrorHandler;
 | 
			
		||||
import org.xml.sax.SAXException;
 | 
			
		||||
 | 
			
		||||
import org.springframework.core.io.Resource;
 | 
			
		||||
import org.springframework.core.io.support.ResourcePatternResolver;
 | 
			
		||||
import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +83,8 @@ class PersistenceUnitReader {
 | 
			
		|||
 | 
			
		||||
	private static final String META_INF = "META-INF";
 | 
			
		||||
 | 
			
		||||
	private static final String VERSION_1 = "1.0";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private final Log logger = LogFactory.getLog(getClass());
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -268,8 +270,14 @@ class PersistenceUnitReader {
 | 
			
		|||
 | 
			
		||||
		// exclude unlisted classes
 | 
			
		||||
		Element excludeUnlistedClasses = DomUtils.getChildElementByTagName(persistenceUnit, EXCLUDE_UNLISTED_CLASSES);
 | 
			
		||||
		if (excludeUnlistedClasses != null) {
 | 
			
		||||
			unitInfo.setExcludeUnlistedClasses(true);
 | 
			
		||||
		if (excludeUnlistedClasses == null) {
 | 
			
		||||
			// element is not defined, use default appropriate for version
 | 
			
		||||
			unitInfo.setExcludeUnlistedClasses(!VERSION_1.equals(version));
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			String excludeText = DomUtils.getTextValue(excludeUnlistedClasses);
 | 
			
		||||
			unitInfo.setExcludeUnlistedClasses(StringUtils.isEmpty(excludeText) ||
 | 
			
		||||
					Boolean.valueOf(excludeText));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// set JPA 2.0 shared cache mode
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 | 
			
		||||
			 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
			 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
 | 
			
		||||
          http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
 | 
			
		||||
			 version="1.0">
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="NoExcludeElement" />
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="EmptyExcludeElement">
 | 
			
		||||
		<exclude-unlisted-classes />
 | 
			
		||||
	</persistence-unit>
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="TrueExcludeElement">
 | 
			
		||||
		<exclude-unlisted-classes>true</exclude-unlisted-classes>
 | 
			
		||||
	</persistence-unit>
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="FalseExcludeElement">
 | 
			
		||||
		<exclude-unlisted-classes>false</exclude-unlisted-classes>
 | 
			
		||||
	</persistence-unit>
 | 
			
		||||
</persistence>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 | 
			
		||||
			 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
			 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
 | 
			
		||||
          http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
 | 
			
		||||
			 version="2.0">
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="NoExcludeElement" />
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="EmptyExcludeElement">
 | 
			
		||||
		<exclude-unlisted-classes />
 | 
			
		||||
	</persistence-unit>
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="TrueExcludeElement">
 | 
			
		||||
		<exclude-unlisted-classes>true</exclude-unlisted-classes>
 | 
			
		||||
	</persistence-unit>
 | 
			
		||||
 | 
			
		||||
	<persistence-unit name="FalseExcludeElement">
 | 
			
		||||
		<exclude-unlisted-classes>false</exclude-unlisted-classes>
 | 
			
		||||
	</persistence-unit>
 | 
			
		||||
</persistence>
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +43,7 @@ import static org.junit.Assert.*;
 | 
			
		|||
 *
 | 
			
		||||
 * @author Costin Leau
 | 
			
		||||
 * @author Juergen Hoeller
 | 
			
		||||
 * @author Nicholas Williams
 | 
			
		||||
 */
 | 
			
		||||
public class PersistenceXmlParsingTests {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,6 +61,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertEquals(2, info[0].getJarFileUrls().size());
 | 
			
		||||
		assertEquals(new ClassPathResource("order.jar").getURL(), info[0].getJarFileUrls().get(0));
 | 
			
		||||
		assertEquals(new ClassPathResource("order-supplemental.jar").getURL(), info[0].getJarFileUrls().get(1));
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", info[0].excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -72,6 +75,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertNotNull(info);
 | 
			
		||||
		assertEquals(1, info.length);
 | 
			
		||||
		assertEquals("OrderManagement", info[0].getPersistenceUnitName());
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", info[0].excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +94,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertEquals(1, info[0].getMappingFileNames().size());
 | 
			
		||||
		assertEquals("mappings.xml", info[0].getMappingFileNames().get(0));
 | 
			
		||||
		assertEquals(0, info[0].getProperties().keySet().size());
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", info[0].excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +116,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertEquals(0, info[0].getProperties().keySet().size());
 | 
			
		||||
		assertNull(info[0].getJtaDataSource());
 | 
			
		||||
		assertNull(info[0].getNonJtaDataSource());
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", info[0].excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -134,7 +143,7 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertEquals("com.acme.Customer", info[0].getManagedClassNames().get(1));
 | 
			
		||||
		assertEquals("com.acme.Item", info[0].getManagedClassNames().get(2));
 | 
			
		||||
 | 
			
		||||
		assertTrue(info[0].excludeUnlistedClasses());
 | 
			
		||||
		assertTrue("Exclude unlisted should be true when no value.", info[0].excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		assertSame(PersistenceUnitTransactionType.RESOURCE_LOCAL, info[0].getTransactionType());
 | 
			
		||||
		assertEquals(0, info[0].getProperties().keySet().size());
 | 
			
		||||
| 
						 | 
				
			
			@ -163,6 +172,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
 | 
			
		||||
		assertEquals("com.acme.AcmePersistence", info[0].getPersistenceProviderClassName());
 | 
			
		||||
		assertEquals(0, info[0].getProperties().keySet().size());
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", info[0].excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -206,6 +217,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
 | 
			
		||||
		assertSame(ds, pu1.getJtaDataSource());
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", pu1.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo pu2 = info[1];
 | 
			
		||||
 | 
			
		||||
		assertSame(PersistenceUnitTransactionType.JTA, pu2.getTransactionType());
 | 
			
		||||
| 
						 | 
				
			
			@ -222,6 +235,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
 | 
			
		||||
		assertNull(pu2.getJtaDataSource());
 | 
			
		||||
		assertEquals(ds, pu2.getNonJtaDataSource());
 | 
			
		||||
 | 
			
		||||
		assertTrue("Exclude unlisted should be true when no value.", pu2.excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -233,6 +248,8 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertEquals(1, info.length);
 | 
			
		||||
		assertEquals("pu", info[0].getPersistenceUnitName());
 | 
			
		||||
		assertEquals(0, info[0].getProperties().keySet().size());
 | 
			
		||||
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", info[0].excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Ignore  // not doing schema parsing anymore for JPA 2.0 compatibility
 | 
			
		||||
| 
						 | 
				
			
			@ -290,4 +307,66 @@ public class PersistenceXmlParsingTests {
 | 
			
		|||
		assertTrue("the archive location should have been returned", archive.getURL().sameFile(url));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testJpa1ExcludeUnlisted() throws Exception {
 | 
			
		||||
		PersistenceUnitReader reader = new PersistenceUnitReader(
 | 
			
		||||
				new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup());
 | 
			
		||||
		String resource = "/org/springframework/orm/jpa/persistence-exclude-1.0.xml";
 | 
			
		||||
		PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource);
 | 
			
		||||
 | 
			
		||||
		assertNotNull(info);
 | 
			
		||||
		assertEquals("The number of persistence units is incorrect.", 4, info.length);
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo noExclude = info[0];
 | 
			
		||||
		assertNotNull("noExclude should not be null.", noExclude);
 | 
			
		||||
		assertEquals("noExclude name is not correct.", "NoExcludeElement", noExclude.getPersistenceUnitName());
 | 
			
		||||
		assertFalse("Exclude unlisted should default false in 1.0.", noExclude.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo emptyExclude = info[1];
 | 
			
		||||
		assertNotNull("emptyExclude should not be null.", emptyExclude);
 | 
			
		||||
		assertEquals("emptyExclude name is not correct.", "EmptyExcludeElement", emptyExclude.getPersistenceUnitName());
 | 
			
		||||
		assertTrue("emptyExclude should be true.", emptyExclude.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo trueExclude = info[2];
 | 
			
		||||
		assertNotNull("trueExclude should not be null.", trueExclude);
 | 
			
		||||
		assertEquals("trueExclude name is not correct.", "TrueExcludeElement", trueExclude.getPersistenceUnitName());
 | 
			
		||||
		assertTrue("trueExclude should be true.", trueExclude.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo falseExclude = info[3];
 | 
			
		||||
		assertNotNull("falseExclude should not be null.", falseExclude);
 | 
			
		||||
		assertEquals("falseExclude name is not correct.", "FalseExcludeElement", falseExclude.getPersistenceUnitName());
 | 
			
		||||
		assertFalse("falseExclude should be false.", falseExclude.excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void testJpa2ExcludeUnlisted() throws Exception {
 | 
			
		||||
		PersistenceUnitReader reader = new PersistenceUnitReader(
 | 
			
		||||
				new PathMatchingResourcePatternResolver(), new JndiDataSourceLookup());
 | 
			
		||||
		String resource = "/org/springframework/orm/jpa/persistence-exclude-2.0.xml";
 | 
			
		||||
		PersistenceUnitInfo[] info = reader.readPersistenceUnitInfos(resource);
 | 
			
		||||
 | 
			
		||||
		assertNotNull(info);
 | 
			
		||||
		assertEquals("The number of persistence units is incorrect.", 4, info.length);
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo noExclude = info[0];
 | 
			
		||||
		assertNotNull("noExclude should not be null.", noExclude);
 | 
			
		||||
		assertEquals("noExclude name is not correct.", "NoExcludeElement", noExclude.getPersistenceUnitName());
 | 
			
		||||
		assertTrue("Exclude unlisted should default true in 2.0.", noExclude.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo emptyExclude = info[1];
 | 
			
		||||
		assertNotNull("emptyExclude should not be null.", emptyExclude);
 | 
			
		||||
		assertEquals("emptyExclude name is not correct.", "EmptyExcludeElement", emptyExclude.getPersistenceUnitName());
 | 
			
		||||
		assertTrue("emptyExclude should be true.", emptyExclude.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo trueExclude = info[2];
 | 
			
		||||
		assertNotNull("trueExclude should not be null.", trueExclude);
 | 
			
		||||
		assertEquals("trueExclude name is not correct.", "TrueExcludeElement", trueExclude.getPersistenceUnitName());
 | 
			
		||||
		assertTrue("trueExclude should be true.", trueExclude.excludeUnlistedClasses());
 | 
			
		||||
 | 
			
		||||
		PersistenceUnitInfo falseExclude = info[3];
 | 
			
		||||
		assertNotNull("falseExclude should not be null.", falseExclude);
 | 
			
		||||
		assertEquals("falseExclude name is not correct.", "FalseExcludeElement", falseExclude.getPersistenceUnitName());
 | 
			
		||||
		assertFalse("falseExclude should be false.", falseExclude.excludeUnlistedClasses());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue