java - ModelMapper:自定义 PropertyMap 抛出 NullPointer 异常
问题描述
我在我的 Spring Boot 应用程序(Java 12)中使用 ModelMapper,以便将 DatabaseEntities 映射到 DTO,这些 DTO 将用于 REST 端点。
配方类(数据库实体)包含多个变量。其中一些具有自定义类型,因此它们能够包含多种语言。但是,对于 REST 端点,应该返回一个仅包含一种语言的简单对象。因此我有两个子类:RecipeENG_DTO
它们RecipeGER_DTO
都继承自它们的超类Recipe_DTO
。
我的目标是将对象映射
Recipe
到RecipeGER_DTO
对象
Java 代码
REST 端点
@Autowired
private ModelMapper modelMapper;
@GetMapping(path = "/all")
public @ResponseBody
List<? extends RecipeName_DTO> getAllRecipes(HttpServletRequest request) {
Iterable<Recipe> recipes = recipeRepository.findAll();
if (request.getHeader("Accept-Language").equals("de")) {
return StreamSupport.stream(recipes.spliterator(), false).map(recipe -> modelMapper.map(recipe, RecipeNameGER_DTO.class)).collect(Collectors.toList());
} else if (request.getHeader("Accept-Language").equals("en")) {
return StreamSupport.stream(recipes.spliterator(), false).map(recipe -> modelMapper.map(recipe, RecipeNameENG_DTO.class)).collect(Collectors.toList());
} else {
return null;
}
}
}
食谱类
@Entity
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"},
allowGetters = true)
@Getter
@Setter
public class Recipe {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "recipe_name_id")
@JsonManagedReference
private RecipeName recipe_name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "method_id")
@JsonManagedReference
private Method method;
private Time prep_time;
private Time cook_time;
private int serves;
private String image;
private String source;
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
@JsonManagedReference
private List<RecipeIngredient> recipeIngredients;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "recipe_categories",
joinColumns = @JoinColumn(name = "recipe_id"),
inverseJoinColumns = @JoinColumn(name = "category_id"))
private List<Category> categories;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
@JsonManagedReference
private User user_id;
private short access;
@Column(nullable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@LastModifiedDate
private Date updatedAt;
public Recipe() {
recipeIngredients = new ArrayList<>();
categories = new ArrayList<>();
}
}
RecipeDTO 类
@Getter
@Setter
public class Recipe_DTO {
private Long id;
private String recipe_name;
private String method;
private Time prep_time;
private Time cook_time;
private int serves;
private String image;
private String source;
private List<String> categories;
private String user;
private short access;
private Date createdAt;
private Date updatedAt;
}
RecipeENG_DTO 类
@Getter
@Setter
public class RecipeENG_DTO extends Recipe_DTO{
private List<RecipeIngredientENG_DTO> recipeIngredients;
public RecipeENG_DTO() {
super();
}
}
RecipeGER_DTO 类
@Getter
@Setter
public class RecipeGER_DTO extends Recipe_DTO {
private List<RecipeIngredientGER_DTO> recipeIngredients;
public RecipeGER_DTO() {
super();
}
}
AppConfig 类(ModelMapper 配置)
@Configuration
public class AppConfig {
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
//modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
modelMapper.addMappings(new PropertyMap<RecipeIngredient, RecipeIngredientGER_DTO>() {
@Override
protected void configure() {
map().setIngredient(source.getIngredient().getGer());
map().setAmount(source.getAmount());
map().setUnit(source.getUnit().getGer());
map().setGroup(source.getGroup().getGer());
}
});
modelMapper.addMappings(new PropertyMap<Recipe, RecipeGER_DTO>() {
@Override
protected void configure() {
map().setId(source.getId());
map().setRecipe_name(source.getRecipe_name().getGer());
map().setMethod(source.getMethod().getGer());
map().setPrep_time(source.getPrep_time());
map().setCook_time(source.getCook_time());
map().setServes(source.getServes());
map().setImage(source.getImage());
map().setSource(source.getSource());
map().setCategories(source.getCategories().stream().map(Category::getGer).collect(Collectors.toList()));
map().setUser(source.getUser_id().getName());
map().setAccess(source.getAccess());
map().setCreatedAt(source.getCreatedAt());
map().setUpdatedAt(source.getUpdatedAt());
map().setRecipeIngredients(mapAll(source.getRecipeIngredients(), RecipeIngredientGER_DTO.class));
}
});
return modelMapper;
}
}
以下映射导致 NullPointerException
map().setCategories(source.getCategories().stream().map(Category::getGer).collect(Collectors.toList()));
map().setUser(source.getUser_id().getName());
map().setUser(source.getUser_id().getName());
map().setRecipeIngredients(mapAll(source.getRecipeIngredients(), RecipeIngredientGER_DTO.class));
错误日志
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'recipeEndpoints': Unsatisfied dependency expressed through field 'modelMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'modelMapper' defined in class path resource [xyz/gigler/cook/AppConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:
1) Failed to configure mappings
1 error
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:845)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at xyz.gigler.cook.CookApplication.main(CookApplication.java:12)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'modelMapper' defined in class path resource [xyz/gigler/cook/AppConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:
1) Failed to configure mappings
1 error
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:456)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1321)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
... 24 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:
1) Failed to configure mappings
1 error
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
... 37 common frames omitted
Caused by: org.modelmapper.ConfigurationException: ModelMapper configuration errors:
1) Failed to configure mappings
1 error
at org.modelmapper.internal.Errors.throwConfigurationExceptionIfErrorsExist(Errors.java:241)
at org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:244)
at org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:96)
at org.modelmapper.internal.TypeMapImpl.addMappings(TypeMapImpl.java:92)
at org.modelmapper.internal.TypeMapStore.getOrCreate(TypeMapStore.java:124)
at org.modelmapper.ModelMapper.addMappings(ModelMapper.java:113)
at xyz.gigler.cook.AppConfig.modelMapper(AppConfig.java:51)
at xyz.gigler.cook.AppConfig$$EnhancerBySpringCGLIB$$93f5c8e.CGLIB$modelMapper$0(<generated>)
at xyz.gigler.cook.AppConfig$$EnhancerBySpringCGLIB$$93f5c8e$$FastClassBySpringCGLIB$$c2501590.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
at xyz.gigler.cook.AppConfig$$EnhancerBySpringCGLIB$$93f5c8e.modelMapper(<generated>)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 38 common frames omitted
Caused by: java.lang.NullPointerException: null
at xyz.gigler.cook.AppConfig$4.configure(AppConfig.java:63)
at org.modelmapper.PropertyMap.configure(PropertyMap.java:389)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:227)
... 53 common frames omitted
Process finished with exit code 0
解决方案
推荐阅读
- listview - 如何在 Flutter 中的 ListView 顶部添加标题?
- woocommerce - Woo commerce add-to-cart 将图像添加到购物车
- fish - 为什么 argv[-1] 在 fish_title 中显示手册标题?
- git - 文件完全从我的存储库中消失了,硬重置没有帮助,我能做些什么吗?
- php - 如何从 JSON 中提取数据并将其插入到 Laravel 中 MySQL 的相应列中?
- sql - 在 postgresql 中执行多个独立查询
- python - 如何让 Qt 异步运行以进行交互使用,如 Matplotlib 的离子模式?
- python-3.x - 为什么堆排序算法中的build_heap函数不执行
- html - HTML/CSS 单选按钮多级手风琴在选择时自动关闭
- c# - 升级“DependencyInjection”后的 C# 身份验证问题