spring-native icon indicating copy to clipboard operation
spring-native copied to clipboard

Add support for Spring Cloud Gateway

Open joshlong opened this issue 4 years ago • 22 comments

I've got a Graal + Spring Cloud Gateway app that I can't quite get over the GraalVM compilation hump. The code is in this repository.

And there's a compile.sh at the root of the project that illustrates my build. I get an inscrutible error, like this:

01:47:50.613 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.maxDirectMemory: 13362528256 bytes
01:47:50.613 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.uninitializedArrayAllocationThreshold: -1
01:47:50.613 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.internal.CleanerJava6 - java.nio.ByteBuffer.cleaner(): available
01:47:50.613 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.internal.PlatformDependent - -Dio.netty.noPreferDirect: false
01:47:50.616 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
01:47:50.616 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.targetRecords: 4
01:47:56.091 [ForkJoinPool-4-worker-9] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 4096
01:47:56.091 [ForkJoinPool-4-worker-9] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
01:47:56.091 [ForkJoinPool-4-worker-9] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
01:47:56.091 [ForkJoinPool-4-worker-9] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
01:47:56.091 [ForkJoinPool-4-worker-9] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.delayedQueue.ratio: 8
01:48:09.991 [ForkJoinPool-2-worker-15] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkAccessible: true
01:48:09.991 [ForkJoinPool-2-worker-15] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkBounds: true
01:48:09.991 [ForkJoinPool-2-worker-15] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@57afd16
01:48:10.027 [ForkJoinPool-2-worker-15] DEBUG io.netty.buffer.AdvancedLeakAwareByteBuf - -Dio.netty.leakDetection.acquireAndReleaseOnly: false
01:48:15.387 [ForkJoinPool-2-worker-0] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.noKeySetOptimization: false
01:48:15.388 [ForkJoinPool-2-worker-0] DEBUG io.netty.channel.nio.NioEventLoop - -Dio.netty.selectorAutoRebuildThreshold: 512
[gateway:70358]     analysis:  26,237.13 ms,  4.59 GB
Fatal error:java.lang.NullPointerException
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.getParsingContext(MethodTypeFlow.java:99)
	at com.oracle.graal.pointsto.util.AnalysisError.parsingContext(AnalysisError.java:122)
	at com.oracle.graal.pointsto.util.AnalysisError.access$000(AnalysisError.java:37)
	at com.oracle.graal.pointsto.util.AnalysisError$ParsingError.message(AnalysisError.java:97)
	at com.oracle.graal.pointsto.util.AnalysisError$ParsingError.<init>(AnalysisError.java:87)
	at com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:138)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:336)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:311)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:112)
	at com.oracle.graal.pointsto.DefaultAnalysisPolicy$DefaultVirtualInvokeTypeFlow.onObservedUpdate(DefaultAnalysisPolicy.java:228)
	at com.oracle.graal.pointsto.flow.TypeFlow.notifyObservers(TypeFlow.java:470)
	at com.oracle.graal.pointsto.flow.TypeFlow.update(TypeFlow.java:542)
	at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:530)
	at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:173)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Error: Image build request failed with exit status 1
com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 1
	at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1541)
	at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1299)
	at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1260)
	at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1219)


joshlong avatar Jun 17 '20 08:06 joshlong

This problem was already in the Graal tracker ( https://github.com/oracle/graal/issues/2595 ) so I've added a reference to this bug and your test project. They are using different spring cloud dependencies in that version but exception looks the same. Doesn't work on Graal 20.2 dev builds either.

aclement avatar Jun 29 '20 15:06 aclement

Ah, I hadn't run that darn gu install native-image command on the 20.2 I grabbed. Now I've done this, the sample is compiling without NPE. Grab 20.2 (I used 20200627) from https://github.com/graalvm/graalvm-ce-dev-builds/releases

aclement avatar Jun 29 '20 15:06 aclement

Now building, the app doesn't run of course, but it fails for expected reasons :) I bet running it with the agent to collect a first go of config and then re-attempting native image build will behave better.

aclement avatar Jun 29 '20 15:06 aclement

Ran with the agent to collect config. Gets further, now breaks with ObjenesisCglibAopProxy usage.

aclement avatar Jun 29 '20 16:06 aclement

Ok, upgraded the project to 0.8.0-SNAPSHOT of the Spring GraalVM feature. Now we're at:

Caused by: org.springframework.cglib.core.CodeGenerationException: com.oracle.svm.core.jdk.UnsupportedFeatureError-->Unsupported method java.lang.ClassLoader.defineClass1(String, byte[], int, int, ProtectionDomain, String) is reachable
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:538) ~[na:na]
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363) ~[na:na]
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110) ~[na:na]
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108) ~[na:na]
	at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) ~[na:na]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:na]
	at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) ~[na:na]
	at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[na:na]
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134) ~[na:na]
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319) ~[na:na]
	at org.springframework.cglib.core.KeyFactory$Generator.create(KeyFactory.java:237) ~[na:na]
	at org.springframework.cglib.core.KeyFactory.create(KeyFactory.java:184) ~[na:na]
	at org.springframework.cglib.core.KeyFactory.create(KeyFactory.java:160) ~[na:na]
	at org.springframework.cglib.proxy.Enhancer.<clinit>(Enhancer.java:104) ~[na:na]
	at com.oracle.svm.core.classinitialization.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:351) ~[na:na]
	at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:271) ~[na:na]

aclement avatar Jun 29 '20 21:06 aclement

Hmm, I got it going but not totally happy with the solution:

2020-06-30 22:02:30.019  INFO 53618 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-06-30 22:02:30.025  INFO 53618 --- [           main] com.example.gateway.GatewayApplication   : Started GatewayApplication in 0.147 seconds (JVM running for 0.149)

But I guess that means I understand all the issues in play, so that's good :)

aclement avatar Jul 01 '20 15:07 aclement

OK - to get it working (these are the current steps, obviously not how it'll be in the end):

  1. Enable all security features in the native image build, otherwise you'll get a nasty security exception ( add parameter --enable-all-security-services to native-image call)
  2. Switch to a Graal 20.2 dev build.
  3. Update to GraalVM spring feature 0.8.0-SNAPSHOT instead of 0.7.1
  4. Tweak the Spring application to currently turn off the validation config. Tweak it to: @SpringBootApplication (proxyBeanMethods = false, exclude = {ValidationAutoConfiguration.class})
  5. Run it with the agent:
mkdir -p graal/META-INF/native-image
java -agentlib:native-image-agent=config-output-dir=graal/META-INF/native-image -jar target/gateway-0.0.1-SNAPSHOT.jar

and add the graal folder to the classpath in compile.sh:

  -cp $CP:../../graal $MAINCLASS

aclement avatar Jul 02 '20 21:07 aclement

Hello! I'm trying to replicate a native spring gateway with your repository but doesn't work

Piranha900 avatar Oct 02 '20 05:10 Piranha900

I've followed @aclement steps and managed to boot up a native spring cloud gateway. you can find the demo project here. Using :

<spring-cloud.version>2020.0.2</spring-cloud.version>
<spring-native.version>0.9.1</spring-native.version>
<graalvm.version>21.0.0.2</graalvm.version>

But at the first Http request I get this error:

java.lang.NoClassDefFoundError: Could not initialize class io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder
        at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:239) ~[na:na]
        at io.netty.resolver.dns.DnsServerAddressStreamProviders.unixDefault(DnsServerAddressStreamProviders.java:107) ~[gatewayapplication.exe:4.1.60.Final]
        at io.netty.resolver.dns.DnsServerAddressStreamProviders.platformDefault(DnsServerAddressStreamProviders.java:103) ~[gatewayapplication.exe:4.1.60.Final]
        at io.netty.resolver.dns.DnsNameResolverBuilder.<init>(DnsNameResolverBuilder.java:60) ~[na:na]
        at reactor.netty.transport.NameResolverProvider.newNameResolverGroup(NameResolverProvider.java:405) ~[na:na]
        at reactor.netty.tcp.TcpResources.getOrCreateDefaultResolver(TcpResources.java:306) ~[na:na]
        at reactor.netty.http.HttpResources.getOrCreateDefaultResolver(HttpResources.java:140) ~[na:na]
        at reactor.netty.http.client.HttpClientConfig.defaultAddressResolverGroup(HttpClientConfig.java:380) ~[na:na]
        at reactor.netty.transport.ClientTransportConfig.resolverInternal(ClientTransportConfig.java:219) ~[na:na]
        at reactor.netty.http.client.HttpClientConfig.resolverInternal(HttpClientConfig.java:434) ~[na:na]
        at reactor.netty.http.client.HttpClientConnect$MonoHttpConnect.lambda$subscribe$0(HttpClientConnect.java:264) ~[na:na]
        at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:57) ~[na:na]
        at reactor.core.publisher.FluxRetryWhen.subscribe(FluxRetryWhen.java:76) ~[na:na]
        at reactor.core.publisher.MonoRetryWhen.subscribeOrReturn(MonoRetryWhen.java:46) ~[na:na]
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:57) ~[na:na]
        at reactor.netty.http.client.HttpClientConnect$MonoHttpConnect.subscribe(HttpClientConnect.java:271) ~[na:na]

And Im stuck. Can't find a workaround

hanouard avatar Apr 21 '21 12:04 hanouard

@hanouard I tried your project with Spring Boot 2.4.5, Spring Native 0.9.2 and GraalVM 20.1.0, I was able to compile with mvn -Pnative-image clean package and run it successfully.

sdeleuze avatar May 11 '21 13:05 sdeleuze

@sdeleuze did you try to make a GET /test/posts ?

hanouard avatar May 11 '21 13:05 hanouard

@hanouard Yes it seems to work.

sdeleuze avatar May 11 '21 13:05 sdeleuze

@sdeleuze I can't reproduce what you've done. I get this error: Could not find option 'InlineBeforeAnalysis' Which is normal since this option was added in GraalVM 21.0.0

hanouard avatar May 28 '21 09:05 hanouard

It was a typo, I meant GraalVM 21.0.0.

sdeleuze avatar May 31 '21 10:05 sdeleuze

@joshlong Could you please check again the status of Gateway support with 0.10.2-SNAPSHOT and share your feedback?

sdeleuze avatar Jul 28 '21 09:07 sdeleuze

Aloha! Things are much improved! But not 100% there.

Given the following program:


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.nativex.hint.AccessBits;
import org.springframework.nativex.hint.TypeHint;

@SpringBootApplication
public class GatewayNativeApplication {

	@Bean
	RouteLocator gateway(RouteLocatorBuilder rlb) {
		return rlb
			.routes()
			.route(rs -> rs
				.path("/")
				.uri("https://start.spring.io")
			)
			.build();
	}

	public static void main(String[] args) {
		SpringApplication.run(GatewayNativeApplication.class, args);
	}

}

and the following Maven build:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>gateway-native</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>gateway-native</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
		<repackage.classifier/>
		<spring-cloud.version>2020.0.3</spring-cloud.version>
		<spring-native.version>0.10.2-SNAPSHOT</spring-native.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.experimental</groupId>
			<artifactId>spring-native</artifactId>
			<version>${spring-native.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<classifier>${repackage.classifier}</classifier>
					<image>
						<builder>paketobuildpacks/builder:tiny</builder>
						<env>
							<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
						</env>
					</image>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.springframework.experimental</groupId>
				<artifactId>spring-aot-maven-plugin</artifactId>
				<version>${spring-native.version}</version>
				<executions>
					<execution>
						<id>test-generate</id>
						<goals>
							<goal>test-generate</goal>
						</goals>
					</execution>
					<execution>
						<id>generate</id>
						<goals>
							<goal>generate</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
			<releases>
				<enabled>false</enabled>
			</releases>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>https://repo.spring.io/snapshot</url>
		</pluginRepository>
	</pluginRepositories>

	<profiles>
		<profile>
			<id>native</id>
			<properties>
				<repackage.classifier>exec</repackage.classifier>
				<native-buildtools.version>0.9.1</native-buildtools.version>
			</properties>
			<dependencies>
				<dependency>
					<groupId>org.graalvm.buildtools</groupId>
					<artifactId>junit-platform-native</artifactId>
					<version>${native-buildtools.version}</version>
					<scope>test</scope>
				</dependency>
			</dependencies>
			<build>
				<plugins>
					<plugin>
						<groupId>org.graalvm.buildtools</groupId>
						<artifactId>native-maven-plugin</artifactId>
						<version>${native-buildtools.version}</version>
						<executions>
							<execution>
								<id>test-native</id>
								<phase>test</phase>
								<goals>
									<goal>test</goal>
								</goals>
							</execution>
							<execution>
								<id>build-native</id>
								<phase>package</phase>
								<goals>
									<goal>build</goal>
								</goals>
							</execution>
						</executions>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>

</project>


It fails. But, it's one type hint away from working:

I added

@TypeHint(
	typeNames = "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$Config",
	access = AccessBits.ALL
)

and it worked! :-)

curl http://localhost:8080/

This is a super trivial Gateway example that uses none of the filters or does anything beyond proxying an HTTP request, but it's still very cool that it can work with just that one change. Congrats!

I would love to take this further and contribute some hints for your consideration when I get back from vacation on Monday. If that one hint is all that's required, then maybe this is an ideal ticket to open to first-time contributors? Either way, thanks for all your work thus far, and c'ya in ~50h

joshlong avatar Aug 01 '21 06:08 joshlong

OK, a bit of a sledgehammer approach, but, adding all of the following seems to allow me a lot of forward progress. These are all subclasses of Configurable<T>.class and the T.class itself. So, FooFactory<T>.class and FooFactory<T>.T.class, if that makes sense.

@TypeHint(
	access = AccessBits.ALL,
	typeNames = {
		"org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory",
		"org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactory",
		"org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.PrefixPathGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory$NameConfig",
		"org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RemoveRequestParameterGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.SetRequestHostHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.HeaderRoutePredicateFactory",
		"org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFactory",
		"org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.MapRequestHeaderGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter",
		"org.springframework.cloud.gateway.filter.factory.RewriteLocationResponseHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.RequestHeaderSizeGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RedirectToGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.support.WeightConfig",
		"org.springframework.cloud.gateway.handler.predicate.CookieRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory",
		"org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.AfterRoutePredicateFactory",
		"org.springframework.cloud.gateway.handler.predicate.CookieRoutePredicateFactory",
		"org.springframework.cloud.gateway.config.conditional.OnEnabledPredicate$DefaultValue",
		"org.springframework.cloud.gateway.filter.factory.AddRequestParameterGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.BetweenRoutePredicateFactory",
		"org.springframework.cloud.gateway.filter.factory.PrefixPathGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.SecureHeadersGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RequestHeaderSizeGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.BetweenRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.BeforeRoutePredicateFactory",
		"org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.WeightRoutePredicateFactory",
		"org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.TokenRelayGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.SetResponseHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory",
		"org.springframework.cloud.gateway.handler.predicate.MethodRoutePredicateFactory",
		"org.springframework.cloud.gateway.config.conditional.OnEnabledFilter$DefaultValue",
		"org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RewriteResponseHeaderGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.AddResponseHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.AfterRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.SetStatusGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerResilience4JFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.RequestSizeGatewayFilterFactory$RequestSizeConfig",
		"org.springframework.cloud.gateway.filter.factory.SetPathGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.SaveSessionGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.CloudFoundryRouteServiceRoutePredicateFactory",
		"org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RewriteLocationResponseHeaderGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter$Config",
		"org.springframework.cloud.gateway.filter.factory.MapRequestHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.SetRequestHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.HeaderRoutePredicateFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.RemoveRequestHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.SetRequestHostHeaderGatewayFilterFactory$Config",
		"org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory$RetryConfig",
		"org.springframework.cloud.gateway.filter.factory.RewriteResponseHeaderGatewayFilterFactory",
		"org.springframework.cloud.gateway.filter.factory.RedirectToGatewayFilterFactory",
		"org.springframework.cloud.gateway.handler.predicate.HostRoutePredicateFactory$Config"
	}
)

joshlong avatar Aug 04 '21 19:08 joshlong

Alrght, I've gotten something more future-proof working here: https://github.com/joshlong/gateway-hints/blob/main/gateway-hints/src/main/java/gateway/GatewayHints.java

Spring Cloud Gateway makes use of classes of the form FooFactory, and those in turn have .class references to nested FooFactory.Config classes. So long as this pattern holds true, this hint should buy us a lot

joshlong avatar Aug 07 '21 07:08 joshlong

I haven't tried it with every possible filter (as some of htem require other libraries on the classpath, like resilience4j and spring security), but let's cross that bridge later.

joshlong avatar Aug 07 '21 07:08 joshlong

Hi, is possible use in pom <parent> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-parent</artifactId> <version>Hoxton.SR12</version> </parent>

tnx.

marcoberri avatar Sep 28 '21 11:09 marcoberri

Any updates on this? Would love to try out native with cloud gateway, but currently build fails for the newest version 2021.0.0 with your big list @joshlong.
Fatal error:java.lang.TypeNotPresentException: Type org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager not present

The source you provided in your repo seems to not work with a newer version if I'm correct. At least some of the types you used are not available in newest Spring native version (at least that's what IntelliJ suggesting)

cmdjulian avatar Jan 05 '22 00:01 cmdjulian

Cc @OlgaMaciaszek.

sdeleuze avatar Jan 06 '22 08:01 sdeleuze

Spring Native is now superseded by Spring Boot 3 official native support, see the related reference documentation for more details.

As a consequence, I am closing this issue, and recommend trying your use case with latest Spring Boot 3 version. If you still experience the issue reported here, please open an issue directly on the related Spring project (Spring Framework, Data, Security, Boot, Cloud, etc.) with a reproducer.

Thanks for your contribution on the experimental Spring Native project, we hope you will enjoy the official native support introduced by Spring Boot 3.

sdeleuze avatar Jan 02 '23 12:01 sdeleuze