EventHandlers getting mixed up

I have two event handlers and one of them is called even if I publish a different event in the event bus. Why. It was working in version 4.6.9 but I had a problem in the previous version for the event.getProductId() which was returning an object instead of a String and so the latest version helped there but now this latest version can’t tell which event has been published recently and which has not.

Just for a follow up, I was checking the path that is being called and I found out that Command Gateway is doing fine, the event sourcing handler is also fine but the event handler is the one getting mixed up, here are my two event handlers and the latter is being called rather than the first although the command and event sourcing states the correct command and event which has been called.

@EventHandler
	public void onProductCreatedEvent(ProductCreatedEvent event) {
		System.out.println("Is it being called - > " + event.toString());
		Product product = new Product();
		BeanUtils.copyProperties(event, product);
		
		productRepository.save(product);
	}
	
	
	@EventHandler
	public void onProductDeletedEvent(ProductDeletedEvent productDeletedEvent) {
		
		productRepository.deleteById(productDeletedEvent.getProductId().trim());
	}
	

This also causes the product not being saved but returns the id, so when I remove the latter eventhandler , it gets saved . Help please thanks.

Does the ProductDeletedEvent extend from the ProductCreatedEvent? Then still, it should pick the most specific handler. Can you share how the events are stored, as well as the Java classes of both events?

No. It’s not extended.
Here is the ProductCreatedEvent.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ProductCreatedEvent {
	private String productId;
	private String name;
	private BigDecimal price;
	private Integer quantity;
	private String image;
	private String category;
	private String subcategory;
	private String description;
	private Float rating;
}

ProductDeletedEvent.java

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductDeletedEvent {
	@AggregateIdentifier
	private String productId;
	
	
}

Then my aggregate is here:

@Aggregate
@SuppressWarnings( "unused")
public class ProductAggregate {
	
	
	@AggregateIdentifier
	private String productId;
	private String name;
	private BigDecimal price;
	private Integer quantity;
	private String image;
	private String category;
	private String subcategory;
	private String description;
	private Float rating;
	
	//constructor to take the command
	
	public ProductAggregate() {
		
	}
	@CommandHandler
	public ProductAggregate(CreateProductCommand createProductCommand) {
		//business logic or validations confirm if the user exists
		
		//create the events object and since the product command has
		//similar data as what we need in the event , then we use beans
		ProductCreatedEvent productCreatedEvent = 
					new ProductCreatedEvent();
		BeanUtils.copyProperties(createProductCommand, productCreatedEvent);
		
		//publish the events
		AggregateLifecycle.apply(productCreatedEvent);
		
	}
	
	
	
	@EventSourcingHandler
	public void onProductCreatedEvent(ProductCreatedEvent event) {
		this.category = event.getCategory();
		this.description = event.getDescription();
		this.image = event.getImage();
		this.name = event.getName();
		this.price = event.getPrice();
		this.productId = event.getProductId();
		this.quantity = event.getQuantity();
		this.rating = event.getRating();
		this.subcategory = event.getSubcategory();
	}
	
	@CommandHandler
	public ProductAggregate(DeleteProductCommand deleteProductCommand) {
		//create the events object and since the product command has
		//similar data as what we need in the event , then we use beans
		ProductDeletedEvent productDeletedEvent = 
					new ProductDeletedEvent();
		BeanUtils.copyProperties(deleteProductCommand, productDeletedEvent);
		//publish the events
		AggregateLifecycle.apply(productDeletedEvent);
		
		
	}
	
	
	
	@EventSourcingHandler
	public void onProductDeletedEvent(ProductDeletedEvent event) {
		this.productId = event.getProductId();
		this.category = null;
		this.description = null;
		this.image = null;
		this.name = null;
		this.price = null;
		this.quantity = null;
		this.rating = null;
		this.subcategory = null;
	}
}

And the event handlers are here:

@Component
@ProcessingGroup("product")
public class ProductEventsHandler {
	
	private ProductRepository productRepository;
	
	public ProductEventsHandler(ProductRepository productRepository) {
		this.productRepository = productRepository;
	}
	
	
	@EventHandler
	public void onProductDeletedEvent(ProductDeletedEvent productDeletedEvent) {
		
		
		//create the events object and since the product command has
		productRepository.deleteById(productDeletedEvent.getProductId().trim());
	}
	
	@EventHandler
	public void onProductCreatedEvent(ProductCreatedEvent event) {
		Product product = new Product();
		BeanUtils.copyProperties(event, product);
		
		productRepository.save(product);
	}
	
	@ExceptionHandler
	public void handle(Exception exception) throws Exception {
		throw exception;
	}
}

That’s weird, do you use the default XStream serializer?

I just checked since I have no Xtream dependecy in my pom.xml but I saw a file xtream-1.4.19.jar in my maven dependencies but am also seeing all other seriliazation dependencies, but I don’t know which one is being used by default.

Your commad handler for DeleteProductCommand is a constructor:

	@CommandHandler
	public ProductAggregate(DeleteProductCommand deleteProductCommand) {

try converting it to method and see if that helps.

1 Like