2014-03-04 80 views
4

我想提出一個RESTful應用程序,並試圖對象列表轉換成JSON用於特定URL(@RequestMapping/@ResponseBody)使用Jackson2與Spring 4.0(MVC + REST +休眠)

我有傑克遜hibernate4和jackson-core,databind等在我的classpath中。

這是我的對象,我想在json中轉換。

@Entity 
@Table(name="Product") 
public class Product { 
@Id 
@Column(name="productId") 
@GeneratedValue 
protected int productId; 
@Column(name="Product_Name") 
protected String name; 

@Column(name="price") 
protected BigDecimal baseprice; 


@OneToMany(cascade = javax.persistence.CascadeType.ALL,mappedBy="product",fetch=FetchType.EAGER) 
protected List<ProductOption> productoption = new ArrayList<ProductOption>(); 

@OneToMany(cascade = javax.persistence.CascadeType.ALL,mappedBy="product",fetch=FetchType.EAGER) 
protected List<ProductSubOption> productSubOption = new ArrayList<ProductSubOption>(); 


@ManyToOne 
@JoinColumn(name="ofVendor") 
protected Vendor vendor; 

產品內部的兩個對象也都是POJO'S ..

這裏是我的方法檢索產品

@Override 
public List<Product> getMenuForVendor(int vendorId) { 
    List<Product> result = em.createQuery("from "+Product.class.getName()+" where ofVendor = :vendorId").setParameter("vendorId", vendorId).getResultList(); 
    System.out.println(result.size()); 
    return result; 
} 

名單當我嘗試在我的控制器我回到這個名單得到一個「不能懶惰地加載JSON」,所以我設置我的對象熱切地提取。 這裏是我的控制器

@Autowired 
private MenuDaoImpl ms; 

@RequestMapping(value = "/{vendorId}", method = RequestMethod.GET) 
public @ResponseBody List<Product> getMenu(@PathVariable int vendorId){ 

    List<Product> Menu = Collections.unmodifiableList(ms.getMenuForVendor(vendorId)); 
    return Menu; 
} 

現在,當我打我的網址本地主機:8080 /使用getMenu/1我應該得到一個JSON字符串顯示,但我得到的錯誤的大名單

WARN : org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver -  Handling of [org.springframework.http.converter.HttpMessageNotWritableException] resulted in Exception 
    java.lang.IllegalStateException: Cannot call sendError() after the response has been  committed 
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:467) 
Could not write JSON: Infinite recursion (StackOverflowError) (through reference chain: 

我不知道我是否缺少任何東西。請指導。

+2

好像你在你的實體中有循環引用。 –

+0

我只是在某種程度上能夠在我的瀏覽器上得到json,但現在它無限打印,直到我的控制檯上有一個stackoverflow ..它在哪裏有這個循環.. – Nikhil

+0

'Vendor'是否有'Product' ? –

回答

10

我使用@JsonBackReference for @ManyToOne綁定和@OneToMany綁定@JsonManagedReference解決了這個問題。

謝謝「索蒂里奧斯Delimanolis」

+0

如果喜歡是@OneToOne,該怎麼辦 –

0

我知道這可能不是100%你是什麼之後,但從來沒有少,我的感覺就像分享它,因爲我花了很多時間與這個問題反撲天。

此外,您可以考慮使用定製的Json解析器,而不是使用Json註釋。 請務必爲Jackson罐子使用正確的包裝,因爲他們最近更改了包裝結構(當您使用其中的任何一個類別爲2的類別時,如下所示)。

開始通過創建一個HttpMessageConverter:

@Bean 
    public HttpMessageConverter jacksonMessageConverter() { 
     MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
     converter.setPrefixJson(false); 
     converter.setPrettyPrint(true); 
     converter.setObjectMapper(objectMapper()); 
     return converter; 
    } 

添加在您連接映射模塊ObjectMapper並附上您將使用串行。

public ObjectMapper objectMapper() { 
    ObjectMapper objectMapper = new ObjectMapper(); 
    objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true); 

    SimpleModule module = new SimpleModule("jacksonJsonMapper", Version.unknownVersion()); 
    module.addSerializer(Product.class, new Product()); 

    objectMapper.registerModule(module); 

    return objectMapper; 
} 

現在創建一個序列化程序。這個類將提供您在獲取對象時看到的輸出,而傑克遜將完成剩下的工作。你只是提供它應該看起來的骨架。

public class Product erializer extends JsonSerializer<Product> { 

@Override 
public void serialize(Product product, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { 
    if(product == null) { 
     //Handle it, if you want 
    } 

    if(product != null) { 

     jsonGenerator.writeStartObject(); 

     jsonGenerator.writeStringField("id", productId.getId().toString()); 
     jsonGenerator.writeStringField("title", product.getName()); 
     jsonGenerator.writeStringField("basePrice", product.getBasePrice()); 


     //Add items to the json array representation 
     jsonGenerator.writeArrayFieldStart("productoptions"); 
     for(ProductOption productOption: product.getProductoption()) { 
      jsonGenerator.writeStartObject("field", productOption.getFoo()); 

      jsonGenerator.writeEndObject(); 
     } 
     jsonGenerator.writeEndArray(); 

     jsonGenerator.writeEndObject(); 
    } 
} 

}

在一個側面說明,但其中一個我還是希望這將是有用的: 你需要確保通過延遲加載取得的實體,當你有一個可用的交易。您還應該記住,懶惰是加載實體的首選方式,除非您想在每次獲取任何引用時徹底粉碎您的服務器。

嘗試通過在其上添加@Transactional來更改獲取數據的方法,以確保在其運行時爲方法打開一個事務,如果沒有,它可能會在嘗試獲取時關閉子對象。