我是新来的,知道下面的问题很多时候已经讨论过了,但我找不到明确解决问题的方法......
所以,我在一个由两部分组成的应用程序上工作: - AngularJS的前端 - Spring MVC的后端 两部分都以JSON格式与杰克逊交换。 将JSON与View Object(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类是通用的,因为这个控制器可以接收/发送2种ReferenceVO(VO1和VO2),它们都是从Abstract类(AbstractReferenceEntityVO)继承。
今天我在尝试调用此保存功能时遇到了以下问题:
*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类。所以我想我必须指定杰克逊继承了必须用于映射的VO所以我需要首先对我的引用的“类型”做一个条件,以便与正确的VO联系...
这是我的ObjectMapper&amp; 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?说实话,我有点迷失了怎么做!
非常感谢你的帮助!
答案 0 :(得分:0)
您需要将类型标识符作为json中的字段传递。使用@JsonTypeInfo
注释基类以指定字段的名称和要使用的标识符。默认情况下,如果您使用类名作为标识符,则字段名称为@class
。
有关详细信息,请参阅polymorphic deserialisation上的Wiki页面。
示例:
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;
}
}
}