- What I would like to achieve:
I want to be able to configure the @GetMapping
route with some properties.
- What I have tried:
We have a service whose business logic is the same. But we deploy it in different companies, and each of the companies has its rest API routes.
For example, the company A would like our service exposed to /api/v1.1/bar
Company B would like our service exposed to: /api/foo
etc
Therefore, we went to try this piece of code:
@RestController
public class DummyController {
@Value("${configuration.route}")
private String route;
@GetMapping(value = route)
String doSomeBusinessLogic() {
doSomeVeryCoolBusinessLogic();
Expected:
With the code above, we were expecting that it would work, making the route configurable
Actual: we are getting this compilation error: Attribute value must be constant
The current workaround, we are creating an N version of the same apps, just to change one line, the get mapping line
App for company A
@GetMapping(value = "/api/v1.1/bar")
String doSomeBusinessLogic() {
doSomeVeryCoolBusinessLogic();
app for company B
@GetMapping(value = "/api/foo")
String doSomeBusinessLogic() {
doSomeVeryCoolBusinessLogic();
We believe this is not the way to go, therefore:
Question:
how to make the route configurable with SpringBoot ?
- What I would like to achieve:
I want to be able to configure the @GetMapping
route with some properties.
- What I have tried:
We have a service whose business logic is the same. But we deploy it in different companies, and each of the companies has its rest API routes.
For example, the company A would like our service exposed to /api/v1.1/bar
Company B would like our service exposed to: /api/foo
etc
Therefore, we went to try this piece of code:
@RestController
public class DummyController {
@Value("${configuration.route}")
private String route;
@GetMapping(value = route)
String doSomeBusinessLogic() {
doSomeVeryCoolBusinessLogic();
Expected:
With the code above, we were expecting that it would work, making the route configurable
Actual: we are getting this compilation error: Attribute value must be constant
The current workaround, we are creating an N version of the same apps, just to change one line, the get mapping line
App for company A
@GetMapping(value = "/api/v1.1/bar")
String doSomeBusinessLogic() {
doSomeVeryCoolBusinessLogic();
app for company B
@GetMapping(value = "/api/foo")
String doSomeBusinessLogic() {
doSomeVeryCoolBusinessLogic();
We believe this is not the way to go, therefore:
Question:
how to make the route configurable with SpringBoot ?
Share Improve this question asked Mar 18 at 7:49 PatPandaPatPanda 5,13029 gold badges119 silver badges256 bronze badges1 Answer
Reset to default 1I am not saying this is necessarily a good idea :) but here are some options
1. Use Router Function
You should of course consider using RouterFunctions instead. But if for whatever reason you don't want to use option #2
2. Update the route with BeanPostProcessor
The problem is that the annotations (like @GetMapping
) have to have constant values, therefore hard to change at runtime. We can use a BeanPostProcessor
to do that:
@Component
public class DemoBeanPostProcessor implements BeanPostProcessor {
@Value("${configuration.route}")
private String newUrl;
@SneakyThrows
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof DummyController myController) {
GetMapping annotation = myController.getClass().getAnnotation(GetMapping.class);
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
Field field = handler.getClass().getDeclaredField("memberValues");
field.setAccessible(true);
Map<String, Object> memberValues = (Map) field.get(handler);
memberValues.put("value", newUrl);
return bean;
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
since we are changing private members, for this to work you would need to allow reflection with:
--add-opens=java.base/sun.reflect.annotation=ALL-UNNAMED