Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix NPE when fetch config containing an empty array #1599

Closed
yan-khonski-it opened this issue Apr 24, 2020 · 13 comments
Closed

Fix NPE when fetch config containing an empty array #1599

yan-khonski-it opened this issue Apr 24, 2020 · 13 comments

Comments

@yan-khonski-it
Copy link

yan-khonski-it commented Apr 24, 2020

1) Empty array causes NPE in Spring Cloud config

2) Spring cloud config does not log the exception.

We use config-service. Spring Cloud version 2.1 used to work well.
When we updated Spring Cloud version 2.2, it stopped working.

I use Spring profile native and fetch configuration from local file on dev machine
(not from git repository).

This is an example of a configuration file in spring config.
python-service.yml

resources:
  - resource1
  - resource2

newResources: []

The problem is caused by newResources: []. However, it worked in Spring Cloud v 2.1.
Examples, I used curl and Postman.
HTTP http://localhost:8888/python-service/dev
Accept: application/vnd.spring-cloud.config-server.v2+json
returns fail result 1).

{
    "timestamp": "2020-04-24T08:38:19.803+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Could not construct context for config=python-service profile=dev label=null includeOrigin=true; nested exception is java.lang.NullPointerException",
    "path": "/python-service/dev"
}

Next, without the Accept header, it works.
HTTP http://localhost:8888/python-service/dev
Returns success result 2).

{
    "name": "python-service",
    "profiles": [
        "dev"
    ],
    "label": null,
    "version": null,
    "state": null,
    "propertySources": [
        {
            "name": "file:/configuration/python-service.yml",
            "source": {
                "resources[0]": "resource1",
                "resources[1]": "resource2",
                "newResources": ""
            }
        }
    ]
}

By the way, why "newResources": "" is an empty String, if it was an array.

However, the header Accept: application/vnd.spring-cloud.config-server.v2+json is sent by Spring Cloud config client (unfortunately, I had to debug it!).
In the version 2.1, there is
Accept: application/json

As you see, different value for Accept header.

Next, when I down-graded Spring Cloud 2.1
It works
http://localhost:8888/python-service/dev
Accept: application/json
Success result 2).

When I use Spring Cloud config-service version 2.2 and remove empty array from python-service.yml on local machine, it works as well.
http://localhost:8888/python-service/dev
returns success result 3)

{
    "name": "python-service",
    "profiles": [
        "dev"
    ],
    "label": null,
    "version": null,
    "state": null,
    "propertySources": [
        {
            "name": "file:/configuration/python-service.yml",
            "source": {
                "resources[0]": {
                    "value": "resource1",
                    "origin": "2:5"
                },
                "resources[1]": {
                    "value": "resource2",
                    "origin": "3:5"
                }
            }
        }
    ]
}

I do not know what origin: "3.5" is though.
Please, advise.

How to support empty array in the configuration. It breaks our services.

Links
#866
spring-projects/spring-boot#12965
spring-projects/spring-framework#21310

@spencergibb
Copy link
Member

Please provide the stack trace

@yan-khonski-it
Copy link
Author

I do not have stack trace. The problem is that when config-service fails, there are not logs in the config service. I have not debugged config-service; I debugged config service client.

@spencergibb
Copy link
Member

can you look on the config server?

@yan-khonski-it
Copy link
Author

please, give me one hour. I will check...

@yan-khonski-it
Copy link
Author

2020-04-24 15:10:58.756 DEBUG 1 --- [io-8888-exec-10] o.s.web.servlet.DispatcherServlet        : GET "/python-service/dev", parameters={}
2020-04-24 15:10:58.761 DEBUG 1 --- [io-8888-exec-10] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.cloud.config.server.environment.EnvironmentController#defaultLabelIncludeOrigin(String, String)
2020-04-24 15:10:59.123 DEBUG 1 --- [io-8888-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler org.springframework.cloud.config.server.environment.EnvironmentController#environmentException(HttpServletResponse, EnvironmentException)
2020-04-24 15:10:59.126 DEBUG 1 --- [io-8888-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException: Could not construct context for config=python-service profile=dev label=null includeOrigin=true; nested exception is java.lang.NullPointerException]
2020-04-24 15:10:59.138 DEBUG 1 --- [io-8888-exec-10] o.s.web.servlet.DispatcherServlet        : Completed 500 INTERNAL_SERVER_ERROR
2020-04-24 15:10:59.140 DEBUG 1 --- [io-8888-exec-10] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}

This a debug log.

@spencergibb
Copy link
Member

I'm unable to reproduce the issue.

Can you provide a complete, minimal, verifiable sample that reproduces the problem? It should be available as a GitHub (or similar) project or attached to this issue as a zip file.

@yan-khonski-it
Copy link
Author

Yes, I can make an example, but later.
For now, the NPE was caused by org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException

@yan-khonski-it
Copy link
Author

yan-khonski-it commented Apr 24, 2020

More stack trace

org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException: Could not construct context for config=python-service profile=dev label=null 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.FailedToConstructEnvironmentException.<init>(FailedToConstructEnvironmentException.java:31)
	at org.springframework.cloud.config.server.environment.NativeEnvironmentRepository.findOne(NativeEnvironmentRepository.java:161)
	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:144)
	at org.springframework.cloud.config.server.environment.EnvironmentController.defaultLabelIncludeOrigin(EnvironmentController.java:115)
	at jdk.internal.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	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$$38d99eeb.defaultLabelIncludeOrigin(<generated>)
	at jdk.internal.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	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:888)
	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:108)
	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:860)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)
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)
	... 68 more

@yan-khonski-it
Copy link
Author

debug-config-service-1

@yan-khonski-it
Copy link
Author

As I promised, I added logs. Next week, I will make a docker compose example for you to reproduce.
Have a good weekend for now!@

@yan-khonski-it
Copy link
Author

Hi
Please, check this repository
https://github.com/yan-khonski-it/spring-cloud-config-demo

README.md file explains how to start the example.
Use maven and Java 11 to build the project.
Use docker to run it.

@ryanjbaxter
Copy link
Contributor

Why do we need to use docker compose to reproduce this? Does the JDK version make a difference? Why are you not using the Spring Cloud BOM?

@spencergibb spencergibb added this to To do in Hoxton.SR5 via automation Apr 27, 2020
@spencergibb spencergibb added this to To do in 2020.0.0-M2 via automation Apr 27, 2020
@spencergibb spencergibb added this to the 2.2.3.RELEASE milestone Apr 27, 2020
@spencergibb spencergibb added duplicate and removed bug labels Apr 27, 2020
@spencergibb spencergibb removed this from To do in Hoxton.SR5 Apr 27, 2020
@spencergibb spencergibb removed this from To do in 2020.0.0-M2 Apr 27, 2020
@spencergibb spencergibb removed this from the 2.2.3.RELEASE milestone Apr 27, 2020
@spencergibb
Copy link
Member

Duplicates #1572

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants