2

I try to get per request some parameters from my application properties.

My ApplicationConfig-Class:

@Configuration
@ConfigurationProperties("org.a.b")
public class ApplicationConfig implements Serializable {

    private String name;
    private String ip;
// GETTER AND SETTER

My application.properties:

org.a.b.name=huhu
org.a.b.ip=x.x.x.x

I try different possibilies:

@RestController
public class HelloController

First:

@Autowired
private ApplicationConfig applicationConfig;

@ResponseBody
@GetMapping(value = "/", produces = "application/json")
public ApplicationConfig index() {
    return applicationConfig;
}

Exception:

{"timestamp":"2018-08-24T12:28:50.623+0000","status":500,"error":"Internal Server Error","message":"Type definition error: [simple type, class org.springframework.context.expression.StandardBeanExpressionResolver]; nested exception is com.fasterxml.jackson.datab
ind.exc.InvalidDefinitionException: No serializer found for class org.springframework.context.expression.StandardBeanExpressionResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (
through reference chain: hello.bootstrap.ApplicationConfig$$EnhancerBySpringCGLIB$$31a0e3d2[\"$$beanFactory\"]->org.springframework.beans.factory.support.DefaultListableBeanFactory[\"beanExpressionResolver\"])","path":"/"}

Second:

@ResponseBody
@GetMapping(value = "/", produces = "application/json")
public ApplicationConfig index() {
    return new ApplicationConfig();
}
// return nothing {"name": null, "ip": null}

Third:

@ResponseBody
@GetMapping(value = "/", produces = "application/json")
public String index() {
    return applicationConfig.getIp();
}
// return x.x.x.x

My pom.xml:

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

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>


    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>hello.ConfigServiceApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

I want the Application properties as Object, something like:

{"name": "dev", "ip": "x.x.x.x"}
emoleumassi
  • 4,881
  • 13
  • 67
  • 93

2 Answers2

1

You're on the right lines with your first attempt, the problem you're finding is that when Spring takes over the management of objects like this one - to set the values from your config file - it doesn't use a 'normal' instance of it, but a proxied version.

There's plenty written online about the details of how that proxying works, I won't try to explain it here (mostly because, as far as I'm concerned, it's magic).

The simplest option for your case though, would probably be to convert from the class marked with the @Configuration annotation to a simple POJO. Mostly simply that might be something like:

public class ApplicationConfigResponse {
    private final String name;
    private final String ip;

    public ApplicationConfigResponse(ApplicationConfig applicationConfig) {
        this.name = applicationConfig.getName();
        this.ip = applicationConfig.getIp();
    }

    public String getName() {
        return name;
    }

    public String getIp() {
        return ip;
    }
}

Then you can return that POJO from your controller as in your first example:

@Autowired
private ApplicationConfig applicationConfig;

@ResponseBody
@GetMapping(value = "/", produces = "application/json")
public ApplicationConfigResponse index() {
    return new ApplicationConfigResponse(applicationConfig);
}

If you expect to have lots more properties or for this to be a pattern that's used repeatedly in a larger application, you might prefer to look at Spring's built-in functionality for converting between objects - this Tutorial is a good starting point: https://www.baeldung.com/spring-type-conversions

DaveyDaveDave
  • 9,821
  • 11
  • 64
  • 77
  • it is working, but i try a different solution with the ResponseEntity. `@ResponseBody @GetMapping(value = "/", produces = "application/json") public ResponseEntity index() { return new ResponseEntity(applicationConfig, HttpStatus.OK); }` I have a lot of application with differents profile. I cannot use a pojo for each property. – emoleumassi Aug 24 '18 at 13:13
-1

It is not recommended to annotate a class with @Configuration & @ConfigurationProperties as spring treats anything with @Configuration in a special way.

Use the first approach and do not annotate ApplicationConfig with @Configuration. Your first approach should work.