diff --git a/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java b/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java index 5050fc841..9e92d94e6 100644 --- a/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java +++ b/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.data.jpa.support; import java.io.IOException; +import java.net.URI; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -51,6 +52,7 @@ public class ClasspathScanningPersistenceUnitPostProcessor implements Persistenc private static final Logger LOG = LoggerFactory.getLogger(ClasspathScanningPersistenceUnitPostProcessor.class); private final String basePackage; + private ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader()); private String mappingFileNamePattern; @@ -142,7 +144,7 @@ public class ClasspathScanningPersistenceUnitPostProcessor implements Persistenc for (Resource resource : scannedResources) { try { - String resourcePath = resource.getURI().getPath(); + String resourcePath = getResourcePath(resource.getURI()); String resourcePathInClasspath = resourcePath.substring(resourcePath.indexOf(basePackagePathComponent)); mappingFileUris.add(resourcePathInClasspath); } catch (IOException e) { @@ -152,4 +154,30 @@ public class ClasspathScanningPersistenceUnitPostProcessor implements Persistenc return mappingFileUris; } + + /** + * Returns the path from the given {@link URI}. In case the given {@link URI} is opaque, e.g. beginning with jar:file, + * the path is extracted from URI by leaving out the protocol prefix. + * + * @param uri + * @return + * @see DATAJPA-519 + */ + private static String getResourcePath(URI uri) throws IOException { + + if (uri.isOpaque()) { + // e.g. jar:file:/foo/lib/somelib.jar!/com/acme/orm.xml + String rawPath = uri.toString(); + if (rawPath != null) { + int exclamationMarkIndex = rawPath.lastIndexOf('!'); + if (exclamationMarkIndex > -1) { + + // /com/acme/orm.xml + return rawPath.substring(exclamationMarkIndex + 1); + } + } + } + + return uri.getPath(); + } } diff --git a/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java b/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java index 927c9589a..3e8866e8f 100644 --- a/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,11 @@ package org.springframework.data.jpa.support; import static org.mockito.Mockito.*; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; + import javax.persistence.Entity; import org.junit.Test; @@ -24,8 +29,13 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; +import org.springframework.test.util.ReflectionTestUtils; /** * Unit tests for {@link ClasspathScanningPersistenceUnitPostProcessor}. @@ -108,6 +118,49 @@ public class ClasspathScanningPersistenceUnitPostProcessorUnitTests { verify(pui).addMappingFileName("org/springframework/data/jpa/support/module2/module2-orm.xml"); } + /** + * @see DATAJPA-519 + */ + @Test + public void shouldFindJpaMappingFilesFromNestedJarLocationsOnClasspath() { + + String nestedModule3Path = "org/springframework/data/jpa/support/module3/module3-orm.xml"; + final String fileInJarUrl = "jar:file:/foo/bar/lib/somelib.jar!/" + nestedModule3Path; + + ResourceLoader resolver = new PathMatchingResourcePatternResolver(new DefaultResourceLoader()) { + + public Resource[] getResources(String locationPattern) throws IOException { + + Resource[] resources = super.getResources(locationPattern); + resources = Arrays.copyOf(resources, resources.length + 1); + resources[resources.length - 1] = new UrlResource(fileInJarUrl); + + return resources; + } + + @Override + protected Set doFindPathMatchingJarResources(Resource rootDirResource, String subPattern) + throws IOException { + + if (fileInJarUrl.equals(rootDirResource.getURI().toString())) { + return Collections.singleton(rootDirResource); + } + + return super.doFindPathMatchingJarResources(rootDirResource, subPattern); + } + }; + + ClasspathScanningPersistenceUnitPostProcessor processor = new ClasspathScanningPersistenceUnitPostProcessor( + basePackage); + ReflectionTestUtils.setField(processor, "resolver", resolver); + processor.setMappingFileNamePattern("**/*orm.xml"); + processor.postProcessPersistenceUnitInfo(pui); + + verify(pui).addMappingFileName("org/springframework/data/jpa/support/module1/module1-orm.xml"); + verify(pui).addMappingFileName("org/springframework/data/jpa/support/module2/module2-orm.xml"); + verify(pui).addMappingFileName(nestedModule3Path); + } + @Entity public static class SampleEntity {