esastack / esa-restlight Goto Github PK
View Code? Open in Web Editor NEWA lightweight and rest-oriented web framework.
Home Page: https://restlight.esastack.io/
License: Apache License 2.0
A lightweight and rest-oriented web framework.
Home Page: https://restlight.esastack.io/
License: Apache License 2.0
Interface spec of HttpBodySerializer
@Override
default boolean supportsRead(MediaType mediaType, Type type) {
return true;
}
@Override
default boolean supportsWrite(MediaType mediaType, Type type) {
return true;
}
byte[] serialize(Object target) throws Exception;
<T> T deSerialize(byte[] data, Type type) throws Exception;
Problem is that the end-user do not know how to serialize/deserialize after calling supportsRead(MediaType mediaType, Type type)
because parameters of MediaType
and Type
is not passed in serialize()
and deSerialize()
MediaType
and Type
in serialize()
and deSerialize()
supportsRead()
and supportsWrite()
serialize()
and deSerialize()
.I use "HandlerInterceptor" in its includes method internal configuration "/v1/stat/, /v1/get/,/v1/list/**" these parameters, I hope restlight can help us intercept similar "/ v1/get/xxxxx/hello, /v1/stat/12234435" such interface
It can only intercept interfaces such as "/v1/stat/12234435"
There is a problem with the implementation of "neverIntersect(includes, patterns)" in the method of judging affinity in the HandlerInterceptorWrap class parseAffinity;
for (String include : includes) {
if (Arrays.stream(patterns)
.noneMatch(pattern -> PathMatcher.isPotentialIntersect(include, pattern))) {
return true;
}
}
The above piece of code will cause the logic to exit due to the disjointness of “/v1/stat/” before judging whether the interface “/v1/get/123456” will not intersect with “/v1/get/”. Finally, the affinity is -1 misjudgment
We can configure the warming up by restlight.server.warm-up.delay
, which just takes a Thread.sleep(delay)
before starting the Restlight server, but could not support doing some logic before starting the Restlight server asynchronously.
In Restlight, We have tried our best not to introduce dependencies for reducing conflicts. But the dependency named hibernate validator
introduced in restlight-core
is introducing a lot of dependencies(such as jboss-logging
, validation-api
and so on...) which makes Restlight prone to conflict. And this bean validation feature is not required by every end-user.
So, It would be better if we make the bean validation feature pluggable by SPI, which is introduced by default and it also can be excluded if it is not required or it is conflicting with other dependencies.
work normal
org.springframework.beans.factory.BeanCreationException: Failed to start Restlight server.; nested exception is java.util.concurrent.ExecutionException: java.lang.NullPointerException: underlying
at io.esastack.restlight.starter.ServerStarter.afterSingletonsInstantiated(ServerStarter.java:99)
at io.esastack.restlight.integration.test.BaseIntegrationTest.setUp(BaseIntegrationTest.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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.util.concurrent.ExecutionException: java.lang.NullPointerException: underlying
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1928)
at io.esastack.restlight.starter.ServerStarter.afterSingletonsInstantiated(ServerStarter.java:95)
... 18 more
Caused by: java.lang.NullPointerException: underlying
at esa.commons.Checks.checkNotNull(Checks.java:52)
at io.esastack.restlight.core.configure.DelegatingDeployContext.<init>(DelegatingDeployContext.java:46)
at io.esastack.restlight.core.handler.impl.HandlerContext.<init>(HandlerContext.java:41)
at io.esastack.restlight.springmvc.resolver.exception.SpringMvcExceptionResolverFactory.lambda$extractExceptionHandlers$0(SpringMvcExceptionResolverFactory.java:120)
at java.util.Optional.ifPresent(Optional.java:159)
at io.esastack.restlight.springmvc.resolver.exception.SpringMvcExceptionResolverFactory.extractExceptionHandlers(SpringMvcExceptionResolverFactory.java:119)
at io.esastack.restlight.springmvc.resolver.exception.SpringMvcExceptionResolverFactory.extractMappings(SpringMvcExceptionResolverFactory.java:109)
at io.esastack.restlight.springmvc.resolver.exception.SpringMvcExceptionResolverFactory.createMappersFromControllerAdvice(SpringMvcExceptionResolverFactory.java:91)
at io.esastack.restlight.core.resolver.exception.AbstractExceptionResolverFactory.initControllerAdviceToExceptionHandlerBean(AbstractExceptionResolverFactory.java:93)
at io.esastack.restlight.core.resolver.exception.AbstractExceptionResolverFactory.init(AbstractExceptionResolverFactory.java:61)
at io.esastack.restlight.core.resolver.exception.AbstractExceptionResolverFactory.<init>(AbstractExceptionResolverFactory.java:39)
at io.esastack.restlight.springmvc.resolver.exception.SpringMvcExceptionResolverFactory.<init>(SpringMvcExceptionResolverFactory.java:57)
at io.esastack.restlight.springmvc.spi.SpringMvcExceptionResolverFactoryProvider.factory(SpringMvcExceptionResolverFactoryProvider.java:38)
at io.esastack.restlight.core.Deployments.registerRoutes(Deployments.java:1115)
at io.esastack.restlight.core.Deployments.createRestlightHandler(Deployments.java:1619)
at io.esastack.restlight.core.Deployments.doGetRestlightHandler(Deployments.java:1036)
at io.esastack.restlight.core.Deployments.getRestlightHandler(Deployments.java:1611)
at io.esastack.restlight.core.Deployments.applyDeployments(Deployments.java:1606)
at io.esastack.restlight.core.AbstractRestlight.buildServer(AbstractRestlight.java:216)
at io.esastack.restlight.core.AbstractRestlight.start(AbstractRestlight.java:198)
at io.esastack.restlight.server.bootstrap.AbstractDelegatedRestlightServer.start(AbstractDelegatedRestlightServer.java:34)
at io.esastack.restlight.starter.ServerStarter.lambda$afterSingletonsInstantiated$0(ServerStarter.java:86)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:750)
1.add customize exceptionHandler like below.
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(CustomException.class)
public String handleCustomException(CustomException customException, HttpResponse httpResponse) {
httpResponse.status(HttpStatus.UNAUTHORIZED.code());
return customException.getMessage();
}
}
2.start the application.
In Restlight, it seems that StandardCharsets.UTF_8
is the default charset, but we should flow the HTTP standard to handle the charset such as content-type
header, accept
header.
And Here are some wrong uses
How can we make sure that UTF-8
is compatible with the given value
We should try to retrieve charset from the content-type rather than using UTF8
directly
We should re-examine the handling of charset in this whole project
can convert the string value to byte
2022-04-14 11:25:28.657 ERROR 13796 --- [stlight-Biz-0#3] i.e.r.s.bootstrap.DispatcherHandlerImpl : Error occurred when doing request(url=/esastack/stability/test/byte, method=POST)
io.esastack.restlight.server.bootstrap.WebServerException: java.lang.NumberFormatException: For input string: "xxxx"
at io.esastack.restlight.server.bootstrap.WebServerException.wrap(WebServerException.java:61) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractExecution.resolveArgs(AbstractExecution.java:106) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.lambda$doHandle$0(AbstractRouteExecution.java:92) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:143) ~[na:na]
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.doHandle(AbstractRouteExecution.java:87) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.LinkedRouteFilterChain.lambda$immutable$0(LinkedRouteFilterChain.java:48) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.spi.impl.RouteTracking.routed(RouteTracking.java:55) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.LinkedRouteFilterChain.doNext(LinkedRouteFilterChain.java:60) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.handle(AbstractRouteExecution.java:78) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.bootstrap.DispatcherHandlerImpl.service(DispatcherHandlerImpl.java:82) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$null$1(ScheduledHandler.java:83) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:883) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2251) ~[na:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$processByFixedScheduler$2(ScheduledHandler.java:74) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.RequestTaskImpl.run(RequestTaskImpl.java:45) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.52.Final.jar:4.1.52.Final]
at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
Caused by: java.lang.NumberFormatException: For input string: "xxxx"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:na]
at java.base/java.lang.Integer.parseInt(Integer.java:652) ~[na:na]
at java.base/java.lang.Byte.parseByte(Byte.java:152) ~[na:na]
at java.base/java.lang.Byte.parseByte(Byte.java:178) ~[na:na]
at io.esastack.restlight.core.util.ConverterUtils.lambda$static$1(ConverterUtils.java:69) ~[restlight-common-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.util.ConverterUtils$Strs2ArrayConverter.apply(ConverterUtils.java:279) ~[restlight-common-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.util.ConverterUtils$Str2ArrayConverter.apply(ConverterUtils.java:307) ~[restlight-common-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.util.ConverterUtils$Str2ArrayConverter.apply(ConverterUtils.java:288) ~[restlight-common-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.spi.impl.DefaultStringConverterFactory$1.fromString(DefaultStringConverterFactory.java:43) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.resolver.reqentity.FlexibleRequestEntityResolverFactory$DefaultResolver.readFrom(FlexibleRequestEntityResolverFactory.java:121) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.resolver.RequestEntityResolverContextImpl.proceed(RequestEntityResolverContextImpl.java:66) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AdvisedRequestEntityResolver.resolve(AdvisedRequestEntityResolver.java:48) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractExecution.resolveArgs(AbstractExecution.java:103) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
... 21 common frames omitted
1.define the controller method like below
@PostMapping("/byte")
@ResponseBody
public byte[] requestByte(@RequestBody byte[] bytes) {
2.request the uri use header Content-Type:text/plain
@Bean
public Filter foo() {
return new Filter() { xxx };
}
MockMvc mockMvc = MockMvcBuilders.contextSetup(context);
...
mockMvc.perform(xxx);
this foo
Filter should be applied.
The filter will NOT be applied
can work normally
throw Exception
Method [public io.esastack.restlight.integration.entity.UserData io.esastack.restlight.integration.cases.RestAnnotationController.matrix(org.springframework.util.MultiValueMap<java.lang.String, java.lang.String>)]
Resolved arguments:
[0] [type=java.util.Collections$EmptyMap]
at io.esastack.restlight.server.bootstrap.WebServerException.badRequest(WebServerException.java:81)
at io.esastack.restlight.core.handler.impl.HandlerInvokerImpl.doInvoke(HandlerInvokerImpl.java:56)
at io.esastack.restlight.core.handler.impl.HandlerInvokerImpl.invoke(HandlerInvokerImpl.java:46)
at io.esastack.restlight.core.handler.impl.HandlerImpl.invoke(HandlerImpl.java:54)
at io.esastack.restlight.core.handler.impl.AbstractExecution.invoke(AbstractExecution.java:130)
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.lambda$doHandle$1(AbstractRouteExecution.java:96)
at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995)
at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137)
at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110)
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.doHandle(AbstractRouteExecution.java:96)
at io.esastack.restlight.core.handler.LinkedRouteFilterChain.lambda$immutable$0(LinkedRouteFilterChain.java:48)
at io.esastack.restlight.core.spi.impl.RouteTracking.routed(RouteTracking.java:55)
at io.esastack.restlight.core.handler.LinkedRouteFilterChain.doNext(LinkedRouteFilterChain.java:60)
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.handle(AbstractRouteExecution.java:78)
at io.esastack.restlight.server.bootstrap.DispatcherHandlerImpl.service(DispatcherHandlerImpl.java:82)
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$null$1(ScheduledHandler.java:83)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:774)
at java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:792)
at java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2153)
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$processByFixedScheduler$2(ScheduledHandler.java:74)
at io.esastack.restlight.server.schedule.RequestTaskImpl.run(RequestTaskImpl.java:45)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
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 io.esastack.restlight.core.handler.impl.HandlerInvokerImpl.doInvoke(HandlerInvokerImpl.java:53)
1.define the controller
@GetMapping("get/matrix")
public UserData matrix(@MatrixVariable MultiValueMap<String, String> map) {
return UserData.Builder.aRestResult()
.name(map.getFirst("name")).build();
}
2.request the url: get/matrix?name=test,test2
Use HttpResponseStatus#TOO_MANY_REQUESTS instead of customized status and reason phrase
add Integration test for Jaxrs.
None
None
have pull request template
do not have pull request template
no
We are always using AsyncRequest
and AsyncResponse
in pairs, but AsyncRequest
and AsyncResponse
are always separated into two parameters.
Which means
AsyncRequest
and AsyncResponse
is in the same lifecycleUsing a composed interface(or class) to present a REQUEST.
public interface RequestContext {
AsyncRequest request();
AsyncResponse response();
// other functions
}
Advantages
AsyncRequest
and AsyncResponse
is in the same lifecycleWhen I started a simple MockMvc, the application failed to start. The error describes as:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oldAccessLogFilter' defined in class path resource [esa/restlight/ext/filter/starter/autoconfigurer/RestlightExtFilterAutoConfiguration.class]: Unsatisfied dependency expressed through method 'oldAccessLogFilter' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'esa.restlight.starter.autoconfigure.AutoRestlightServerOptions' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:509)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
... 25 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'esa.restlight.starter.autoconfigure.AutoRestlightServerOptions' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1651)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1210)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1164)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:857)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:760)
... 43 more
and the application.properties configured as:
restlight.server.port=9997
restlight.server.ext.accesslog.enable=true
Lines 21 to 24 in ce8fe48
As we all know, protostuff
is also an excellent serialization format and
has been used widely. So why not considering to support it ?
Now we are using biz threads configuration like
restlight.server.blocking-queue-length=128
restlight.server.keep-alive-time-seconds=60
But it is hard to understand what restlight.server.keep-alive-time-seconds
and restlight.server.blocking-queue-length
means.
Same with restlight.server.core-biz-threads
and restlight.server.max-biz-threads
that are easier to understand than above because of the suffix of biz-threads
.
It would be clear if we change the configuration to this
restlight.server.biz-threads.core=1
restlight.server.biz-threads.max=2
restlight.server.biz-threads.blocking-queue-length=128
restlight.server.biz-threads.keep-alive-time-seconds=60
can assign the value to the pojo.
sometime can, sometime can not.
1.define the controller like below.
@GetMapping("get/querybean")
public UserData queryBean(@QueryBean UserData user) {
return user;
}
@GetMapping("get/requestbean")
public UserData requestBean(@RequestBean UserData user) {
return user;
}
pojo like below.
public class UserData {
private String name;
private Integer age;
private BigDecimal weight;
public BigDecimal getWeight() {
return weight;
}
private Date birthDay;
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Date getBirthDay() {
return birthDay;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setWeight(BigDecimal weight) {
this.weight = weight;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
@Override
public String toString() {
return "UserData{" +
"name='" + name + '\'' +
", age=" + age +
", weight=" + weight +
", birthDay=" + birthDay +
'}';
}
public static final class Builder {
private String name;
private Integer age;
private BigDecimal weight;
private Date birthDay;
private Builder() {
}
public static Builder aRestResult() {
return new Builder();
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(Integer age) {
this.age = age;
return this;
}
public Builder weight(BigDecimal weight) {
this.weight = weight;
return this;
}
public Builder birthDay(Date birthDay) {
this.birthDay = birthDay;
return this;
}
public UserData build() {
UserData userData = new UserData();
userData.name = this.name;
userData.weight = this.weight;
userData.birthDay = this.birthDay;
userData.age = this.age;
return userData;
}
}
}
2.request the url with param name=test
.
request normal.
client timeout.
java.util.concurrent.ExecutionException: java.net.SocketTimeoutException: Request: http://127.0.0.1:53867/integration/test/validation/param exceeds read timeout: 6000ms
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908)
at io.esastack.restlight.integration.jaxrs.test.ValidationTest.testParam(ValidationTest.java:31)
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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.net.SocketTimeoutException: Request: http://127.0.0.1:53867/integration/test/validation/param exceeds read timeout: 6000ms
at io.esastack.httpclient.core.netty.ReadTimeoutTask.lambda$run$76(ReadTimeoutTask.java:49)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:750)
1.define the resource like below.
@Controller
@Path("/validation/")
public class ValidationResource {
@GET
@Path("param")
public UserData param(@NotEmpty @QueryParam("name") String name) {
return UserData.Builder.anUserData()
.name(name).build();
}
}
2.request it like below.
RestResponseBase responseBase = restClient.get(domain + "/validation/param").execute().toCompletableFuture().get();
Assert.assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.code(), responseBase.status());
We are using the netty interfaces(or classes) in interfaces that would be used by the end-user such as io.netty.buffer.ByteBuf
, io.netty.handler.codec.http.HttpHeaders
, io.netty.handler.codec.http.cookie.Cookie
and so on...
And this time we want to replace these interfaces(or classes) with our own interfaces(or classes) such as esa.commons.netty.core.Buffer
, esa.commons.http.HttpHeaders
, esa.commons.http.Cookie
and so on...
Try to prevent the end-user from using origin netty interfaces directly, and let end-user use our own interfaces(or classes).
Restlight should be shut down before closing Spring context.
Restlight does the graceful shutdown by adding an individual shutdown hook, which has a different lifecycle from Spring's shutdown hook. This would cause errors when invoking the controller methods because the beans these methods belong to would have been destroyed in Spring's shutdown hook if Spring's shutdown hook is executed before Restlight's shutdown hook.
Maybe we should bind the shutdown hook lifecycle with Spring context(if it is in Spring env).
see above
Hi, maybe a bug have been found out. The specific scene is:
when a customize aop arounds the bean which is
annotated with @RestControllerAdvice and then it's
internal methods which are expected to handle the
exception will make no effect.
When I added restlight-ext-filter-starter
and restlight-starter-actuator
dependencies at the same time, it's failed
to start the server successfully. The error describes as:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method oldAccessLogFilter in esa.restlight.ext.filter.starter.autoconfigurer.RestlightExtFilterAutoConfiguration required a single bean, but 2 were found:
- restlight.server-esa.restlight.starter.autoconfigure.AutoRestlightServerOptions: defined in null
- management.server.restlight-esa.restlight.starter.actuator.autoconfigurer.ManagementOptions: defined in null
support the date format pattern yyyy-MM-dd HH:mm:ss
as default.
throw exception when I input date time like yyyy-MM-dd HH:mm:ss
.
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2022-04-11 19:33:00": not a valid representation (error: Failed to parse Date value '2022-04-11 19:33:00': Cannot parse date "2022-04-11 19:33:00": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSZ', parsing fails (leniency? null))
at [Source: (byte[])"{
"id": 1,
"userName": "张三",
"age": 20,
"sex": "M",
"time": 1649676789851,
"amount": 100.332,
"weight": 75,
"createTime": "2022-04-11 19:33:00"
}"; line: 9, column: 17] (through reference chain: io.esastack.stability.test.controller.StabilityController$Pojo["createTime"])
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1676) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:932) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:550) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._parseDate(StdDeserializer.java:491) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateBasedDeserializer._parseDate(DateDeserializers.java:195) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:285) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.std.DateDeserializers$DateDeserializer.deserialize(DateDeserializers.java:268) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202) ~[jackson-databind-2.10.1.jar:2.10.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3300) ~[jackson-databind-2.10.1.jar:2.10.1]
at io.esastack.restlight.core.serialize.JacksonSerializer.deserialize(JacksonSerializer.java:54) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.serialize.BaseHttpBodySerializer.doDeserialize(BaseHttpBodySerializer.java:54) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.serialize.BaseHttpBodySerializer.deserialize(BaseHttpBodySerializer.java:34) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.resolver.reqentity.FlexibleRequestEntityResolverFactory$DefaultResolver.readFrom(FlexibleRequestEntityResolverFactory.java:127) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.resolver.RequestEntityResolverContextImpl.proceed(RequestEntityResolverContextImpl.java:66) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AdvisedRequestEntityResolver.resolve(AdvisedRequestEntityResolver.java:48) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractExecution.resolveArgs(AbstractExecution.java:103) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
... 21 common frames omitted
1.add a date property in pojo.
2.request the url use date pattern yyyy-MM-dd HH:mm:ss
.
I want to execute my custom biz logic when failing fast. But now there is no way to achieve it.
Use deserialize
instead of deSerialize
see esastack/esa-httpserver#11
upgrade httpserver before next release
CI and unit test can pass.
The CI and unit test can not pass now.
see the workflow in PR.
@GetMapping("/foo")
public void foo(@RequestParam(defaultValue = "") List<String> foo) {
// ...
}
expecting a null(or empty ?) list value of argument foo
400 error
can work
don't work.
1.define the customize ReaderInterceptor
.
@Provider
@Component
public class RequestInterceptor implements ReaderInterceptor {
@Override
public Object aroundReadFrom(ReaderInterceptorContext context) throws WebApplicationException, IOException {
System.out.println(context.getType());
return context.proceed();
}
}
2.request the rest api.
add integration test for restlight.
have no integration test.
none
make the PathMatcher performance up
Now, We are using regex to match the path variables of the URI. eg. /foo/{bar}/baz
Maybe we should stop using regex and try to resolve the path variables directly for a nice performance.
application start successfully.
org.springframework.beans.factory.BeanCreationException: Failed to start Restlight server.; nested exception is java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: There is no suitable resolver to handle param: [MethodParam: io.esastack.restlight.starter.actuator.adapt.OperationHandler=>handle@body]
at io.esastack.restlight.starter.ServerStarter.afterSingletonsInstantiated(ServerStarter.java:99) ~[restlight-starter-1.0.0-SNAPSHOT.jar:na]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:863) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE]
at io.esastack.demo.DemoApplication.main(DemoApplication.java:10) ~[classes/:na]
Caused by: java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: There is no suitable resolver to handle param: [MethodParam: io.esastack.restlight.starter.actuator.adapt.OperationHandler=>handle@body]
at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2022) ~[na:na]
at io.esastack.restlight.starter.ServerStarter.afterSingletonsInstantiated(ServerStarter.java:95) ~[restlight-starter-1.0.0-SNAPSHOT.jar:na]
... 9 common frames omitted
Caused by: java.lang.IllegalArgumentException: There is no suitable resolver to handle param: [MethodParam: io.esastack.restlight.starter.actuator.adapt.OperationHandler=>handle@body]
at io.esastack.restlight.core.handler.impl.HandlerMethodAdapter.getResolverWrap(HandlerMethodAdapter.java:123) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.HandlerMethodAdapter.buildParamResolvers(HandlerMethodAdapter.java:103) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.HandlerMethodAdapter.<init>(HandlerMethodAdapter.java:54) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.RouteHandlerMethodAdapter.<init>(RouteHandlerMethodAdapter.java:61) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.SingletonRouteMethod.<init>(SingletonRouteMethod.java:43) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.util.RouteUtils.extractRoute(RouteUtils.java:178) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.configure.HandlerRegistryImpl.lambda$addHandlerMappings$7(HandlerRegistryImpl.java:202) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) ~[na:na]
at io.esastack.restlight.core.configure.HandlerRegistryImpl.addHandlerMappings(HandlerRegistryImpl.java:202) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.Deployments.lambda$registerHandlers$11(Deployments.java:1156) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
at io.esastack.restlight.core.Deployments.registerHandlers(Deployments.java:1153) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.Deployments.registerRoutes(Deployments.java:1128) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.Deployments.createRestlightHandler(Deployments.java:1594) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.Deployments.doGetRestlightHandler(Deployments.java:1033) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.Deployments.getRestlightHandler(Deployments.java:1586) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.Deployments.applyDeployments(Deployments.java:1581) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.AbstractRestlight.buildServer(AbstractRestlight.java:217) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.AbstractRestlight.start(AbstractRestlight.java:199) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.bootstrap.AbstractDelegatedRestlightServer.start(AbstractDelegatedRestlightServer.java:34) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.starter.ServerStarter.lambda$afterSingletonsInstantiated$0(ServerStarter.java:86) ~[restlight-starter-1.0.0-SNAPSHOT.jar:na]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.52.Final.jar:4.1.52.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
1.import restlight-starter-actuator
<dependency>
<groupId>io.esastack</groupId>
<artifactId>restlight-starter-actuator</artifactId>
<version>${restlight.version}</version>
</dependency>
2.start application.
There are some comments like
we should remove or fix it.
目前项目需要整合swagger,方便调试。请问如何整合
not contains the @RequestParam
, the application still start normally.
throw exception
Caused by: java.lang.IllegalArgumentException: There is no suitable resolver to handle param: [MethodParam: io.esastack.demo.controller.HelloController=>hello@name]
can resolve the exception.
does not work.
ExceptionResolver
.@Component
public class GlobalExceptionResolver implements ExceptionResolver<RuntimeException> {
@Override
public CompletionStage<Void> handleException(RequestContext context, RuntimeException exception) {
context.response().status(HttpStatus.FORBIDDEN.code());
context.response().entity(exception.getMessage());
return CompletableFuture.completedFuture(null);
}
}
2.add exception controller
@GetMapping("get/exception")
public void exception() {
throw new RuntimeException("Forbidden");
}
We need more documents to tell users how to use ESA Httpclient
Maybe README or Wiki
@Path("/hello")
public interface HelloService {
@Path("/echo")
String echo(@QueryParam(value = "name") String name);
}
@Service
public class HelloServiceImpl implements HelloService {
@Override
public String echo(String name) {
return name;
}
}
As we show above, if we visit http://127.0.0.1:8080/hello/service?name=LiMing
then we can get 200 response code successfully.
The 404 will be returned.
can work
doesn't work.
1.customize MessageBodyReader
and MessageBodyWriter
like below:
@Provider
@Component
public class BodyReader implements MessageBodyReader<MessageBodyData> {
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public MessageBodyData readFrom(Class<MessageBodyData> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
InputStream entityStream) throws WebApplicationException {
return MessageBodyData.Builder.aBodyMessageData().name("test").build();
}
}
@Provider
@Component
public class BodyWriter implements MessageBodyWriter<MessageBodyData> {
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
@Override
public void writeTo(MessageBodyData messageBodyData, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws WebApplicationException, IOException {
httpHeaders.add("Content-Type", mediaType.getType() + "/" + mediaType.getSubtype());
if (messageBodyData == null) {
entityStream.write("{\"name\": \"test\"}".getBytes(StandardCharsets.UTF_8));
} else {
entityStream.write(new JacksonSerializer().serialize(messageBodyData));
}
}
}
2.request the request api in MessageBodyResource
.
work normal.
throw NPE
io.esastack.restlight.server.bootstrap.WebServerException: java.lang.NullPointerException
at io.esastack.restlight.server.bootstrap.WebServerException.wrap(WebServerException.java:61) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractExecution.resolveArgs(AbstractExecution.java:106) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.lambda$doHandle$0(AbstractRouteExecution.java:92) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:680) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:143) ~[na:na]
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.doHandle(AbstractRouteExecution.java:87) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.LinkedRouteFilterChain.lambda$immutable$0(LinkedRouteFilterChain.java:48) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.spi.impl.RouteTracking.routed(RouteTracking.java:55) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.LinkedRouteFilterChain.doNext(LinkedRouteFilterChain.java:60) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractRouteExecution.handle(AbstractRouteExecution.java:78) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.bootstrap.DispatcherHandlerImpl.service(DispatcherHandlerImpl.java:82) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$null$1(ScheduledHandler.java:83) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:883) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2251) ~[na:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$processByFixedScheduler$2(ScheduledHandler.java:74) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.RequestTaskImpl.run(RequestTaskImpl.java:45) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at esa.commons.concurrent.DirectExecutor.execute(DirectExecutor.java:32) ~[commons-0.2.1-20220331.024855-1.jar:na]
at io.esastack.restlight.server.schedule.ExecutorSchedulerImpl.schedule(ExecutorSchedulerImpl.java:38) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.processByFixedScheduler(ScheduledHandler.java:88) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.lambda$new$0(ScheduledHandler.java:48) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledHandler.process(ScheduledHandler.java:64) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledRestlightHandler.process(ScheduledRestlightHandler.java:116) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.ScheduledRestlightHandler.process(ScheduledRestlightHandler.java:45) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.schedule.AbstractRestlightHandler.process(AbstractRestlightHandler.java:46) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.RestlightHandlerImpl.process(RestlightHandlerImpl.java:75) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.server.bootstrap.NettyRestlightServer.lambda$null$5(NettyRestlightServer.java:254) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.httpserver.impl.BaseRequestHandle.handleEnd(BaseRequestHandle.java:272) ~[httpserver-0.1.1-20211213.125310-5.jar:na]
at io.esastack.httpserver.impl.Http1Handler.end(Http1Handler.java:318) ~[httpserver-0.1.1-20211213.125310-5.jar:na]
at io.esastack.httpserver.impl.Http1Handler.channelRead0(Http1Handler.java:149) ~[httpserver-0.1.1-20211213.125310-5.jar:na]
at io.esastack.httpserver.impl.Http1Handler.channelRead0(Http1Handler.java:57) ~[httpserver-0.1.1-20211213.125310-5.jar:na]
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) ~[netty-codec-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286) ~[netty-handler-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324) ~[netty-codec-4.1.52.Final.jar:4.1.52.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) ~[netty-codec-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.52.Final.jar:4.1.52.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.52.Final.jar:4.1.52.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.52.Final.jar:4.1.52.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.52.Final.jar:4.1.52.Final]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: java.lang.NullPointerException: null
at io.esastack.restlight.core.spi.impl.DefaultStringConverterFactory$1.fromString(DefaultStringConverterFactory.java:43) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.resolver.nav.NameAndStringsValueResolver.resolve(NameAndStringsValueResolver.java:74) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.resolver.nav.NameAndValueResolverAdapter.resolve(NameAndValueResolverAdapter.java:42) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AdvisedParamResolver.resolve(AdvisedParamResolver.java:41) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
at io.esastack.restlight.core.handler.impl.AbstractExecution.resolveArgs(AbstractExecution.java:103) ~[restlight-core-1.0.0-SNAPSHOT.jar:na]
... 65 common frames omitted
1.use the @RequestParam to declare a parameter.
2.request the uri.
The exception shouldn't be logged when the custom ExceptionHandler
can be used to handle it normally.
Even if the exception is handled by ExceptionHandler
normally, it will also
be logged again.
See more information from AbstractHandlerExecution#invoke()
.
We expect that the request which has queued long time should
be discarded before real executing.
More specifically, we can compute the time from decode request
to executed by BizThredPool
, if it's greater than the specified timeout
param, the request shoud be terminated immediately. If so, we can
avoid wasting resources to process requests that have expired.
I hopefully it will support the spring security component
AsyncRequest
and AsyncResponse
provide methods:
AsyncRequest#inputStream()
is holding the aggregated body which has been received completely, It doesn't make much sense to do this.InputStream
that will block until input data is available, which it may block on the IO EventloopGroupAsyncResponse#outputStream()
is writing bytes asynchronously, which means it is allowed to write bytes very frequently without any check of channel's writability and ByteBufAllocator
's allocatability, which may cause an OOM error.OutputStream
that will block until output data is writable, which it may block on the IO EventloopGroupReactive programing
is exactly what we want@GetMapping("/foo")
public void test(@RequestParam String[] bar) {
}
the bar
could be bound as String[] {"a", "b", "c"}
in request whoes uri is /foo?bar=a&bar=b&bar=c
the bar
is bound as String[] {"a"}
what is wrk options ? (like connections and thread)
thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.