I'm writing a microservice to interact with my company's Jira server via REST API, with hopes of automating various aspects of our release process. Most of it is going fine, but I'm unable to add a comment to an issue via the REST API. When I try to do it, I receive the following error:
{
"errorMessages": [
"Illegal character ((CTRL-CHAR, code 31)): only regular white space (\\r, \\n, \\t) is allowed between tokens\n at [Source: org.apache.catalina.connector.CoyoteInputStream@63d9221e; line: 1, column: 2]"
]
}The response I get is a 400, with the following stack trace:
org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:1011)
org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:819)
org.glassfish.jersey.client.JerseyInvocation.access$700(JerseyInvocation.java:92)
org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:701)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:228)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:697)
org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:448)
org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:349)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO.executeAddComment(HttpJiraDAO.kt:72)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO$addComment$1.apply(HttpJiraDAO.kt:58)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO$addComment$1.apply(HttpJiraDAO.kt:26)
au.com.ioof.asis.app.component.clients.RetryClient$Policy.lambda$null$0(RetryClient.java:137)
rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:48)
rx.internal.operators.OnSubscribeFromCallable.call(OnSubscribeFromCallable.java:33)
rx.Observable.unsafeSubscribe(Observable.java:10327)
rx.internal.operators.OnSubscribeRedo$2.call(OnSubscribeRedo.java:273)
rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73)
rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52)
rx.internal.operators.OnSubscribeRedo$5.request(OnSubscribeRedo.java:361)
rx.Subscriber.setProducer(Subscriber.java:211)
rx.internal.operators.OnSubscribeRedo.call(OnSubscribeRedo.java:353)
rx.internal.operators.OnSubscribeRedo.call(OnSubscribeRedo.java:47)
rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
rx.Observable.subscribe(Observable.java:10423)
rx.Observable.subscribe(Observable.java:10390)
rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:443)
rx.observables.BlockingObservable.single(BlockingObservable.java:340)
au.com.ioof.asis.app.component.clients.RetryClient$Policy.execute(RetryClient.java:165)
au.com.ioof.asis.ocd.core.dao.http.HttpJiraDAO.addComment(HttpJiraDAO.kt:57)
au.com.ioof.asis.ocd.core.service.SignOffAuditService.auditRelease(SignOffAuditService.kt:49)
au.com.ioof.asis.ocd.resources.ReleaseStagingVerifiedResource.releaseVerified(ReleaseStagingVerifiedResource.kt:25)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
org.glassfish.jersey.internal.Errors.process(Errors.java:315)
org.glassfish.jersey.internal.Errors.process(Errors.java:297)
org.glassfish.jersey.internal.Errors.process(Errors.java:267)
org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
io.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:49)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:35)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
io.dropwizard.jersey.filter.AllowedMethodsFilter.handle(AllowedMethodsFilter.java:45)
io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter(AllowedMethodsFilter.java:39)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:89)
com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:120)
com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:133)
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:239)
io.dropwizard.jetty.RoutingHandler.handle(RoutingHandler.java:52)
org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:455)
io.dropwizard.jetty.BiDiGzipHandler.handle(BiDiGzipHandler.java:67)
org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:56)
org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:169)
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
org.eclipse.jetty.server.Server.handle(Server.java:530)
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:347)
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:256)
org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:289)
org.eclipse.jetty.io.ssl.SslConnection$3.succeeded(SslConnection.java:149)
org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:247)
org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:140)
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:708)
org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:626)
java.lang.Thread.run(Thread.java:748)
Weird thing is, I can do it through Postman just fine. This leads me to suspect that it's something unique to my code, but I can't determine what. My code is as follows:
protected fun executeAddComment(client: Client, issueId: String, comment: JiraComment) {
try {
val response = client.target(UriBuilder.fromPath("$restApi/issue/{issueId}/comment").build(issueId))
.request()
.header(HttpHeaders.AUTHORIZATION, credentials.getBase64EncodedCredentials())
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
.post(Entity.entity(comment, MediaType.APPLICATION_JSON_TYPE), Map::class.java)
} catch (e: BadRequestException) {
LOGGER.error("Stack trace: \n")
e.stackTrace.forEach {
LOGGER.error(it.toString())
}
throw e
}
}Any ideas? I'm happy to post any other bits of my code you need. The Jira Server version I'm POSTing to is 7.7.2. I can also provide versions of any Java libraries I'm using that you're curious about.