我正在创建一个restful应用程序,并试图将对象列表转换为特定url的json (@RequestMapping / @ResponseBody )
我的类路径中有jackson-hibernate4 4和jackson-core、databind等。
这是我想在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的..。
下面是我检索产品列表的方法
@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;
}现在,当我访问url localhost: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:我不确定我是不是错过了什么。请指点。
发布于 2014-03-04 21:43:49
我为@ManyToOne绑定使用了@JsonBackReference,在@OneToMany绑定上使用了@JsonManagedReference。
谢谢“索提里奥斯·德里马诺利”
发布于 2014-11-04 09:55:08
这个问题已经回答了。我只是简单地提出一个很好的例子,清楚地解释了问题和解决方案。http://geekabyte.blogspot.in/2013/09/fixing-converterhttpmessagenotwritablee.html
发布于 2014-03-05 11:37:09
我意识到这可能不是你想要的100%,但从来没有少,我想分享它,因为我花了很多时间与这个问题在过去的日子里。
另外,您可以考虑使用自定义Json解析器,而不是使用Json注释。确保对Jackson jars使用正确的包,因为它们最近更改了它们的包结构(当您使用它们的类中有数字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;
}现在创建一个序列化程序。这个类将提供您在获取对象时看到的输出,而Jackson将执行其余的操作。你只是提供了它应该是什么样的骨架。
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();
}
}}
顺便提一句,但我仍然希望这将是有用的:当您懒洋洋地获取实体时,您需要确保有一个事务可用。您还应该记住,懒散是加载实体的最好方式,除非每次获取引用时都要彻底粉碎服务器。
尝试更改获取数据的方法,在其上面添加@Trans显着,以确保该方法在运行时有一个事务打开,如果没有,则可能在尝试获取子对象时关闭它。
https://stackoverflow.com/questions/22183160
复制相似问题