Skip to content

Commit

Permalink
4.x: JPA testing-related improvements (#9131)
Browse files Browse the repository at this point in the history
* In jpa-cdi, adds dependency on MicroProfile Config API and uses it to locate persistence.xml resources

Signed-off-by: Laird Nelson <[email protected]>

* Squashable commit; fix checkstyle problems

Signed-off-by: Laird Nelson <[email protected]>

* Squashable commit; introduces StackedMap and blends MicroProfile Config properties into the persistence unit properties

Signed-off-by: Laird Nelson <[email protected]>

* Squashable commit; adds unit test to prove alternate persistence.xml location works

Signed-off-by: Laird Nelson <[email protected]>

---------

Signed-off-by: Laird Nelson <[email protected]>
  • Loading branch information
ljnelson authored Sep 19, 2024
1 parent 5134b93 commit 4f40082
Show file tree
Hide file tree
Showing 8 changed files with 474 additions and 60 deletions.
11 changes: 11 additions & 0 deletions integrations/cdi/jpa-cdi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@
<artifactId>jakarta.transaction-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile.config</groupId>
<artifactId>microprofile-config-api</artifactId>
<scope>provided</scope>
</dependency>

<!-- Runtime-scoped dependencies. -->
<dependency>
Expand Down Expand Up @@ -147,6 +152,12 @@
<artifactId>jaxb-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.config</groupId>
<artifactId>helidon-microprofile-config</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<!-- Test-scoped dependencies. -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import org.eclipse.microprofile.config.ConfigProvider;

import static jakarta.interceptor.Interceptor.Priority.LIBRARY_AFTER;
import static jakarta.interceptor.Interceptor.Priority.LIBRARY_BEFORE;
Expand Down Expand Up @@ -316,7 +317,10 @@ public JpaExtension() {
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.entering(cn, mn);
}
this.enabled = Boolean.parseBoolean(System.getProperty(this.getClass().getName() + ".enabled", "false"));
this.enabled =
Boolean.parseBoolean(ConfigProvider.getConfig()
.getOptionalValue(this.getClass().getName() + ".enabled", String.class)
.orElse("false"));
if (LOGGER.isLoggable(Level.FINE) && !this.enabled) {
LOGGER.logp(Level.FINE, cn, mn, "jpaExtensionDisabled", this.getClass().getName());
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed 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 io.helidon.integrations.cdi.jpa;

import java.util.AbstractMap;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toUnmodifiableSet;
import static java.util.stream.StreamSupport.stream;

final class StackedMap<K, V> extends AbstractMap<K, V> {


/*
* Instance fields.
*/


private final Supplier<? extends Set<? extends K>> ks;

private final Function<? super K, ? extends V> vf;


/*
* Constructors.
*/


StackedMap(Iterable<? extends Supplier<? extends Stream<? extends K>>> kss,
Iterable<? extends Function<? super K, ? extends V>> vfs) {
this(union(kss), vf(vfs));
}

StackedMap(Supplier<Set<? extends K>> ks, Function<? super K, ? extends V> vf) {
super();
this.ks = Objects.requireNonNull(ks, "ks");
this.vf = Objects.requireNonNull(vf, "vf");
}


/*
* Instance methods.
*/


@Override // AbstractMap<K, V>
public Set<Entry<K, V>> entrySet() {
return new EntrySet();
}


/*
* Static methods.
*/


private static <K> Supplier<Set<? extends K>> union(Iterable<? extends Supplier<? extends Stream<? extends K>>> i) {
Objects.requireNonNull(i, "i");
return () -> stream(i.spliterator(), false)
.flatMap(Supplier::get)
.collect(toUnmodifiableSet());
}

private static <K, V> Function<? super K, ? extends V> vf(Iterable<? extends Function<? super K, ? extends V>> vfs) {
Objects.requireNonNull(vfs, "vfs");
return k -> stream(vfs.spliterator(), false)
.flatMap(vf -> Optional.ofNullable(vf.apply(k)).stream())
.findFirst()
.orElse(null);
}


/*
* Inner and nested classes.
*/


private final class EntrySet extends AbstractSet<Entry<K, V>> {


/*
* Constructors.
*/


private EntrySet() {
super();
}


/*
* Instance methods.
*/


@Override // AbstractSet<Entry<K, V>>
public int size() {
return ks.get().size();
}

@Override // AbstractSet<Entry<K, V>>
public Iterator<Entry<K, V>> iterator() {
return new I();
}


/*
* Inner and nested classes.
*/


private final class I implements Iterator<Entry<K, V>> {


/*
* Instance fields.
*/


private final Iterator<? extends K> ki;


/*
* Constructors.
*/


private I() {
super();
this.ki = ks.get().iterator();
}


/*
* Instance methods.
*/


@Override // Iterator<Entry<K, V>>
public boolean hasNext() {
return this.ki.hasNext();
}

@Override // Iterator<Entry<K, V>>
public Entry<K, V> next() {
K k = this.ki.next();
return new SimpleImmutableEntry<>(k, vf.apply(k));
}

}

}

}
16 changes: 8 additions & 8 deletions integrations/cdi/jpa-cdi/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023 Oracle and/or its affiliates.
* Copyright (c) 2020, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -28,13 +28,13 @@
* @see io.helidon.integrations.cdi.jpa.PersistenceUnitInfoBean
*/
@Feature(value = "JPA",
description = "Jakarta persistence API support for Helidon MP",
in = HelidonFlavor.MP,
path = "JPA"
description = "Jakarta persistence API support for Helidon MP",
in = HelidonFlavor.MP,
path = "JPA"
)
@SuppressWarnings({ "deprecation", "requires-automatic"})
@SuppressWarnings({ "deprecation", "requires-automatic" })
module io.helidon.integrations.cdi.jpa {

requires jakarta.xml.bind;

requires jakarta.inject; // automatic module
Expand All @@ -47,8 +47,8 @@
requires transitive jakarta.persistence; // automatic module
requires transitive java.sql;

// JTA is optional at runtime, as well as the modules that support
// it.
requires microprofile.config.api;

requires static io.helidon.common.features.api;

// Static metamodel generation requires access to java.compiler at
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed 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 io.helidon.integrations.cdi.jpa;

import jakarta.annotation.sql.DataSourceDefinition;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceContext;

import io.helidon.microprofile.config.ConfigCdiExtension;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

class TestAlternatePersistenceXmlLocation {

private SeContainer sec;

private TestAlternatePersistenceXmlLocation() {
super();
}

@BeforeEach
@SuppressWarnings("unchecked")
final void initializeCdiContainer() {
System.setProperty(JpaExtension.class.getName() + ".enabled", "false");
System.setProperty(PersistenceExtension.class.getName() + ".enabled", "true");
System.setProperty("jakarta.persistence.descriptor.resource.name", "META-INF/test-persistence.xml");
Class<?> cdiSeJtaPlatformClass;
try {
// Load it dynamically because Hibernate won't be on the classpath when we're testing with Eclipselink
cdiSeJtaPlatformClass =
Class.forName("io.helidon.integrations.cdi.hibernate.CDISEJtaPlatform",
false,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
cdiSeJtaPlatformClass = null;
}
SeContainerInitializer i = SeContainerInitializer.newInstance()
.disableDiscovery()
.addExtensions(PersistenceExtension.class,
ConfigCdiExtension.class,
com.arjuna.ats.jta.cdi.TransactionExtension.class,
io.helidon.integrations.datasource.hikaricp.cdi.HikariCPBackedDataSourceExtension.class)
.addBeanClasses(Frobnicator.class);
if (cdiSeJtaPlatformClass != null) {
i = i.addBeanClasses(cdiSeJtaPlatformClass);
}
this.sec = i.initialize();
}

@AfterEach
final void closeCdiContainer() {
if (this.sec != null) {
this.sec.close();
}
System.setProperty(PersistenceExtension.class.getName() + ".enabled", "false");
System.setProperty(JpaExtension.class.getName() + ".enabled", "true");
System.clearProperty("jakarta.persistence.descriptor.resource.name");
}

@Test
final void testAlternatePersistenceXmlLocation() {
Instance<Frobnicator> fi = sec.select(Frobnicator.class);
Frobnicator f = fi.get();
assertThat(f.em.isOpen(), is(true));
fi.destroy(f);
}

@DataSourceDefinition(
name = "test",
className = "org.h2.jdbcx.JdbcDataSource",
url = "jdbc:h2:mem:TestAlternatePersistenceXmlLocation",
serverName = "",
properties = {
"user=sa"
}
)
@Dependent
private static class Frobnicator {

@PersistenceContext(unitName = "test-alternate")
private EntityManager em;

@Inject
Frobnicator() {
super();
}

}

}
Loading

0 comments on commit 4f40082

Please sign in to comment.