I have this Object, which has a field that is a ZonedDateTime:
import java.time.ZonedDateTime;
public class TestObject {
private ZonedDateTime testTime;
public ZonedDateTime getTestTime() {
return testTime;
}
public void setTestTime(ZonedDateTime testTime) {
this.testTime = testTime;
}
}
And two different controller where endpoints use the same object:
@Controller
@RequestMapping("/web")
@Import(ControllerWebConfiguration.class)
public class ControllerWeb {
@PostMapping("/example")
public ResponseEntity<String> example(@RequestBody TestObject testObject) {
return ResponseEntity.ok(testObject.toString());
}
}
@Controller
@RequestMapping("/mobile")
@Import(ControllerMobileConfiguration.class)
public class ControllerMobile {
@PostMapping("/example")
public ResponseEntity<String> example(@RequestBody TestObject testObject) {
return ResponseEntity.ok(testObject.toString());
}
}
They both use slightly different "deserialize" for their ZonedDateTime:
public class ZonedDateTimeDeserializerWeb extends JsonDeserializer<ZonedDateTime> {
@Override
public ZonedDateTime deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
String dateTimeString = node.asText();
return ZonedDateTime.parse(dateTimeString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssX"));
}
}
public class ZonedDateTimeDeserializerMobile extends JsonDeserializer<ZonedDateTime> {
@Override
public ZonedDateTime deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
String dateTimeString = node.asText();
return ZonedDateTime.parse(dateTimeString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX"));
}
}
@Configuration
public class ControllerWebConfiguration {
@Bean
public ObjectMapper objectMapperWeb() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule moduleWeb = new SimpleModule();
moduleWeb.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializerWeb());
objectMapper.registerModule(moduleWeb);
return objectMapper;
}
}
@Configuration
public class ControllerMobileConfiguration {
@Bean
public ObjectMapper objectMapperMobile() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule moduleMobile = new SimpleModule();
moduleMobile.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializerMobile());
objectMapper.registerModule(moduleMobile);
return objectMapper;
}
}
I have tried the above solution but Springboot does not allow two objectMapper beans; Is there any way to achieve what I want?
Thanks in advance!
As explained in this answer, under the hood Spring uses a single MessageConverter
which in turn uses the primary ObjectMapper
. So you can't just have multiple deserializer beans of the same class using the @Primary
and @Qualifier
annotations, as is shown in this Baeldung tutorial, as it will not work.
You can use the solution provided in the linked answer, but I think it is not worth the hassle in your case. I would just replace the TestObject
with an interface that defines the getter/setter, and implement the interface in a WebTestObject
and a MobileTestObject
, each one with a field annotated with an hint for Jackson, for example using @JsonSerialize
or Spring @DateTimeFormat.
public interface TestObject {
ZonedDateTime getTestTime();
void setTestTime(ZonedDateTime testTime);
}
@Getter @Setter
public class WebTestObject implements TestObject {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ssX")
private ZonedDateTime testTime;
}
@Getter @Setter
public class MobileTestObject implements TestObject {
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssX")
private ZonedDateTime testTime;
}
@Controller
public class Controller {
@PostMapping("/mobile/example")
public ResponseEntity<String> mobileExample(@RequestBody MobileTestObject testObject) {
//in your business logic you can then just use the TestObject interface
return ResponseEntity.ok(testObject.toString());
}
@PostMapping("/web/example")
public ResponseEntity<String> webExample(@RequestBody WebTestObject testObject) {
//in your business logic you can then just use the TestObject interface
return ResponseEntity.ok(testObject.toString());
}
}