我是新来的,知道下面的问题可能已经讨论过很多次了,但我找不到解决我的问题的明确解决方案...
因此,我正在开发一个由两部分组成的应用程序: - AngularJS 的前端 - Spring MVC 的后端 两者都以 JSON 格式与 Jackson 进行交换。 将 JSON 关联到 View 对象 (VO)
所以我在 FrontEnd 上有下面的 Javascript 函数:
/**
* Reference save.
* @param reference The reference to save
* @param type Type of reference
*/
save: function(reference,type) {
return $http.post('myApplication/reference/save/'+ type, reference);
}
将数据发送到下面的 Java 函数:
**
* Reference Controller.
* @param <VO> Reference
* @param <E> Entity
*/
@RequestMapping("/reference/")
@Controller
public class ReferenceController<VO extends AbstractReferenceEntityVO, E extends AbstractReferenceEntity> {
/** Reference management service. */
@Autowired
private ReferenceService<VO, E> referenceService;
/**
* Reference save method.
* @param referenceVO View Object of the reference to save
* @param type Reference type
* @return VO
*/
@ResponseBody
@RequestMapping(value = "/save/{type}", method = RequestMethod.POST,
headers = "Accept=application/json")
public VO save(@Validated @RequestBody final VO referenceVO,
@PathVariable final String type)
{
return this.referenceService.save(type, referenceVO);
}
}
这个JAVA类是一个通用类,因为这个 Controller 可以接收/发送2种ReferenceVO(VO1和VO2),两者都继承自抽象类(AbstractReferenceEntityVO)。
今天,我在尝试调用此保存函数时遇到了以下 jackson 问题:
*Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of myApplication.AbstractReferenceEntityVO, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: java.io.PushbackInputStream@1a956b3d; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:889)
at
com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:139)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:205)
... 88 more*
经过研究,我发现我必须使用 jackson“TypeReference”来管理 Generic 类。所以我想我必须向 Jackson 指定它必须用于映射的继承 VO,因此我需要首先对我的引用的“类型”执行一个条件以与正确的 VO 关联...
这是我的 ObjectMapper 和 XML 配置:
<mvc:annotation-driven conversion-service="applicationConversionService">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="myApplication.CustomObjectMapper" />
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
/**
* Mapper JSON objets.
*/
public class CustomObjectMapper
extends ObjectMapper
{
/** Id. */
private static final long serialVersionUID = 6488036405547458525L;
/** Constructor. */
public PlageObjectMapper()
{
super();
this.registerModule(new JodaModule());
this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
this.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
TypeReference ref = new TypeReference<AbstractReferenceEntityVO>() {
// if(type== "TYPE_1") {
// TODO
// } else {
// TODO
// }
};
}
}
有人已经必须做类似的事情了吗?或者如何在我的案例中使用 TypeReference ?老实说,我有点不知道该做什么!
非常感谢您的帮助!
最佳答案
您需要将类型标识符作为 json 中的字段传递。使用 @JsonTypeInfo
注释您的基类,以指定要使用的字段名称和标识符。默认情况下,如果您使用类名作为标识符,则字段名称为 @class
。
请参阅 wiki 页面 polymorphic deserialisation了解详情。
示例:
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.xml.sax.SAXException;
import javax.xml.transform.TransformerException;
import java.io.IOException;
public class Scratch {
private static ObjectMapper mapper = new ObjectMapper();
public static void main(String[] args) throws IOException, TransformerException, SAXException {
System.out.println(mapper.readValue("{\"@class\": \"Scratch$B\", \"payload\": \"hello, world.\"}", A.class));
System.out.println(mapper.readValue("{\"@class\": \"Scratch$C\", \"payload\": \"hello again.\", \"extra\": 1}", A.class));
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
abstract public static class A {
abstract public String getPayload();
@Override
public String toString() {
try {
return "I'm a " + getClass().getSimpleName() + ": " + mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
public static class B extends A {
private String payload;
@Override
public String getPayload() {
return payload;
}
public void setPayload(String payload) {
this.payload = payload;
}
}
public static class C extends B {
private int extra;
public int getExtra() {
return extra;
}
public void setExtra(int extra) {
this.extra = extra;
}
}
}
关于java - 如何将 Jackson TypeReference 用于泛型类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40709429/