Reputation:
Let's say I have this code structure:
public class NotificationService {
public void send(Notification notification) {
// call other services and send the notification
}
}
public class OrderNotification implements Notification {
@Autowired
public TranslationService translationService;
private String orderNumber;
public OrderNotification(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getMessage() {
return translationService.trans('notification.order', new Object[]{orderNumber});
}
}
So, my goal is to use the NotificationService
in this way:
notificationService.send(new OrderNotification(orderNumber));
But I know that code above won't work, because of the translationService
won't be resolved.
My goal is to pass custom parameters to my Notification
classes and being able to use services inside that class. What is the best way to do it in the Spring?
Upvotes: 0
Views: 614
Reputation: 2570
I know that below is not the correct answer to your question. It is however a bad design pattern to combine Entities
and Services
. An Entity
should only contain information about the object and not business logic. A Service
contains all the business logic.
You need to separate your Service
from your Entity
.
OrderNotification looks like a regular entity. The entity should not contain business logic. You need a specific service for the business logic.
public class OrderNotification implements Notification {
private String orderNumber;
public OrderNotification(String orderNumber) {
this.orderNumber = orderNumber;
}
public String getMessage() {
return "Order number: " + orderNumber;
}
//Getter & Setters
...
}
@Service
public class NotificationService {
@Autowired
public TranslationService translationService;
public void send(Notification notification) {
//I do not know what trans accepts, so I assume it can accept Notification
translationService.trans(notification.getMessage());
}
}
If you really need to combine the entity and service - Then I recommend this approach:
@Service
public class Master{
@Autowired
NotificationService notificationService
public void testMethod(){
Notification notification = notificationService.createOrder("order1");
notificationService.send(notification);
}
}
@Service
public class NotificationService {
@Autowired
public TranslationService translationService;
public Notification createOrder(String orderNumber){
return new OrderNotification(orderNumber, translationService);
}
public void send(Notification notification) {
// call other services and send the notification
notification.getMessage();
}
}
public class OrderNotification implements Notification {
private TranslationService translationService;
private String orderNumber;
//I have changed this constructor to accept TranslationService.
public OrderNotification(String orderNumber, TranslationService translationService) {
this.orderNumber = orderNumber;
this.translationService = translationService;
}
public String getMessage() {
return translationService.trans('notification.order', new Object[]{orderNumber});
}
}
Upvotes: 2
Reputation: 44952
You have few options available:
Configure AOP and load time weaving to process Spring annotations on objects created with new
keyword. This is explained in the docs 5.8.1. Using AspectJ to dependency inject domain objects with Spring.
Declare OrderNotification
as a prototype scoped bean and obtain each instance from the context using BeanFactory.getBean(Class<T> requiredType, Object... args)
method.
String orderNumber = "123";
OrderNotificaton = factory.getBean(OrderNotificaton.class, orderNumber);
Drop the @Autowired
and use plain constructor injection.
public OrderNotification(TranslationService translationService, String orderNumber) {
this.translationService = Objects.requireNonNull(translationService);
this.orderNumber = Objects.requireNonNull(orderNumber);
}
If you only require simple @Autowired
I'd go with option 3. It's the simplest approach and makes writing unit tests easier as you don't have to depend on Spring.
Upvotes: 0