我通过以下方式使用ModelMapper:
我有一些转换器类是Spring组件,它们注册了自定义ModelMapper映射
@Component
public class FooConverter {
@Autowired
private ModelMapper modelMapper;
public static final PropertyMap<Foo, FooModel> FOO_TO_FOO_MODEL_MAP = new PropertyMap<Foo, FooModel>() {
@Override
protected void configure() {
map().setTimeZone(source.getTimeZone().getID());
}
};
@PostConstruct
public void init() {
modelMapper.addMappings(FOO_TO_FOO_MODEL_MAP);
}
}
但是当Spring启动时出现以下错误,因为配置函数被调用并且源为空。
那应该如何工作?
我用错了吗?
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 com.agilitypr.neptune.account.api.v1.controllers.PreferenceController.getUserAccountPreferences(PreferenceController.java:63)
at com.agilitypr.neptune.account.api.v1.controllers.PreferenceController$$FastClassBySpringCGLIB$$3559fcbb.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
at com.agilitypr.neptune.account.api.v1.filters.AuthorizationFilter.doAuthorize(AuthorizationFilter.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:174)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
at com.agilitypr.neptune.account.api.v1.filters.AuthenticationFilter.doAuthenticate(AuthenticationFilter.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:174)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at com.agilitypr.neptune.account.api.v1.controllers.PreferenceController$$EnhancerBySpringCGLIB$$a4d3aeda.getUserAccountPreferences(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1655)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:215)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1317)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1219)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:531)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:352)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
at org.modelmapper.internal.ExplicitMappingBuilder$ExplicitMappingInterceptor.access$000(ExplicitMappingBuilder.java:304)
at org.modelmapper.internal.ExplicitMappingBuilder.createAccessorProxies(ExplicitMappingBuilder.java:287)
at org.modelmapper.internal.ExplicitMappingBuilder.createProxies(ExplicitMappingBuilder.java:277)
at org.modelmapper.internal.ExplicitMappingBuilder.visitPropertyMap(ExplicitMappingBuilder.java:266)
at org.modelmapper.PropertyMap.configure(PropertyMap.java:386)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:227)
... 90 more
这样声明bean,并且Foo和FooModel不是最终的
@Configuration
public class FooConfiguration {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
重要修改
实际上,即使我在主类中的函数中显式创建了映射,我也会得到相同的NullPointerException。
public class main {
public static void main(String[] args) {
ModelMapper mapper = new ModelMapper();
final PropertyMap<Foo, FooModel> FOO_TO_FOO_MODEL_MAP = new PropertyMap<Foo, FooModel>() {
@Override
protected void configure() {
map().setTimeZone(source.getTimeZone().getID());
}
};
mapper.addMappings(FOO_TO_FOO_MODEL_MAP );
}
}
怎么了?
我正在遵循他们的documentation中的示例。
编辑
深度映射正在与这些
一起使用public class InnerFoo {
private int prop3;
public int getProp3() {
return prop3;
}
public void setProp3(int prop3) {
this.prop3 = prop3;
}
}
public class Foo {
private InnerFoo innerFoo;
public InnerFoo getInnerFoo() {
return innerFoo;
}
public void setInnerFoo(InnerFoo innerFoo) {
this.innerFoo = innerFoo;
}
}
public class FooModel {
private int prop2;
public int getProp2() {
return prop2;
}
public void setProp2(int prop2) {
this.prop2 = prop2;
}
}
问题仅出在TimeZone对象上,因此我必须使用一个不理想的转换器。
map().setTimeZone(source.getTimeZone().getID());
public class Foo {
private TimeZone timeZone;
//Setters//Getters
}
public class FooModel {
private String timeZoneId;
//Setters//Getters
}
答案 0 :(得分:1)
我认为这最终是由于在配置映射器时ModelMapper无法实例化TimeZone
对象(也不能实例化LocalDateTime
等)。
实际上,您无需进行任何配置。
ModelMapper mapper = new ModelMapper();
Foo foo = new Foo();
foo.setTimeZone(TimeZone.getDefault());
FooModel model = mapper.map(foo, FooModel.class);
System.out.println(model.getTimeZoneId()); // "Europe/Berlin" here
这对我有用。 ModelMapper发现您想将TimeZone
的属性ID
映射到FooModel
的属性timeZoneId
。
尽管如此,以防万一您想手动执行此操作:
迅速跟踪文档,我发现了converters的概念。
使用将Converter
转换为TimeZone
的{{1}},您可以执行以下操作:
String
答案 1 :(得分:0)
对于遇到相同问题的任何人:我的问题是我将PropertyMap与匿名实现一起使用,例如spring配置中建议的文档。这在ExplicitMappingBuilder中被弄乱了。我现在所拥有的是以下内容:
@Configuration
public class ApplicationConfig {
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.addMappings(new UserPropertyMap());
return modelMapper;
}
}
我的UserPropertyMap如下:
public class UserPropertyMap extends PropertyMap<UserRepresentation, UserDTO> {
@Override
protected void configure() {
map().setUserName(source.getUsername());
}
}
这在Spring Boot 2中就像一个魅力。
答案 2 :(得分:-1)
使用构造函数自动装配 像
public FooConverter(ModelMapper modelMapper){
this.modelMapper = modelMapper;
}
还要确保已在spring config类中定义了ModelMapper bean,如下所示:
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}