如何在不将其作为方法参数传递的情况下,为POJO类提供转换器服务

huangapple go评论71阅读模式
英文:

How to provide converter service to POJO class without passing it as method argument

问题

我有一个名为ShoppingList的服务,负责生成购物清单,还有一个名为IngredientConverter的服务,它是一个用于转换对象的辅助工具。我的当前实现如下所示:

@Service
@AllArgsConstructor
public class ShoppingListService {

    private final RecipeService recipeService;
    private final IngredientConverter ingredientConverter;

    public ShoppingList generateShoppingList(List<UUID> uuidsOfRecipes) {
        List<Recipe> recipes = recipeService.getAllByIDIn(uuidsOfRecipes);
        ShoppingList shoppingList = ShoppingList.empty();

        for (Recipe recipe : recipes) {
            shoppingList.addIngredients(recipe.getIngredients());
        }
        shoppingList.finishAddition(ingredientConverter);

        return shoppingList;
    }

}
@RequiredArgsConstructor
public class ShoppingList {

    @Getter
    private final List<IngredientQuantity> optimizedList;
    private final Map<Ingredient, Integer> ingredientAmountMap;

    public static ShoppingList empty() {
        return new ShoppingList(new ArrayList<>(), new HashMap<>());
    }

    public void addIngredients(List<IngredientQuantity> ingredients) { ... }

    public void addIngredient(IngredientQuantity ingredientQuantity) { ... }

    public void finishAddition(IngredientConverter ingredientConverter) {
        for (Ingredient ingredient : ingredientAmountMap.keySet()) {
            IngredientQuantity ingredientQuantity = ingredientConverter.convertWithAmount(
                    ingredient.getName(),
                    ingredientAmountMap.get(ingredient),
                    ingredient.getUnit());

            optimizedList.add(ingredientQuantity);
        }
    }
}
@Service 
public class IngredientConverter {

    public IngredientQuantity convertWithAmount(String name, int amount, Unit unit) { ... }
}

关于如何更好地为这个类提供IngredientConverter服务,是否有更好的策略?是否可以通过某种方式自动装配它,尽管ShoppingList是一个POJO类?或者ShoppingList是否应该标记为组件(Component)?不太确定什么是最佳方法。

英文:

I have ShoppingList service which is responsible for generating shopping list and a IngredientConverter service which is a helping tool for converting objects. My current implementation looks like this

@Service
@AllArgsConstructor
public class ShoppingListService {

    private final RecipeService recipeService;
    private final IngredientConverter ingredientConverter;

    public ShoppingList generateShoppingList(List&lt;UUID&gt; uuidsOfRecipes) {
        List&lt;Recipe&gt; recipes = recipeService.getAllByIDIn(uuidsOfRecipes);
        ShoppingList shoppingList = ShoppingList.empty();

        for (Recipe recipe : recipes) {
            shoppingList.addIngredients(recipe.getIngredients());
        }
        shoppingList.finishAddition(ingredientConverter);

        return shoppingList;
    }

}
@RequiredArgsConstructor
public class ShoppingList {

    @Getter
    private final List&lt;IngredientQuantity&gt; optimizedList;
    private final Map&lt;Ingredient, Integer&gt; ingredientAmountMap;

    public static ShoppingList empty() {
        return new ShoppingList(new ArrayList&lt;&gt;(), new HashMap&lt;&gt;());
    }

    public void addIngredients(List&lt;IngredientQuantity&gt; ingredients) { ... }

    public void addIngredient(IngredientQuantity ingredientQuantity) { ... }

    public void finishAddition(IngredientConverter ingredientConverter) {
        for (Ingredient ingredient : ingredientAmountMap.keySet()) {
            IngredientQuantity ingredientQuantity = ingredientConverter.convertWithAmount(
                    ingredient.getName(),
                    ingredientAmountMap.get(ingredient),
                    ingredient.getUnit());

            optimizedList.add(ingredientQuantity);
        }
    }
}
@Service 
public class IngredientConverter {

    public IngredientQuantity convertWithAmount(String name, int amount, Unit unit) { ... }
}

Is there a better strategy for providing IngredientConverter service to this class? Could I Autowire it somehow despite ShoppingList being POJO class? Should ShoppingList be marked as Component maybe? Not sure what is the best approach.

答案1

得分: 0

你不能将服务类自动装配到POJO中。自动装配只能在Spring管理的类内部进行。我可以看出ShoppingList不是一个由Spring管理的类。添加@Component也不是理想的解决方案。据我所知,在这里最好的解决方案是使用MapStruct。MapStruct可以用来在实体和POJO之间映射字段。对于需要单独计算任何字段的情况,你可以编写自定义逻辑并进行自动装配。以下是步骤:

  1. pom.xml中添加MapStruct库。
  2. 在项目中添加下面的映射器类。componentModel="spring"告诉系统这个映射器由Spring管理。
  3. 所有字段名相同的字段将会自动映射。
  4. 对于需要转换的字段,你可以编写@BeforeMapping方法。
@Mapper(componentModel="spring")
public abstract class ShoppingListMapper 
{
    @Autowired
    IngredientConverter ingredientConverter; //autowire method you use.
    
    public abstract ShoppingListDTO shoppingListToShoppingListDTO(ShoppingList shoppingList) throws Exception;
    public abstract List<ShoppingListDTO> mapShoppingListsToDTOs(List<ShoppingList> shoppingLists) throws Exception;
    
    @BeforeMapping
    public void convertLogic(ShoppingList la, @MappingTarget ShoppingListDTO slDto) throws Exception 
    {
        //your logic to set required shoppinglist field using converter
    }
    
}

如果这个示例不清楚,你可以在网络上查找各种MapStruct示例。如果需要进一步帮助,请告诉我。

英文:

You cannot autowire service class into POJO. Autowire can be done only within spring managed classes. I can see that ShoppingList is not a spring managed class. Adding @Component will also not be ideal solution. AFAIK, The best solution to use here would be mapStruct. mapStruct can be used to map fields between entity and POJO. And in cases where any field has to be calculated separately, you can write your custom logic and autowire services. Below are steps

  1. Add mapStruct library to pom.xml
  2. Add below mapper class to your project. componentModel="spring" tells the system that this mapper is managed by spring.
  3. All the fields that have same name will be automapped.
  4. For fields which require conversions, you can write @BeforeMapping
Mapper(componentModel=&quot;spring&quot;)
public abstract class ShoppingListMapper 
{
	@Autowired
	IngredientConverter ingredientConverter; //autowire method you use.
	
	public abstract shoppingListToShoppingListDTO(ShoppingList shoppingList) throws Exception;
	public abstract List&lt;ShoppingList&gt; mapShoppingListsToDTOs(List&lt;ShoppingList&gt; shoppingLists) throws Exception;
	
	@BeforeMapping
    public void convertLogic(ShoppingList la, @MappingTarget ShoppingListDTO slDto) throws Exception 
	{
		//your logic to set required shoppinglist field using converter
    }
	
}

If this example is not clear, you can refer to web for various mapstruct examples. Let me know if you need further help

huangapple
  • 本文由 发表于 2020年9月26日 19:41:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/64077257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定