GH-2 - Upgrade to Spring Boot 3.

Upgrade to Spring Boot 3 and Java 17 as project baselines. Removed legacy JavaEE modules and replaced them by ones compatible with JakartaEE 9.

Disabled the Observability module for now as Spring Cloud Sleuth has been removed the Boot 3 compatible Spring Cloud branch and we need to migrate the module to Micrometer first.
This commit is contained in:
Oliver Drotbohm
2022-07-07 23:22:05 +02:00
parent 817aaabbdb
commit 1cc44cf065
30 changed files with 70 additions and 812 deletions

16
pom.xml
View File

@@ -12,7 +12,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<version>3.0.0-SNAPSHOT</version>
<relativePath />
</parent>
@@ -22,10 +22,9 @@
<module>spring-modulith-events</module>
<module>spring-modulith-test</module>
<module>spring-modulith-docs</module>
<module>spring-modulith-observability</module>
<!--<module>spring-modulith-observability</module>-->
<module>spring-modulith-moments</module>
<module>spring-modulith-starter-jpa</module>
<module>spring-modulith-starter-jpa-jakarta</module>
<module>spring-modulith-starter-test</module>
</modules>
@@ -111,6 +110,13 @@ limitations under the License.
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</profile>
@@ -201,8 +207,8 @@ limitations under the License.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>17</source>
<target>17</target>
</configuration>
</plugin>

View File

@@ -82,7 +82,7 @@ class Types {
@UtilityClass
static class JavaXTypes {
private static final String BASE_PACKAGE = "javax";
private static final String BASE_PACKAGE = "jakarta";
static final String AT_ENTITY = BASE_PACKAGE + ".persistence.Entity";
static final String AT_INJECT = BASE_PACKAGE + ".inject.Inject";

View File

@@ -17,24 +17,24 @@ package org.springframework.modulith.model;
import static org.assertj.core.api.Assertions.*;
import jakarta.persistence.Entity;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Stream;
import javax.persistence.Entity;
import org.jmolecules.event.annotation.DomainEventHandler;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.springframework.modulith.model.ArchitecturallyEvidentType.SpringAwareArchitecturallyEvidentType;
import org.springframework.modulith.model.ArchitecturallyEvidentType.SpringDataAwareArchitecturallyEvidentType;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.EventListener;
import org.springframework.data.repository.CrudRepository;
import org.springframework.modulith.model.ArchitecturallyEvidentType.SpringAwareArchitecturallyEvidentType;
import org.springframework.modulith.model.ArchitecturallyEvidentType.SpringDataAwareArchitecturallyEvidentType;
import org.springframework.stereotype.Repository;
import com.tngtech.archunit.core.domain.JavaClass;

View File

@@ -16,7 +16,6 @@
<modules>
<module>spring-modulith-events-core</module>
<module>spring-modulith-events-jpa</module>
<module>spring-modulith-events-jpa-jakarta</module>
<module>spring-modulith-events-jackson</module>
<module>spring-modulith-events-tests</module>
<module>spring-modulith-events-starter</module>

View File

@@ -1,96 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-events</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Spring Modulith - Events - Jakarta JPA-based registry</name>
<artifactId>spring-modulith-events-jpa-jakarta</artifactId>
<properties>
<java.version>17</java.version>
<module.name>org.springframework.modulith.events.jpa.jakarta</module.name>
<spring-framework.version>6.0.0-M1</spring-framework.version>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-modulith-events-core</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Jakarta Persistence -->
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<!-- Testing -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.0.0.CR2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<version>2.0.1-RC1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2017 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.
* 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 org.springframework.modulith.events.jpa;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import java.time.Instant;
import java.util.UUID;
/**
* @author Oliver Gierke
*/
@Data
@Entity
@NoArgsConstructor(force = true)
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class JpaEventPublication {
private final @Id @Column(length = 16) UUID id;
private final Instant publicationDate;
private final String listenerId;
private final String serializedEvent;
private final Class<?> eventType;
private Instant completionDate;
@Builder
static JpaEventPublication of(Instant publicationDate, String listenerId, Object serializedEvent,
Class<?> eventType) {
return new JpaEventPublication(UUID.randomUUID(), publicationDate, listenerId, serializedEvent.toString(),
eventType);
}
JpaEventPublication markCompleted() {
this.completionDate = Instant.now();
return this;
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.modulith.events.jpa;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.context.annotation.Configuration;
/**
* @author Oliver Drotbohm
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigurationPackage
class JpaEventPublicationAutoConfiguration {}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2017 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.
* 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 org.springframework.modulith.events.jpa;
import lombok.RequiredArgsConstructor;
import jakarta.persistence.EntityManager;
import org.springframework.modulith.events.EventSerializer;
import org.springframework.modulith.events.config.EventPublicationConfigurationExtension;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Oliver Gierke
*/
@Configuration(proxyBeanMethods = false)
@RequiredArgsConstructor
class JpaEventPublicationConfiguration implements EventPublicationConfigurationExtension {
@Bean
public JpaEventPublicationRegistry jpaEventPublicationRegistry(JpaEventPublicationRepository repository,
EventSerializer serializer) {
return new JpaEventPublicationRegistry(repository, serializer);
}
@Bean
public JpaEventPublicationRepository jpaEventPublicationRepository(EntityManager em) {
return new JpaEventPublicationRepository(em);
}
}

View File

@@ -1,175 +0,0 @@
/*
* Copyright 2017-2020 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.
* 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 org.springframework.modulith.events.jpa;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.time.Instant;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.modulith.events.CompletableEventPublication;
import org.springframework.modulith.events.EventPublication;
import org.springframework.modulith.events.EventPublicationRegistry;
import org.springframework.modulith.events.EventSerializer;
import org.springframework.modulith.events.PublicationTargetIdentifier;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
/**
* JPA based {@link EventPublicationRegistry}.
*
* @author Oliver Gierke
*/
@Slf4j
@RequiredArgsConstructor
class JpaEventPublicationRegistry implements EventPublicationRegistry, DisposableBean {
private final @NonNull JpaEventPublicationRepository events;
private final @NonNull EventSerializer serializer;
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublicationRegistry#store(java.lang.Object, java.util.Collection)
*/
@Override
public void store(Object event, Stream<PublicationTargetIdentifier> listeners) {
listeners.map(it -> CompletableEventPublication.of(event, it)) //
.map(this::map) //
.forEach(it -> events.create(it));
}
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublicationRegistry#findIncompletePublications()
*/
@Override
public Iterable<EventPublication> findIncompletePublications() {
List<EventPublication> result = events.findByCompletionDateIsNull().stream() //
.map(it -> JpaEventPublicationAdapter.of(it, serializer)) //
.collect(Collectors.toList());
return result;
}
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublicationRegistry#markCompleted(java.lang.Object, org.springframework.events.ListenerId)
*/
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void markCompleted(Object event, PublicationTargetIdentifier listener) {
Assert.notNull(event, "Domain event must not be null!");
Assert.notNull(listener, "Listener identifier must not be null!");
events.findBySerializedEventAndListenerId(serializer.serialize(event), listener.toString()) //
.map(JpaEventPublicationRegistry::LOGCompleted) //
.ifPresent(it -> events.update(it.markCompleted()));
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
List<JpaEventPublication> publications = events.findByCompletionDateIsNull();
if (publications.isEmpty()) {
LOG.info("No publications outstanding!");
return;
}
LOG.info("Shutting down with the following publications left unfinished:");
for (int i = 0; i < publications.size(); i++) {
String prefix = (i + 1) == publications.size() ? "└─" : "├─";
JpaEventPublication it = publications.get(i);
LOG.info("{} {} - {} - {}", prefix, it.getId(), it.getEventType().getName(), it.getListenerId());
}
}
private JpaEventPublication map(EventPublication publication) {
JpaEventPublication result = JpaEventPublication.builder() //
.eventType(publication.getEvent().getClass()) //
.publicationDate(publication.getPublicationDate()) //
.listenerId(publication.getTargetIdentifier().toString()) //
.serializedEvent(serializer.serialize(publication.getEvent()).toString()) //
.build();
LOG.debug("Registering publication of {} with id {} for {}.", //
result.getEventType(), result.getId(), result.getListenerId());
return result;
}
private static JpaEventPublication LOGCompleted(JpaEventPublication publication) {
LOG.debug("Marking publication of event {} with id {} to listener {} completed.", //
publication.getEventType(), publication.getId(), publication.getListenerId());
return publication;
}
@EqualsAndHashCode
@RequiredArgsConstructor(staticName = "of")
static class JpaEventPublicationAdapter implements EventPublication {
private final JpaEventPublication publication;
private final EventSerializer serializer;
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublication#getEvent()
*/
@Override
public Object getEvent() {
return serializer.deserialize(publication.getSerializedEvent(), publication.getEventType());
}
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublication#getListenerId()
*/
@Override
public PublicationTargetIdentifier getTargetIdentifier() {
return PublicationTargetIdentifier.of(publication.getListenerId());
}
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublication#getPublicationDate()
*/
@Override
public Instant getPublicationDate() {
return publication.getPublicationDate();
}
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.modulith.events.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import java.util.List;
import java.util.Optional;
import org.springframework.transaction.annotation.Transactional;
/**
* Repository to store {@link JpaEventPublication}s.
*
* @author Oliver Drotbohm
*/
@RequiredArgsConstructor
public class JpaEventPublicationRepository {
private final EntityManager entityManager;
@Transactional
JpaEventPublication create(JpaEventPublication publication) {
entityManager.persist(publication);
return publication;
}
@Transactional
JpaEventPublication update(JpaEventPublication publication) {
entityManager.merge(publication);
entityManager.flush();
return publication;
}
/**
* Returns all {@link JpaEventPublication} that have not been completed yet.
*/
@Transactional(readOnly = true)
List<JpaEventPublication> findByCompletionDateIsNull() {
String query = "select p from JpaEventPublication p where p.completionDate is null";
return entityManager.createQuery(query, JpaEventPublication.class).getResultList();
}
/**
* Return the {@link JpaEventPublication} for the given serialized event and listener identifier.
*
* @param event must not be {@literal null}.
* @param listenerId must not be {@literal null}.
* @return
*/
@Transactional(readOnly = true)
Optional<JpaEventPublication> findBySerializedEventAndListenerId(Object event, String listenerId) {
String query = "select p from JpaEventPublication p where p.serializedEvent = ?1 and p.listenerId = ?2";
TypedQuery<JpaEventPublication> typedQuery = entityManager.createQuery(query, JpaEventPublication.class)
.setParameter(1, event)
.setParameter(2, listenerId);
try {
return Optional.of(typedQuery.getSingleResult());
} catch (Exception o_O) {
return Optional.empty();
}
}
}

View File

@@ -1,2 +0,0 @@
@org.springframework.lang.NonNullApi
package org.springframework.modulith.events.jpa;

View File

@@ -1 +0,0 @@
restart.include.spring-modulith-events:/spring-modulith-events-jpa-[\\w-\\.]+\.jar

View File

@@ -1,6 +0,0 @@
org.springframework.modulith.events.config.EventPublicationConfigurationExtension=\
org.springframework.modulith.events.jpa.JpaEventPublicationConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.modulith.events.jpa.JpaEventPublicationAutoConfiguration,\
org.springframework.modulith.events.jpa.JpaEventPublicationConfiguration

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.modulith.events.jpa;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.modulith.events.EventSerializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestConstructor;
import org.springframework.test.context.TestConstructor.AutowireMode;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* @author Oliver Drotbohm
*/
@ExtendWith(SpringExtension.class)
@TestConstructor(autowireMode = AutowireMode.ALL)
@RequiredArgsConstructor
public class JpaEventPublicationConfigurationIntegrationTests {
private final ApplicationContext context;
@Configuration
@Import(JpaEventPublicationConfiguration.class)
static class TestConfig {
@Bean
EventSerializer eventSerializer() {
return mock(EventSerializer.class);
}
@Bean
EntityManager entityManager() {
EntityManager em = mock(EntityManager.class);
// Mock API for query executed at bootstrap time
TypedQuery<?> query = mock(TypedQuery.class);
doReturn(query).when(em).createQuery(any(String.class), any());
return em;
}
}
@Test
void bootstrapsApplicationComponents() {
assertThat(context.getBean(JpaEventPublicationRegistry.class)).isNotNull();
assertThat(context.getBean(JpaEventPublicationRepository.class)).isNotNull();
}
}

View File

@@ -1,118 +0,0 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://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 org.springframework.modulith.events.jpa;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import lombok.RequiredArgsConstructor;
import java.time.Instant;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.modulith.events.EventSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.SharedEntityManagerCreator;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.test.context.TestConstructor;
import org.springframework.test.context.TestConstructor.AutowireMode;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Oliver Drotbohm
*/
@ExtendWith(SpringExtension.class)
@TestConstructor(autowireMode = AutowireMode.ALL)
@Transactional
@RequiredArgsConstructor
class JpaEventPublicationRepositoryIntegrationTests {
@Configuration
@Import(JpaEventPublicationConfiguration.class)
static class TestConfig {
@Bean
EventSerializer eventSerializer() {
return mock(EventSerializer.class);
}
// Database
@Bean
EmbeddedDatabase hsqlDatabase() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build();
}
// JPA
@Bean
LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
AbstractJpaVendorAdapter vendor = new HibernateJpaVendorAdapter();
vendor.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendor);
factory.setDataSource(dataSource);
factory.setPackagesToScan(getClass().getPackage().getName());
return factory;
}
@Bean
EntityManager entityManager(EntityManagerFactory factory) {
return SharedEntityManagerCreator.createSharedEntityManager(factory);
}
@Bean
JpaTransactionManager transactionManager(EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
}
private final JpaEventPublicationRepository repository;
@Test
void persistsJpaEventPublication() {
JpaEventPublication publication = JpaEventPublication.of(Instant.now(), "listener", "", Object.class);
// Store publication
repository.create(publication);
assertThat(repository.findByCompletionDateIsNull()).containsExactly(publication);
assertThat(repository.findBySerializedEventAndListenerId("", "listener")).isPresent();
// Complete publication
repository.update(publication.markCompleted());
assertThat(repository.findByCompletionDateIsNull()).isEmpty();
}
}

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<root level="error">
<appender-ref ref="console" />
</root>
<logger name="org.springframework.modulith" level="info" />
</configuration>

View File

@@ -12,6 +12,7 @@
<artifactId>spring-modulith-events-jpa</artifactId>
<properties>
<java.version>17</java.version>
<module.name>org.springframework.modulith.events.jpa</module.name>
</properties>
@@ -23,11 +24,11 @@
<version>${project.version}</version>
</dependency>
<!-- JPA -->
<!-- Jakarta Persistence -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency>
@@ -37,13 +38,27 @@
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.1.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -64,4 +79,14 @@
</dependencies>
<repositories>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>

View File

@@ -15,6 +15,9 @@
*/
package org.springframework.modulith.events.jpa;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Data;
@@ -24,10 +27,6 @@ import lombok.RequiredArgsConstructor;
import java.time.Instant;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* @author Oliver Gierke
*/

View File

@@ -23,6 +23,4 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigurationPackage
class JpaEventPublicationAutoConfiguration {
}
class JpaEventPublicationAutoConfiguration {}

View File

@@ -17,7 +17,7 @@ package org.springframework.modulith.events.jpa;
import lombok.RequiredArgsConstructor;
import javax.persistence.EntityManager;
import jakarta.persistence.EntityManager;
import org.springframework.modulith.events.EventSerializer;
import org.springframework.modulith.events.config.EventPublicationConfigurationExtension;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2022 the original author or authors.
* Copyright 2017-2020 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.
@@ -85,7 +85,7 @@ class JpaEventPublicationRegistry implements EventPublicationRegistry, Disposabl
Assert.notNull(listener, "Listener identifier must not be null!");
events.findBySerializedEventAndListenerId(serializer.serialize(event), listener.toString()) //
.map(JpaEventPublicationRegistry::logCompleted) //
.map(JpaEventPublicationRegistry::LOGCompleted) //
.ifPresent(it -> events.update(it.markCompleted()));
}
@@ -130,7 +130,7 @@ class JpaEventPublicationRegistry implements EventPublicationRegistry, Disposabl
return result;
}
private static JpaEventPublication logCompleted(JpaEventPublication publication) {
private static JpaEventPublication LOGCompleted(JpaEventPublication publication) {
LOG.debug("Marking publication of event {} with id {} to listener {} completed.", //
publication.getEventType(), publication.getId(), publication.getListenerId());
@@ -145,20 +145,13 @@ class JpaEventPublicationRegistry implements EventPublicationRegistry, Disposabl
private final JpaEventPublication publication;
private final EventSerializer serializer;
private Object deserializedEvent;
/*
* (non-Javadoc)
* @see org.springframework.events.EventPublication#getEvent()
*/
@Override
public Object getEvent() {
if (deserializedEvent == null) {
this.deserializedEvent = serializer.deserialize(publication.getSerializedEvent(), publication.getEventType());
}
return deserializedEvent;
return serializer.deserialize(publication.getSerializedEvent(), publication.getEventType());
}
/*

View File

@@ -15,14 +15,13 @@
*/
package org.springframework.modulith.events.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import java.util.List;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.springframework.transaction.annotation.Transactional;
/**

View File

@@ -1,2 +0,0 @@
org.springframework.modulith.events.jpa.JpaEventPublicationAutoConfiguration
org.springframework.modulith.events.jpa.JpaEventPublicationConfiguration

View File

@@ -19,11 +19,10 @@ import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import lombok.RequiredArgsConstructor;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.modulith.events.EventSerializer;

View File

@@ -18,12 +18,12 @@ package org.springframework.modulith.events.jpa;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import lombok.RequiredArgsConstructor;
import java.time.Instant;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
@@ -102,14 +102,13 @@ class JpaEventPublicationRepositoryIntegrationTests {
@Test
void persistsJpaEventPublication() {
String listenerId = "listener";
JpaEventPublication publication = JpaEventPublication.of(Instant.now(), listenerId, "", Object.class);
JpaEventPublication publication = JpaEventPublication.of(Instant.now(), "listener", "", Object.class);
// Store publication
repository.create(publication);
assertThat(repository.findByCompletionDateIsNull()).containsExactly(publication);
assertThat(repository.findBySerializedEventAndListenerId("", listenerId)).isPresent();
assertThat(repository.findBySerializedEventAndListenerId("", "listener")).isPresent();
// Complete publication
repository.update(publication.markCompleted());

View File

@@ -34,8 +34,9 @@
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.1.1.Final</version>
</dependency>
<dependency>

View File

@@ -15,8 +15,9 @@
*/
package example.events;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;

View File

@@ -18,7 +18,6 @@ package com.acme.myproject.stereotypes;
import lombok.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
@@ -67,7 +66,6 @@ public class Stereotypes {
static class SomeAppInterfaceImplementation implements SomeAppInterface {}
@Value
@ConstructorBinding
@ConfigurationProperties("org.springframework.modulith.sample")
static class SomeConfigurationProperties {

View File

@@ -1,53 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith</artifactId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<artifactId>spring-modulith-starter-jpa-jakarta</artifactId>
<name>Spring Modulith - Starter JPA (Jakarta)</name>
<properties>
<module.name>org.springframework.modulith.starter.jpa.jakarta</module.name>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-api</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-moments</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<!-- Events -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-events-core</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-events-jackson</artifactId>
<version>0.1.0-SNAPSHOT</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-events-jpa-jakarta</artifactId>
<version>0.1.0-SNAPSHOT</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>