복붙노트

[SPRING] 사용자 지정 PropertyMap을 정의하려고 할 때 NullPointerException이 발생합니다.

SPRING

사용자 지정 PropertyMap을 정의하려고 할 때 NullPointerException이 발생합니다.

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);
    }
}

하지만 구성 함수가 호출되고 소스가 null이기 때문에 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은 final이 아닙니다.

@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 );
}

}

뭐가 잘못 되었 니?

나는 그들의 문서에서 예제를 따르고있다.

편집하다

딥 매핑은 이들과 함께 작동합니다.

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
}

해결법

  1. ==============================

    1.이것은 궁극적으로 ModelMapper가 매퍼 구성시 TimeZone 객체 (또는 LocalDateTime 등)를 인스턴스화 할 수 없다는 사실에 기인한다고 생각합니다.

    이것은 궁극적으로 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에 매핑하려고한다는 것을 알았습니다.

    그럼에도 불구하고 수동으로 수행하려는 경우 문서를 빠르게 따라 가면서 변환기 개념을 발견했습니다. TimeZone을 String으로 변환하는 Converter를 사용하면 다음과 같이 할 수 있습니다 :

    ModelMapper mapper = new ModelMapper();
    TypeMap<Foo, FooModel> typeMap = mapper.createTypeMap(Foo.class, FooModel.class);
    Converter<TimeZone, String> tzConverter = ctx -> ctx.getSource().getID() + "!!!";
    typeMap.addMappings(map -> {
        map.using(tzConverter).map(Foo::getTimeZone, FooModel::setTimeZoneId);
    });
    
    Foo foo = new Foo();
    foo.setTimeZone(TimeZone.getDefault());
    
    FooModel model = mapper.map(foo, FooModel.class);
    System.out.println(model.getTimeZoneId()); // "Europe/Berlin!!!" here
    
  2. ==============================

    2.생성자를 사용한 Autowire 처럼

    생성자를 사용한 Autowire 처럼

    public FooConverter(ModelMapper modelMapper){
       this.modelMapper = modelMapper;
    }
    

    ModelMapper 빈이 다음과 같이 봄 설정 클래스에 정의되어 있는지 확인하십시오 :

    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
    
  3. from https://stackoverflow.com/questions/53287450/nullpointerexception-when-trying-to-define-a-custom-propertymap by cc-by-sa and MIT license