简体   繁体   中英

spring entity to DTO with compute getter

Trying to understand the best practice here, i have an entity and i add some login to the getPrice property:

public class Order{
 
    private Integer price;
    private Integer addOn;

    public Integer setAddOn(Integer addOn){
       this.addOn=addOn;
    }
    public Integer getAddOn(){
       return addOn;
    }
    public Integer setPrice(Integer price){
       this.price=price;
    }
    // standard getters and setters
    public Integer getPrice(){
      if(addOn==null){
       return price;
      }
      else{
        return addOn+price;
      }
    }
}


and a DTO

public class OrderDTO{
 
    private Integer price;
    private Integer addOn;

    // getters and setters
}

the issue is that when I am mapping the order to orderDTO the price in the DTO is changing since the entity price getter is calculating.

    OrderDTO orderDTO= modelMapper.map(order, OrderDTO.class);

what's the best approach here? thanks

Currently, MapStruct only supports mapping from public fields/properties. See contributor comment and issue .
Solution 1: using MapStruct, create a separate getter for the problematic field
Objects:

public class Order {

    private Integer price;
    private Integer addOn;
    

    public void setAddOn(Integer addOn){
        this.addOn=addOn;
    }

    public Integer getAddOn(){
        return addOn;
    }

    public void setPrice(Integer price){
        this.price=price;
    }

    public Integer getFullPrice() {
        if (addOn == null) {
            return getPrice();
        } else {
            return addOn + getPrice();
        }
    }

    public Integer getPrice() {
        return price;
    }
}

public class OrderDTO {

    private Integer price;
    private Integer addOn;

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Integer getAddOn() {
        return addOn;
    }

    public void setAddOn(Integer addOn) {
        this.addOn = addOn;
    }
}

Mapper:

@Mapper
public interface OrderMapper {
    OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);

    OrderDTO map(Order order);
}

Generated code:

public class OrderMapperImpl implements OrderMapper {

    @Override
    public OrderDTO map(Order order) {
        if ( order == null ) {
            return null;
        }

        OrderDTO orderDTO = new OrderDTO();

        orderDTO.setPrice( order.getPrice() );
        orderDTO.setAddOn( order.getAddOn() );

        return orderDTO;
    }
}

Example of using:

    @Test
    public void mapperMapStructTest() {

        Integer price = 100;
        Integer addOn = 10;
        Order order = new Order();
        order.setAddOn(addOn);
        order.setPrice(price);
        OrderDTO orderDTO = OrderMapper.INSTANCE.map(order);

        Assert.assertEquals(orderDTO.getPrice(), price);
        Assert.assertEquals(orderDTO.getAddOn(), addOn);
    }


Solution 2: using Jackson , do not change structure of object
Unlike MapStruct, Jackson can access private fields thru reflection. The main advantage of that solution is that you do not need to add an additional getter for accessing the problematic field.

public class TestClass {
    @Test
    public void mapperTest() {
        ObjectMapper objectMapper = new ObjectMapper();
        //configuring Jackson ObjectMapper to access private fields
        objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
        objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

        Integer price = 100;
        Integer addOn = 10;
        Order order = new Order();
        order.setAddOn(addOn);
        order.setPrice(price);
        OrderDTO orderDTO = objectMapper.convertValue(order, OrderDTO.class);

        Assert.assertEquals(orderDTO.getPrice(), price);
        Assert.assertEquals(orderDTO.getAddOn(), addOn);
    }
}

Summary: I think the first solution is preferable. It is simple and has better performance than the second solution because for conversion Jackson will use reflection to access private fields and use intermediate JSON object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM