0
\$\begingroup\$

This is the code for adding addon product to carts. Suppose the cart has a cake so a candle would be an addon. I see this addonCart.getItems().stream().findFirst().get() repeated and want to use this once among other usages.

Also how do I remove this declaration of exception: catch (UnsupportedOperationException e)

Adding addon products to cart

public String addAddonToCart(final Cart addonCart) {
        log.info("Start : addAddonToCart method started");
        final var cart = this.cartRepository.findById(addonCart.getId()).map(e -> e).orElseThrow(() -> {
            throw new ResourceNotFoundException(new ErrorInfo(ErrorConstants.CART_NOT_FOUND));
        });
        final var items = cart.getItems().stream().map(item -> {
            if (item.getItemId().equals(addonCart.getItems().stream().findFirst().get().getItemId())) {
                if (Objects.isNull(item.getAddOns())) {
                    item.setAddOns(addonCart.getItems().stream().findFirst().get().getAddOns());
                } else {
                    try {
                        item.getAddOns().addAll(addonCart.getItems().stream().findFirst().get().getAddOns());
                    } catch (UnsupportedOperationException e) {
                    }
                }
            }
            return item;
        }).collect(Collectors.toList());

        cart.setItems(items);
        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
        return Constants.CART_ADDON_ADDED_SUCCESSFULLY;
    }



Delete item from cart

/**
     * Delete product from cart.
     *
     * @param itemId the item id
     * @return the string
     */
    public String deleteProductFromCart(final String itemId) {
        log.info("Start : deleteProductFromCart method started");
        final var cart = this.cartRepository.findByItemsItemId(itemId);
        if (cart.isPresent()) {
            final var itemList = cart.get().getItems().stream().filter(item -> {
                return !item.getItemId().equals(itemId);
            }).collect(Collectors.toList());
            cart.get().setItems(itemList);
            this.cartRepository.save(cart.get());
        } else {
            log.info("End : deleteProductFromCart method ended");
            throw new ResourceNotFoundException(new ErrorInfo(ErrorConstants.PRODUCT_NOT_FOUND));
        }
        log.info("End : deleteProductFromCart method ended");
        return Constants.CART_ITEM_DELETE_SUCCESSFULLY;
    }

Delete addon from cart

public String deleteAddonFromCart(Cart addonCart) {
        log.info("Start : deleteAddonFromCart method started");
        final var itemId = addonCart.getItems().stream().findFirst().get().getItemId();
        final var addonId = addonCart.getItems().stream().findFirst().get().getAddOns().stream().findFirst().get()
                .getProductId();
        final var cart = this.cartRepository.findByItemsItemId(itemId).map(e -> e).orElseThrow(() -> {
            throw new ResourceNotFoundException(new ErrorInfo(ErrorConstants.CART_NOT_FOUND));
        });
        final var items = cart.getItems().stream().filter(item -> item.getItemId().equals(itemId)).map(item -> {
            try {
                item.getAddOns().removeIf(addon -> addon.getProductId().equals(addonId));
            } catch (UnsupportedOperationException e) {
            }
            return item;
        }).collect(Collectors.toList());
        try {
            cart.getItems().removeIf(item -> item.getItemId().equals(itemId));
            cart.getItems().addAll(items);
        } catch (UnsupportedOperationException e) {
        }
        this.cartRepository.save(cart);
        log.info("Start : deleteAddonFromCart method ended");
        return Constants.CART_ADDON_DELETED_SUCCESSFULLY;
    }

Cart Entity

@NoArgsConstructor
@Document("cart")
@JsonInclude(JsonInclude.Include.NON_NULL)
@EqualsAndHashCode(callSuper = true)
public class Cart extends BaseEntity implements Serializable {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;

    /** The id. */
    @NotNull(message = "cartId can not be null", groups = { CartViews.AddonAddView.class })
    @NotBlank(message = "cartId can not be blank", groups = { CartViews.AddonAddView.class })
    @Id
    @JsonView({ CartViews.AddonAddView.class })
    private String id;

    /** The domain id. */
    private String domainId;

    /** The checkout id. */
    private String checkoutId;

    /** The user IP. */
    private String userIP;

    /** The agents. */
    @JsonProperty("agents")
    private List<Agent> agents;

    /** The customer party id. */
    // @JsonView({ CartViews.AddItemDetailsView.class })
    private String customerPartyId;

    /** The guuid. */
    // @JsonView({ CartViews.AddItemDetailsView.class })
    private String guuid;

    /** The sender. */
    @JsonProperty("sender")
    private Sender sender;

    /** The channel id. */
    @NotNull(message = "channelId can not be null", groups = { CartViews.AddItemDetailsView.class })
    @NotBlank(message = "channelId can not be blank", groups = { CartViews.AddItemDetailsView.class })
    @JsonView({ CartViews.AddItemDetailsView.class })
    private String channelId;

    /** The action. */
    private String action;

    /** The reason id. */
    private String reasonId;

    /** The sub reason id. */
    private String subReasonId;

    /** The comments. */
    private String comments;

    /** The cart total. */
    private Float cartTotal;

    /** The tax included in cart total. */
    private Float taxIncludedInCartTotal;

    /** The tax on cart total. */
    private Float taxOnCartTotal;

    /** The adjustment. */
    @JsonProperty("adjustment")
    private List<Adjustment> adjustment;

    /** The status. */
    private String status;

    /** The items. */
    @Valid
    @NotNull(message = "items can not be null", groups = { CartViews.AddItemDetailsView.class,
            CartViews.AddonDeleteView.class, CartViews.AddonAddView.class })
    @JsonProperty("items")
    @JsonView({ CartViews.AddItemDetailsView.class, CartViews.AddonDeleteView.class, CartViews.AddonAddView.class })
    private List<Item> items;

}

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Please edit your question so that the title describes the purpose of the code, rather than its mechanism. We really need to understand the motivational context to give good reviews. Thanks! \$\endgroup\$ Jan 5, 2022 at 14:46
  • \$\begingroup\$ Please include the documented interface for Cart. \$\endgroup\$
    – greybeard
    Jan 6, 2022 at 7:42
  • \$\begingroup\$ Added Cart entity \$\endgroup\$
    – diaop
    Jan 6, 2022 at 10:49
  • 1
    \$\begingroup\$ does your code work as you intended? \$\endgroup\$
    – Blaž Mrak
    Jan 6, 2022 at 12:02

1 Answer 1

2
\$\begingroup\$

Initial impressions:

public String addAddonToCart(final Cart addonCart) {
        log.info("Start : addAddonToCart method started");
        final var cart = this.cartRepository.findById(addonCart.getId())
                .map(e -> e) // why
                .orElseThrow(() -> {
                        throw new ResourceNotFoundException(new ErrorInfo(ErrorConstants.CART_NOT_FOUND)); // this can be extracted
                });

        final var items = cart.getItems().stream()
                 // map is not appropriate for what you are doing
                .map(item -> {
                        // holy sausage conditionals
                        if (item.getItemId().equals(addonCart.getItems().stream().findFirst().get().getItemId())) {
                                if (Objects.isNull(item.getAddOns())) {
                    item.setAddOns(addonCart.getItems().stream().findFirst().get().getAddOns());
                                } else {
                                        try {
                        item.getAddOns().addAll(addonCart.getItems().stream().findFirst().get().getAddOns());
                                        } catch (UnsupportedOperationException e) {
                                }
                        }
                }
            return item;
        }).collect(Collectors.toList());

        cart.setItems(items);
        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
        return Constants.CART_ADDON_ADDED_SUCCESSFULLY; // Why are you returning statuses? This method should be a void.
    }

Most of the refactoring is done by avoiding streams and using meaningful variables instead:

    public void addAddonToCart(final Cart addonCart) {
        log.info("Start : addAddonToCart method started");
        final var cart = this.cartRepository.findById(addonCart.getId())
            .orElseThrow(CartNotFound::new);

        for(var item : cart.getItems()) {
            if (item.getItemId().equals(addonCart.getItems().get(0).getItemId())) {
                if (Objects.isNull(item.getAddOns())) {
                    item.setAddOns(addonCart.getItems().get(0).getAddOns());
                } else {
                    item.getAddOns()
                         .addAll(addonCart.getItems().get(0).getAddOns());
                }
            }
        }

        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
    }

    private static class CartNotFound extends ResourceNotFoundException {
        public CartNotFound() {
            super(new ErrorInfo(ErrorConstants.CART_NOT_FOUND))
        }
    }

But this whole method definition is "wrong" and is making you jump through the hoops. You are adding addons to the cart meaning this:

    public void addAddonToCart(final cartId, final itemId, final List<Addon> addons) {
        log.info("Start : addAddonToCart method started");
        final var cart = this.cartRepository.findById(cartId)
            .orElseThrow(CartNotFound::new);

        for(var item : cart.getItems()) {
            if (item.getItemId().equals(itemId)) {
                if (Objects.isNull(item.getAddOns())) {
                    item.setAddOns(addons);
                } else {
                    item.getAddOns().addAll(addons);
                }
            }
        }

        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
    }

You can make the code even cleaner by having item addons set from the beginning.

    public void addAddonToCart(final cartId, final itemId, final List<Addon> addons) {
        log.info("Start : addAddonToCart method started");
        final var cart = this.cartRepository.findById(cartId)
            .orElseThrow(CartNotFound::new); // why are you searching for a cart here?

        for(var item : cart.getItems()) {
            if (item.getItemId().equals(itemId)) {
                item.getAddOns().addAll(addons); // now, this is stinky
                break;
            }
        }

        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
    }

addAddOns should be a method on the item. Finding the correct cart should also be separate.

    public Cart findById(String cartId) {
        return this.cartRepository.findById(cartId)
           .orElseThrow(CartNotFound::new);
    }

    public void addAddonToItem(final String cartId, final String itemId, final List<Addon> addons) {
        log.info("Start : addAddonToCart method started");
        final var cart = findById(cartId);

        for(var item : cart.getItems()) {
            if (item.getItemId().equals(itemId)) {
                item.addAddOns(addons);
                break;
            }
        }

        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
    }

Same thing happens in the delete method:

public Cart findByItemId(String itemId) {
    return this.cartRepository.findByItemId(itemId)
        .orElseThrow(CartNotFound::new);
}

    public void deleteAddonFromCart(final String itemId, String addonId){
        log.info("Start : deleteAddonFromCart method started");
        final var cart = findByItemId(itemId);

        final Optional<Item> item = cart.getItem(itemId);
        
        item.ifPresent(item -> item.removeAddon(addonId));

        this.cartRepository.save(cart);
        log.info("Start : deleteAddonFromCart method ended");
    }

...

in cart entity
class Cart ... {
    ...
    public Optional<Item> getItem(String itemId) {
        return this.items.stream()
            .filter(item -> item.getItemId().equals(itemId)
            .findAny();
    }
}

...

in item entity
class Item {
    ...
    public void removeAddon(String addonId) {
         this.addons.removeIf(addon -> addon.getProductId().equals(addonId));
    }
}

You can even introduce some more errors if you want:

    public void deleteAddonFromCart(final String itemId, String addonId){
        log.info("Start : deleteAddonFromCart method started");
        final var cart = findByItemId(itemId);

        cart.getItem(itemId)
            .orElseThrow(ItemNotFound::new)
            .removeAddon(addonId);

        this.cartRepository.save(cart);
        log.info("Start : deleteAddonFromCart method ended");
    }

With additional methods we can even refactor the addon addition:


    public void addAddonToItem(final String cartId, final String itemId, final List<Addon> addons) {
        log.info("Start : addAddonToCart method started");
        final var cart = findById(cartId);

        cart.getItem(itemId)
            // .orElseThrow(ItemNotFound::new)
            // .addAddOns(addons)
            .ifPresent(item -> item.addAddOns(addons));

        this.cartRepository.save(cart);
        log.info("End : addAddonToCart method ended");
    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.