6. 5 -Lab 3 -Events on CDI
In this event lab we will learn how to use DDD events exploring CDI events.
6.1 Step 1: Create the event:
import java.math.BigDecimal;
public record ProductPriceChanged(String productId, BigDecimal oldPrice, BigDecimal newPrice) {
}
6.2 Step 2: Create Update Product price domain event:
package com.example.ecommerce.domain;
import com.example.ecommerce.annotations.DomainService;
import com.example.ecommerce.domain.events.ProductPriceChanged;
import jakarta.enterprise.event.Event;
import jakarta.inject.Inject;
import java.math.BigDecimal;
import java.util.Objects;
@DomainService
public class UpdateProductPrice {
private final ProductRepository repository;
private final Event<ProductPriceChanged> productPriceChangedEvent;
@Inject
public UpdateProductPrice(ProductRepository repository, Event<ProductPriceChanged> productPriceChangedEvent) {
this.repository = repository;
this.productPriceChangedEvent = productPriceChangedEvent;
}
public void execute(Product product, BigDecimal price) {
Objects.requireNonNull(product, "Product must not be null.");
Objects.requireNonNull(price, "Price must not be null.");
if (price.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Price must be > 0.");
}
var event = new ProductPriceChanged(product.getId(), product.getPrice().amount(), price);
this.productPriceChangedEvent.fire(event);
product.update(price);
this.repository.save(product);
}
}
Update the Application class to call the new UpdateProductPrice
service, thus update the class ProductService
:
package com.example.ecommerce.domain;
import com.example.ecommerce.annotations.ApplicationService;
import jakarta.inject.Inject;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
@ApplicationService
public class ProductService {
private final ProductRepository repository;
private final UpdateProductPrice updateProductPrice;
@Inject
public ProductService(ProductRepository repository, UpdateProductPrice updateProductPrice) {
this.repository = repository;
this.updateProductPrice = updateProductPrice;
}
public Product save(Product product) {
return repository.save(product);
}
public void deleteById(String id) {
repository.deleteById(id);
}
public Optional<Product> findById(String id) {
return repository.findById(id);
}
public List<Product> findAll() {
return repository.findAll();
}
public void changePrice(String id, BigDecimal price) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Product with id " + id + " not found"));
//we could improve this exception as well.
this.updateProductPrice.execute(product, price);
}
}
Update the Resource class to call the new method:
@PATCH
@Path("{id}/price")
public void changePrice(@PathParam("id") String id, UpdatePriceRequest body) {
service.changePrice(id, body.price());
}
On the Product
class also include the update method:
Create a new class to listen to the event:
package com.example.ecommerce.marketing;
import com.example.ecommerce.domain.events.ProductPriceChanged;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import java.math.BigDecimal;
@ApplicationScoped
public class SocialMediaPriceChangePublisher {
public void onPriceChange(@Observes ProductPriceChanged event) {
BigDecimal oldP = event.oldPrice();
BigDecimal newP = event.newPrice();
// demo behavior: print only when the price dropped
if (newP.compareTo(oldP) < 0) {
System.out.println("[SOCIAL] 🎉 Promo! Product " + event.productId()
+ " dropped from " + oldP + " to " + newP + ". #Sale #Deal");
} else {
// keep it simple for the lab—no op on increases
System.out.println("[SOCIAL] (ignored) price increased for " + event.productId()
+ " from " + oldP + " to " + newP);
}
}
}
6.3 Step 3: Execute the application and test the new endpoint:
6.4 Step 4: Test the new endpoint:
curl --location 'http://localhost:8181/products' \
--header 'Content-Type: application/json' \
--data '{"name": "Pen", "currency": "USD", "amount": 10}'
curl --location --request PATCH 'http://localhost:8181/products/61c848a9-3bb8-4668-89c1-227cc6a4e049/price' \
--header 'Content-Type: application/json' \
--data '{"price": 6}'
Last update:
2025-09-05