1

Let's say I have this application.yml (which will be environment-dependent e.g. via Spring profiles):

app.remote:
  url: http://whatever.url.it.is:8080/

and matching Java-style configuration properties class:

@Configuration
@ConfigurationProperties("app.remote")
public class MyRemoteProperties {

    @NotBlank
    private String url;

    // matching getter/setter...
}

I want some kind of client for my remote url:

@Service
@FeignClient(value = "remote", url = "${app.remote.url}")
public interface MyRemote {

    @GetMapping("/what/ever/rest/api")
    String stuff();

}

Unfortunately I can't get the validation work for MyRemoteProperties e.g. when the app.remote.url property is blank (empty) the application doesn't start (Spring fails at wiring the MyRemote bean) and I get this error:

Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?

(and I don't want load-balancing; I assume this is because the URL is empty at some point, then it expects some load-balancer config hence Ribbon here in the error message).

Or maybe I don't known how to plug it into the MyRemote interface's configuration, e.g. I also tried:

@FeignClient(value = "remote", configuration = MyRemoteProperties.class)

But same result.

How do I get this validation thing to work?

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

At some point where the interface is called:

@Service
public RandomServiceOrController {

    @Autowired
    private MyRemote myRemote;

    public void processMyStuff() {
        // ...
        String myStuff = myRemote.stuff();
        // ...
    }

}
maxxyme
  • 2,164
  • 5
  • 31
  • 48
  • In fact, I missed the `@Validated` in my properties class. This isn't told in the Baeldung's article: https://www.baeldung.com/configuration-properties-in-spring-boot (which I read first...) while it's in the Spring Boot doc: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-validation // confirmed it looking at the test class `spring-boot/blob/master/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java` – maxxyme Sep 26 '19 at 15:54

1 Answers1

0

Don't forget the @Validated annotation on your Java properties class:

@Validated
@Configuration
@ConfigurationProperties("app.remote")
public class MyRemoteProperties {

    @NotBlank
    private String url;

    // matching getter/setter...
}

Your application won't start because of the missing property, not because of a non-defined-loadbalancing-client-you-don't-need (thus making its error message more awkward).

maxxyme
  • 2,164
  • 5
  • 31
  • 48