0

I have three maven projects:

  • demo-api: Contains POJOs for function APIs i.e. OutputPojo.class, InputPojo.class
  • demo-packaged-function: Defines a single function public OutputPojo apply(InputPojo) {...} that depends on the 'demo-api' project.
  • demo-deployer: Uses spring-cloud-function-deployer to run the packaged function, also depends on the 'demo-api' project.

If I use simple types for the function signature (i.e. refactor to String apply(String input) {...} then everything works fine. However, with the setup described above I get the following exception:

Exception in thread "main" java.lang.ClassCastException: class org.example.function.api.InputPojo cannot be cast to class org.example.function.api.InputPojo (org.example.function.api.InputPojo is in unnamed module of loader 'app'; org.example.function.api.InputPojo is in unnamed module of loader org.springframework.cloud.function.deployer.FunctionArchiveDeployer$1 @7fedfe27)

Which makes sense becaues the class InputPojo is loaded by both class loaders. If I don't package the function as a fat jar, i get ClassNotFoundException when trying to deploy the jar, and I can't remove the dependency on demo-api from the deployer project as otherwise I cannot use the POJO classes when calling the function. How is this meant to work without simple argument types for the functions?

The documentation doesn't cover this, and while there are examples of packaged functions using POJOs, i cannot find any examples of them actually being called by the deployer - other than one is the unit tests which demos type conversion and converts the POJO to Message.

James
  • 1,237
  • 4
  • 22
  • 43
  • Why is the demo-deployer depends on demo-api? Based on what I see demo-packaged-function should depend on demo-api. – Oleg Zhurakousky Jan 29 '20 at 12:28
  • In the example both depend on the demo-api, the deployer - which acts as a delegate for invoking the function, needs to be aware of the argument types for converting to different infrastructure adapters. i.e. The function is defined as `public OutputPojo apply(InputPojo) ` in the demo-packaged-function, and is invoked in the deployer as `OutputPojo output = deployedFunction.apply(InputPojoInstance)` – James Jan 29 '20 at 14:01
  • 1
    That would not work since it would have to pass through the class loader boundary. In other words we would have to serialize your instance of POHO to let's say JSON and then pass it as byte[] and then deserialize back into the same POJO in he context of a different class loader. Quite frankly, that is not what the deployer is for so I am now wondering why are you interested in the explicit deployment as opposed to running functions in your application context? – Oleg Zhurakousky Jan 29 '20 at 14:05
  • I was thinking to use it to abstract the function away from different infrastructure level adapters, but in some cases the adapters might need to be aware of details about the messages or at least headers in order to route/blah. Hence was trying to create some higher-level POJO around the actual function payload - perhaps this is the wrong approach as the Spring messaging API has headers as part of the message object but it's not clear how/if the function can provide such metadata (preferably in a way that doesn't couple it to spring messaging). – James Jan 29 '20 at 14:33
  • 1
    You can use spring [Message](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/Message.html) for it, this way you can pass a structure without worrying about a) creating your own, b) worry about class loader isolation – Oleg Zhurakousky Jan 29 '20 at 14:37
  • Thanks man, feel free to add an answer summarising the above and i'll mark it as answered – James Jan 29 '20 at 14:54

0 Answers0