Kotlin class servlet provoke NoClassDefFoundError - kotlin

In a sample Java servlet project in my IntelliJ IDE, i have created this class in Kotlin :
#WebServlet(name = "TwitterAPIServlet", description = "This is used to test the servlet api", urlPatterns = ["/twitterAPIServlet"])
class TwitterAPIServlet : HttpServlet() {
#Throws(IOException::class)
override fun doGet(req: HttpServletRequest, resp: HttpServletResponse) {
// Print answer
val out = resp.writer
out.println("Request Done : </br>")
}
}
When i am trying to call this with my .jsp page, i have this error :
2020-05-10 15:30:34.218:WARN:oejs.HttpChannel:qtp60559178-27: /twitterAPIServlet
java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
at main.java.co.rezo.api.internal.v1.TwitterAPIServlet.doGet(TwitterAPIServlet.kt)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
When i am trying the same code in Java, it's working :
#WebServlet(
name = "TwitterAPIServlet",
description = "This is used to test the servlet api",
urlPatterns = "/twitterAPIServlet")
public class TwitterAPIServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
PrintWriter out = resp.getWriter();
out.println("Request Done : </br>");
}
}
What can i do to make my Kotlin code working?

Most probably the issue is that Kotlin's standard library is not included in the generated WAR (or is not on a classpath if you run the exploded app). Make sure to include it in your build.
Instructions for Gradle can be found in the official examples repository: kotlin-examples.
Maven is similar: https://kotlinlang.org/docs/reference/using-maven.html.
In case of pure IDEA (though it's recommended to use one of the build tools above), check the projects settings:
You should see Kotlin's stdlib included in the artifact:

Related

java.lang.UnsupportedOperationException: Packages and file facades are not yet supported in Kotlin reflection

When starting a basic Ktor app, I get:
Exception in thread "main" java.lang.UnsupportedOperationException: Packages and file facades are not yet supported in Kotlin reflection. Meanwhile please use Java reflection to inspect this class: class com.example.ApplicationKt
at kotlin.reflect.jvm.internal.KClassImpl.reportUnresolvedClass(KClassImpl.kt:301)
at kotlin.reflect.jvm.internal.KClassImpl.access$reportUnresolvedClass(KClassImpl.kt:43)
at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:53)
at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:44)
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
at kotlin.reflect.jvm.internal.KClassImpl$Data.getDescriptor(KClassImpl.kt)
at kotlin.reflect.jvm.internal.KClassImpl$Data$objectInstance$2.invoke(KClassImpl.kt:106)
at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
at kotlin.reflect.jvm.internal.KClassImpl$Data.getObjectInstance(KClassImpl.kt)
at kotlin.reflect.jvm.internal.KClassImpl.getObjectInstance(KClassImpl.kt:239)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createModuleContainer(ApplicationEngineEnvironmentReloading.kt:328)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.executeModuleFunction(ApplicationEngineEnvironmentReloading.kt:317)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:275)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:127)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:247)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:106)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:18)
at io.ktor.server.engine.ApplicationEngine$DefaultImpls.start$default(ApplicationEngine.kt:52)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:17)
at com.example.ApplicationKt.main(Application.kt:10)
The app is just:
fun main(args: Array<String>): Unit = EngineMain.main(args)
fun Application.demoModule() {
routing {
get("/") {
call.respondText("Hello ${call.parameters["name"]}")
}
}
}
I just noticed the file resources.application.conf had an issue.
It had the wrong module name. I changed com.example.ApplicationKt.module to com.example.ApplicationKt.demoModule:
ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ com.example.ApplicationKt.demoModule ]
}
}
What's annoying is that the error help says nothing about it.

Quarkus Vert.x Example

I want to test Quarkus and the native image for Docker with an existing project written in Kotlin and using Vert.x verticles.
Can you point me to an example on how to deploy verticles using Quarkus?
My dependencies are vertx-sockjs-service-proxy and vertx-lang-kotlin.
I found some examples in the Vert.x extension tests but I cannot find how to deploy my verticles at server startup.
#Inject
EventBus eventBus;
#Route(path = "/hello-event-bus", methods = GET)
void helloEventBus (RoutingExchange exchange){
eventBus.send("hello", exchange.getParam("name").orElse("missing"), ar -> {
if (ar.succeeded()) {
exchange.ok(ar.result().body().toString());
} else {
exchange.serverError().end(ar.cause().getMessage());
}
});
}
You can use verticle as follows:
#Inject Vertx vertx;
void onStart(#Observes StartupEvent ev) {
vertx.deploy(new MyVerticleA());
vertx.deploy(new MyVerticleB());
}

CDI doesn't work in a simple adapter

I've added the CDI feature to the server.xml file<feature>cdi-1.2</feature>.
My maven module contains the beans.xml inside the <module_name>/src/main/resources/META-INF folder.
This is the beans.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
But when I use the #Inject annotation it doesn't work, my bean is always null.
Code:
package ch.webapp.presentation;
...
#Path("/test/")
public class MyController {
#Inject
private MyService myService;
#GET
#Path("/foo/{count}")
#OAuthSecurity(scope = "login")
#Produces("application/json")
public Response news(#PathParam("count") int count) {
return Response
.ok(myService.getBar(count))
.build();
}
}
EDIT:
That's my bean
package ch.webapp.service;
...
#RequestScoped
public class MyService {
public String getBar(int count) {
return "foo";
}
}
I initialize jax-rs by extended the MFPJAXRSApplication class
package ch.webapp;
...
public class AccountApplication extends MFPJAXRSApplication {
#Override
protected void init() throws Exception {
}
#Override
protected void destroy() throws Exception {
}
#Override
protected String getPackageToScan() {
return getClass().getPackage().getName();
}
}
Environment details:
Launching mfp (WebSphere Application Server 8.5.5.8/wlp-1.0.11.cl50820151201-1942) on Java HotSpot(TM) 64-Bit Server VM, version 1.8.0_172-b11 (en_CH)
Console Product version: 8.0.0.00-20180717-175523
What's wrong?
First it seems that websphere jax-rs implementation does not integrate jax-rs resources automatically unless you annotate them appropriately.
Put the jax-rs in a CDI managed context by annotating it appropriately
#Path("/test/")
#javax.enterprise.context.RequestScoped
public class MyController {
#Inject
private MyService myService;
#GET
#Path("/foo/{count}")
#OAuthSecurity(scope = "login")
#Produces("application/json")
public Response news(#PathParam("count") int count) {
return Response
.ok(myService.getBar(count))
.build();
}
}
Also be sure that the annotation used for your service is
#javax.enterprise.context.RequestScoped
Based on the inputs provided by you please go through the below checklist.
Your services and controllers are in the same module and its packaging type is war, So you must place your beans.xml in this path src/main/resources/WEB-INF/beans.xml. (If this is Java EE 7 application then beans.xml is optional.
In your AccountApplication class try hardcoding the package name to ch.webapp.presentation
#Override
protected String getPackageToScan() {
return "ch.webapp.presentation";
}
This is just to check Behaviour of MFPJAXRSApplication.getPackageToScan() method whether it is scanning the specified package only or its child packages too.
Except these, everything seems fine to me. If this still doesn't work add complete application startup logs so that community can find the root cause of it.
This is classical mistake. CDI works for managed beans (for instance EJB's and servlets). If you want to enable it on your JAXRS bean, you have to make it "managed", that is annotate MyController as (for instance) javax.annotation.ManagedBean or as a javax.ejb.Stateless.
Also beware that in case of webapp (.war), the beans.xml file has to be located in the WEB-INF folder !

#BeanParam does not work with Apache CXF 3.0.x

I am trying to use #BeanParam annotation from JAX-RS.
It was working perfectly fine with Apache cxf 2.7.7 but after upgrading to Apache cxf 3.0.1 it does not work. In my rest service, bean param is null and i get NullPointerException.
I have tried with cxf 3.0.3 but result is same.
My RestService looks like
Class MyService {
#BeanParam
private MyBean params;
#Path("/test")
public Response testIt() {
// params is null here
}
}
class MyBean {
#QueryParam
private String message;
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
My dependency in gradle looks like
def cxfVersion = "3.0.1"
ext.libraries = [
cxf: [
"org.apache.cxf:apache-cxf:$cxfVersion",
"org.apache.cxf:cxf-rt-frontend-jaxrs:$cxfVersion"
]
Does anybody have any idea what has changed form cxf 2.7.7 to cxf 3.0.x, that will make this non functioning.
I found the problem. It was due to presence of another cxf version jar present on classpath (version 2.3.3) coming from other projects dependencies. Somehow that was getting the precedence over 3.x version and that didn't had support for BeanParam.
Removing that jar from classpath worked for me.

How can I configure a Swagger in Glassfish 4 without a web.xml?

The Swagger documentation covers a number of different ways to configure Swagger in an application. Unfortunately all of them leverage web.xml and rely on hard coding the api version and base url in the web.xml
Is there a way to configure Swagger without using a web.xml and without hardcoding the api version and base path?
I used the following approach to configure Swagger in Glassfish 4 without a resource XML.
Includes the following dependency in by gradle build file (this approach also applies to Maven):
compile ('com.wordnik:swagger-jaxrs_2.9.1:1.3.0') {
exclude group: 'org.scala-lang', module: 'scala-compiler'
}
Create a class that extends javax.ws.rs.core.Application and configure the ApplicationPath e.g.
#ApplicationPath("resources")
public class RESTConfig extends Application {}
2a. Create a class that extends com.wordnik.swagger.jaxrs.config.DefaultJaxrsConfig and annotate as follows:
#WebServlet(name = "SwaagerJaxrsConfig" initParams = {#WebInitParam(name="api.version", value="0.1.0"), #WebInitParam(name="swagger.api.basepath", value="http://localhost:8080/resources"})}, loadOnStartup = 2)
public class SwaagerJaxrsConfig extends DefaultJaxrsConfig{}
The downside of this approach is that the api version and base url of your app is hardcoded in the annotation. In order to get around this I used the following approach instead of the one above
2b. Create a class that extends HttpServlet and performs the bootstrapping done by DefaultJaxrsConfig e.g.
#WebServlet(name = "SwaggerJaxrsConfig", loadOnStartup = 2)
public class SwaggerJaxrsConfig extends HttpServlet {
private Logger log = Logger.getLogger(SwaggerJaxrsConfig.class);
#Inject Version version;
#Override public void init(ServletConfig servletConfig) {
try {
super.init(servletConfig);
SwaggerConfig swaggerConfig = new SwaggerConfig();
ConfigFactory.setConfig(swaggerConfig);
swaggerConfig.setBasePath("http://localhost:8080/resources"); //TODO look up app path
swaggerConfig.setApiVersion(version.getVersion());
ScannerFactory.setScanner(new DefaultJaxrsScanner());
ClassReaders.setReader(new DefaultJaxrsApiReader());
} catch (Exception e) {
log.error("Failed to configure swagger", e);
}
}
}