class WebClientTransportClientFactory implements TransportClientFactory {

	private final Supplier<WebClient.Builder> builderSupplier;

	public WebClientTransportClientFactory(Supplier<WebClient.Builder> builderSupplier) {
		this.builderSupplier = builderSupplier;
	}

	@Override
	public EurekaHttpClient newClient(EurekaEndpoint endpoint) {
		// we want a copy to modify. Don't change the original
		WebClient.Builder builder = this.builderSupplier.get().clone();
		setUrl(builder, endpoint.getServiceUrl());
		setCodecs(builder);
		builder.filter(http4XxErrorExchangeFilterFunction());
		return new WebClientEurekaHttpClient(builder.build());
	}

	private WebClient.Builder setUrl(WebClient.Builder builder, String serviceUrl) {
		String url = UriComponentsBuilder.fromUriString(serviceUrl).userInfo(null).toUriString();

		try {
			URI serviceURI = new URI(serviceUrl);
			if (serviceURI.getUserInfo() != null) {
				String[] credentials = serviceURI.getUserInfo().split(":");
				if (credentials.length == 2) {
					builder.filter(ExchangeFilterFunctions.basicAuthentication(credentials[0], credentials[1]));
				}
			}
		}
		catch (URISyntaxException ignore) {
		}
		return builder.baseUrl(url);
	}

	private static BeanSerializerModifier createJsonSerializerModifier() {
		return new BeanSerializerModifier() {
			@Override
			public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
					JsonSerializer<?> serializer) {
				if (beanDesc.getBeanClass().isAssignableFrom(InstanceInfo.class)) {
					return new InstanceInfoJsonBeanSerializer((BeanSerializerBase) serializer, false);
				}
				return serializer;
			}
		};
	}

	private void setCodecs(WebClient.Builder builder) {
		ObjectMapper objectMapper = objectMapper();
		builder.codecs(configurer -> {
			ClientCodecConfigurer.ClientDefaultCodecs defaults = configurer.defaultCodecs();
			defaults.jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
			defaults.jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));

		});
	}

	/**
	 * Provides the serialization configurations required by the Eureka Server. JSON
	 * content exchanged with eureka requires a root node matching the entity being
	 * serialized or deserialized. Achieved with
	 * {@link SerializationFeature#WRAP_ROOT_VALUE} and
	 * {@link DeserializationFeature#UNWRAP_ROOT_VALUE}.
	 * {@link PropertyNamingStrategies.SnakeCaseStrategy} is applied to the underlying
	 * {@link ObjectMapper}.
	 * @return a {@link ObjectMapper} object
	 */
	private ObjectMapper objectMapper() {
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

		SimpleModule jsonModule = new SimpleModule();
		jsonModule.setSerializerModifier(createJsonSerializerModifier());
		objectMapper.registerModule(jsonModule);

		objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
		objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
		objectMapper.addMixIn(Applications.class, ApplicationsJsonMixIn.class);
		objectMapper.addMixIn(InstanceInfo.class, InstanceInfoJsonMixIn.class);

		return objectMapper;
	}

	// Skip over 4xx http errors
	private ExchangeFilterFunction http4XxErrorExchangeFilterFunction() {<FILL_FUNCTION_BODY>}

	@Override
	public void shutdown() {
	}

}

		return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
			// literally 400 pass the tests, not 4xxClientError
			if (clientResponse.statusCode().value() == 400) {
				ClientResponse newResponse = clientResponse.mutate().statusCode(HttpStatus.OK).build();
				newResponse.body((clientHttpResponse, context) -> clientHttpResponse.getBody());
				return Mono.just(newResponse);
			}
			if (clientResponse.statusCode().equals(HttpStatus.NOT_FOUND)) {
				ClientResponse newResponse = clientResponse.mutate().statusCode(clientResponse.statusCode())
						// ignore body on 404 for heartbeat, see gh-4145
						.body(Flux.empty()).build();
				return Mono.just(newResponse);
			}
			return Mono.just(clientResponse);
		});
	
<no_super_class>