Git Product home page Git Product logo

Comments (4)

liweinan avatar liweinan commented on August 14, 2024

Hi @itineric The project has not verified with native compilation yet, any contribution on this field is welcome.

from resteasy-spring-boot.

itineric avatar itineric commented on August 14, 2024

I got something that works based on your servlet/resteasy-servlet-spring-boot-sample-app.

Hope it helps you to add your lib to the graalvm supported ones: https://www.graalvm.org/native-image/libraries-and-frameworks/

Bean double registration

First you need to declare a BeanRegistrationExcludeFilter because of this code in your library:
https://github.com/resteasy/resteasy-spring-boot/blob/main/servlet/resteasy-servlet-spring-boot-starter/src/main/java/org/jboss/resteasy/springboot/ResteasyBeanProcessorTomcat.java#L57

Why ? the bean registered there is added once during Spring AOT process, then again during the runtime. The error is then The bean 'com.sample.app.configuration.JaxrsApplication' could not be registered. A bean with that name has already been defined and overriding is disabled.

The implementation of the BeanRegistrationExcludeFilter looks like this:

class ServletRegistrationBeanExcludeFilter implements BeanRegistrationExcludeFilter
{
  @Override
  public boolean isExcludedFromAotProcessing(final RegisteredBean registeredBean)
  {
    return registeredBean.getBeanClass().equals(ServletRegistrationBean.class);
  }
}

Maybe in more complex applications filtering needs to be more specific (not excluding every ServletRegistrationBean from AOT process). But for applications built like the sample, it works.

Another solution may be to keep AOT for that bean registration (thats the point of AOT after all) but then the registration code in https://github.com/resteasy/resteasy-spring-boot/blob/main/servlet/resteasy-servlet-spring-boot-starter/src/main/java/org/jboss/resteasy/springboot/ResteasyBeanProcessorTomcat.java must be excluded from native deliverable (since already done during AOT).

In order for the BeanRegistrationExcludeFilter to be triggered it must be declared in a file named META-INF/spring/aot.factories using the following key: org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=com.sample.app.configuration.ServletRegistrationBeanExcludeFilter

Reflection hints

When thats done, you then get reflection errors.
Such errors can to be addressed using hints or reflect-config.json files.
I have done it using hints (which spring native will use to generation reflect-config.json).

The class with comments:

import static org.springframework.aot.hint.ExecutableMode.INVOKE;

import java.io.OutputStream;

import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;

@Configuration
@ImportRuntimeHints(NativeImageHints.class)
public class NativeImageHints implements RuntimeHintsRegistrar
{
  @Override
  public void registerHints(final RuntimeHints hints, final ClassLoader classLoader)
  {
    try
    {
      hints.reflection()
        // resteasy hints (yous should add them to your lib for now since resteasy is not (yet) a supported graalvm lib)
        .registerConstructor(org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages_$logger.class.getConstructor(org.jboss.logging.Logger.class),
                             INVOKE)
        .registerConstructor(org.jboss.resteasy.plugins.validation.i18n.LogMessages_$logger.class.getConstructor(org.jboss.logging.Logger.class),
                             INVOKE)
        .registerField(org.jboss.resteasy.resteasy_jaxrs.i18n.Messages_$bundle.class.getField("INSTANCE"))
        .registerField(org.jboss.resteasy.plugins.validation.i18n.Messages_$bundle.class.getField("INSTANCE"))
        .registerConstructor(classLoader.loadClass("org.jboss.resteasy.core.ContextServletOutputStream").getDeclaredConstructor(classLoader.loadClass("org.jboss.resteasy.core.ContextParameterInjector"),
                                                                                                                                OutputStream.class),
                             ExecutableMode.INVOKE)
        // this lib hint
        .registerType(classLoader.loadClass("org.jboss.resteasy.springboot.ResteasyApplicationBuilder"),
                      MemberCategory.INTROSPECT_PUBLIC_METHODS,
                      MemberCategory.INVOKE_PUBLIC_METHODS)

        // app hints (thats only here to make the sample work, must not be included in your lib)
        .registerType(JaxrsApplication.class,
                      MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)
        .registerType(org.jboss.resteasy.springboot.common.sample.resources.Echo.class,
                      MemberCategory.INVOKE_PUBLIC_METHODS)
        .registerType(org.jboss.resteasy.springboot.common.sample.resources.Foo.class,
                      MemberCategory.INVOKE_PUBLIC_METHODS)
        .registerType(org.jboss.resteasy.springboot.common.sample.resources.EchoMessage.class,
                      MemberCategory.INTROSPECT_PUBLIC_METHODS,
                      MemberCategory.INVOKE_PUBLIC_METHODS);

    }
    catch (final ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | SecurityException exception)
    {
      throw new RuntimeHintsException(exception);
    }
  }

  private static class RuntimeHintsException extends RuntimeException
  {
    private static final long serialVersionUID = 1L;

    RuntimeHintsException(final Throwable cause)
    {
      super(cause);
    }
  }
}

The build

To build all that natively, thats the profile I added to the pom.xml

<build>
 ...
 ...
 ...
  <pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.graalvm.buildtools</groupId>
        <artifactId>native-maven-plugin</artifactId>
        <version>0.9.25</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>
  </pluginManagement>
</build>

<profiles>
  <profile>
    <id>native</id>
    <build>
      <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
              <image>
                <builder>paketobuildpacks/builder:tiny</builder>
                <env>
                  <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                </env>
              </image>
            </configuration>
            <executions>
              <execution>
                <id>process-aot</id>
                <goals>
                  <goal>process-aot</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <groupId>org.graalvm.buildtools</groupId>
            <artifactId>native-maven-plugin</artifactId>
            <configuration>
              <classesDirectory>${project.build.outputDirectory}</classesDirectory>
              <metadataRepository>
                <enabled>true</enabled>
              </metadataRepository>
              <requiredVersion>22.3</requiredVersion>
            </configuration>
            <executions>
              <execution>
                <id>add-reachability-metadata</id>
              <goals>
                <goal>add-reachability-metadata</goal>
              </goals>
            </execution>
            <execution>
              <id>build-native</id>
              <goals>
                <goal>compile-no-fork</goal>
              </goals>
              <phase>package</phase>
              <configuration>
                <fallback>false</fallback>
                <buildArgs>
                  <arg>--install-exit-handlers</arg>
                </buildArgs>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

And the command line: mvn -f servlet/resteasy-servlet-spring-boot-sample-app -Pnative package that will produce some ./servlet/resteasy-servlet-spring-boot-sample-app/target/resteasy-servlet-spring-boot-sample-app executable

Resources:
Setup graalvm: https://www.graalvm.org/jdk17/docs/getting-started/
The graalvm manual to understand what I am talking about: https://www.graalvm.org/latest/reference-manual/native-image/metadata/

from resteasy-spring-boot.

liweinan avatar liweinan commented on August 14, 2024

@itineric Thanks for sharing the information! I've talked with @jamezp on this topic, who is the leader of the RESTEasy project, and the conclusion is that currently the RESTEasy project hasn't supported native build formally.(In Quarkus it uses resteasy-reactive which officially supports native build). So the native build of RESTEasy projects are not formally supported yet (except the resteasy-reactive for Quarkus). But any contribution in this field is welcome :D

from resteasy-spring-boot.

liweinan avatar liweinan commented on August 14, 2024

Close as answered.

from resteasy-spring-boot.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.