【问题标题】:Hibernate and Jackson (java.lang.IllegalStateException: Cannot call sendError() after the response has been committed)Hibernate 和 Jackson(java.lang.IllegalStateException:在响应提交后无法调用 sendError())
【发布时间】:2014-12-21 17:27:37
【问题描述】:

您好,Hibernate 和 Jackson 有问题。有两个 POJO

@Entity
@Table(name = "USERS")
public class User implements Serializable {
static final long serialVersionUID = 4235637833262722256L;

@Id
@GeneratedValue
private int id;

@Column(name = "CREATION_DATE")
private Date creationDate;

@Column(name = "FIRST_NAME")
private String firstName;

@Column(name = "LAST_NAME")
private String lastName;

@Version
@Column(name = "VERSION")
private int version;

@Column(name = "E_MAIL")
private String email;

@Column(name = "ENABLED")
private boolean enabled;

@Column(name = "LOGIN")
private String login;

@Column(name = "PASSWORD")
private String password;

@JsonManagedReference("role")
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Set<UserRole> userRole;

为 Spring 安全集成创建的用户及其角色。

@Entity
@Table(name = "USER_ROLES")
public class UserRole {

@Version
@Column(name = "VERSION")
int version;
@Id
@GeneratedValue
private int id;

@JsonBackReference("role")
@ManyToOne()
@JoinColumn(name = "USER_ID", referencedColumnName = "ID")
private User user;

@Column(name = "ROLE")
private String role;

并且有一个控制器,它通过 Jackson 由用户 Json 制作。用方法

  @RequestMapping(value = "/login", method = RequestMethod.GET, produces = "application/json")
private @ResponseBody User checkLoginAvailability(@RequestParam String login) {
    User user = appContext.getUserService().readUserByLogin(login);
    if (user != null) {
        return user;
    }
    return new User();
}

当此方法返回没有空字段的用户时,它会抛出:

26-Oct-2014 14:31:17.652 WARNING [http-nio-8080-exec-4] 
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException 
Handling of [org.springframework.http.converter.HttpMessageNotWritableException]
resulted Exception java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

当我添加 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL,fetch = FetchType.EAGER) 时出现了问题,之前它只是 fetch = FetchType.EAGER,但我无法保存用户在这种情况下,由于他的角色,表 USER_ROLE 是空的。我在杰克逊某处的无限循环中解决了这个问题,添加了一些注释 @JsonBackReference("role") 和 @JsonManagedReference("role") 但没有任何改变。我怎么解决这个问题?谢谢!

【问题讨论】:

    标签: java json hibernate orm jackson


    【解决方案1】:

    我建议在导致循环引用的属性上添加@jsonignore。这将告诉杰克逊不要序列化该属性。

    【讨论】:

      【解决方案2】:

      使用 IllegalStateException 的异常断点在调用 sendError 时停止执行,然后检查堆栈上的局部变量以获取无法报告的异常,并调用其 printStackTrace 方法以查看其堆栈跟踪。

      希望,异常的根本原因会很清楚,以及如何解决问题所在。

      【讨论】:

        【解决方案3】:

        有时复合 bean 会导致此类问题。正如我看到您的关系 @OneToMany 是 EAGER 一样,如果您在将列表序列化为 JSON 时使用 LAZY 会丢失依赖项对象,那么这是正确的原因。你的问题是序列化问题,我不怀疑。

        你可以试试:

        @Entity
        @Table(name = "USERS")
        //To suppress serializing properties with null values
        @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
        //Ignoring new fields on JSON objects
        @JsonIgnoreProperties(ignoreUnknown = true)
        public class User implements Serializable {
        ...
        

        但我建议您使用一种称为数据传输对象 (DTO) 的良好做法。 DTO 是用于持久 bean 和表单中间层的 bean。最常被 (N) 层应用程序中的服务层或控制器用于在其自身和 UI 层之间传输数据。您可以在服务层创建DTO,也可以直接在控制器中(服务更好)并将其发送到表单,它还允许您直接在控制器中将表单条目绑定到验证(基本上您需要添加参数 BindingResult 结果在控制器方法的签名中)。 DTO 允许您创建像 @NotEmpty、@PasswordsNotEqual、@Size(max = 100) 这样进行验证的注解,这些注解在 bean 中,您也可以将这些注解放在持久性 bean 中,但不推荐,因为您是创建一个非常复杂的bean。验证消息以查看方式显示:

        <form:errors id="error-password" path="password" cssClass="help-block"/>
        

        相信我,DTO 非常适合您的场景,因为它允许您以正确的方式验证表单条目。

        最好的问候

        【讨论】:

          【解决方案4】:

          我找到的最佳解决方案是不直接返回实体。 在您的情况下,您将直接在登录控制器中返回“用户”实体。而是只返回 user.id 或 user.firstname 等。它会正常工作。当我们返回任何实体时,编译器会进入无限递归循环。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-11-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-09-23
            • 1970-01-01
            • 2014-08-22
            相关资源
            最近更新 更多