Closed aks-wp closed 2 years ago
Could you please double check that your application is working as expected without AOT? I am asking that because:
scanBasePackages
with an AOT application and it seems to work as expected (both on JVM and native)@SpringBootApplication(scanBasePackages = "com.xyz.package.*")
be @SpringBootApplication(scanBasePackages = "com.xyz.package")
?
- Shouldn't
@SpringBootApplication(scanBasePackages = "com.xyz.package.*")
be@SpringBootApplication(scanBasePackages = "com.xyz.package")
?
Yes, the original app actually doesn't have the wildcard at the end, but without it, the native image would complain about missing dependencies...
With regards to running the app without AOT... I get the following error when starting the native image
ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor':
Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.context.annotation.ConfigurationClassPostProcessor]:
No default constructor found; nested exception is java.lang.NoSuchMethodException: org.springframework.context.annotation.ConfigurationClassPostProcessor.<init>()
(If you meant, as a regular cloud function app - yes, those are running live today - this is just a migration effort to move them to Native)
@sdeleuze Thank you for the pointer about the wildcard used at the end of scanBasePackages - that seems to have caused the issue about being unable to locate the function. Interestingly, when I used the functional style earlier, I didn't get the same issue with the wildcard, so I didn't think too much of it.
Now I'm working through a different issue with a NPE by adding hints. (Since these are from other modules). Will keep you posted.
Caused by: java.lang.NullPointerException: null at org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:134) ~[na:na] at org.springframework.cloud.function.adapter.aws.AWSLambdaUtils.generateMessage(AWSLambdaUtils.java:68) ~[na:na] at org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.eventLoop(CustomRuntimeEventLoop.java:89) ~[scrubbed] at org.springframework.cloud.function.adapter.aws.CustomRuntimeInitializer.lambda$null$0(CustomRuntimeInitializer.java:47) ~[na:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:791)
Okay, so @sdeleuze I found a work around from an existing issue (https://github.com/spring-projects-experimental/spring-native/issues/241) . The trick seemed to be to generate spring.components in the dependencies and use that jar instead.
However, Autowiring dependencies still seems to be an issue and I get NoSuchBeanDefinitionException
. Since I'm using 0.10.4, I'd be safe to assume (https://github.com/spring-projects-experimental/spring-native/issues/782) is fixed. So I removed spring-context-indexer
from the main pom (I only use it now in the dependencies as mentioned above) and I don't get the NoSuchBeanDefinitionException
for my dependency. But when deploying it to AWS lambda, the function throws the below error
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.function.context.FunctionCatalog' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) ~[na:na] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) ~[na:na] at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172) ~[na:na] at org.springframework.cloud.function.adapter.aws.CustomRuntimeEventLoop.eventLoop(CustomRuntimeEventLoop.java:76) ~[] at org.springframework.cloud.function.adapter.aws.CustomRuntimeInitializer.lambda$null$0(CustomRuntimeInitializer.java:47) ~[na:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:791)
Note that if I keep the indexer in the pom and remove the autowiring, everything works as expected. But since these are multiple microservices hooked together, I'm hoping to get all the pieces working together on the cloud function app.
I'll also try to get a reproducer going, but in the meantime, if you have any suggestions that I can try out, do let me know. Basically, from my original post, the @Autowired Bar bar is from the dependency jar.
Thanks much!
@olegz @OlgaMaciaszek Could you please check why spring.components
is needed here with Spring Cloud Function (we should not rely on that) and if that's Spring Cloud Function specific or a more global issue?
Is there a sample application that demonstrates the issue? Both https://github.com/spring-projects-experimental/spring-native/tree/main/samples/cloud-function-aws and https://github.com/spring-projects-experimental/spring-native/tree/main/samples/cloud-function-netty have ben tested in AWS without issues. I basically need a way to reproduce it so a sample app with bare minimum in github somewhere would be nice
@aks-wp Please provide a repro project.
@olegz Yeah, I've had no problem with running a simple demo app. In the first link you shared, the only difference is, instead of Function<String, String>, I use Function<FooBar, FooBar> and FooBar is a from a dependency (and is a different package so scanBasePackages is used) There's no problem starting the app locally, but it fails on AWS. I'll try to get the repro over the weekend.
Ok, i'll give it a shot shortly based on your description, see if I can reproduce
I seemed to reproduced something, but it is not what you have. Basically i modified the sample to look like
@Component
public class NameUppercaser implements Function<Person, String> {
@Override
public String apply(Person input) {
return "hi " + input.getName().toUpperCase() + "!";
}
}
with Person
looking like
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
And i get this
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.demo.domain.Person` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
. . which is very weird and most definitely leads me to believe that there is some native voodoo going on here since this is the simplest possible example and runs find locally and in AWS without native.
Will keep on digging. . .
@aks-wp I just updated the sample - https://github.com/spring-projects-experimental/spring-native/tree/main/samples/cloud-function-aws to use POJO and successfully tested it in AWS. Please take a look and let me know if I am missing something as I still can not reproduce your error
Thanks @olegz - I've forked your sample. For simplicity sake, I've moved Person to a different package (in reality, this would be it's own module) but my main point was using scanBasePackages seems to cause issues for me - https://github.com/aks-wp/spring-native/blob/main/samples/cloud-function-aws/src/main/java/com/example/demo/DemoApplication.java#L10
@aks-wp i see, but scanBasePackages
is part of the spring-boot, so I am not sure what relevance does it have for s-c-function. Perhaps I am missing something. May be @sdeleuze @snicoll can chime in?
Actually, just chatted with @sdeleuze , so let me modify the sample and test it again. Will let you know once done
@aks-wp I now think there is no issue as I just tested it with
@SpringBootApplication(scanBasePackages="com.example.demo")
Now, couple of problems that could get you off track:
scanBasePackages = "com.example.demo.*
) that would simply be the wrong syntax and would not work. By definition of 'base package' it (the asterisk) is not needed, since it already implies "start scanning from here and recursively scan the rest of the hierarchy"scanBasePackages=com.example.dependency
which is a non-existing package in your example, so it will not work since by scanning it it can not find anything.scanBasePackages
says "Base packages to scan for annotated components". It is not a general class loading instruction to search for any type of classes. So if you simply have some POJO in some package that is not spring managed component it will not work either.@sdeleuze I believe we can resolve it as there is nothing to be done. As for the TypeHint
and implementation of BeanFactoryNativeConfigurationProcessor
to simplify things for the user, that is a whole other issue which I am already working on, so you can create one and assign to me.
Context: Migrating Spring Cloud Function AWS apps to use Spring Native
I've been able to run dsyer's spring cloud function aws demo successfully, but when migrating my existing cloud function apps to spring native, I get the error "Failed to locate function". Running in debug mode, I can see it does try to look for my function
c.f.c.c.BeanFactoryAwareFunctionRegistry : Function '****' is not available in FunctionCatalog or BeanFactory _Caused by: java.lang.IllegalArgumentException: Failed to locate function. Tried locating default function, function by 'DEFAULT_HANDLER', 'HANDLER' env variable as well as'spring.cloud.function.definition'. Functions available in catalog are: [functionRouter]
The main difference between the demo app and the real app is scanning base packages @SpringBootApplication(scanBasePackages = "com.xyz.package.*")
Removing that ensures the function is invoked.
I've used spring native version 0.10.4 and 0.10.5 (Release versions), 0.11.0-SNAPSHOT and RC1 with Spring Cloud functions 3.1.5 and 3.2.0-M3 respectively.
The scrubbed version in a nutshell is
cc: @olegz (Not sure if this issue belongs here or in the Cloud Function repo)