Как сериализовать JSON, содержащий ленивые ассоциации - PullRequest
0 голосов
/ 29 июня 2018

У меня есть объект Person, который @ManyToOne связан с объектом Contact с типом выборки LAZY. Я использую Spring-Boot для предоставления REST API. Один из моих вызовов POST содержит вложенный JSON для сохранения родительской сущности Person вместе с ассоциацией Contact

Поскольку Contact тип извлечения LAZY, я сталкиваюсь со следующим исключением

    ERROR 17415 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.rest.RestResultObject["results"]->java.util.ArrayList[0]->com.example.model.Person["contact"]->com.example.model.Contact_$$_jvst8d1_4["handler"])] with root cause

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.rest.RestResultObject["results"]->java.util.ArrayList[0]->com.example.model.Person["contact"]->com.example.model.Contact_$$_jvst8d1_4["handler"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.3.jar:2.9.3]

Без изменения контакта на EAGER. Есть ли лучший способ решить эту проблему?

Изменено:

Person.java

public class Person {
    private long id;
    private String name;
    private String rno;
    @ManyToOne(fetch = FetchType.LAZY)
    private Contact contact;

    // Getters and setters
}

Contact.java

public class Contact {
    private long id;
    private String info;
    @OneToMany
    private List<Person> persons;
}

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

Проблема, скорее всего, связана с обработкой транзакций. Сериализация JSON выполняется вне области транзакции. Если это так, то самое простое решение (не обязательно лучшее с архитектурной точки зрения) состоит в создании службы, которая оборачивает загрузку объекта (выделенную для операций REST) ​​и выполняет «делазификацию» связанных данных, например, (ключевым элементом является @Transactional аннотация).

@Sevice
@Transactional(readOnly=true)
public class DataReaderServiceImpl extends DataLoaderService{
    //initialization code
    public Person loadPerson(PredicatesType somePredicate){
        Person person = //get person using predicates expression
        //"delazy" contacts in transaction scope
        person.getContacts();
        return person;
    }
}

Архитектурно, в такой службе было бы лучше иметь отображение на DTO и возвращать экземпляры DTO вместо сущностей.

0 голосов
/ 02 июля 2018

Я добавил следующие вещи

  • @ Сущность на каждом объекте
  • Chnage long to Long в id, это поможет вам, если вы используете данные весны jpa
  • добавить @Id для объявления идентификатора в качестве первичного ключа
  • @ JsonBackReference & @JsonManagedReference, чтобы избежать бесконечного цикла по jacson

Персональный класс

@Entity
public class Person {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;

 private String name;

 private String rno;

 @JsonManagedReference
 @ManyToOne(fetch = FetchType.LAZY)
 private Contact contact;

 //setter & getter

}

Контактный класс

@Entity
public class Contact {

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;

 private String info;

 @JsonBackReference
 @OneToMany(cascade = CascadeType.ALL, mappedBy = "contact")
 private List<Person> persons;

 //setter & getter
}

и добавить зависимость

<dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>

и наконец добавьте новый конфиг

@Configuration
public class JacksonConfig {

@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomBigDecimalDeserialization() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            jacksonObjectMapperBuilder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            jacksonObjectMapperBuilder.modules(new Hibernate5Module());
        }

    };
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...