英文:
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<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) { ... }
}
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之间映射字段。对于需要单独计算任何字段的情况,你可以编写自定义逻辑并进行自动装配。以下是步骤:
- 在
pom.xml
中添加MapStruct库。 - 在项目中添加下面的映射器类。
componentModel="spring"
告诉系统这个映射器由Spring管理。 - 所有字段名相同的字段将会自动映射。
- 对于需要转换的字段,你可以编写
@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
- Add mapStruct library to pom.xml
- Add below mapper class to your project. componentModel="spring" tells the system that this mapper is managed by spring.
- All the fields that have same name will be automapped.
- For fields which require conversions, you can write @BeforeMapping
Mapper(componentModel="spring")
public abstract class ShoppingListMapper
{
@Autowired
IngredientConverter ingredientConverter; //autowire method you use.
public abstract shoppingListToShoppingListDTO(ShoppingList shoppingList) throws Exception;
public abstract List<ShoppingList> 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
}
}
If this example is not clear, you can refer to web for various mapstruct examples. Let me know if you need further help
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论