当前位置: 首页 > 知识库问答 >
问题:

在Spring4.0中使用Jackson2(MVC REST Hibernate)

孟沛
2023-03-14

我正在制作一个restful应用程序,并尝试将对象列表转换为特定url(@RequestMapping/@ResponseBody)的json

我的类路径中有jackson-hibernate4和jackson-core,datind等。

这是我想用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 = html" target="_blank">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:

我不确定我是否遗漏了什么。请导游。

共有3个答案

狄德泽
2023-03-14

我意识到这可能不是你所追求的100%,但从来没有少过,我想分享它,因为我花了很多时间来解决这个问题。

此外,您可以考虑自定义Json解析器,而不是使用Json注释。确保为Jackson jar使用正确的包,因为它们最近更改了它们的包结构(当您使用它们的任何带有数字2的类时,如下面所示)。

首先创建一个HttpMessageConzer:

   @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();
    }
}

}

另一方面,我仍然希望这一点会有用:在惰性地获取实体时,需要确保有一个可用的事务。您还应该记住,lazy是加载实体的首选方式,除非您每次获取任何引用时都想彻底摧毁服务器。

尝试通过在方法上添加@Transactional来更改获取数据的方法,以确保该方法在运行时有一个打开的事务,如果没有,则可能在尝试获取子对象时关闭该事务。

晏正豪
2023-03-14

这个问题已经回答了。我只是简单地把一个好例子的链接,清楚地解释了问题和解决方案。http://geekabyte.blogspot.in/2013/09/fixing-converterhttpmessagenotwritablee.html

苏淇
2023-03-14

我使用@JsonBackReference对@manytone绑定和@JsonManagedReference对@OneToMany绑定进行了解决。

谢谢“Sotirios Delimanolis”

 类似资料:
  • 我想将Jackson2与<code>SpringRoboSpice commons-io-1.3.2.jar commons-lang3-3.2.1.jar jackson-annotations-2.2.3.jar jackson-core-2.2.3.jar jackson-databind-2.2.3.jar robospice-1.4.11.jar robospice-cache-1.4.

  • 我正在使用spring(4.2.0.RELEASE)、hibernate validator(5.2.1.Final)和validation api(1.1.0.Final)对后端应用程序进行JSR验证,配置如下:, 但是没有一个JSR303注释在我的应用程序中工作。 注意:在POJO类上添加了JSR303注释,在服务类(使用POJO)上添加了@Validated注释,还尝试在方法级别添加@Val

  • 我一直试图获得一个简单的web操作来向API发出一个经过身份验证的get请求(我已经从示例代码中删除了实际的url和秘密)。 我已经在本地成功地运行了这一点,但是当我测试web动作时,它只是在记录“调用Axios”之后死亡。 它不会报告错误,我尝试实现一个承诺,认为线程在api响应之前就结束了,但没有效果。有什么线索吗?

  • 问题内容: 我想使用Android Studio使用Gradle构建工具开发应用程序。我无法在上插入存储库和库。我的文件如下: 如何在项目中添加OpenCV? 问题答案: 您可以在Android Studio中轻松完成此操作。 请按照以下步骤将Open CV作为库添加到您的项目中。 libraries在项目主目录下创建一个文件夹。例如,如果您的项目是OpenCVExamples,则将创建一个Ope

  • 我想使用Android Studio开发一个应用程序使用Gradle构建工具。我无法在上插入OpenCV repo和库。我的文件如下所示: 我如何在我的项目中添加OpenCV?