DATAJPA-519 - Spec compliant mapping file URI handling in ClasspathScanningPersistenceUnitPostProcessor.

JPA requires mapping file locations to be classpath relative. Previously we handed the full path to the file (including protocol and JAR path) to the provider, which they happened to understand by accident. To be more spec compliant, we now massage the detected URIs into the expected format.

Original pull request: #81.
This commit is contained in:
Thomas Darimont
2014-04-25 15:17:19 +02:00
committed by Oliver Gierke
parent 68e2ee5ed9
commit fe55862bcf
2 changed files with 84 additions and 3 deletions

View File

@@ -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();
}
}

View File

@@ -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<Resource> 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 {