I'm currently working on a spring boot e-commerce backend with frontend in Angular. This is the exact error message:
2024-11-22T15:47:36.290+01:00 WARN 12532 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"par1":"par2"}')]
The error occurs when I try to add a new item to the store with parameters with field type Map<String, String>
, which is deserialized wrong. All I have is this 400 (Bad Request) error.
I'd like to see the JSON sent in the request, but I cannot log anything in console from service to controller level.
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Response> save(@RequestBody ProductFormDTO productFormDTO) {
System.out.println("Received ProductFormDTO: " + productFormDTO);
return productMediator.saveProduct(productFormDTO);
}
The method seems to stop at the first line of the method, it doesn't even proceed to the print line.
In the ProductEntity
the parameters field is defined like this:
@Column(columnDefinition = "jsonb")
private Map<String, String> parameters;
Same in productDTO and productFormDTO
private Map<String, String> parameters;
Below I show my saveProduct method in mediator:
public ResponseEntity<Response> saveProduct(ProductFormDTO productFormDTO) {
try{
ProductEntity product = formToProductEntity.toProductEntity(productFormDTO);
categoryService.findCategoryByShortID(product.getCategory().getShortId()).ifPresentOrElse(product::setCategory,()->{
throw new CategoryDontExistException();
});
productService.createProduct(product);
return ResponseEntity.ok(new Response("Successful created a product"));
}catch (RuntimeException e){
e.printStackTrace();
return ResponseEntity.status(400).body(new Response("Can't create product category don't exist"));
}
}
and service:
@Transactional
public void createProduct(ProductEntity product) {
logger.info("Creating product with details: {}", product);
if (product != null) {
product.setCreateAt(LocalDate.now());
product.setUid(UUID.randomUUID().toString());
product.setActivate(true);
productRepository.save(product);
for (String uuid : product.getImageUrls()) {
activateImage(uuid);
}
logger.info("Product created successfully with UID: {}", product.getUid());
return;
}
throw new RuntimeException("Product is null, cannot create.");
}
The logger doesn't work ofc.
Do you know what is the issue or do maybe how to see the exact JSON that is being sent in the request? It has probably some bad formatting. I tried the RequestLoggingFilter
with @WebFilter("/*")
, but it didn't work, I had nothing in console.
Also I am sure that the field parameters in database is set correctly to jsonb
in PostgreSQL
.
ps. It worked before, it has stopped working since I changed parameters field type from String to Map.
Ok, after debugging the request following this blog it turned out that the parameters were being sent as a string "parameters":"{\"par1\":\"par2\"}"
not matching the jsonb
format.
I just changed the declaration of parameters in ProductFormDTO
from
private Map<String, String> parameters;
to
private String parameters;
and deserialized it using ObjectMapper in ProductFormToProductEntity
mapper
ObjectMapper objectMapper = new ObjectMapper();
productEntity.setParameters(objectMapper.readValue(productFormDTO.getParameters(), new TypeReference<Map<String, String>>() {}));