Greetings!
I tried to achieve dynamically adjustable behaviour of a particular button (similar to the “Next” button in all kinds of wizards) by a combination of the Strategy and the Factory Method patterns, when came across this problem.
Here’s some simplified relevant code:
- the core module
@Service(HandlerFactoryService.NAME)
public class HandlerFactoryServiceBean implements HandlerFactoryService {
@Inject
protected Map<String, Handler> handlers;
@Override
public Handler getHandler(String id) {
return handlers.get(id);
}
}
@Service("Impl")
public class ConcreteHandler implements Handler {
@Override
public Boolean doStuff(Map<String, String> params) {
return params.containsKey("test");
}
}
- the web module
public class AbstractScreen extends AbstractWindow {
@Inject
protected Button theBtn;
@Inject
protected HandlerFactoryService factory;
}
public class ConcreteScreen extends AbstractScreen {
@Override
public void init(Map<String, Object> params) {
super.init(params);
theBtn.setAction(new AbstractAction("doStuff") {
@Override
public void actionPerform(Component component) {
Handler handler = factory.getHandler("Impl"); //EXCEPTION OCCURS HERE
//do stuff...
}
});
}
}
The factory itself was registered in web-spring.xml.
It didn’t matter, if concrete handlers had been registered in web-spring.xml or Handler interface had had the “Service”-postfix and extended Serializable, an attempt to obtain a Handler in the web module produced the following:
java.io.NotSerializableException: org.springframework.aop.aspectj.AspectJPointcutAdvisor
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178) ~[na:1.8.0_161]
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348) ~[na:1.8.0_161]
at com.haulmont.cuba.core.sys.serialization.StandardSerialization.serialize(StandardSerialization.java:34) ~[cuba-global-6.8.7.jar:6.8.7]
... 62 common frames omitted
I’m not sure how did an AspectJPointcutAdvisor get queued for serialization.
Anyway, it was very wrong approach for a CUBA-app from the beginning. A LocalServiceProxy is basically an instruction for an invocation handler of some sort: which method of which bean to invoke and what arguments to use.
Thus you should only send data between tiers with a LocalServiceProxy, not dynamically adjust logic.