Jackson ObjectMapper Hibernate issue












2














I am working on a Spring Boot 2.0 / Java 8 shopping cart online application. I use Hibernate as the ORM framework.
I have two entities, Order and OrderDetail shown below:



@Entity
@Table(name = "orders")
public class Order extends AbstractEntityUuid {

@Column(name = "order_number", unique = true)
private String orderNumber;

@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@Column(name = "total_amount")
private BigDecimal totalAmount = BigDecimal.ZERO;

@CreatedDate
@Column(name = "created_on", columnDefinition = "DATETIME", updatable = false)
protected LocalDateTime created;

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JsonManagedReference
private Set<OrderDetail> items = new HashSet<>();

@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(nullable = false, name = "card_details_id")
private CardDetails card;

@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(nullable = false, name = "shipping_address_id")
private Address shippingAddress;

@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(name = "billing_address_id")
private Address billingAddress;

//getters and setters
}

@Entity
@Table(name = "order_detail")
public class OrderDetail extends AbstractPersistable<Long> {

@Column(name = "quantity")
private Integer quantity;

@Column(name = "total_amount")
private BigDecimal totalAmount = BigDecimal.ZERO;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id", nullable = false)
@JsonBackReference
private Order order;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private Product product;

//getters and setters
}


When the user heads over to his Orders, he should be able to see information related only to the order itself (no details).
For that reason, I retrieve data only from the order table. Following is my repository:



public interface OrderRepository extends CrudRepository<Order, Long> {

@Query("FROM Order o WHERE o.user.email = ?1")
List<Order> findOrdersByUser(String email);
}


In the service, what I do is simply calling the above method and converting to a the dto counterpart.



@Transactional(readOnly = true)
public List<OrdersPreviewDTO> getOrdersPreview(String email) {
List<Order> orders = orderRepository.findOrdersByUser(email);
return orderConverter.convertToOrderPreviewDTOs(orders);
}


The converter uses an Jackson ObjectMapper object under the hood.



List<OrdersPreviewDTO> convertToOrderPreviewDTOs(List<Order> orders) {
return orders.stream()
.map(o -> objectMapper.convertValue(o, OrdersPreviewDTO.class))
.collect(toList());
}


The objectMapper is inject by Spring and defined in a configuration class:



@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
return objectMapper;
}


The OrdersPreviewDTO dto object contains just a subset of the Order entity, because as I already mentioned, in the Orders page I want to show only high level properties of the user's orders, and nothing related to their details.



@JsonIgnoreProperties(ignoreUnknown = true)
public class OrdersPreviewDTO {

private String orderNumber;

@JsonFormat(pattern = "dd/MM/yyyy HH:mm")
private LocalDateTime created;

private BigDecimal totalAmount;

@JsonCreator
public OrdersPreviewDTO(
@JsonProperty("orderNumber") String orderNumber,
@JsonProperty("created") LocalDateTime created,
@JsonProperty("totalAmount") BigDecimal totalAmount) {
this.orderNumber = orderNumber;
this.created = created;
this.totalAmount = totalAmount;
}

//getters and setters
}


Everything works fine, the order entity is converted automagically by Jackson into its dto counterpart.
The problem come out when looking at the query executed by Hibernate under the hood.
Hibernate unwrap the collection of order details for each order and execute a query to retrieve data from each child collection:



select carddetail0_.id as id1_2_0_, carddetail0_.brand as brand2_2_0_, carddetail0_.created as created3_2_0_, carddetail0_.exp_month as exp_mont4_2_0_, carddetail0_.exp_year as exp_year5_2_0_, carddetail0_.last4 as last6_2_0_ from card_details carddetail0_ where carddetail0_.id=?

select address0_.id as id1_1_0_, address0_.created as created2_1_0_, address0_.last_modified as last_mod3_1_0_, address0_.city as city4_1_0_, address0_.country as country5_1_0_, address0_.first_name as first_na6_1_0_, address0_.last_name as last_nam7_1_0_, address0_.postal_code as postal_c8_1_0_, address0_.state as state9_1_0_, address0_.street_address as street_10_1_0_, address0_.telephone as telepho11_1_0_ from address address0_ where address0_.id=?

select items0_.order_id as order_id4_4_0_, items0_.id as id1_4_0_, items0_.id as id1_4_1_, items0_.order_id as order_id4_4_1_, items0_.product_id as product_5_4_1_, items0_.quantity as quantity2_4_1_, items0_.total_amount as total_am3_4_1_ from order_detail items0_ where items0_.order_id=?


and tons of others more.



Whether I modify the code in the following way, Hibernate runs only the expected query on the Order table:



This line of code:



objectMapper.convertValue(o, OrdersPreviewDTO.class)


is replaced by the following dirty fix:



new OrdersPreviewDTO(o.getOrderNumber(), o.getCreated(), o.getTotalAmount())


Query run by Hibernate:



select order0_.id as id1_5_, order0_.billing_address_id as billing_6_5_, order0_.card_details_id as card_det7_5_, order0_.created_on as created_2_5_, order0_.one_address as one_addr3_5_, order0_.order_number as order_nu4_5_, order0_.shipping_address_id as shipping8_5_, order0_.total_amount as total_am5_5_, order0_.user_id as user_id9_5_
from orders order0_ cross join user user1_
where order0_.user_id=user1_.id and user1_.user_email=?


My question is. Is there a way to tell Jackson to map only the Dtos field so that it doesn't trigger lazy loading fetches through Hibernate for the non required fields?



Thank you










share|improve this question



























    2














    I am working on a Spring Boot 2.0 / Java 8 shopping cart online application. I use Hibernate as the ORM framework.
    I have two entities, Order and OrderDetail shown below:



    @Entity
    @Table(name = "orders")
    public class Order extends AbstractEntityUuid {

    @Column(name = "order_number", unique = true)
    private String orderNumber;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Column(name = "total_amount")
    private BigDecimal totalAmount = BigDecimal.ZERO;

    @CreatedDate
    @Column(name = "created_on", columnDefinition = "DATETIME", updatable = false)
    protected LocalDateTime created;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonManagedReference
    private Set<OrderDetail> items = new HashSet<>();

    @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinColumn(nullable = false, name = "card_details_id")
    private CardDetails card;

    @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinColumn(nullable = false, name = "shipping_address_id")
    private Address shippingAddress;

    @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinColumn(name = "billing_address_id")
    private Address billingAddress;

    //getters and setters
    }

    @Entity
    @Table(name = "order_detail")
    public class OrderDetail extends AbstractPersistable<Long> {

    @Column(name = "quantity")
    private Integer quantity;

    @Column(name = "total_amount")
    private BigDecimal totalAmount = BigDecimal.ZERO;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id", nullable = false)
    @JsonBackReference
    private Order order;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id", nullable = false)
    private Product product;

    //getters and setters
    }


    When the user heads over to his Orders, he should be able to see information related only to the order itself (no details).
    For that reason, I retrieve data only from the order table. Following is my repository:



    public interface OrderRepository extends CrudRepository<Order, Long> {

    @Query("FROM Order o WHERE o.user.email = ?1")
    List<Order> findOrdersByUser(String email);
    }


    In the service, what I do is simply calling the above method and converting to a the dto counterpart.



    @Transactional(readOnly = true)
    public List<OrdersPreviewDTO> getOrdersPreview(String email) {
    List<Order> orders = orderRepository.findOrdersByUser(email);
    return orderConverter.convertToOrderPreviewDTOs(orders);
    }


    The converter uses an Jackson ObjectMapper object under the hood.



    List<OrdersPreviewDTO> convertToOrderPreviewDTOs(List<Order> orders) {
    return orders.stream()
    .map(o -> objectMapper.convertValue(o, OrdersPreviewDTO.class))
    .collect(toList());
    }


    The objectMapper is inject by Spring and defined in a configuration class:



    @Bean
    public ObjectMapper objectMapper() {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.findAndRegisterModules();
    return objectMapper;
    }


    The OrdersPreviewDTO dto object contains just a subset of the Order entity, because as I already mentioned, in the Orders page I want to show only high level properties of the user's orders, and nothing related to their details.



    @JsonIgnoreProperties(ignoreUnknown = true)
    public class OrdersPreviewDTO {

    private String orderNumber;

    @JsonFormat(pattern = "dd/MM/yyyy HH:mm")
    private LocalDateTime created;

    private BigDecimal totalAmount;

    @JsonCreator
    public OrdersPreviewDTO(
    @JsonProperty("orderNumber") String orderNumber,
    @JsonProperty("created") LocalDateTime created,
    @JsonProperty("totalAmount") BigDecimal totalAmount) {
    this.orderNumber = orderNumber;
    this.created = created;
    this.totalAmount = totalAmount;
    }

    //getters and setters
    }


    Everything works fine, the order entity is converted automagically by Jackson into its dto counterpart.
    The problem come out when looking at the query executed by Hibernate under the hood.
    Hibernate unwrap the collection of order details for each order and execute a query to retrieve data from each child collection:



    select carddetail0_.id as id1_2_0_, carddetail0_.brand as brand2_2_0_, carddetail0_.created as created3_2_0_, carddetail0_.exp_month as exp_mont4_2_0_, carddetail0_.exp_year as exp_year5_2_0_, carddetail0_.last4 as last6_2_0_ from card_details carddetail0_ where carddetail0_.id=?

    select address0_.id as id1_1_0_, address0_.created as created2_1_0_, address0_.last_modified as last_mod3_1_0_, address0_.city as city4_1_0_, address0_.country as country5_1_0_, address0_.first_name as first_na6_1_0_, address0_.last_name as last_nam7_1_0_, address0_.postal_code as postal_c8_1_0_, address0_.state as state9_1_0_, address0_.street_address as street_10_1_0_, address0_.telephone as telepho11_1_0_ from address address0_ where address0_.id=?

    select items0_.order_id as order_id4_4_0_, items0_.id as id1_4_0_, items0_.id as id1_4_1_, items0_.order_id as order_id4_4_1_, items0_.product_id as product_5_4_1_, items0_.quantity as quantity2_4_1_, items0_.total_amount as total_am3_4_1_ from order_detail items0_ where items0_.order_id=?


    and tons of others more.



    Whether I modify the code in the following way, Hibernate runs only the expected query on the Order table:



    This line of code:



    objectMapper.convertValue(o, OrdersPreviewDTO.class)


    is replaced by the following dirty fix:



    new OrdersPreviewDTO(o.getOrderNumber(), o.getCreated(), o.getTotalAmount())


    Query run by Hibernate:



    select order0_.id as id1_5_, order0_.billing_address_id as billing_6_5_, order0_.card_details_id as card_det7_5_, order0_.created_on as created_2_5_, order0_.one_address as one_addr3_5_, order0_.order_number as order_nu4_5_, order0_.shipping_address_id as shipping8_5_, order0_.total_amount as total_am5_5_, order0_.user_id as user_id9_5_
    from orders order0_ cross join user user1_
    where order0_.user_id=user1_.id and user1_.user_email=?


    My question is. Is there a way to tell Jackson to map only the Dtos field so that it doesn't trigger lazy loading fetches through Hibernate for the non required fields?



    Thank you










    share|improve this question

























      2












      2








      2







      I am working on a Spring Boot 2.0 / Java 8 shopping cart online application. I use Hibernate as the ORM framework.
      I have two entities, Order and OrderDetail shown below:



      @Entity
      @Table(name = "orders")
      public class Order extends AbstractEntityUuid {

      @Column(name = "order_number", unique = true)
      private String orderNumber;

      @JsonBackReference
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "user_id", nullable = false)
      private User user;

      @Column(name = "total_amount")
      private BigDecimal totalAmount = BigDecimal.ZERO;

      @CreatedDate
      @Column(name = "created_on", columnDefinition = "DATETIME", updatable = false)
      protected LocalDateTime created;

      @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
      @JsonManagedReference
      private Set<OrderDetail> items = new HashSet<>();

      @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
      @JoinColumn(nullable = false, name = "card_details_id")
      private CardDetails card;

      @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
      @JoinColumn(nullable = false, name = "shipping_address_id")
      private Address shippingAddress;

      @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
      @JoinColumn(name = "billing_address_id")
      private Address billingAddress;

      //getters and setters
      }

      @Entity
      @Table(name = "order_detail")
      public class OrderDetail extends AbstractPersistable<Long> {

      @Column(name = "quantity")
      private Integer quantity;

      @Column(name = "total_amount")
      private BigDecimal totalAmount = BigDecimal.ZERO;

      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "order_id", nullable = false)
      @JsonBackReference
      private Order order;

      @OneToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "product_id", nullable = false)
      private Product product;

      //getters and setters
      }


      When the user heads over to his Orders, he should be able to see information related only to the order itself (no details).
      For that reason, I retrieve data only from the order table. Following is my repository:



      public interface OrderRepository extends CrudRepository<Order, Long> {

      @Query("FROM Order o WHERE o.user.email = ?1")
      List<Order> findOrdersByUser(String email);
      }


      In the service, what I do is simply calling the above method and converting to a the dto counterpart.



      @Transactional(readOnly = true)
      public List<OrdersPreviewDTO> getOrdersPreview(String email) {
      List<Order> orders = orderRepository.findOrdersByUser(email);
      return orderConverter.convertToOrderPreviewDTOs(orders);
      }


      The converter uses an Jackson ObjectMapper object under the hood.



      List<OrdersPreviewDTO> convertToOrderPreviewDTOs(List<Order> orders) {
      return orders.stream()
      .map(o -> objectMapper.convertValue(o, OrdersPreviewDTO.class))
      .collect(toList());
      }


      The objectMapper is inject by Spring and defined in a configuration class:



      @Bean
      public ObjectMapper objectMapper() {
      ObjectMapper objectMapper = new ObjectMapper();
      objectMapper.findAndRegisterModules();
      return objectMapper;
      }


      The OrdersPreviewDTO dto object contains just a subset of the Order entity, because as I already mentioned, in the Orders page I want to show only high level properties of the user's orders, and nothing related to their details.



      @JsonIgnoreProperties(ignoreUnknown = true)
      public class OrdersPreviewDTO {

      private String orderNumber;

      @JsonFormat(pattern = "dd/MM/yyyy HH:mm")
      private LocalDateTime created;

      private BigDecimal totalAmount;

      @JsonCreator
      public OrdersPreviewDTO(
      @JsonProperty("orderNumber") String orderNumber,
      @JsonProperty("created") LocalDateTime created,
      @JsonProperty("totalAmount") BigDecimal totalAmount) {
      this.orderNumber = orderNumber;
      this.created = created;
      this.totalAmount = totalAmount;
      }

      //getters and setters
      }


      Everything works fine, the order entity is converted automagically by Jackson into its dto counterpart.
      The problem come out when looking at the query executed by Hibernate under the hood.
      Hibernate unwrap the collection of order details for each order and execute a query to retrieve data from each child collection:



      select carddetail0_.id as id1_2_0_, carddetail0_.brand as brand2_2_0_, carddetail0_.created as created3_2_0_, carddetail0_.exp_month as exp_mont4_2_0_, carddetail0_.exp_year as exp_year5_2_0_, carddetail0_.last4 as last6_2_0_ from card_details carddetail0_ where carddetail0_.id=?

      select address0_.id as id1_1_0_, address0_.created as created2_1_0_, address0_.last_modified as last_mod3_1_0_, address0_.city as city4_1_0_, address0_.country as country5_1_0_, address0_.first_name as first_na6_1_0_, address0_.last_name as last_nam7_1_0_, address0_.postal_code as postal_c8_1_0_, address0_.state as state9_1_0_, address0_.street_address as street_10_1_0_, address0_.telephone as telepho11_1_0_ from address address0_ where address0_.id=?

      select items0_.order_id as order_id4_4_0_, items0_.id as id1_4_0_, items0_.id as id1_4_1_, items0_.order_id as order_id4_4_1_, items0_.product_id as product_5_4_1_, items0_.quantity as quantity2_4_1_, items0_.total_amount as total_am3_4_1_ from order_detail items0_ where items0_.order_id=?


      and tons of others more.



      Whether I modify the code in the following way, Hibernate runs only the expected query on the Order table:



      This line of code:



      objectMapper.convertValue(o, OrdersPreviewDTO.class)


      is replaced by the following dirty fix:



      new OrdersPreviewDTO(o.getOrderNumber(), o.getCreated(), o.getTotalAmount())


      Query run by Hibernate:



      select order0_.id as id1_5_, order0_.billing_address_id as billing_6_5_, order0_.card_details_id as card_det7_5_, order0_.created_on as created_2_5_, order0_.one_address as one_addr3_5_, order0_.order_number as order_nu4_5_, order0_.shipping_address_id as shipping8_5_, order0_.total_amount as total_am5_5_, order0_.user_id as user_id9_5_
      from orders order0_ cross join user user1_
      where order0_.user_id=user1_.id and user1_.user_email=?


      My question is. Is there a way to tell Jackson to map only the Dtos field so that it doesn't trigger lazy loading fetches through Hibernate for the non required fields?



      Thank you










      share|improve this question













      I am working on a Spring Boot 2.0 / Java 8 shopping cart online application. I use Hibernate as the ORM framework.
      I have two entities, Order and OrderDetail shown below:



      @Entity
      @Table(name = "orders")
      public class Order extends AbstractEntityUuid {

      @Column(name = "order_number", unique = true)
      private String orderNumber;

      @JsonBackReference
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "user_id", nullable = false)
      private User user;

      @Column(name = "total_amount")
      private BigDecimal totalAmount = BigDecimal.ZERO;

      @CreatedDate
      @Column(name = "created_on", columnDefinition = "DATETIME", updatable = false)
      protected LocalDateTime created;

      @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
      @JsonManagedReference
      private Set<OrderDetail> items = new HashSet<>();

      @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
      @JoinColumn(nullable = false, name = "card_details_id")
      private CardDetails card;

      @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
      @JoinColumn(nullable = false, name = "shipping_address_id")
      private Address shippingAddress;

      @OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
      @JoinColumn(name = "billing_address_id")
      private Address billingAddress;

      //getters and setters
      }

      @Entity
      @Table(name = "order_detail")
      public class OrderDetail extends AbstractPersistable<Long> {

      @Column(name = "quantity")
      private Integer quantity;

      @Column(name = "total_amount")
      private BigDecimal totalAmount = BigDecimal.ZERO;

      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "order_id", nullable = false)
      @JsonBackReference
      private Order order;

      @OneToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "product_id", nullable = false)
      private Product product;

      //getters and setters
      }


      When the user heads over to his Orders, he should be able to see information related only to the order itself (no details).
      For that reason, I retrieve data only from the order table. Following is my repository:



      public interface OrderRepository extends CrudRepository<Order, Long> {

      @Query("FROM Order o WHERE o.user.email = ?1")
      List<Order> findOrdersByUser(String email);
      }


      In the service, what I do is simply calling the above method and converting to a the dto counterpart.



      @Transactional(readOnly = true)
      public List<OrdersPreviewDTO> getOrdersPreview(String email) {
      List<Order> orders = orderRepository.findOrdersByUser(email);
      return orderConverter.convertToOrderPreviewDTOs(orders);
      }


      The converter uses an Jackson ObjectMapper object under the hood.



      List<OrdersPreviewDTO> convertToOrderPreviewDTOs(List<Order> orders) {
      return orders.stream()
      .map(o -> objectMapper.convertValue(o, OrdersPreviewDTO.class))
      .collect(toList());
      }


      The objectMapper is inject by Spring and defined in a configuration class:



      @Bean
      public ObjectMapper objectMapper() {
      ObjectMapper objectMapper = new ObjectMapper();
      objectMapper.findAndRegisterModules();
      return objectMapper;
      }


      The OrdersPreviewDTO dto object contains just a subset of the Order entity, because as I already mentioned, in the Orders page I want to show only high level properties of the user's orders, and nothing related to their details.



      @JsonIgnoreProperties(ignoreUnknown = true)
      public class OrdersPreviewDTO {

      private String orderNumber;

      @JsonFormat(pattern = "dd/MM/yyyy HH:mm")
      private LocalDateTime created;

      private BigDecimal totalAmount;

      @JsonCreator
      public OrdersPreviewDTO(
      @JsonProperty("orderNumber") String orderNumber,
      @JsonProperty("created") LocalDateTime created,
      @JsonProperty("totalAmount") BigDecimal totalAmount) {
      this.orderNumber = orderNumber;
      this.created = created;
      this.totalAmount = totalAmount;
      }

      //getters and setters
      }


      Everything works fine, the order entity is converted automagically by Jackson into its dto counterpart.
      The problem come out when looking at the query executed by Hibernate under the hood.
      Hibernate unwrap the collection of order details for each order and execute a query to retrieve data from each child collection:



      select carddetail0_.id as id1_2_0_, carddetail0_.brand as brand2_2_0_, carddetail0_.created as created3_2_0_, carddetail0_.exp_month as exp_mont4_2_0_, carddetail0_.exp_year as exp_year5_2_0_, carddetail0_.last4 as last6_2_0_ from card_details carddetail0_ where carddetail0_.id=?

      select address0_.id as id1_1_0_, address0_.created as created2_1_0_, address0_.last_modified as last_mod3_1_0_, address0_.city as city4_1_0_, address0_.country as country5_1_0_, address0_.first_name as first_na6_1_0_, address0_.last_name as last_nam7_1_0_, address0_.postal_code as postal_c8_1_0_, address0_.state as state9_1_0_, address0_.street_address as street_10_1_0_, address0_.telephone as telepho11_1_0_ from address address0_ where address0_.id=?

      select items0_.order_id as order_id4_4_0_, items0_.id as id1_4_0_, items0_.id as id1_4_1_, items0_.order_id as order_id4_4_1_, items0_.product_id as product_5_4_1_, items0_.quantity as quantity2_4_1_, items0_.total_amount as total_am3_4_1_ from order_detail items0_ where items0_.order_id=?


      and tons of others more.



      Whether I modify the code in the following way, Hibernate runs only the expected query on the Order table:



      This line of code:



      objectMapper.convertValue(o, OrdersPreviewDTO.class)


      is replaced by the following dirty fix:



      new OrdersPreviewDTO(o.getOrderNumber(), o.getCreated(), o.getTotalAmount())


      Query run by Hibernate:



      select order0_.id as id1_5_, order0_.billing_address_id as billing_6_5_, order0_.card_details_id as card_det7_5_, order0_.created_on as created_2_5_, order0_.one_address as one_addr3_5_, order0_.order_number as order_nu4_5_, order0_.shipping_address_id as shipping8_5_, order0_.total_amount as total_am5_5_, order0_.user_id as user_id9_5_
      from orders order0_ cross join user user1_
      where order0_.user_id=user1_.id and user1_.user_email=?


      My question is. Is there a way to tell Jackson to map only the Dtos field so that it doesn't trigger lazy loading fetches through Hibernate for the non required fields?



      Thank you







      java spring hibernate spring-boot jackson






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 13 '18 at 9:47









      ShaunylShaunyl

      182111




      182111
























          3 Answers
          3






          active

          oldest

          votes


















          2














          The short answer is no, don't try and be so clever, manually create your DTO to control any lazy loading, then use Jackson on the DTO outside the transaction.



          The Long answer is yes, you can override MappingJackson2HttpMessageConverter and control which fields get called from the entity.



          @Configuration
          public class MixInWebConfig extends WebMvcConfigurationSupport {

          @Bean
          public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter2() {
          MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
          ObjectMapper objectMapper = new ObjectMapper();
          objectMapper.addMixIn(DTO1.class, FooMixIn.class);
          objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
          jsonConverter.setObjectMapper(objectMapper);
          return jsonConverter;
          }

          @Override
          public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
          converters.add(customJackson2HttpMessageConverter2());
          }
          }


          Then



              @Override
          protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
          super.processViews(config, builder);
          if (classes.contains(builder.getBeanDescription().getBeanClass())) {
          List<BeanPropertyWriter> originalWriters = builder.getProperties();
          List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();
          for (BeanPropertyWriter writer : originalWriters) {
          String propName = writer.getName();
          if (!fieldsToIgnore.contains(propName)) {
          writers.add(writer);
          }
          }
          builder.setProperties(writers);
          }
          }
          }


          here is a working example.






          share|improve this answer





























            1














            +1 for Essex Boy answer. I just want to add that you can directly return DTO from your JPQL Queries instead of using Jackson. It avoids a transformation from the database to your object Order and then another transformation from Order object to OrdersPreviewDTO object.



            For example, you need to change your query in your repository to do it. It would be something like :



            public interface OrderRepository extends CrudRepository<Order, Long> {

            @Query("SELECT new OrdersPreviewDTO(o.order_number, o.created_on, o.total_amount)) FROM Order o WHERE o.user.email = ?1")
            List<OrdersPreviewDTO> findOrdersByUser(String email);
            }





            share|improve this answer





























              1














              If OrdersPreviewDTO is strictly a subset of your Order class, why not simply use the @JsonView annotation to automatically create a simple view in your controller? See https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring for example.



              In case you need a DTO for both input and output, also consider using http://mapstruct.org/






              share|improve this answer





















                Your Answer






                StackExchange.ifUsing("editor", function () {
                StackExchange.using("externalEditor", function () {
                StackExchange.using("snippets", function () {
                StackExchange.snippets.init();
                });
                });
                }, "code-snippets");

                StackExchange.ready(function() {
                var channelOptions = {
                tags: "".split(" "),
                id: "1"
                };
                initTagRenderer("".split(" "), "".split(" "), channelOptions);

                StackExchange.using("externalEditor", function() {
                // Have to fire editor after snippets, if snippets enabled
                if (StackExchange.settings.snippets.snippetsEnabled) {
                StackExchange.using("snippets", function() {
                createEditor();
                });
                }
                else {
                createEditor();
                }
                });

                function createEditor() {
                StackExchange.prepareEditor({
                heartbeatType: 'answer',
                autoActivateHeartbeat: false,
                convertImagesToLinks: true,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: 10,
                bindNavPrevention: true,
                postfix: "",
                imageUploader: {
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                },
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                });


                }
                });














                draft saved

                draft discarded


















                StackExchange.ready(
                function () {
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53278128%2fjackson-objectmapper-hibernate-issue%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                3 Answers
                3






                active

                oldest

                votes








                3 Answers
                3






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes









                2














                The short answer is no, don't try and be so clever, manually create your DTO to control any lazy loading, then use Jackson on the DTO outside the transaction.



                The Long answer is yes, you can override MappingJackson2HttpMessageConverter and control which fields get called from the entity.



                @Configuration
                public class MixInWebConfig extends WebMvcConfigurationSupport {

                @Bean
                public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter2() {
                MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
                ObjectMapper objectMapper = new ObjectMapper();
                objectMapper.addMixIn(DTO1.class, FooMixIn.class);
                objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                jsonConverter.setObjectMapper(objectMapper);
                return jsonConverter;
                }

                @Override
                public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                converters.add(customJackson2HttpMessageConverter2());
                }
                }


                Then



                    @Override
                protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
                super.processViews(config, builder);
                if (classes.contains(builder.getBeanDescription().getBeanClass())) {
                List<BeanPropertyWriter> originalWriters = builder.getProperties();
                List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();
                for (BeanPropertyWriter writer : originalWriters) {
                String propName = writer.getName();
                if (!fieldsToIgnore.contains(propName)) {
                writers.add(writer);
                }
                }
                builder.setProperties(writers);
                }
                }
                }


                here is a working example.






                share|improve this answer


























                  2














                  The short answer is no, don't try and be so clever, manually create your DTO to control any lazy loading, then use Jackson on the DTO outside the transaction.



                  The Long answer is yes, you can override MappingJackson2HttpMessageConverter and control which fields get called from the entity.



                  @Configuration
                  public class MixInWebConfig extends WebMvcConfigurationSupport {

                  @Bean
                  public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter2() {
                  MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
                  ObjectMapper objectMapper = new ObjectMapper();
                  objectMapper.addMixIn(DTO1.class, FooMixIn.class);
                  objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                  jsonConverter.setObjectMapper(objectMapper);
                  return jsonConverter;
                  }

                  @Override
                  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                  converters.add(customJackson2HttpMessageConverter2());
                  }
                  }


                  Then



                      @Override
                  protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
                  super.processViews(config, builder);
                  if (classes.contains(builder.getBeanDescription().getBeanClass())) {
                  List<BeanPropertyWriter> originalWriters = builder.getProperties();
                  List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();
                  for (BeanPropertyWriter writer : originalWriters) {
                  String propName = writer.getName();
                  if (!fieldsToIgnore.contains(propName)) {
                  writers.add(writer);
                  }
                  }
                  builder.setProperties(writers);
                  }
                  }
                  }


                  here is a working example.






                  share|improve this answer
























                    2












                    2








                    2






                    The short answer is no, don't try and be so clever, manually create your DTO to control any lazy loading, then use Jackson on the DTO outside the transaction.



                    The Long answer is yes, you can override MappingJackson2HttpMessageConverter and control which fields get called from the entity.



                    @Configuration
                    public class MixInWebConfig extends WebMvcConfigurationSupport {

                    @Bean
                    public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter2() {
                    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.addMixIn(DTO1.class, FooMixIn.class);
                    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                    jsonConverter.setObjectMapper(objectMapper);
                    return jsonConverter;
                    }

                    @Override
                    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                    converters.add(customJackson2HttpMessageConverter2());
                    }
                    }


                    Then



                        @Override
                    protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
                    super.processViews(config, builder);
                    if (classes.contains(builder.getBeanDescription().getBeanClass())) {
                    List<BeanPropertyWriter> originalWriters = builder.getProperties();
                    List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();
                    for (BeanPropertyWriter writer : originalWriters) {
                    String propName = writer.getName();
                    if (!fieldsToIgnore.contains(propName)) {
                    writers.add(writer);
                    }
                    }
                    builder.setProperties(writers);
                    }
                    }
                    }


                    here is a working example.






                    share|improve this answer












                    The short answer is no, don't try and be so clever, manually create your DTO to control any lazy loading, then use Jackson on the DTO outside the transaction.



                    The Long answer is yes, you can override MappingJackson2HttpMessageConverter and control which fields get called from the entity.



                    @Configuration
                    public class MixInWebConfig extends WebMvcConfigurationSupport {

                    @Bean
                    public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter2() {
                    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.addMixIn(DTO1.class, FooMixIn.class);
                    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                    jsonConverter.setObjectMapper(objectMapper);
                    return jsonConverter;
                    }

                    @Override
                    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                    converters.add(customJackson2HttpMessageConverter2());
                    }
                    }


                    Then



                        @Override
                    protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
                    super.processViews(config, builder);
                    if (classes.contains(builder.getBeanDescription().getBeanClass())) {
                    List<BeanPropertyWriter> originalWriters = builder.getProperties();
                    List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();
                    for (BeanPropertyWriter writer : originalWriters) {
                    String propName = writer.getName();
                    if (!fieldsToIgnore.contains(propName)) {
                    writers.add(writer);
                    }
                    }
                    builder.setProperties(writers);
                    }
                    }
                    }


                    here is a working example.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 13 '18 at 10:31









                    Essex BoyEssex Boy

                    4,4481815




                    4,4481815

























                        1














                        +1 for Essex Boy answer. I just want to add that you can directly return DTO from your JPQL Queries instead of using Jackson. It avoids a transformation from the database to your object Order and then another transformation from Order object to OrdersPreviewDTO object.



                        For example, you need to change your query in your repository to do it. It would be something like :



                        public interface OrderRepository extends CrudRepository<Order, Long> {

                        @Query("SELECT new OrdersPreviewDTO(o.order_number, o.created_on, o.total_amount)) FROM Order o WHERE o.user.email = ?1")
                        List<OrdersPreviewDTO> findOrdersByUser(String email);
                        }





                        share|improve this answer


























                          1














                          +1 for Essex Boy answer. I just want to add that you can directly return DTO from your JPQL Queries instead of using Jackson. It avoids a transformation from the database to your object Order and then another transformation from Order object to OrdersPreviewDTO object.



                          For example, you need to change your query in your repository to do it. It would be something like :



                          public interface OrderRepository extends CrudRepository<Order, Long> {

                          @Query("SELECT new OrdersPreviewDTO(o.order_number, o.created_on, o.total_amount)) FROM Order o WHERE o.user.email = ?1")
                          List<OrdersPreviewDTO> findOrdersByUser(String email);
                          }





                          share|improve this answer
























                            1












                            1








                            1






                            +1 for Essex Boy answer. I just want to add that you can directly return DTO from your JPQL Queries instead of using Jackson. It avoids a transformation from the database to your object Order and then another transformation from Order object to OrdersPreviewDTO object.



                            For example, you need to change your query in your repository to do it. It would be something like :



                            public interface OrderRepository extends CrudRepository<Order, Long> {

                            @Query("SELECT new OrdersPreviewDTO(o.order_number, o.created_on, o.total_amount)) FROM Order o WHERE o.user.email = ?1")
                            List<OrdersPreviewDTO> findOrdersByUser(String email);
                            }





                            share|improve this answer












                            +1 for Essex Boy answer. I just want to add that you can directly return DTO from your JPQL Queries instead of using Jackson. It avoids a transformation from the database to your object Order and then another transformation from Order object to OrdersPreviewDTO object.



                            For example, you need to change your query in your repository to do it. It would be something like :



                            public interface OrderRepository extends CrudRepository<Order, Long> {

                            @Query("SELECT new OrdersPreviewDTO(o.order_number, o.created_on, o.total_amount)) FROM Order o WHERE o.user.email = ?1")
                            List<OrdersPreviewDTO> findOrdersByUser(String email);
                            }






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Nov 13 '18 at 11:11









                            victor galletvictor gallet

                            1,114716




                            1,114716























                                1














                                If OrdersPreviewDTO is strictly a subset of your Order class, why not simply use the @JsonView annotation to automatically create a simple view in your controller? See https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring for example.



                                In case you need a DTO for both input and output, also consider using http://mapstruct.org/






                                share|improve this answer


























                                  1














                                  If OrdersPreviewDTO is strictly a subset of your Order class, why not simply use the @JsonView annotation to automatically create a simple view in your controller? See https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring for example.



                                  In case you need a DTO for both input and output, also consider using http://mapstruct.org/






                                  share|improve this answer
























                                    1












                                    1








                                    1






                                    If OrdersPreviewDTO is strictly a subset of your Order class, why not simply use the @JsonView annotation to automatically create a simple view in your controller? See https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring for example.



                                    In case you need a DTO for both input and output, also consider using http://mapstruct.org/






                                    share|improve this answer












                                    If OrdersPreviewDTO is strictly a subset of your Order class, why not simply use the @JsonView annotation to automatically create a simple view in your controller? See https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring for example.



                                    In case you need a DTO for both input and output, also consider using http://mapstruct.org/







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered Nov 13 '18 at 12:18









                                    mindexmindex

                                    1,279616




                                    1,279616






























                                        draft saved

                                        draft discarded




















































                                        Thanks for contributing an answer to Stack Overflow!


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        To learn more, see our tips on writing great answers.





                                        Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                        Please pay close attention to the following guidance:


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        To learn more, see our tips on writing great answers.




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function () {
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53278128%2fjackson-objectmapper-hibernate-issue%23new-answer', 'question_page');
                                        }
                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        Xamarin.iOS Cant Deploy on Iphone

                                        Glorious Revolution

                                        Dulmage-Mendelsohn matrix decomposition in Python