spring-guice
spring-guice copied to clipboard
Support for SpringBoot 3 Aot and GraalVM native images
Version Info
java:17 spring-boot:3.0.1 spring-framework:6.0.3 spring-guice:2.0.2 native-maven-plugin:0.9.19
Description
I followed the requirements of the SpringBoot3 native-image document and made relevant configuration. like this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>${mainClass}</mainClass>
</configuration>
<executions>
<execution>
<configuration>
<jvmArguments>
<!-- -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005-->
</jvmArguments>
</configuration>
<id>process-aot</id>
<goals>
<goal>process-aot</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>${native-maven-plugin.version}</version>
</plugin>
But encountered java.lang.IllegalArgumentException: Code generation does not support com.google.inject.Key<?>
when execute spring-boot-maven-plugin#process-aot
BeanDefinitionPropertyValueCodeGenerator#generateCode
private CodeBlock generateCode(@Nullable Object value, ResolvableType type) {
if (value == null) {
return NULL_VALUE_CODE_BLOCK;
}
for (Delegate delegate : this.delegates) {
CodeBlock code = delegate.generateCode(value, type);
if (code != null) {
return code;
}
}
throw new IllegalArgumentException("Code generation does not support " + type);
}
This seems entirely expected, but I didn't see the same error when I tried it with an empty project from start.spring.io. Whether it can be fixed or not I don't know. Maybe you could provide a complete, minimal sample?
This seems entirely expected, but I didn't see the same error when I tried it with an empty project from start.spring.io. Whether it can be fixed or not I don't know. Maybe you could provide a complete, minimal sample?
You can download and unzip spring-native-guice-demo.zip
And mvn -X -Dmaven.test.skip=true package
Thanks, that helps. Using @EnableGuiceModules
is enough, in fact, to make a project fail on AOT processing.
I don't know if this is fixable. Spring Guice does some really extremely dynamic things to an ApplicationContext
and one of the assumptions of AOT is that the ApplicationContext
is fixed at build time. Actually I'm surprised it didn't break in other places, or possibly it did and this is just the first of a long series of errors. If we do fix it there will likely be compromises to do with the "fixed world" assumptions that have to be made in AOT - behaviour at runtime for some apps might be different. Hopefully that wouldn't affect too many people, and it's consistent with the limitations of AOT generally, not just with Spring Guice.
BTW why did you exclude spring-context
from the dependencies (shouldn't be necessary)?
BTW why did you exclude spring-context from the dependencies (shouldn't be necessary)?
spring-boot 3.0.1
need spring-context 6.0.3
, but spring-guice 2.0.2
need spring-context 5.3.16
This should have no impact.
With some changes to spring-guice (replacing constructor-based bean definitions with reflection-free variants) I was able to make your sample compile with AOT. But it will never run in GraalVM native, unless Guice supports it, and I don't see any appetite for that. If AOT on its own is interesting for anyone I can show you how to do it.
I think I got something working. Try 2.0.3-SNAPSHOT and make sure you add reflection hints like this:
class DemoRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
// Guice needs reflection access to at least these...
hints.reflection().registerType(Integer.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Long.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Double.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Float.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Boolean.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Byte.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Short.class, MemberCategory.INVOKE_DECLARED_METHODS);
hints.reflection().registerType(Named.class, MemberCategory.INTROSPECT_DECLARED_METHODS);
// add more here - all the Guice modules declared as @Bean and all classes bound in those, e.g.
hints.reflection().registerType(MyModule.class, MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
hints.reflection().registerType(MyService.class, MemberCategory.INVOKE_DECLARED_METHODS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
...
}
}
and add a filter like this in META-INF/spring.aot.factories
:
org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\
com.example.demo.ExcludeFilter
where
public class ExcludeFilter implements BeanRegistrationExcludeFilter {
static final String IGNORE_ME = "spring-guice";
@Override
public boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {
if (registeredBean.getMergedBeanDefinition().hasAttribute(IGNORE_ME)) {
return true;
}
return false;
}
}
Complete sample: https://github.com/scratches/guice-demo.
Thanks! I will try this demo.