Приложение Undertow не запускается при запуске jar с зависимостями

#java #kotlin #undertow

#java #kotlin #undertow

Вопрос:

Я тренируюсь с Kotlin и хочу запустить облегченное приложение Rest. У меня есть опыт работы с Undertow с Jersey, Jackson и Weld CDI на Java.

Я написал минимум для запуска веб-контейнера, и он отлично работает в IntelliJ. Хотя, когда я пытаюсь запустить jar-with-dependencies с помощью java -jar app-with-dependencies.jar , я получаю ошибки.

Основной класс:

 package nl.orhun.samplerestapp

import io.undertow.Handlers
import io.undertow.Undertow
import io.undertow.servlet.Servlets
import io.undertow.servlet.Servlets.servlet
import nl.orhun.samplerestapp.config.JerseyConfig
import org.glassfish.jersey.servlet.ServletContainer
import org.jboss.weld.environment.servlet.Listener

fun main() {
    val servletBuilder = Servlets.deployment()

    servletBuilder.setClassLoader(ClassLoader.getSystemClassLoader())
            .setContextPath("/app")
            .setDeploymentName("app.war")
            .addListener(Servlets.listener(Listener::class.java))
            .addServlets(
                    servlet("jerseyServlet", ServletContainer::class.java)
                            .setLoadOnStartup(1)
                            .addInitParam("javax.ws.rs.Application", JerseyConfig::class.java.name)
                            .addMapping("/rest/*")
            )

    val manager = Servlets.defaultContainer().addDeployment(servletBuilder)
    manager.deploy()

    val path = Handlers.path(Handlers.redirect("/app"))
            .addPrefixPath("/app", manager.start())

    val server = Undertow.builder()
            .addHttpListener(8090, "localhost")
            .setHandler(path)
            .build()
    server.start()
}
  

Ошибка:

 $ java -jar target/nl.orhun.samplerestapi-1.0-SNAPSHOT-jar-with-dependencies.jar
Mar 06, 2019 9:04:48 PM org.jboss.weld.environment.servlet.Listener contextInitialized
INFO: WELD-ENV-001007: Initialize Weld using ServletContextListener
Mar 06, 2019 9:04:48 PM org.jboss.weld.bootstrap.WeldStartup <clinit>
INFO: WELD-000900: 2.4.8 (Final)
Mar 06, 2019 9:04:48 PM org.jboss.weld.bootstrap.WeldStartup startContainer
INFO: WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.glassfish.hk2.osgiresourcelocator.ServiceLoaderImpl because of underlying class loading error: Type org.osgi.framework.BundleListener not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.logging.JBossLogManagerLogger because of underlying class loading error: Type org.jboss.logmanager.Level not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.weld.injection.spi.helpers.ForwardingJpaInjectionServices because of underlying class loading error: Type javax.persistence.EntityManager not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from io.undertow.servlet.osgi.Activator because of underlying class loading error: Type org.osgi.framework.BundleActivator not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.jboss.weld.jsf.FacesUrlTransformer because of underlying class loading error: Type javax.faces.context.FacesContext not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.glassfish.jersey.internal.OsgiRegistry$OsgiServiceFinder because of underlying class loading error: Type org.osgi.framework.SynchronousBundleListener not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.glassfish.jersey.server.internal.scanning.PackageNamesScanner$1 because of underlying class loading error: Type org.osgi.framework.SynchronousBundleListener not found.  If this is unexpected, enable DEBUG logging to see the full error.
Mar 06, 2019 9:04:49 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
<.... truncated...>
Exception in thread "main" java.lang.RuntimeException: org.jboss.weld.exceptions.DeploymentException: Malformed class name
        at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:252)
        at nl.orhun.samplerestapp.MainKt.main(Main.kt:26)
        at nl.orhun.samplerestapp.MainKt.main(Main.kt)
Caused by: org.jboss.weld.exceptions.DeploymentException: Malformed class name
        at org.jboss.weld.executor.AbstractExecutorServices.checkForExceptions(AbstractExecutorServices.java:66)
        at org.jboss.weld.executor.AbstractExecutorServices.invokeAllAndCheckForExceptions(AbstractExecutorServices.java:43)
        at org.jboss.weld.executor.AbstractExecutorServices.invokeAllAndCheckForExceptions(AbstractExecutorServices.java:51)
        at org.jboss.weld.bootstrap.ConcurrentBeanDeployer.addClasses(ConcurrentBeanDeployer.java:58)
        at org.jboss.weld.bootstrap.BeanDeployment.createClasses(BeanDeployment.java:224)
        at org.jboss.weld.bootstrap.WeldStartup.startInitialization(WeldStartup.java:398)
        at org.jboss.weld.bootstrap.WeldBootstrap.startInitialization(WeldBootstrap.java:76)
        at org.jboss.weld.environment.servlet.WeldServletLifecycle.initialize(WeldServletLifecycle.java:191)
        at org.jboss.weld.environment.servlet.Listener.contextInitialized(Listener.java:125)
        at io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
        at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:216)
        at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:185)
        at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
        at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
        at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:250)
        ... 2 more
Caused by: java.lang.InternalError: Malformed class name
        at java.lang.Class.getSimpleBinaryName(Unknown Source)
        at java.lang.Class.isMemberClass(Unknown Source)
        at org.jboss.weld.util.reflection.Reflections.getNesting(Reflections.java:138)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedConstructor.initParameters(BackedAnnotatedConstructor.java:50)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedConstructor.initParameters(BackedAnnotatedConstructor.java:28)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedCallable.<init>(BackedAnnotatedCallable.java:34)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedConstructor.<init>(BackedAnnotatedConstructor.java:38)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedConstructor.of(BackedAnnotatedConstructor.java:32)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType$BackedAnnotatedConstructors.computeValue(BackedAnnotatedType.java:168)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType$BackedAnnotatedConstructors.computeValue(BackedAnnotatedType.java:161)
        at org.jboss.weld.util.LazyValueHolder.get(LazyValueHolder.java:58)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType$EagerlyInitializedLazyValueHolder.<init>(BackedAnnotatedType.java:157)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType$BackedAnnotatedConstructors.<init>(BackedAnnotatedType.java:161)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType$BackedAnnotatedConstructors.<init>(BackedAnnotatedType.java:161)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType.<init>(BackedAnnotatedType.java:62)
        at org.jboss.weld.annotated.slim.backed.BackedAnnotatedType.of(BackedAnnotatedType.java:46)
        at org.jboss.weld.resources.ClassTransformer$TransformClassToBackedAnnotatedType.apply(ClassTransformer.java:80)
        at org.jboss.weld.resources.ClassTransformer$TransformClassToBackedAnnotatedType.apply(ClassTransformer.java:77)
        at org.jboss.weld.util.cache.ReentrantMapBackedComputingCache$1.apply(ReentrantMapBackedComputingCache.java:55)
        at org.jboss.weld.util.cache.ReentrantMapBackedComputingCache$1.apply(ReentrantMapBackedComputingCache.java:51)
        at org.jboss.weld.util.cache.ReentrantMapBackedComputingCache.getValue(ReentrantMapBackedComputingCache.java:64)
        at org.jboss.weld.util.cache.ReentrantMapBackedComputingCache.getCastValue(ReentrantMapBackedComputingCache.java:80)
        at org.jboss.weld.resources.ClassTransformer.getBackedAnnotatedType(ClassTransformer.java:175)
        at org.jboss.weld.resources.ClassTransformer.getBackedAnnotatedType(ClassTransformer.java:192)
        at org.jboss.weld.bootstrap.AnnotatedTypeLoader.loadAnnotatedType(AnnotatedTypeLoader.java:83)
        at org.jboss.weld.bootstrap.AnnotatedTypeLoader.loadAnnotatedType(AnnotatedTypeLoader.java:62)
        at org.jboss.weld.bootstrap.BeanDeployer.addClass(BeanDeployer.java:94)
        at org.jboss.weld.bootstrap.ConcurrentBeanDeployer$1.doWork(ConcurrentBeanDeployer.java:61)
        at org.jboss.weld.bootstrap.ConcurrentBeanDeployer$1.doWork(ConcurrentBeanDeployer.java:58)
        at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:62)
        at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:55)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: -6
        at java.lang.String.substring(Unknown Source)
        ... 35 more

  

Сегмент сборки pom:

  <build>
        <plugins>
            <plugin>
                <artifactId>kotlin-maven-plugin</artifactId>
                <groupId>org.jetbrains.kotlin</groupId>
                <version>${kotlin.version}</version>
                <executions>
                    <execution>
                        <id>compile</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <sourceDirs>
                                <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
                                <sourceDir>${project.basedir}/src/main/java</sourceDir>
                            </sourceDirs>
                        </configuration>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                        <configuration>
                            <sourceDirs>
                                <sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
                                <sourceDir>${project.basedir}/src/test/java</sourceDir>
                            </sourceDirs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>nl.orhun.samplerestapp.MainKt</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
                        <phase>package</phase> <!-- bind to the packaging phase -->
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  

Я думаю, что это как-то связано с тем, как я создаю файл jar, но я не уверен.

Почему мое приложение не запускается при запуске файла jar?

Ответ №1:

Я не использую Undertow, но я использую Weld SE в настройке сервлета, запущенной на Jetty, и, похоже, столкнулся с той же проблемой, что и вы. Мне немного повезло с исключением kotlin-пакетов из проверки обнаружения компонентов в моем beans.xml :

 <?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"
       bean-discovery-mode="all"
       version="1.1">
    <scan>
        ...
        <exclude name="kotlin.**" />
        <exclude name="kotlinx.**" />
    </scan>
</beans>
  

Я попытался отладить проблему, и для меня она java.lang.InternalError: Malformed class name возникла из Java Class.getSimpleBinaryName , вызванной некоторым лямбда-символом в теле kotlin.coroutines.CoroutineContext.plus , с именем kotlin.coroutines.CoroutineContext$plus$1 , которое, по-видимому, имеет заключающий класс, kotlin.coroutines.CoroutineContext$DefaultImpls который на 6 символов длиннее имени лямбда-класса, вызывая IndexOutOfBoundsException при попытке подстроки лямбда-имени с длиной заключающего имени класса, чтобы получить простое имя лямбды. Это может рассматриваться как ошибка в том, как Kotlin называет / вводит лямбды. По крайней мере, в отношении отражения.

Я также попытался воспроизвести проблему, создав этот интерфейс:

 interface Foo {

    fun fooBar(operation: (Foo) -> Foo): Foo

    fun plus(foo: Foo): Foo = fooBar { f -> f.plus(f) }
}
  

И это вызывает ту же проблему ( operator ранее fun или без нее). Однако создание Foo класса и реализация fooBar устраняют проблему. Не знаю почему.

Использование, например, let в теле Foo.plus не вызвало никаких проблем. Вероятно, потому, что let встроено. Так что, если вы можете избежать использования не встроенных лямбд в телах функций интерфейса, возможно, все будет в порядке. И вы всегда можете поместить интерфейс, вызывающий проблемы, в собственный пакет и исключить его из проверки, если вы не собираетесь его внедрять. Надеюсь, эта проблема не является широко распространенной.

Надеюсь, это помогло, несмотря на то, что это не ответ, специфичный для Undertow!

РЕДАКТИРОВАТЬ: Вы можете добавить @JvmDefault (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/index.html ) аннотация к реализованной функции в интерфейсе для создания байт-кода, совместимого с методом по умолчанию (функция Java 8), и, следовательно, устранения проблемы, описанной выше. Обратите внимание, что затем вам нужно указать аргумент компилятора -Xjvm-default=enable or -Xjvm-default=compatibility . В этой статье проливается больше света @JvmDefault :https://realjenius.com/2018/06/29/jvm-default /.