Spring Boot 2 controller returns a callable but http response remains empty - spring-boot

I'm in the process of migrating a Spring Boot 1.5 project to Spring Boot 2.1.8 (JDK 1.8, Kotlin 1.3.50).
I have a few controllers whose methods look like:
#PostMapping("post")
fun post(#RequestBody input: String): Callable<JsonNode> {
return Callable {
requestAsJson(input)
}
}
This works well in Spring Boot 1.5, without any further configuration. However with Spring Boot 2.1.8, the call does not fail but the HTTP response remains empty.
When I use start.spring.io to generate a minimalistic example, it works fine, so I guess that there is something wrong in my configuration.
When I enable debug traces for the Spring MVC, the final trace I get is:
[nio-8080-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing [{"data":{"...
[nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Exiting from "ASYNC" dispatch, status 200
So this looks fine to me, but still no response is received (using Curl or Postman to test).
I'm a bit at a loss now, since it was working like a charm in Spring Boot 1.5 and I'm trying to get a hint on how to get out of this issue.
Thanks for any help,
Damien

I had declared a ShallowEtagHeaderFilter bean the following way in my WebMvcConfigurer:
#Bean
fun shallowEtagHeaderFilter(): ShallowEtagHeaderFilter {
return ShallowEtagHeaderFilter()
}
While this was working fine in Spring Boot 1.5, this causes the controller async methods (returning a Callable) to not return any content any longer. Removing this bean for Spring Boot 2.1 restores a normal behavior.
I still need to seek a way to have my e-tag, but for now, this solves the present issue.

Related

How Do I Access The Spring Boot Startup Actuator During A Test

I would like to record the startup information about my application during a Spring Boot test. I have the startup actuator configured and working in Spring Boot 'bootrun' mode. However, when I try to access that actuator during a test using a TestRestTemplate, I get a 404 error.
I have written an example program that demonstrates the problem. The issue isn't with acutators overall as I have the metrics and health actuators working in the same test. Just the startup actuator.
The example code is on GitHub
I have a solution for this so I thought I would post it. For complete details, see the original repo in GitHub and check the solution branch.
One possible way to enable ApplicationStartup data collection during a Spring Boot Test is to create a ContextCustomizer. This allows you to get into the testing context early enough to record all of the data that you are looking for. The ContextCustomizer should have a single static BufferingApplicationStartup that it registers as a singleton bean into the test context's bean factory. It also needs to set the bean factory's ApplicationStartup because that will be passed to the SpringApplication just before it is run.
Here is the snippet of the customizer that holds the key:
#Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Object possibleSingleton = beanFactory.getSingleton(BEAN_NAME);
// The only way it wouldn't be an instance of a BufferingApplicationStartup is if it is null or we haven't
// run yet (and it is the DefaultApplicationStartup). In either case, jam our BufferingApplicationStartup
// in here.
if(!(possibleSingleton instanceof BufferingApplicationStartup)) {
beanFactory.registerSingleton(BEAN_NAME, APPLICATION_STARTUP);
beanFactory.setApplicationStartup(APPLICATION_STARTUP);
}
}
When you do this, make sure you implement a good equals and hashCode for your customizer or else you will break the test context caching and you will refresh your test context with every test class. Since the only relevant part of the customizer is the static BufferingApplicationStartup, I chose to return its hashcode.
Finally, don't forget to add your ContextCustomizerFactory to the src/test/resources/META-INF/spring.factories or else the rest of the Spring Boot testing support won't see your customizer.
Once this is all setup, you can access the Startup Actuator endpoint just like you would any other actuator.

Springdoc Swagger 3 - Failed to load API definition after adding API Group

I have a Spring boot application that works perfectly fine with Springdoc until I add the following code to group the endpoints into a default group.
#Bean
public GroupedOpenApi hideApis() {
return GroupedOpenApi.builder().group("default")
.pathsToExclude("/api/v2/**", "/v2/**")
.pathsToMatch("/api/v1/**", "/v1/**")
.addOperationCustomizer(new customCustomizer())
.build();
}
As soon as this part of code is added I'm getting the below error
Any idea what is wrong?
Springdoc v1.4.3
Spring-boot 2.x
Cause by a Null Pointer Exception in the OperationCustomizer class, i.e in the customCustomizer() of the given code.

Spring MVC GET Request Logging

I have a Spring Boot/Spring MVC REST app that has a GET mapping endpoint for ex.
#GetMapping(value = "/person")
public ResponseEntity<Person> getPerson(#RequestParam final String personID)
{
//service call for a person
return new ResponseEntity.ok(personObj);
}
I am using PostMan to hit the endpoint and I have the spring boot jar running and something I noticed was that every PUT and POST method is logged but when it came to GET requests, they were not logged. The only time I got a GET in the running spring boot server logs was if I hit the wrong endpoint path for i.e localhost:8080/personn (misspelling) the log would show the URL with the requestparam value appended to the URL like "GET /personn?personID=123 HTTP/1.1" 404 - "-" "PostmanRuntime
It seems like successful GET calls are not logged but unsuccessful GET calls are logged. Is this normal behavior?
If personID was sensitive data then I should probably use POST?
You can set the logging level of the Spring web package to DEBUG in the application.properties, something like:
logging.level.org.springframework.web=debug
or in recent version of Spring Boot:
logging.level.web=debug

Spring Boot in Cloud Foundry (PCF) disable Whitelabel Error Page

Related question:
Spring Boot Remove Whitelabel Error Page
For my case,
I disabled whitelabel by setting whitelabel.enabled = false, and I also exclude ErrorMvcAutoConfiguration. It worked in regular spring boot service. But I deployed the same service on PCF cloud foundry, then spring still want to redirect error to /error page.
Any help and suggestion is welcome.
Edit:
I added exclude annotation on Application, then it works on PCF.
Previously I added exclude configuration in application.yml, then it didn't work on PCF
You need to create a separate endpoint /error and then handle it in the method. I would suggest you to maintain a separate controller infact. My code would look something like this
#RestController
#RequestMapping(path = "/error")
public class ErrorController {
#ApiOperation(value = "Error Page", notes = "Error Page")
#GetMapping
public String error() {
return "Some Error Occurred and I will Graciously show the Error"
}
}
It turns out circuit breaker service set exclusion property first, than local application.yml didn't take effect. If I add exclusion property in repo, then it take preference.
I feel this is kind of spring bug, since exclusion is list, it should include all items, instead of taking the first configuration only.

JerseyTest and Spring and creating a ServletContext

I'm working on migrating from Jersey 1.16 to Jersey 2.7. I have the application running and working, but I'm having trouble with the tests.
Some things to note:
The application uses Spring and is configured by a class, ApplicationConfiguration.class.
The application does not have a web.xml - the Jersey servlet and filters are configured programmatically.
I am using the jersey-spring3 library.
Related to using the jersey-spring3 library, I have to add a workaround to my onStartup method
// The following line is required to avoid having jersey-spring3 registering it's own Spring root context.
// https://java.net/jira/browse/JERSEY-2038
servletContext.setInitParameter("contextConfigLocation", "");
Here's the issue:
When the test is starting up, SpringComponentProvider, tries to initialize Spring with a dangerous assumption that I can't figure out how to correct - xml based configuration. Looking at the code, the trouble is this block
ServletContext sc = locator.getService(ServletContext.class);
if(sc != null) {
// servlet container
ctx = WebApplicationContextUtils.getWebApplicationContext(sc);
} else {
// non-servlet container
ctx = createSpringContext();
}
Running a JUnit test, ServletContext is null, and createSpringContext is called.
Here's the question:
Is there a way to run a test and specify a ServletContext/ServletContainer?
I believe this issue is covered by https://java.net/jira/browse/JERSEY-2259.
In short: they removed this functionality from Jersey 2.x and are treating it as a Feature Request (instead of regression) so it's not considered a high-priority item.

Resources