Skip to content

Commit c47b405

Browse files
authored
Fix jpa recipe with persistence.xml in test resources (#966)
* Replicate the issue in test * Optionally filter sourceset by path segment * Add default constructor and javadoc
1 parent 94a4b2e commit c47b405

File tree

10 files changed

+206
-7
lines changed

10 files changed

+206
-7
lines changed

applications/spring-shell/src/test/java/org/springframework/sbm/IntegrationTestBaseClass.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ public static void beforeAll() {
117117
}
118118

119119
if (mvnHome == null) {
120-
System.err.println("You must set $MAVEN_HOME on your system for the integration test to run.");
121-
throw new RuntimeException();
120+
throw new RuntimeException("You must set $MAVEN_HOME on your system for the integration test to run.");
122121
}
123122

124123
System.setProperty("maven.home", mvnHome);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>com.example</groupId>
6+
<artifactId>persistence-xml-in-test</artifactId>
7+
<packaging>jar</packaging>
8+
<version>1.0.0</version>
9+
<properties>
10+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
11+
</properties>
12+
<dependencies>
13+
<dependency>
14+
<groupId>org.apache.tomee</groupId>
15+
<artifactId>javaee-api</artifactId>
16+
<version>8.0-5</version>
17+
<scope>provided</scope>
18+
</dependency>
19+
<dependency>
20+
<groupId>org.hibernate</groupId>
21+
<artifactId>hibernate-core</artifactId>
22+
<version>5.4.24.Final</version>
23+
</dependency>
24+
<dependency>
25+
<groupId>org.hibernate.javax.persistence</groupId>
26+
<artifactId>hibernate-jpa-2.1-api</artifactId>
27+
<version>1.0.0.Final</version>
28+
<scope>runtime</scope>
29+
</dependency>
30+
</dependencies>
31+
</project>

applications/spring-shell/src/test/resources/testcode/project-with-persistence-xml-in-test-resources/src/main/java/.keep

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2021 - 2022 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<persistence version="2.2"
18+
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
21+
<persistence-unit name="person-unit">
22+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
23+
<jta-data-source>movieDatabase</jta-data-source>
24+
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
25+
<properties>
26+
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
27+
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
28+
<property name="tomee.jpa.cdi" value="false"/>
29+
</properties>
30+
</persistence-unit>
31+
</persistence>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2021 - 2022 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<persistence version="2.2"
18+
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
21+
<persistence-unit name="person-unit">
22+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
23+
<jta-data-source>movieDatabase</jta-data-source>
24+
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
25+
<properties>
26+
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
27+
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
28+
<property name="tomee.jpa.cdi" value="false"/>
29+
</properties>
30+
</persistence-unit>
31+
</persistence>

components/sbm-core/src/main/java/org/springframework/sbm/project/resource/GenericTypeFilter.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515
*/
1616
package org.springframework.sbm.project.resource;
1717

18+
import org.openrewrite.SourceFile;
1819
import org.springframework.sbm.project.resource.filter.GenericTypeListFilter;
1920
import org.springframework.sbm.project.resource.filter.ProjectResourceFinder;
2021
import org.springframework.sbm.project.resource.filter.ResourceFilterException;
2122
import lombok.Getter;
2223

24+
import java.nio.file.FileSystems;
25+
import java.nio.file.Files;
26+
import java.nio.file.PathMatcher;
2327
import java.util.List;
2428
import java.util.Optional;
2529
import java.util.stream.Collectors;
@@ -28,20 +32,39 @@ public class GenericTypeFilter<T> implements ProjectResourceFinder<Optional<T>>
2832

2933
@Getter
3034
private final Class<T> type;
35+
private final String directoryPattern;
36+
private final PathMatcher pathMatcher;
3137

3238
public GenericTypeFilter(Class<T> type) {
3339
this.type = type;
40+
this.directoryPattern = null;
41+
this.pathMatcher = null;
42+
}
43+
44+
public GenericTypeFilter(Class<T> type, String directoryPattern) {
45+
this.type = type;
46+
this.directoryPattern = directoryPattern;
47+
this.pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + directoryPattern);
3448
}
3549

3650
@Override
3751
public Optional<T> apply(ProjectResourceSet projectResourceSet) {
3852
List<T> collect = projectResourceSet.stream()
3953
.filter(pr -> type.isAssignableFrom(pr.getClass()))
54+
.filter(this::matchDirectoryPattern)
4055
.map(type::cast)
4156
.collect(Collectors.toList());
4257
if (collect.size() > 1) {
4358
throw new ResourceFilterException(String.format("Found more than one resource of type '%s'. Use %s instead.", type.getClass(), GenericTypeListFilter.class));
4459
}
4560
return collect.isEmpty() ? Optional.empty() : Optional.of(collect.get(0));
4661
}
62+
63+
private boolean matchDirectoryPattern(RewriteSourceFileHolder<? extends SourceFile> pr) {
64+
if(pathMatcher == null) {
65+
return true;
66+
} else {
67+
return pathMatcher.matches(pr.getAbsolutePath());
68+
}
69+
}
4770
}

components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jpa/actions/MigrateEclipseLinkToSpringBoot.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ private List<Dependency> createExcludedDependencies() {
289289
private List<SpringBootJpaProperty> extractEclipseLinkProperties(Module module) {
290290
List<SpringBootJpaProperty> springBootJpaProperties = new ArrayList<>();
291291

292-
Optional<PersistenceXml> optPersistenceXml = module.search(new PersistenceXmlResourceFilter());
292+
Optional<PersistenceXml> optPersistenceXml = module.search(new PersistenceXmlResourceFilter("**/src/main/resources/**"));
293293
return optPersistenceXml.map(persistenceXml -> persistenceXml.getPersistence().getPersistenceUnit().get(0) // FIXME: should multiple persistence-units be handled or fail?
294294
.getProperties())
295295
.filter(not(properties -> properties.getProperty().isEmpty()))

components/sbm-recipes-jee-to-boot/src/main/java/org/springframework/sbm/jee/jpa/actions/MigratePersistenceXmlToApplicationPropertiesAction.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ public class MigratePersistenceXmlToApplicationPropertiesAction extends Abstract
3939
@Override
4040
public void apply(ProjectContext context) {
4141
Module module = context.getApplicationModules().stream()
42-
.filter(m -> m.search(new PersistenceXmlResourceFilter()).isPresent())
42+
.filter(m -> m.search(new PersistenceXmlResourceFilter("**/src/main/resources/**")).isPresent())
4343
.findFirst()
4444
.orElseThrow(() -> new RuntimeException("No file 'META-INF/persistence.xml' could be found."));
4545

46-
PersistenceXml persistenceXml = module.search(new PersistenceXmlResourceFilter()).get();
46+
PersistenceXml persistenceXml = module.search(new PersistenceXmlResourceFilter("**/src/main/resources/**")).get();
4747
List<SpringBootApplicationProperties> applicationProperties = module.search(new SpringBootApplicationPropertiesResourceListFilter());
4848
if (applicationProperties.isEmpty()) {
4949
AddSpringBootApplicationPropertiesAction addSpringBootApplicationPropertiesAction = new AddSpringBootApplicationPropertiesAction(executionContext);
@@ -75,6 +75,6 @@ void mapJpaPropertyToProperties(Persistence.PersistenceUnit.Properties.Property
7575

7676
@Override
7777
public boolean isApplicable(ProjectContext context) {
78-
return context.search(new PersistenceXmlResourceFilter()).isPresent();
78+
return context.search(new PersistenceXmlResourceFilter("**/src/main/resources/**")).isPresent();
7979
}
8080
}

components/sbm-recipes-jee-to-boot/src/test/java/org/springframework/sbm/jee/jpa/actions/PersistenceXmlToSpringBootApplicationPropertiesActionTest.java

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
import org.junit.jupiter.api.Disabled;
2525
import org.junit.jupiter.api.Nested;
2626
import org.junit.jupiter.api.Test;
27+
import org.springframework.sbm.project.resource.filter.ResourceFilterException;
2728
import org.springframework.sbm.test.ActionTest;
2829

2930
import java.nio.file.Path;
3031
import java.util.List;
3132

3233
import static org.assertj.core.api.Assertions.assertThat;
3334
import static org.assertj.core.api.Assertions.assertThatThrownBy;
35+
import static org.junit.jupiter.api.Assertions.assertThrows;
3436

3537
class PersistenceXmlToSpringBootApplicationPropertiesActionTest {
3638

@@ -183,10 +185,74 @@ void migrateJpaToSpringBoot() {
183185
SpringBootApplicationProperties springBootApplicationProperties = applicationProperties.get(0);
184186
assertThat(springBootApplicationProperties.getProperty("spring.jpa.hibernate.ddl-auto").get()).isEqualTo("create-drop");
185187
assertThat(springBootApplicationProperties.getProperty("spring.jpa.database-platform").get()).isEqualTo("org.hibernate.dialect.HSQLDialect");
186-
assertThat(context.search(new PersistenceXmlResourceFilter())).isNotEmpty();
188+
assertThat(context.search(new PersistenceXmlResourceFilter("**/src/main/resources/**"))).isNotEmpty();
187189
});
190+
}
191+
192+
// applicable with persistence.xml ONLY in src/main/resources
193+
// applicable with persistence.xml in src/main/resources AND in src/test/resources
194+
// NOT applicable with persistence.xml ONLY in src/test/resources
195+
196+
TestProjectContext.Builder projectContextBuilder = TestProjectContext.buildProjectContext()
197+
.withProjectResource(Path.of("src/main/resources/META-INF/persistence.xml"), """
198+
<persistence version="1.0"
199+
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
200+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
201+
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
202+
<persistence-unit name="movie-unit">
203+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
204+
<jta-data-source>movieDatabase</jta-data-source>
205+
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
206+
<properties>
207+
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
208+
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
209+
</properties>
210+
</persistence-unit>
211+
</persistence>
212+
""")
213+
.withProjectResource(Path.of("src/test/resources/META-INF/persistence.xml"), """
214+
<persistence version="1.0"
215+
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
216+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
217+
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
218+
<persistence-unit name="movie-unit">
219+
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
220+
<jta-data-source>movieDatabase</jta-data-source>
221+
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
222+
<properties>
223+
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
224+
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
225+
</properties>
226+
</persistence-unit>
227+
</persistence>
228+
""")
229+
.addRegistrar(new PersistenceXmlProjectResourceRegistrar());
188230

231+
@Test
232+
void persistenceXmlResourceFilterWithPersistenceXmlInTestResourcesAndNoPathPatternProvided_shouldThrowException() {
233+
assertThrows(ResourceFilterException.class, () -> {
234+
ProjectContext projectContext = projectContextBuilder.build();
235+
assertThat(projectContext.search(new PersistenceXmlResourceFilter())).isNotEmpty();
236+
});
237+
}
189238

239+
@Test
240+
void persistenceXmlResourceFilterWithPersistenceXmlInTestResourcesAndPathPatternProvided_shouldReturnResult() {
241+
ProjectContext projectContext = projectContextBuilder.build();
242+
assertThat(projectContext.search(new PersistenceXmlResourceFilter("**/src/main/**"))).isPresent();
243+
}
190244

245+
@Test
246+
void migrateJpaToSpringBootWithPersistenceXmlOnlyMatchesPersistenceXmlInMain() {
247+
ActionTest.withProjectContext(projectContextBuilder)
248+
.actionUnderTest(new MigratePersistenceXmlToApplicationPropertiesAction())
249+
.verify(projectContext -> {
250+
List<SpringBootApplicationProperties> applicationProperties = projectContext.search(new SpringBootApplicationPropertiesResourceListFilter());
251+
SpringBootApplicationProperties springBootApplicationProperties = applicationProperties.get(0);
252+
assertThat(springBootApplicationProperties.getProperty("spring.jpa.hibernate.ddl-auto").get()).isEqualTo("create-drop");
253+
assertThat(springBootApplicationProperties.getProperty("spring.jpa.database-platform").get()).isEqualTo("org.hibernate.dialect.HSQLDialect");
254+
assertThat(projectContext.search(new PersistenceXmlResourceFilter("**/src/main/resources/**"))).isNotEmpty();
255+
});
191256
}
192257
}
258+

components/sbm-support-jee/src/main/java/org/springframework/sbm/jee/jpa/filter/PersistenceXmlResourceFilter.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,30 @@
1717

1818
import org.springframework.sbm.jee.jpa.api.PersistenceXml;
1919
import org.springframework.sbm.project.resource.GenericTypeFilter;
20+
import org.springframework.sbm.project.resource.filter.ResourceFilterException;
2021

2122
// FIXME: what if persistence.xml in src/test/resources also exists?!
2223
public class PersistenceXmlResourceFilter extends GenericTypeFilter<PersistenceXml> {
2324

25+
/**
26+
* Apply the filter to all resources.
27+
*
28+
* @see org.springframework.sbm.project.resource.filter.GenericTypeListFilter
29+
* @throws ResourceFilterException when more than one resource was found.
30+
*/
2431
public PersistenceXmlResourceFilter() {
2532
super(PersistenceXml.class);
2633
}
2734

35+
/**
36+
* Apply the filter only to resources matching the {@code directoryPattern}.
37+
* The {@code directoryPattern} is used as pattern for {@link java.nio.file.PathMatcher}.
38+
*
39+
* @see org.springframework.sbm.project.resource.filter.GenericTypeListFilter
40+
* @throws ResourceFilterException when more than one resource was found.
41+
*/
42+
public PersistenceXmlResourceFilter(String directoryPattern) {
43+
super(PersistenceXml.class, directoryPattern);
44+
}
45+
2846
}

0 commit comments

Comments
 (0)