2014-10-26 2 views
2

Привет, у вас есть проблемы с Hibernate и Jackson. У вас есть два POJOHibernate и Jackson (java.lang.IllegalStateException: не удалось вызвать sendError() после того, как ответ был зафиксирован)

@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; 

Пользователь и его роль, которые созданы для интеграции весной безопасности.

@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; 

И у вас есть контроллер, который производится от пользователя Json через Jackson. При использовании метода

@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 = «пользователь», каскад = CascadeType.ALL, принеси = FetchType.EAGER), ранее это было просто fetch = FetchType.EAGER, но я не смог сохранить пользователя с его ролью, в этом случае таблица USER_ROLE была пуста. У меня есть красное решение этой проблемы в бесконечном цикле где-то в Джексоне, добавлена ​​некоторая анотация @JsonBackReference («role») и @JsonManagedReference («role»), но ничего не изменилось. Как я могу решить эту проблему? Спасибо!

ответ

3

Я рекомендую добавить @jsonignore к собственности, вызывающей круговую ссылку. это скажет Джексону не сериализовать это свойство.

1

Используйте контрольную точку исключения для IllegalStateException, чтобы остановить выполнение при вызове sendError, а затем проверить локальные переменные в стеке, чтобы получить исключение, которое невозможно сообщить, и вызвать его метод printStackTrace, чтобы увидеть его стек.

Надеемся, что основная причина исключения будет ясна, и с ней, как исправить любую проблему.

1

Иногда комплексы бобов вызывают такую ​​проблему. Поскольку я видел ваши отношения @OneToMany - EAGER, это правильно, если вы используете LAZY, когда вы сериализуете список в JSON, что объекты зависимостей теряются. Ваша проблема - проблема сериализации, я не сомневаюсь.

Юр можно попробовать:

@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-компоненты, используемые в среднем слое устойчивых компонентов и формы. Наиболее часто используется уровнем услуг или контроллером в приложении (N) уровня для передачи данных между собой и уровнем пользовательского интерфейса. Вы можете создать DTO на уровне обслуживания или напрямую в контроллере (лучше в сервисе) и отправить его в форму, а также разрешить привязывать записи формы к проверке непосредственно в контроллере (в основном вам нужно добавить параметр BindingResult result в сигнатуре метода контроллера). DTO позволяют создавать аннотации, которые выполняют валидацию, такие как @NotEmpty, @PasswordsNotEqual, @Size (max = 100), эти аннотации идут в bean-компоненте, и вы также можете поместить эти аннотации в свой упорный компонент, но не рекомендуется, потому что вы создавая очень сложный компонент. Сообщения валидации, показываются в виде Посмотрите, как:

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

Поверь в меня, DTO фантастичны к вашему сценарию потому что это позволяет сделать проверку записей формы в правильном направлении.

С наилучшими пожеланиями

0

Лучшее решение, которое я нашел не возвращать Entity непосредственно. В вашем случае вы возвращаете «пользовательский» объект непосредственно в свой контроллер входа. Вместо этого просто верните user.id или user.firstname и т. Д. Это будет работать нормально. Когда мы возвращаем любую сущность, компилятор переходит в бесконечный рекурсивный цикл.

Смежные вопросы

 Смежные вопросы