The preferred way to send data: is attaching an ID referring your business objects on the signal code. As shown here:
https://developer.axonivy.com/doc/8.0.3/designer-guide/concepts/adaptive-case-management.html#signal-boundary-event
With this ID you can load the data on the receiver side. And e.g. use BusinessData or Persistence (JPA) as store for the data.
Alternatively you can also attach a payload as raw object as shown here: https://dev.axonivy.com/doc/nightly/public-api/ch/ivyteam/ivy/workflow/signal/IBpmSignalService.html#send(ch.ivyteam.ivy.process.model.value.SignalCode,java.lang.Object)
However, I'd not stress that concept too far as signals can be fired over Project/ProcessModelVersion boundaries. But as long as you just send standard Java types, e.g. a string representing JSON, you should be fine with that.
Please check out are WorkflowDemos for more use-cases and Demos:
https://developer.axonivy.com/market/workflow-demo