Tomcat 8 + Spring #EnableAsync = app deployment error - spring

I'm a mobile developer trying to develop a server side app ;-(. It is going well but now, I am facing an annoying problem, trying to run a method in asynchronous way using Spring multitasking. Basically the method is sending an email. I was reading a little about #Async spring annotation and tried to use it in my implementation.
In order to do this I had created this class:
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
#Configuration
#EnableAsync
public class AsynchConfiguration
{
#Bean(name = "asyncExecutor")
public Executor asyncExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsynchThread-");
executor.initialize();
return executor;
}
}
And then in my email service I added a new method:
#Async("asyncExecutor")
public void lostPetSeeAddressAsync(String nameComplete, String to, String petName, String ip, String address, String lat, String lon) throws MessagingException {
lostPetSeeAddress(nameComplete, to, petName, ip, address, lat, lon);
}
Which is just calling my previous synchro method to send emails (lostPetSeeAddress).
But after this code Tomcat is failing to deploy the app. If I remove the AsynchConfiguration class it works well. I tried to set the Async on my xml config but it is failing in the same way. The annoying part of this is the lack of error messages in Tomcat's console.
Perhaps somebody can help me with what I need to do or at least with some hint about how to debug or where to get logs about where and why is Tomcat failing.
Thanks in advance.
Edit: This is the error trace on Eclipse console, when deploy fail:
INFO: Server startup in 33305 ms
Jan 30, 2020 9:37:46 AM org.apache.coyote.http11.AbstractHttp11Processor process
INFO: Error parsing HTTP request header
Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in the HTTP protocol
at org.apache.coyote.http11.AbstractNioInputBuffer.parseRequestLine(AbstractNioInputBuffer.java:345)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1065)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1539)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1495)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

I finally got an error message and could solve the problem. It was caused by a cyclic dependency on com.lowagie library for itext. Here the error message:
Caused by: java.lang.IllegalStateException: Unable to complete the scan for annotations for web application [/app] due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was [org.bouncycastle.asn1.ASN1EncodableVector->org.bouncycastle.asn1.DEREncodableVector->org.bouncycastle.asn1.ASN1EncodableVector]
After solving the com.lowagie library problem, Spring Async configuration works fine.
This is not a real solution but a hint for other people. Because to be honest I still having no idea about why, adding Async Spring configuration rise com.lowagie cyclic dependency problem. Perhaps Async on Spring is using org.bouncycastle? Weird, but perhaps other Spring wise people can enlighten us.

Related

How can I catch the ProvisioningException that can occur when Spring kafka cannot connect to Producer endpoint?

How can I catch the ProvisioningException that can occur when Spring kafka cannot connect to Producer endpoint during Spring-Boot initialization phase?
I am using the lib called spring-cloud-stream, or in my case, more specifically: spring-cloud-starter-stream-kafka .
I assume there must be a way to define a config-Bean, or AOP, that might be able to catch the null error thrown due to connection problems? The existing error is not informative enough when connectivity is gone:
Caused by: java.util.concurrent.TimeoutException: null
at org.apache.kafka.common.internals.KafkaFutureImpl$SingleWaiter.await(KafkaFutureImpl.java:108)
at org.apache.kafka.common.internals.KafkaFutureImpl.get(KafkaFutureImpl.java:272)
at org.springframework.cloud.stream.binder.kafka.provisioning.KafkaTopicProvisioner.createTopicAndPartitions(KafkaTopicProvisioner.java:355)
at org.springframework.cloud.stream.binder.kafka.provisioning.KafkaTopicProvisioner.createTopicIfNecessary(KafkaTopicProvisioner.java:329)
at org.springframework.cloud.stream.binder.kafka.provisioning.KafkaTopicProvisioner.createTopic(KafkaTopicProvisioner.java:306)
I'm talking about the "Bean Creation Phases" documented here: https://reflectoring.io/spring-bean-lifecycle/ which describes how to hook your own code to initialization phases but I want to hook 3rd party code.
NOTE: The bounty is expired. An answer outside of the context of Spring Kafka is ok the answer is still relevant to my question.
NOTE: I found another question that also does not provide a good answer: Spring - catch bean creation exception
you can for example Capture that in ExcepcionHander
#ControllerAdvice
#RestController
public class ExceptionHandler {
#ExceptionHandler(value = {ProvisioningException.class})
public void handleException(ProvisioningExceptione) {
....code....
}
I mean the main paoint is to know when do you get this error....
when invoking a method the method should throw it but instead if it is on the initializacion or something like that, it is diferent. I can see such information in your question, please be more specific

Fault tolerance #Asynchronous on MicroProfile REST client cause open liberty core dump on windows

Fault tolerance #Asynchronous-annotation on a REST client cause a core dump on Windows and the following error on MacOS:
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at ./src/java.instrument/share/native/libinstrument/JPLISAgent.c line: 873
Affected version: (Open Liberty 20.0.0.6/wlp-1.0.41.cl200620200528-0414) on OpenJDK 64-Bit Server VM, version 11.0.8+10-LTS
Used features:
[appSecurity-3.0, beanValidation-2.0, cdi-2.0, concurrent-1.0, distributedMap-1.0, ejbLite-3.2, el-3.0, jaxb-2.2, jaxrs-2.1, jaxrsClient-2.1, jdbc-4.2, jndi-1.0, jpa-2.2, jpaContainer-2.2, json-1.0, jsonb-1.0, jsonp-1.1, monitor-1.0, mpConfig-1.4, mpFaultTolerance-2.1, mpHealth-2.2, mpMetrics-2.3, mpOpenAPI-1.1, mpRestClient-1.4, requestTiming-1.0, servlet-4.0, ssl-1.0, transportSecurity-1.0].
To re-produce:
#ApplicationScoped
#RegisterRestClient(baseUri = "https://postman-echo.com")
public interface TestingClient {
#GET
#Asynchronous
#Path("delay/4")
#Consumes(value = MediaType.APPLICATION_JSON)
CompletionStage<Response> doesItCrashWithDelay(String dummyData);
Inject it:
#Inject
#RestClient
private TestingClient testingClient;
Use it:
#GET
#Path("doesitcrash")
public void doesItCrash() {
final Response response = testingClient.doesItCrashWithDelay("dummydata").toCompletableFuture().join();
logger.info(response.readEntity(String.class));
}
Workaround is to have another CDI bean invoking the rest client which have the fault tolerance annotations. But according to this blog post the REST client interface should be able to have fault tolerance annotations:
https://openliberty.io/blog/2020/06/04/asynchronous-programming-microprofile-fault-tolerance.html
Are #Asynchronous allowed on REST client that is already async due to CompletionStage? As mentioned, all other annotations like #Timeout and #Retry seems to work.
First, you are 100% correct that you don't need the #Asynchronous annotation on the MP Rest Client interface method - per the MP Rest Client specification, a return type of CompletionStage makes it asynchronous. If you remove the #Asynchronous annotation, it should work.
While investigating the JVM error message, I came across this helpful post that indicates that this message means the JVM encountered a super large exception - probably a StackOverflowError. My guess is that the error occurred because there are now two different asynchronous mechanisms (MP Rest Client and MP Fault Tolerance) playing together - and probably not playing nicely. Without seeing the exception stack trace, we won't know for sure.
I would first suggest removing the annotation and verifying that that works - that is probably a better workaround than using a separate CDI bean. Next, I would suggest opening an issue at https://github.com/OpenLiberty/open-liberty/issues to investigate a better overall solution.

Micronaut declarative REST client throws an error - #Introduction method interceptor missing

When I autowire the client interface for my Micronaut declarative client, I get this error:
Caused by: java.lang.IllegalStateException: At least one #Introduction method interceptor required, but missing. Check if your #Introduction stereotype annotation is marked with #Retention(RUNTIME) and #Type(..) with the interceptor type. Otherwise do not load #Introduction beans if their interceptor definitions are missing!
at io.micronaut.aop.chain.InterceptorChain.resolveIntroductionInterceptors(InterceptorChain.java:194)
at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1494)
What's the proper way to fix it?
Details
I have an established Grails application that I recently upgraded from 3.x to 4.0.1.
This app has a service which does several REST calls in parallel, and I am trying to add a new REST call that uses the new Micronaut HTTP declarative client.
I added the client library to dependencies in build.gradle:
compile "io.micronaut:micronaut-http-client"
My client interface looks like this (in src/main/groovy):
package com.mycompany.xyz.rest
import com.mycompany.xyz.rest.myendpoint.Results
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Header
import io.micronaut.http.client.annotation.Client
#Client('xyzRest')
#Header(name = 'myauthkey', value = '${myAuthKey}')
interface XyzRestClient {
#Get('/myendpoint')
Results myendpoint(String param1, String param2)
}
package com.mycompany.xyz.rest.myendpoint
import com.mycompany.xyz.rest.myendpoint.DataItem
import groovy.transform.CompileStatic
#CompileStatic
interface Results extends List<DataItem> {
}
I configured the URL in application.yml:
environments:
development:
micronaut:
http:
services:
xyzRest:
urls:
- http://xyz.mycompany.com/rest/v1
The message about #Introduction makes me think that Micronaut is not doing the process of compiling the declarative client. Is there some
What else am I missing?
Update:
I tried changing the build.gradle dependency to implementation as shown in the Micronaut docs, insteadl of compile, as shown in the Grails docs. No dice.
Update 2:
I found that the constructor for HttpClientIntroductionAdvice is never invoked during startup. I don't know why it's not being included in my project. IntelliJ shows micronaut-http-client:1.1.4 in external libraries, and it's set to compile scope.
A gradlew clean seems to have fixed the issue.
I tried to work backwards and duplicate the problem for posterity's sake, but so far I have not been able to.

Why would "java.lang.IllegalStateException: The resource configuration is not modifiable in this context." appear deploying Jersey app?

I have created an app implementing REST services locally using:
Eclipse Indigo
Jersey 2.4
Tomcat 7.0.47
When running locally using Eclipse, the services work OK, but when deploying my WAR file, I get the following exception when trying to do a GET to one of the services URL:
HTTP Status 500 - Servlet.init() for servlet com.app.rest.MyResourceConfig threw exception
type Exception report
message Servlet.init() for servlet com.app.rest.MyResourceConfig threw exception
description The server encountered an internal error that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: Servlet.init() for servlet com.app.rest.MyResourceConfig threw exception
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
java.lang.Thread.run(Thread.java:662)
root cause
java.lang.IllegalStateException: The resource configuration is not modifiable in this context.
org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:270)
org.glassfish.jersey.server.ResourceConfig$ImmutableState.register(ResourceConfig.java:218)
org.glassfish.jersey.server.ResourceConfig.register(ResourceConfig.java:448)
org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:300)
org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:167)
org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:349)
javax.servlet.GenericServlet.init(GenericServlet.java:160)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
java.lang.Thread.run(Thread.java:662)
I've been unable to find yet a root cause and my only suspicion is that it might be a missing running dependency or some other configuration in Eclipse that differ from my own local Tomcat server environment and the Tomcat at remote server.
My code at the resource configuration class is:
package com.app.rest;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
import com.app.rest.services.RunDetailsService;
import com.app.rest.services.RunHistoryService;
import com.app.rest.services.RunPollService;
import com.app.rest.services.RunTestService;
#ApplicationPath("api")
public class MyResourceConfig extends ResourceConfig {
public MyResourceConfig() {
register(RunHistoryService.class).
register(RunTestService.class).
register(RunDetailsService.class).
register(RunPollService.class);
}
}
What do you think would be a possible cause?
One possible cause is that you have two or more applicable mappings for that URL call.
For example:
#Path("/{myParam}")
And somewhere else:
#Path("/{differentParam}")
Now Jersey have no way of telling what method is actually supposed to be called and gives this error.
I managed to cause the same error, and this was due to two situations:
The definition of paths within the resources ws MUST NOT start from a "/xyz" just be "xyz" to ResourceConfig #ApplicationPath ("/").
Also occurs due to the dependence of any API (jar) in the .war project or tomcat/lib.
It also occurs when there is ambiguity in the resource path (duplicates same name) is presented in the following log:
WARNING: A resource model has ambiguous (sub-)resource method for
HTTP method GET and input mime-types as defined by #Consumes and
#Produces annotations at Java methods public
javax.ws.rs.core.Response
Environment: Netbeans 8.1, Apache Tomcat 8.0.12, JAX-RS 2.0 (Jersey 2.12)
In my case, I had a Jersey POST resource for file uploads.
The resource specified the parameter:
#FormDataParam("file") InputStream file
and consumed MediaType.MULTIPART_FORM_DATA.
To fix the issue, I had to add the following to the Jersey REST configuration in my web.xml file:
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
</init-param>
Posting very late for anyone that stumbles across this problem. I had the exact same problem - worked locally in eclipse, but when I tried to deploy outside of Eclipse, it crashed and burned with the same stack trace in the question. The problem was due to double deployment of our webapps due to improper naming of the war files we were deploying.
When autoDeploy is set to true, tomcat expects a VERY specific naming convention of .war files that is related to the context path. For example, the context path “/foo/bar” must have a corresponding .war file named “foo#bar.war”. Additionally, a context path mapped to “/” or “” expects a war file called ROOT.war.
The complete naming rules can be found here: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Naming
Fixing the names of the war files solved the problem.
I also want to note that, eventually, eclipse also choked on the issue for me. Occasionally, doing a clean of the project and trying to re-run will fix the problem, but not every time, and I'm not sure why it fixes it. I'm still trying to find a complete solution. Solving the problem for eclipse is a bit harder because (as far as I know) I can't specify the name of the directory where eclipse publishes the project. For example, a project in eclipse named "foo" whose context root is "bar/baz" will be published in a directory named "foo" rather than "bar#baz" and tomcat/Jersey does not seem to like that.
I hope this helps save someone the 12+ hours it took me and my team to debug this problem the night before a demo :)
The above exception might be a consequence exception when Jersey cannot inject some user type into e.g. #QueryParam/#PathParam. E.g. you haven't registered your ParamConverterProvider. Look above in the logs, for the first exception trace.
I resolved my case with:
#Component
public static class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
this.register(LocalDateParamProvider.class);
}
}
(I use Spring.) When I inserted the above register() call, the exception has gone.
Not sure if this is still a problem for you but I have recently come across the same issue. However, after digging further into my code I discovered that this error was being thrown because of the following method signature:
public void parseData(#FormParam("data") Collection data)
Once I had tracked the error to this line, I did some googleing and discovered that using the #FormParam with Collection<> does not work.
The solution is to use List<> instead:
public void parseData(#FormParam("data") List data)
Hopefully this will be helpful to anyone finding this post in the future as the error message is really not very useful!
I've experienced the same error message. I posted about it in my blog (spanish).
Reading the above answers and adding up my own experience I can tell that if you see this exception thrown it actually is an initialization problem. Look at syntax changes or code that is executed during initialization. Check your container logs (like catalina.out on Tomcat).
Another possible reason for getting that exception is if you try passing in a form parameter using #FormParam with an HTTP Get (#GET). It should complain since you cannot pass data in the form body with an HTTP Get. An example of code that would throw this exception is...
#GET
#Path("test-get")
#Consumes( MediaType.APPLICATION_FORM_URLENCODED )
public String testGet(#FormParam("name1") String name1) {
Apparently the main causes of failure is because there is duplicate reference in the services path, this is multiple path ("/"), as well as the existence of resources without defined path or such resource classes do not count Less with some defined (#GET, #POST, #UPDATE, #DELETE, ...) method.
In order to solve this, a path (not duplicated) must be indicated for each resource and at least in each resource there must be one or more published methods, the lack of these methods in different versions of jersey could cause this exception.
Example:
package com.contpaq.tech.service.resources;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("/")
public class RootSrv {
#GET
#Produces(MediaType.TEXT_PLAIN + ";charset=utf-8")
public Response getVersion() {
return Response.ok().entity("NodeServer Versión 0.6.69").build();
}
}
I got the same error message.
For me the problem was, that I used #RequestMapping (a Spring annotation) instead of the #QueryParam (JAX-RS annotation) on a method argument due to a copy paste.
The error message was not that informative, but that was the problem for me.
I solved this problem by adding this code into web.xml file
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
In my case it was just a missing #PathParam("id") for the 'int id' declaration.
Wrong code:
#POST
#Path("{id}/messages")
public Response returnMessages(int id, Message[] msgs) {
Corrected code:
#POST
#Path("{id}/messages")
public Response returnMessages(#PathParam("id") int id, Message[] msgs) {
Try to undeploy the ROOT.war in the localhost:8080/manager e redeploy your WAR with this name (ROOT.war), then try again.
That worked for me.
The issue in my case is that the shaded jar did not include the javassist package that Jersey uses to do bytecode manipulation. When shading a jar, make sure to include org.javassist:*.
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.26.0-GA</version>
</dependency>
You can get "java.lang.IllegalStateException" if you close connection to database (especially if this is main connection initialized via web.xml as listener-class which is Servlet) and later on when next request is sent, since no connection to database is available this exception can be thrown.
In my case I found in the middle of some execution mongoClient.close()
In my case i was importing #PathParam from javax.websocket.server.PathParam and not javax.ws.rs.PathParam..
Add
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>

Spring cannot load java based configuration

I want to create a Solr data import handler using Spring as the Ioc. When I try to invoke the handler from Solr, I got below error
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to load bean class: com.yoox.shanghai.AppConfig; nested exception is java.io.FileNotFoundException: class path resource **[com/my/app/AppConfig.class]** cannot be opened because it does not exist
Note the path printed in the message. It looks like it is using a relative path. I have no idea what is the cause.
I am using the Java based container configuration, and the compilation passes. And my code works with JUnit4.
appCtx = new AnnotationConfigApplicationContext(AppConfig.class);
Are you sure that you import AppConfig properly? Otherwise make sure that the class has really been deployed (check the deployment directory).
I googled for a long time, but could not find any answer about how spring resolve the class path by default. But I found people are trying to explicitly set the class loader, so I tried.
appCtx = new AnnotationConfigApplicationContext();
appCtx.setClassLoader(this.getClass().getClassLoader());
appCtx.register(AppConfig.class);
appCtx.refresh();
And it works :D
However I am not satisfied with this answer. I hope some one can point out what's wrong with my class loading logic.

Resources