Hibernate incompatible con SparkJava?

Val:

Tengo un error usando Hibernate con SparkJava en el modo lazy-loading.

Se está trabajando correctamente sin SparkJava, pero cuando se utiliza SparkJava que está tratando de forzar con ganas de carga para una relación OneToMany.


- Modelo

@Entity
@Table(name = "KU_SUPPLIER")
public class Supplier {

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

    @NotEmpty(message = "Please provide a name")
    private String name;

    @OneToMany(mappedBy = "supplier")
    private List<Item> items;  // Should be lazy-loaded

    // Constructor / Getters / Setters
}


- DAO

public class SupplierDao implements Dao<Supplier> {

    private final SessionFactory sessionFactory;

    public SupplierDao(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Supplier> findAll() {
        try (Session session = sessionFactory.openSession()) {
            return session.createQuery("FROM com.seafrigousa.model.Supplier").getResultList();
        }
    }
}


- Principal

// Working perfectly and lazy-load Items as desired    
supplierDao.findAll();

// The method will be called when a web browser goes to "localhost/suppliers"
// It throws org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: model.Supplier.items, could not initialize proxy - no Session
get("/suppliers", "application/json", supplierDao::findAll);


Revisé al no cerrar la sesión desde el DAO y vi que Hibernate se ejecuta la consulta como si estuviera en modo de carga Eager, por lo que estaba ejecutando dos casillas, una para el Proveedor y uno para el artículo.

¿Hay alguna razón para este comportamiento?

¡Gracias!

Tijkijiki:

Supongo que aquí: get("/suppliers", "application/json", supplierDao::findAll);objeto Proveedor está serializando en JSON. Itemscampo no está marcado como excluidos de la serialización, así que conseguir su valor de inicialización perezosa causa de sesión (o redundand segunda consulta para los artículos, si la sesión no se cierra).

Si mi suposición es correcta, hacer su serializador ignorar campo de artículos o buscarlos en su consulta

session.createQuery("FROM com.seafrigousa.model.Supplier s join fetch s.items").getResultList();

Usando GSON como serializador dispone de los siguientes opciones:

  1. @Exposeanotación en los campos que desee para serializar.

    @Entity
    @Table(name = "KU_SUPPLIER")
    public class Supplier {
    
        @Expose
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
    
        @Expose
        @NotEmpty(message = "Please provide a name")
        private String name;
    
        @OneToMany(mappedBy = "supplier")
        private List<Item> items;  // Should be lazy-loaded
    
        // Constructor / Getters / Setters
    }
    

    Con después de la iniciación GSON

    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
    
  2. ExclusionStrategy con la anotación personalizada Fe

    public class IgnoreFieldExclusionStrategy implements ExclusionStrategy {
    
        @Override
        public boolean shouldSkipField(FieldAttributes fieldAttributes) {
            return fieldAttributes.getAnnotation(GsonIgnore.class) != null;
        }
    
        @Override
        public boolean shouldSkipClass(Class<?> aClass) {
            return false;
        }
    }
    

    con la anotación personalizada @GsonIgnore

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface GsonIgnore {}
    

    y GSON iniciación

    Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new IgnoreFieldExclusionStrategy()).create();
    

    su clase sería el siguiente

    @Entity
    @Table(name = "KU_SUPPLIER")
    public class Supplier {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
    
        @NotEmpty(message = "Please provide a name")
        private String name;
    
        @GsonIgnore
        @OneToMany(mappedBy = "supplier")
        private List<Item> items;  // Should be lazy-loaded
    
        // Constructor / Getters / Setters
    }
    

Si usted tendría necesidad serializar Suppliercon itemsen diferentes API, puede crear el objeto DTO para Suppliery asignarla a resultados como este:

package com.seafrigousa.dto

public class SupplierDTO {

    private int id;
    private String name;

    public SupplierDTO(int id, String name) {
        this.id = id;
        this.name = name;
   }

    // Getters / Setters
}

y consulta:

session.createQuery("select new com.seafrigousa.dto.SupplierDTO(s.id, s.name) FROM com.seafrigousa.model.Supplier s").getResultList();

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=210720&siteId=1
Recomendado
Clasificación