I want to create a generic method for sending emails with attachments, I was thinking about using something like this:
public class MailAttachment<T> {
private String attachmentName;
private T attachment;
public MailAttachment(String attachmentName, T attachment) {
super();
this.attachmentName = attachmentName;
this.attachment = attachment;
}
//Getters and setters
}
Later, send the generic type and let Java decide in compilation time the instance type sent. But the compiler adds an error saying that it needs to be cast to the correct type (File, DataSource, InputStreamSource).
@Autowired
private JavaMailSender mailSender;
public void sendHtmlMail(Mail mail, MailAttachment<?> attachment) {
new Thread(() -> {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(mail.getTo());
helper.setSubject(mail.getSubject());
helper.setFrom(host);
message.setContent(mail.getContent(), "text/html");
if (attachment != null) {
//Casting error
helper.addAttachment(attachment.getAttachmentName(), attachment.getAttachment());
}
mailSender.send(message);
} catch (MessagingException | MailException e) {
logger.error("Error sending email: ", e);
}
}).start();
}
So I had to use a workaround to validate and cast to the correct type, something like this:
if (attachment.getAttachment() instanceof DataSource) {
helper.addAttachment(attachment.getAttachmentName(),
(DataSource) attachment.getAttachment());
} else if (attachment.getAttachment() instanceof File) {
helper.addAttachment(attachment.getAttachmentName(),
(File) attachment.getAttachment());
} else if (attachment.getAttachment() instanceof InputStreamSource) {
helper.addAttachment(attachment.getAttachmentName(),
(InputStreamSource) attachment.getAttachment());
}
So, I was wondering if there is a better way to check this kind of stuff using only this method while keeping the generic type in the parameter?
Create an interface Attachable:
interface Attachable {
void attach(Helper helper);
}
and then implement this for the various types:
class DataSourceAttachable implements Attachable {
String name;
DataSource dataSource; // Initialize in ctor.
void attach(Helper helper) {
helper.addAttachment(name, dataSource);
}
}
// etc, for other types
Then there is no need for generics:
public void sendHtmlMail(Mail mail, Attachable attachable) {
// ...
attachable.attach(helper);
// ...
}