I've encountered a problem in my application when sending request to create a single property object in the server.
When sending a Post/Put request with a json body, the only way the server accept the request is to flat the request - remove the curly brackets and only send the value of the class property, without the property name (the key in the json), while receiving it back as a nested json.
Sending the Request with the json received back, as nested object results in bad request, and so the situation is that the request and response are asymmetrical.
(I'm using String as an example, but the same happed with int, float etc)
in this example, I simplified the code to have 2 classes -
- TimeStamp
- TimeStampWrapper
I'm sending the request (the timestamp) as follows (flat):
"2023-02-19T16:08:41.897+00:00"
When receiving the object back, I receive it correctly (nested):
{
"timestamp": "2023-02-19T16:08:41.897+00:00"
}
The server side code:
- The MyTimeStamp one property class:
package brokenjson.demo.demo;
import lombok.*;
@AllArgsConstructor
@ToString
@Getter
@Setter
public class MyTimeStamp {
private String timestamp;
}
- The MyTimeWrapper class, which contains only MyTimeStamp as a property:
package brokenjson.demo.demo;
import lombok.*;
import java.beans.ConstructorProperties;
@ToString
@Getter
@Setter
public class MyTimeWrapper {
private MyTimeStamp myTimeStamp;
public MyTimeWrapper() {
}
}
The Main/Controller:
package brokenjson.demo.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@PutMapping("/time")
public MyTimeStamp gettingTimeStamp(@RequestBody MyTimeStamp myTimeStamp) {
System.out.println(myTimeStamp);
return myTimeStamp;
}
@PutMapping("/timeWrap")
public MyTimeWrapper gettingTimeStamp(@RequestBody MyTimeWrapper myTimeWrapper) {
System.out.println(myTimeWrapper);
return myTimeWrapper;
}
}
The reason I have a wrapping class in this demo is that the problem first arose when trying to send a request to create such a wrapping class, and not understanding why the request being sent is flat, and the response being received is nested.
The request:
{
"myTimeStamp":"2023-02-19T16:08:41.897+00:00"
}
The response:
{
"myTimeStamp": {
"timestamp": "2023-02-19T16:08:41.897+00:00"
}
}
I'm using Java 17 (although this problem also occurred when using java 19).
My pom.xml -
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>brokenjson.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
In my application I'm using webFlux, so I originally thought it was a problem with the webFlux deserializer or something like that, but when I created a new project with spring-boot-strter-web I observed the problem persistent.
Sidenote: In the "MyTimeWrapper" class, spring requested me to create an empty constructor to be able to receive the request, I don't believe it's related but I think it should be mentioned.