Исключение Strange Jackson, возникающее при сериализации объекта Hibernate

Джексон бросает странное исключение, которое я не знаю, как исправить. Я использую Spring, Hibernate и Jackson.

Я уже считал, что ленивая загрузка вызывает проблему, но я принял меры, чтобы сообщить Джексону НЕ обрабатывать различные свойства следующим образом:

@JsonIgnoreProperties({ "sentMessages", "receivedMessages", "educationFacility" })
public class Director extends UserAccount implements EducationFacilityUser {
   ....
}

Я сделал то же самое для всех других подклассов UserAccount.

Здесь исключение:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[46]->jobprep.domain.educationfacility.Director_$$_javassist_2["handler"])
    at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)
    at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:268)
    at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:146)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:118)
    at org.codehaus.jackson.map.ser.ContainerSerializers$IndexedListSerializer.serializeContents(ContainerSerializers.java:236)
    at org.codehaus.jackson.map.ser.ContainerSerializers$IndexedListSerializer.serializeContents(ContainerSerializers.java:189)
    at org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:111)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:296)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:224)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:925)
    at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:153)

Предложения о том, как я могу получить больше информации, чтобы узнать, что вызывает это? Кто-нибудь знает, как это исправить?

EDIT: Я обнаружил, что getHander() и другие методы get *() существуют на прокси-объекте. GRR!! Есть ли какой-либо способ, которым я могу сказать, что Джексон не обрабатывал ничего на прокси, или я зов? Это действительно странно, потому что метод, который выплевывает JSON, падает только при определенных обстоятельствах, не все время. Тем не менее, это связано с методами get *() на прокси-объекте.

Кроме того, Прокси - зло. Они нарушают Jackson, equals() и многие другие части обычного программирования Java. Я испытываю соблазн полностью отказаться от Hibernate:/

Ответ 1

Это не идеально, но вы можете отключить автоматическое обнаружение свойств JSON Джексона, используя @JsonAutoDetect на уровне класса. Это помешало бы ему попытаться обработать материал Javassist (и потерпеть неудачу).

Это означает, что вам нужно вручную аннотировать каждый получатель (с помощью @JsonProperty), но это не обязательно плохо, поскольку оно сохраняет явные вещи.

Ответ 2

У меня была аналогичная проблема с ленивой загрузкой через прокси-объект hibernate. Общайтесь с ним, аннотируя класс, имеющий lazyloaded private properties:

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

Я предполагаю, что вы можете добавить свойства на свой прокси-объект, который разбивает сериализацию JSON на эту аннотацию.

Избегайте сериализации Джексона на непривлекательных ленивых объектах

Ответ 3

я получил ту же ошибку, но без отношения к Hibernate. Я испугался здесь от всех пугающих предложений, которые, я думаю, уместно в случае Hibernate и ленивой загрузки... Однако в моем случае я получил ошибку, так как во внутреннем классе у меня не было геттеров/сеттеров, поэтому BeanSerializer не смог сериализовать данные...

Добавление геттеров и сеттеров разрешило проблему.

Ответ 4

Для чего стоит проект Jackson Hibernate module, который только начинался, и который должен решить эту проблему и, надеюсь, и другие. Проект связан с проектом Джексона, хотя он и не является частью основного источника. Это в основном для упрощения процесса выпуска; это потребует от Jackson 1.7, когда внедряется модуль API.

Ответ 5

У меня была та же проблема. Посмотрите, используете ли вы hibernatesession.load(). Если да, попробуйте преобразовать в hibernatesession.get(). Это решило мою проблему.

Ответ 6

У меня было такое же сообщение об ошибке от spring @RestController. Класс контроллера останова использовал класс spring JpaRepository, и, заменив вызов repository.getOne(id) методом repository.findOne(id), проблема исчезла.

Ответ 9

Вы можете использовать аннотацию @JsonIgnoreProperties(value = { "handler", "hibernateLazyInitializer" }) для вашего класса "Директор"

Ответ 10

Как и в других ответах, проблема для меня заключалась в том, чтобы объявить столбец "один-к-одному", чтобы сделать ленивый выбор. Исправлена ​​проблема переключения на целевую выборку. До:

@ManyToOne(targetEntity = StatusCode.class, fetch = FetchType.LAZY)

После:

@ManyToOne(targetEntity = StatusCode.class, fetch = FetchType.EAGER)

Ответ 11

Я новичок в API Jackson, когда получил "org.codehaus.jackson.map.JsonMappingException: сериализатор не найден для класса com.company.project.yourclass", я добавил геттер и setter в com.company. project.yourclass, который помог мне использовать объект Mapper ObjectMapper для записи объекта java в плоский файл.

Ответ 12

Я столкнулся с той же проблемой, и действительно странно, что один и тот же код работает в нескольких случаях, в то время как в некоторых случайных случаях он не срабатывает.

Я исправил это, просто убедившись, что правильный сеттер/геттер (убедитесь, что чувствительность к регистру)

Ответ 13

Я пробовал @JsonDetect и

@JsonIgnoreProperties(value = { "handler", "hibernateLazyInitializer" })

Ни один из них не работал у меня. Использование стороннего модуля показалось мне для меня большой работой. Поэтому я просто попытался сделать вызов get для любого свойства ленивого объекта, прежде чем перейти к jackson для серлизации. Фрагмент рабочего кода выглядел примерно так:

@RequestMapping(value = "/authenticate", produces = "application/json; charset=utf-8")
    @ResponseBody
    @Transactional
    public Account authenticate(Principal principal) {
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) principal;
        LoggedInUserDetails loggedInUserDetails = (LoggedInUserDetails) usernamePasswordAuthenticationToken.getPrincipal();
        User user = userRepository.findOne(loggedInUserDetails.getUserId());
        Account account = user.getAccount();
        account.getFullName();      //Since, account is lazy giving it directly to jackson for serlization didn't worked & hence, this quick-fix.
        return account;
    }

Ответ 14

Кроме того, вы можете сделать конечный объект вашего объекта домена. Это не идеальное решение, но оно предотвращает создание прокси-подкласса вашего класса домена.

Ответ 15

Вы можете добавить микшер Jackson в Object.class, чтобы всегда игнорировать связанные с гибернацией свойства. Если вы используете Spring Boot, поместите это в свой класс Application:

@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
    Jackson2ObjectMapperBuilder b = new Jackson2ObjectMapperBuilder();
    b.mixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
    return b;
}


@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private abstract class IgnoreHibernatePropertiesInJackson{ }