Spring IoC: How about serialization?

I'm just in the middle of developing a new software component using the Spring Framework. I like it, but now I have a question regarding IoC and serialization.

Given that I have this class (excluded imports and package declaration):

public class EMailNotificationEndpoint implements NotificationEndpoint { private List<String> notficationEmailAdresses = new ArrayList<String>(); transient private MailSender mailSender; public EMailNotificationEndpoint(MailSender mailSender) { this.mailSender = mailSender; } @Override public void notify(Notification notification) { SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); simpleMailMessage.setTo(notficationEmailAdresses.toArray(new String[notficationEmailAdresses.size()])); simpleMailMessage.setSubject(notification.getType().toString()); simpleMailMessage.setText(notification.getMessage()); mailSender.send(simpleMailMessage); } } 

NotificationEndpoint extends Serializable to enable serialization of all implementations. The thing is, I cannot serialize MailSender (which is org.springframework.mail.MailSender BTW) and wants it to be injected during deserialization. Now my question is obvious: can I do this? And if the answer is yes: how?

I can change the interface and implementations, so there must be a way to such a substance, even if it means that I have to reorganize the corresponding classes.

Any idea or hint is much appreciated!

+4
source share
2 answers

You are right to make the transition.

All you have to do is restore it if necessary during deserialization.

You can implement an adequate readObject method to perform this initialization:

  /** * Always treat de-serialization as a full-blown constructor, by * initializing or validating the final state of the de-serialized object. */ private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException { //always perform the default de-serialization first aInputStream.defaultReadObject(); //do your other stuff, like initialization this.mailSender = ... } 

Note. Here, the object itself should receive a MailSender implementation that is not very DI (Dependency Injection). Either you are fine with this, or you will find another way (typically a different object is involved after deserialization and establishes the correct dependency).


If you really like to do dependency injections, I found a link for Spring and entities that may contain general knowledge applicable to this case:
http://chris-richardson.blog-city.com/migrating_to_spring_2_part_3__injecting_dependencies_into_en.htm

+2
source

You will need to implement the readObject and writeObject custom methods that serialize / deserialize the MailSender state and class, something like this:

 private void writeObject(ObjectOutputStream out) throws ClassNotFoundException, IOException { try { out.defaultWriteObject(); out.writeObject(mailSender.getClass().getName()); for (Field field : mailSender.getClass().getDeclaredFields()) { if (!(Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()))) { Object value = field.get(mailSender); if (value instanceof Serializable) { out.writeObject(field.getName()); out.writeObject(value); } } } } catch (IllegalAccessException e) { throw new IOException(e.getMessage(), e); } } private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException { try { in.defaultReadObject(); mailSender = (MailSender)Class.forName((String)in.readObject()).newInstance(); Map<String, Field> fields = new HashMap<String, Field>(); for (Field field : mailSender.getClass().getDeclaredFields()) { fields.put(field.getName(), field); } int remainingFields = mailSender.getClass().getDeclaredFields().length; while (remainingFields > 0) { String fieldName = (String)in.readObject(); Object value = in.readObject(); fields.get(fieldName).set(mailSender, value); remainingFields--; } } catch (IllegalAccessException e) { throw new IOException(e.getMessage(), e); } catch (InstantiationException e) { throw new IOException(e.getMessage(), e); } } 

You might want to tighten up the reflective code and perhaps use recursion if the required state is not serializable, but you are the essence of what you need to do.

+1
source

All Articles