spring-cloud / spring-cloud-config

External configuration (server and client) for Spring Cloud
Apache License 2.0
1.96k stars 1.29k forks source link

NullPointerException for yml configuration files with empty list ([]) #1572

Closed copa2 closed 4 years ago

copa2 commented 4 years ago

Requesting config-server for config of a service will throw a NullPointException when using yml configuration which contains an empty list([]). This only occurs when using accept header application/vnd.spring-cloud.config-server.v2+json which is the new default when using a config-client.

Problem is that the origin is null at https://github.com/spring-cloud/spring-cloud-config/blob/v2.2.2.RELEASE/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/PassthruEnvironmentRepository.java#L101

Reproduction Create spring-config-server from https://start.spring.io/ and setup a local repo. (Using Spring Boot 2.2.5) Add following sample (demo-client.yml) into repo and commit

foo: bar
# Emptylist will throw NullPointerException 
emptylist: []

Start config-server and try to access this configuration file.

Working (old without accept header) curl http://localhost:8888/demo-client/default

{
  "name": "demo-client",
  "profiles": [
    "default"
  ],
  "label": null,
  "version": "91e04f01593514508554c85eb42f6b000dd10411",
  "state": null,
  "propertySources": [
    {
      "name": "D:/temp/configserver-repo/demo-client.yml",
      "source": {
        "foo": "bar",
        "list": ""
      }
    }
  ]
}

Exception curl -H "accept: application/vnd.spring-cloud.config-server.v2+json" http://localhost:8888/demo-client/default

{
  "timestamp": "2020-03-11T13:26:01.485+0000",
  "status": 500,
  "error": "Internal Server Error",
  "message": "Could not construct context for config=demo-client profile=default label= includeOrigin=true; nested exception is java.lang.NullPointerException",
  "path": "/demo-client/default"
}

Newer config-clients are accessing this through the new media-type (config-sever.v2). See https://github.com/spring-cloud/spring-cloud-config/blob/v2.2.2.RELEASE/spring-cloud-config-client/src/main/java/org/springframework/cloud/config/client/ConfigServicePropertySourceLocator.java#L254

copa2 commented 4 years ago

Problem is in org.springframework.boot.envOriginTrackedYamlLoader which is in spring-boot. Opened issue there and closing this one.

wilkinsona commented 4 years ago

Without a stack trace, I don't know exactly where the NPE is occurring, but if it's due to a missing origin then I think an investigation here is warranted. A property isn't guaranteed to have an origin so its absence needs to be tolerated.

wilkinsona commented 4 years ago

Here's the exception that's thrown when using Spring Cloud Commons 2.2.2.RELEASE:

org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException: Could not construct context for config=demo-client profile=default label= includeOrigin=true; nested exception is java.lang.NullPointerException
    at org.springframework.cloud.config.server.environment.NativeEnvironmentRepository.findOne(NativeEnvironmentRepository.java:161)
    at org.springframework.cloud.config.server.environment.AbstractScmEnvironmentRepository.findOne(AbstractScmEnvironmentRepository.java:59)
    at org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository.findOne(MultipleJGitEnvironmentRepository.java:187)
    at org.springframework.cloud.config.server.environment.CompositeEnvironmentRepository.findOne(CompositeEnvironmentRepository.java:58)
    at org.springframework.cloud.config.server.environment.EnvironmentEncryptorEnvironmentRepository.findOne(EnvironmentEncryptorEnvironmentRepository.java:61)
    at org.springframework.cloud.config.server.environment.EnvironmentController.getEnvironment(EnvironmentController.java:136)
    at org.springframework.cloud.config.server.environment.EnvironmentController.defaultLabelIncludeOrigin(EnvironmentController.java:115)
    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.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
    at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:499)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at org.springframework.cloud.config.server.environment.EnvironmentController$$EnhancerBySpringCGLIB$$71033f6d.defaultLabelIncludeOrigin(<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:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
    at org.springframework.cloud.config.server.environment.PassthruEnvironmentRepository.getMap(PassthruEnvironmentRepository.java:101)
    at org.springframework.cloud.config.server.environment.PassthruEnvironmentRepository.findOne(PassthruEnvironmentRepository.java:80)
    at org.springframework.cloud.config.server.environment.NativeEnvironmentRepository.findOne(NativeEnvironmentRepository.java:152)
    ... 70 more

PassthruEnvironmentRepository is assuming that OriginLookup.getOrigin(Object, K) will not return null but its javadoc notes that it can do so:

Attempt to lookup the origin from the given source. If the source is not a OriginLookup or if an exception occurs during lookup then null is returned.

yan-khonski-it commented 4 years ago

Related and a duplicate https://github.com/spring-cloud/spring-cloud-config/issues/1599

yan-khonski-it commented 4 years ago

Problem is in org.springframework.boot.envOriginTrackedYamlLoader which is in spring-boot. Opened issue there and closing this one.

Where is the ticked to Spring Boot issue? Please, provide.

wilkinsona commented 4 years ago

@yan-khonski-it There's a link to it above. https://github.com/spring-projects/spring-boot/issues/20506 was opened.