Sleuth doesn't include traceId & spanId when #RequestBody is included - spring-boot

I am fairly new to Sleuth. My issue is that Sleuth does not print traceId & spanId when my #PostMapping Controller includes a #RequestBody annotation. For example:
INFO [myapp,,]
If I remove the #RequestBody, Sleuth does log the traceId/spanId as it's supposed to. But this doesn't suit me, since I have a #RestController. For example:
INFO [myapp,7398d070f16c816f,7983697ee7288d0b]
My controller:
#PostMapping(value = "/traceid", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ApiResponse> getSleuthTraceId(#RequestBody MyCustomerUpdateDto myCustomerUpdateDto) throws IOException {
log.info("Hello with Sleuth");
Span span = tracer.currentSpan();
if (span != null) {
log.info("traceId {}", span.context().traceId());
log.info("spanId {}", span.context().spanId());
}
return myService.editCustomer(myCustomerUpdateDto);
}
spring-cloud-starter-sleuth version: 3.1.2

Related

spring boot controller null multipartfile list request part

updating spring-boot from 2.3.7 to 2.4.6 and encountering NPE issue with requestPart in rest controller. Essentially in 2.3.7 the list of multipartfiles was initialising as an empty list. And with 2.4.6 the list is now a null object. not sure if it's a legitimate change in function or a bug? or possible issue with our code?
public Callable<ResponseEntity<EmailResponse>> process(
#RequestHeader final HttpHeaders requestHeaders,
#RequestPart(name = "email") #Valid EmailRequest email,
#RequestPart(name = "attachments", required = false) List<MultipartFile> attachments,
final HttpServletRequest request) {
...
}

Hide internal parameters from Spring interface for Swagger UI

I have an folowing endpoint:
#PostMapping(value = "/home", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public Mono<String> getData(ServerWebExchange exchange) { return Mono.empty(); }
The ServerWebExchange object is implemented in org.springframework.web.server.
When I run it, in Swagger all the getters objects are shown. While I only need the body (I want to hide the reqest and the respone objects).
Tried to use
.ignoredParameterTypes(Principal.class, ServerHttpRequest.class, ServerHttpResponse.class)
But, it didn't had any effect.
Is there a way to hide those?
Solution found:
Desable the SeverWebExchange interface for swagger
Configure requier input.
`
#PostMapping(value = "/home", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ApiImplicitParams({
#ApiImplicitParam(name = "Body Params", paramType = "body")
})
public Mono<String> getData(
#ApiIgnore ServerWebExchange exchange
) {
return Mono.empty();
}

How to fix multipart/form-data MediaType not being set with Jackson Spring MVC

I'm trying to send a Product and product images from Angular 7 frontend to a SpringMVC backend.
To add support for Multipart files I've added this bean inside my AppConfig.
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(1000000);
return multipartResolver;
}
Since I want to receive the Product object separately inside the controller I'm using #RequestPart to fetch both separately like this:
#RequestMapping(value = "save", method = RequestMethod.POST)
public ResponseEntity addProduct(#Valid #RequestPart Product product, #RequestPart MultipartFile[] images, BindingResult bindingResult, HttpServletRequest
}
On the frontend I'm adding the image to FormData like this:
let formData = new FormData();
formData.append('product', new Blob([JSON.stringify(this.product)],{ type: "application/json" }));
// I iterate and append all the images like this
formData.append('image[]', this.images, this.images.name);
this.http.post(this.appService.getApiUrl() + "api/product/save/", product);
The problem is that whenever I submit the form, I get this exception as a response: HTTP Status 415 – Unsupported Media Type.
I tried debugging this issue by setting breakpoints inside CommonsMultipartResolver class and after tracing the request through the code I've found that when the getSupportedMediaTypes() is called it returns only two media types:
application/json
application/*+json
Inside the following method in AbstractHttpMessageConverter:
protected boolean canRead(#Nullable MediaType mediaType) {
if (mediaType == null) {
return true;
} else {
Iterator var2 = this.getSupportedMediaTypes().iterator();
MediaType supportedMediaType;
do {
if (!var2.hasNext()) {
return false;
}
supportedMediaType = (MediaType)var2.next();
} while(!supportedMediaType.includes(mediaType));
return true;
}
}
Finding this I tried adding MediaType.MULTIPART_FORM_DATA like this inside AppConfig:
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
List<MediaType> types = new ArrayList<>();
types.add(MediaType.APPLICATION_JSON);
types.add(MediaType.APPLICATION_JSON_UTF8);
types.add(MediaType.MULTIPART_FORM_DATA);
((MappingJackson2HttpMessageConverter) converter).setSupportedMediaTypes(types);
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
mapper.registerModule(hibernate5Module);
}
}
}
But it still wouldn't work. When the app starts up, I do see the constructor of AbstractJackson2HttpMessageConverter being called with my MediaTypes but they get overwritten by more calls to the same constructor after it.
Is there any way I can get the MediaType to persist? I might be looking in the wrong direction so any insight will be helpful.
The Jackson library is required on the classpath. Spring does not declare this by default. Make sure that at least com.fasterxml.jackson.core:jackson-databind is available in the classpath of the Spring MVC application. Example for Apache Maven:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
Example for the jackson.version value: 2.9.0
1) You need to give input data supported at server end. Since you are sending File, means server is consuming the Multipart Data.
For multipart we need to set consumes = "multipart/form-data"
#RequestMapping(value = "save", method = RequestMethod.POST, consumes = "multipart/form-data")
public ResponseEntity addProduct(#Valid #RequestPart Product product, #RequestPart MultipartFile[] images, BindingResult bindingResult, HttpServletRequest
}
2) Since form is sending multipart data we need to set content-type at front end too in http header in post call.
content-type: multipart/form-data"

Camel rest API to provide dynamic download

How can we provide document download using camel API, I need to provide an api using camel rest to response the file as download and I have the logic to create the pdf using apache fop, but i need to get some information how to respond the file as rest response using camel rest.
#RestController
public class MyController {
#Autowired
ICityService cityService;
#RequestMapping(
value = "/pdfreport",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_PDF_VALUE
)
public ResponseEntity<InputStreamResource> citiesReport() throws IOException {
List<City> cities = (List<City>) cityService.findAll();
ByteArrayInputStream bis = GeneratePdfReport.citiesReport(cities);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "inline;
filename = citiesreport.pdf");
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.body(new InputStreamResource(bis));
}
}

Block number of request using spring webflux

I currently have below reactive service exposed using spring boot 2(Spring webflux)
#RequestMapping(value = "/tasks/v1", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Mono taskForUserV1(#RequestParam(value = "userId", required = true) String userId,
#RequestParam(required = false) Map<String, String> userData) {
return service.taskForUserV1(userId, userData);
}
But i want to throw an exception to the client requesting my service if the request are lets say more than 500. How to do it?
you can take a look at Rate Limiter design pattern implemented by resileince4j # https://resilience4j.github.io/resilience4j/#_rate_limiting
RateLimiter rateLimiter = RateLimiter.ofDefaults("testName");
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RateLimiterCallAdapter.of(rateLimiter))
.baseUrl("http://localhost:8080/")
.build();

Resources