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

Null pointer exception in ValidatorHandler after reloading modules with a new openapi spec file #406

Open
bvalenti opened this issue Nov 13, 2024 · 1 comment

Comments

@bvalenti
Copy link

Ran into a little error when using the config reloading and OpenAPI validation. I'm playing around with a generic petstore generated example project that has multi-spec enabled.

I want to be able to add or remove openapi spec files from the config directory and reload the modules to pick up on those changes to dynamically change the REST paths.

If I add a new spec file to the config folder, add an entry for it in the openapi-handler.yml, and reload the modules, the following error occurs when I submit a request to an endpoint defined in the new spec file:

15:34:43.266 [XNIO-1 task-2] ERROR com.networknt.exception.ExceptionHandler -- Exception:
java.lang.NullPointerException: Cannot invoke "com.networknt.openapi.RequestValidator.validateRequest(com.networknt.openapi.NormalisedPath, io.undertow.server.HttpServerExchange, com.networknt.openapi.OpenApiOperation)" because "reqV" is null
        at com.networknt.openapi.ValidatorHandler.handleRequest(ValidatorHandler.java:110)
        at com.networknt.handler.Handler.next(Handler.java:211)
        at com.networknt.handler.Handler.next(Handler.java:231)
        at com.networknt.body.BodyHandler.handleRequest(BodyHandler.java:140)
        at com.networknt.handler.Handler.next(Handler.java:211)
        at com.networknt.handler.Handler.next(Handler.java:231)
        at com.networknt.openapi.OpenApiHandler.handleRequest(OpenApiHandler.java:251)
        at com.networknt.handler.Handler.next(Handler.java:211)
        at com.networknt.handler.Handler.next(Handler.java:231)
        at com.networknt.exception.ExceptionHandler.handleRequest(ExceptionHandler.java:77)
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:395)
        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
        at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
        at java.base/java.lang.Thread.run(Thread.java:833)
15:34:43.267 [XNIO-1 task-2] DEBUG io.undertow.request.error-response -- Setting error code 500 for exchange HttpServerExchange{ GET /v4/users}
java.lang.RuntimeException: null
        at io.undertow.server.HttpServerExchange.setStatusCode(HttpServerExchange.java:1492)
        at com.networknt.handler.LightHttpHandler.setExchangeStatus(LightHttpHandler.java:115)
        at com.networknt.handler.LightHttpHandler.setExchangeStatus(LightHttpHandler.java:74)
        at com.networknt.exception.ExceptionHandler.handleRequest(ExceptionHandler.java:91)
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:395)
        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
        at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
        at java.base/java.lang.Thread.run(Thread.java:833)
15:34:43.270 [XNIO-1 task-2] ERROR com.networknt.handler.LightHttpHandler -- {"statusCode":500,"code":"ERR10010","message":"RUNTIME_EXCEPTION","description":"Unexpected runtime exception","severity":"ERROR"}

I'm using the following to reload the modules:

curl -X POST -k http://localhost:9090/adm/modules --header 'Content-Type: application/json' --data-raw '["com.networknt.openapi.OpenApiHandler", "com.networknt.openapi.ValidatorHandler","com.networknt.body.BodyHandler"]'

To clarify, I only get this exception when trying to submit a request against a path defined in the newly added openapi spec file. The previous ones still work fine.

After looking into it a bit, it appears you are creating new instances of each handler class and calling their respective reload methods. In the case of the OpenApiHandler, the helperMap object is static, so when the reload method is called on the newly created instance, the instance present in the handler chain also gets the new data. On the other hand, the ValidatorHandler does not use static variables for requestValidatorMap or responseValidatorMap, so when the reload method is called on the new instance, it doesn’t actually update the requestValidatorMap or responseValidatorMap objects for the instance present in the handler chain.

I created a custom handler class that copies your ValidatorHandler class but makes the requestValidatorMap and responseValidatorMap variables static. Using this handler resolves the above error and provides the behavior I want. Curious to know what you think would be the best way of handling this. Thanks.

@stevehu
Copy link
Contributor

stevehu commented Nov 14, 2024

The module reload is for reloading configuration changes in values.yml (local filesystem) or on config-server. Although openapi.yaml is considered a configuration file, it doesn't support reloading. In a real running environment, the spec should not be changed. However, in a development environment, it is possible. Your solution will resolve the NPE issue but the newly added endpoint won't work. I think we should update the OpenApiHandler to support the openapi.yaml reload.

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

No branches or pull requests

2 participants