[英]Accept two different subclasses with same @RequestMapping
I have WebDeviceInfo
and IOSDeviceInfo
classes that are subclasses of DeviceInfo
.我有
WebDeviceInfo
和IOSDeviceInfo
类,它们是DeviceInfo
子类。 How can I create a single endpoint in a Spring @RestController
that will accept either IOSDeviceInfo
or WebDeviceInfo
?如何在接受
IOSDeviceInfo
或WebDeviceInfo
的 Spring @RestController
中创建单个端点?
Attempt #1尝试 #1
I tried to map the same RequestMapping
to two different methods, one that would get called if the RequestBody
could be mapped to a WebDeviceInfo
and the other that would get called if the RequestBody
could be mapped to a IOSDeviceInfo
.我尝试将相同的
RequestMapping
映射到两种不同的方法,一种在RequestBody
可以映射到WebDeviceInfo
被调用,另一种在RequestBody
可以映射到IOSDeviceInfo
被IOSDeviceInfo
。
@RequestMapping(value = "/register-device", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void registerWebDevice(@RequestBody final WebDeviceInfo webDeviceInfo) {
//register web device
}
@RequestMapping(value = "/register-device", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void registerIOSDevice(@RequestBody final IOSDeviceInfo iosDeviceInfo) {
//register ios device
}
But this does not work, the second RequestMapping
does not get registered and the application fails to start up because Spring sees that /register-device
with the same RequestMethod
and MediaType
is already mapped to another method.但这不起作用,第二个
RequestMapping
没有注册并且应用程序无法启动,因为 Spring 看到具有相同RequestMethod
和MediaType
/register-device
已经映射到另一个方法。
Attempt #2尝试#2
Next, I tried accepting the superclass as the RequestBody
and then casting it to the appropriate subclass.接下来,我尝试接受超类作为
RequestBody
,然后将其转换为适当的子类。
@RequestMapping(value = "/register-device", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void registerDevice(@RequestBody final DeviceInfo deviceInfo) {
if (deviceInfo instanceof WebDeviceInfo) {
final WebDeviceInfo webDeviceInfo = (WebDeviceInfo) deviceInfo;
//register web device
} else if (deviceInfo instanceof IOSDeviceInfo) {
final IOSDeviceInfo iosDeviceInfo = (IOSDeviceInfo) deviceInfo;
//register ios device
} else {
logger.debug("Could not cast deviceInfo to WebDeviceInfo or IOSDeviceInfo");
}
}
This does not work either.这也不起作用。 I always get:
我总是得到:
Could not cast deviceInfo to
WebDeviceInfo
orIOSDeviceInfo
无法将 deviceInfo 转换为
WebDeviceInfo
或IOSDeviceInfo
Attempt #3尝试 #3
Finally, I tried just casting to the correct subclass inside a try
/ catch
.最后,我尝试在
try
/ catch
强制转换为正确的子类。
@RequestMapping(value = "/register-device", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void registerDevice(@RequestBody final DeviceInfo deviceInfo) {
try {
final WebDeviceInfo webDeviceInfo = (WebDeviceInfo) deviceInfo);
//register web device
} catch (final ClassCastException ex) {
try {
final IOSDeviceInfo iosDeviceInfo = (IOSDeviceInfo) deviceInfo);
//register ios device
} catch (final ClassCastException ex2) {
logger.debug("Could not cast deviceInfo to WebDeviceInfo or IOSDeviceInfo");
}
}
}
Again I get error:我再次收到错误:
Could not cast deviceInfo to
WebDeviceInfo
orIOSDeviceInfo
无法将 deviceInfo 转换为
WebDeviceInfo
或IOSDeviceInfo
Is there any way to accomplish this, or am I going to have to create two separate methods with two different RequestMapping
s?有什么办法可以做到这一点,还是我必须用两个不同的
RequestMapping
创建两个单独的方法?
Attempts #2 and #3 should work when you annotate the base class DeviceInfo
with the correct Jackson annotations:当您使用正确的 Jackson 注释对基类
DeviceInfo
进行注释时,尝试 #2 和 #3 应该可以工作:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = IOSDeviceInfo.class, name = "ios"),
@JsonSubTypes.Type(value = WebDeviceInfo.class, name = "web")
})
public abstract class DeviceInfo {
[...]
}
class IOSDeviceInfo extends DeviceInfo {
[...]
}
class WebDeviceInfo extends DeviceInfo {
[...]
}
Then when you receive a request, the body will be deserialized into the correct subclass, either a IOSDeviceInfo or a WebDeviceInfo, depending on the 'type' parameter in the JSON body:然后,当您收到请求时,主体将被反序列化为正确的子类,即 IOSDeviceInfo 或 WebDeviceInfo,具体取决于 JSON 主体中的“type”参数:
{
type : "ios",
[...]
}
Now you only need a single @RequestMapping method:现在你只需要一个 @RequestMapping 方法:
@RequestMapping(value = "/register-device", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void registerDevice(@RequestBody final DeviceInfo deviceInfo) {
if (deviceInfo instanceof WebDeviceInfo) {
final WebDeviceInfo webDeviceInfo = (WebDeviceInfo) deviceInfo;
//register web device
} else if (deviceInfo instanceof IOSDeviceInfo) {
final IOSDeviceInfo iosDeviceInfo = (IOSDeviceInfo) deviceInfo;
//register ios device
} else {
logger.debug("Could not cast deviceInfo to WebDeviceInfo or IOSDeviceInfo");
}
}
You can use @PathVariable
to the parameter to define which type you need to deserialize 您可以对参数使用
@PathVariable
来定义需要反序列化的类型
public void registerDevice(@PathVariable("deviceType") String deviceType, @RequestBody final DeviceInfo deviceInfo) {
switch (deviceType){
...
}
You can use the same @RequestMapping
, however, you still need something to differentiate them. 您可以使用相同的
@RequestMapping
,但是,仍然需要一些区别它们。 By same, I mean the same name, path, and RequestMethod. 同样,我的意思是相同的名称,路径和RequestMethod。
You can use the params
argument in request mapping to differentiate them. 您可以在请求映射中使用
params
参数来区分它们。
For example, 例如,
@RequestMapping(value = "/register-device",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
params="device=android")
public void registerDevice(@RequestBody final WebDeviceInfo deviceInfo){
}
@RequestMapping(value = "/register-device",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
params="device=ios")
public void registerDevice(@RequestBody final IOSDeviceInfo deviceInfo){
}
Then just add an extra parameter to the request with the key "device", and Spring will resolve the correct method. 然后只需使用键“ device”向请求添加一个额外的参数,Spring就会解析正确的方法。
eg, if this were your original payload: 例如,如果这是您的原始有效载荷:
{
deviceInfo : {..}
}
it would now be this: 现在是这样的:
{
device : "ios",
deviceInfo : {..}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.