@RestController @RequestMapping(value = "/{entity}",produces = MediaType.APPLICATION_JSON_VALUE) public class CrudController<T extends SomeSuperEntity> { @RequestMapping(method = GET) public Iterable<T> findAll(@PathVariable String entity) { } @RequestMapping(value = "{id}",method = GET) public T findOne(@PathVariable String entity,@PathVariable String id) { } @RequestMapping(method = POST) public void save(@PathVariable String entity,@RequestBody T body) { } }
SomeSuperEntity类看起来像:
public abstract class SomeSuperEntity extends AbstractEntity { // some logic }
和AbstractEntity它的抽象类有一些字段:
public abstract class AbstractEntity implements Comparable<AbstractEntity>,Serializable { private Timestamp firstField; private String secondField; public Timestamp getFirstField() { return firstField; } public void setFirstField(Timestamp firstField) { this.firstField = firstField; } public String getSecondField() { return secondField; } public void setSecondField(String secondField) { this.secondField = secondField; } }
SomeSuperEntity的所有子类 – 简单的JavaBeans.
如果使用findAll()和findOne(id)方法 – 一切正常.
我在服务层创建实体,它以JSON的形式返回客户端,所有字段都在子类和AbstractEntity中声明.
但是当我试图在保存(实体,正文)中获取请求正文时,我得到以下错误:
Could not read document: Can not construct instance of
SomeSuperEntity,problem: abstract types either need to be mapped to
concrete types,have custom deserializer,or be instantiated with
additional type information
如果我从SomeSuperEntity中删除抽象,一切正常,但我请求正文我只得到那些在AbstractEntity中声明的字段.
这是我的问题,在我的案例中是否有针对此类问题的解决方法?
如果没有,那么在没有任何结构变化的情况下,最佳解决方案会是什么(为每个实体制作子控制器不是一个选项)?将检索体作为纯文本是个好主意吗?或者为此使用Map会更好吗?
我使用Spring v4.2.1和Jackson 2.6.3作为转换器.
有一些关于通用控制器的信息,但我找不到任何涵盖我的情况.所以,请在重复问题的情况下导航.
提前致谢.
UPD:目前其工作如下:
我在MessageConverter中添加了额外的检查,并将@RequestBody定义为String
@Override public Object read(Type type,Class<?> contextClass,HttpInputMessage inputMessage) throws IOException,HttpMessageNotReadableException { if (IGenericController.class.isAssignableFrom(contextClass)) { return CharStreams.toString(new InputStreamReader(inputMessage.getBody(),getCharset(inputMessage.getHeaders()))); } return super.read(type,contextClass,inputMessage); }
然后,在服务层,我定义接收的实体(在普通的json中)并转换它:
final EntityMetaData entityMetadata = getEntityMetadataByName(alias); final T parsedEntity = getGlobalGson().fromJson(entity,entityMetadata.getEntityType());
其中EntityMetaData是枚举,具有实体别名和类之间的已定义关系.别名来自@PathVariable.
解决方法
public class CrudController { @RequestMapping(method = GET) public Iterable<Object> findAll(@PathVariable String entity) { } @RequestMapping(value = "{id}",method = GET) public Object findOne(@PathVariable String entity,@PathVariable String id) { } @RequestMapping(method = POST) public void save(@PathVariable String entity,@RequestBody Object body) { } }
对于返回的对象,没关系,因为Jackson无论如何都会生成输出正确的JSON,但看起来Spring无法以相同的方式处理传入的Object.
您可以尝试使用SomeSuperEntity替换泛型,并查看Spring @RequestBody containing a list of different types (but same interface)