2016-11-20 64 views
1

我是新來的,知道下面的問題很可能已經討論了很多時間,但我無法找到一個明確的解決我的問題......如何使用傑克遜TypeReference爲通用類

所以,我在由兩部分組成的應用程序上工作: - AngularJS中的前端 - Spring MVC中的後端 兩部分都以JSON格式與Jackson交換。 哪個JSON關聯到視圖對象(VO)

所以我下面的JavaScript函數在前端:

\t \t /** 
 
    \t \t * Reference save. 
 
    \t \t * @param reference The reference to save 
 
    \t \t * @param type Type of reference 
 
    \t \t */ 
 
    \t \t save: function(reference,type) { 
 
    \t \t \t return $http.post('myApplication/reference/save/'+ type, reference); 
 
    \t \t }

將數據發送到下面的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 Class(A bstractReferenceEntityVO)。

今天我試圖調用此保存功能時,下面的傑克遜問題:

*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: [email protected]; 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* 

經過研究,我發現我不得不使用傑克遜「TypeReference」來管理通用類。所以我想我必須指定傑克遜繼承VO它必須用於映射,所以我需要做的第一個條件的「類型」我的參考與正確的VO關聯...

這是我的ObjectMapper & XML配置:

\t <mvc:annotation-driven conversion-service="applicationConversionService"> 
 
\t \t <mvc:message-converters> 
 
\t \t \t <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 
 
    \t \t \t \t <property name="objectMapper"> 
 
\t \t \t \t \t <bean class="myApplication.CustomObjectMapper" /> 
 
\t \t \t \t </property> 
 
\t \t \t </bean> 
 
\t \t </mvc:message-converters> 
 
\t </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

您需要在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; 
     } 
    } 
}