繁体   English   中英

Keycloak 和 RESTEasy 客户端:ClassNotFoundException:org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl

[英]Keycloak and RESTEasy client: ClassNotFoundException: org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl

我需要将RESTEasy客户端添加到keycloak (基于WildFly的发行版)。

  1. 我通过扩展org.keycloak.broker.provider.AbstractIdentityProviderMapper
  2. 我在其构造函数中定义了以下代码
Client client = ClientBuilder.newBuilder().build();
ClientWebTarget target = (ClientWebTarget) client.target(UriBuilder.fromPath(URL_PATH));
CustomFetcher fetcher = target.proxy(CustomFetcher.class);
  1. 我将 class 添加到src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper

当我将 jar 复制到keycloakstandalone/deployments目录时,我得到

20:55:01,522 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-2) MSC000001: Failed to start service jboss.deployment.unit."keycloak-user-mapper-0.0.1-SNAPSHOT.jar".POST_MODULE: org.jboss.msc.service.StartException in service jboss.deployment.unit."keycloak-user-mapper-0.0.1-SNAPSHOT.jar".POST_MODULE: WFLYSRV0153: Failed to process phase POST_MODULE of deployment "keycloak-user-mapper-0.0.1-SNAPSHOT.jar"
        at org.jboss.as.server@18.0.4.Final//org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:189)
        at org.jboss.msc@1.4.13.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1739)
        at org.jboss.msc@1.4.13.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.execute(ServiceControllerImpl.java:1701)
        at org.jboss.msc@1.4.13.Final//org.jboss.msc.service.ServiceControllerImpl$ControllerTask.run(ServiceControllerImpl.java:1559)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
        at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.util.ServiceConfigurationError: org.keycloak.broker.provider.IdentityProviderMapper: Provider org.myorg.UserAttributeMapper could not be instantiated
        at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:582)
        at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:804)
        at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:722)
        at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1395)
        at org.keycloak.keycloak-services@17.0.0//org.keycloak.provider.DefaultProviderLoader.load(DefaultProviderLoader.java:60)
        at org.keycloak.keycloak-services@17.0.0//org.keycloak.provider.ProviderManager.load(ProviderManager.java:94)
        at org.keycloak.keycloak-services@17.0.0//org.keycloak.services.DefaultKeycloakSessionFactory.loadFactories(DefaultKeycloakSessionFactory.java:294)
        at org.keycloak.keycloak-services@17.0.0//org.keycloak.services.DefaultKeycloakSessionFactory.deploy(DefaultKeycloakSessionFactory.java:154)
        at org.keycloak.keycloak-services@17.0.0//org.keycloak.provider.ProviderManagerRegistry.deploy(ProviderManagerRegistry.java:42)
        at org.keycloak.keycloak-wildfly-server-subsystem@17.0.0//org.keycloak.subsystem.server.extension.KeycloakProviderDeploymentProcessor.deploy(KeycloakProviderDeploymentProcessor.java:58)
        at org.jboss.as.server@18.0.4.Final//org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:182)
        ... 8 more
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl from [Module "org.jboss.as.server" version 18.0.4.Final from local module loader @66c92293 (finder: local module finder @332796d3 (roots: /opt/jboss/keycloak/modules,/opt/jboss/keycloak/modules/system/layers/keycloak,/opt/jboss/keycloak/modules/system/layers/base))]
        at org.jboss.resteasy.resteasy-client-api@4.7.4.Final//org.jboss.resteasy.client.jaxrs.ProxyBuilder.builder(ProxyBuilder.java:41)
        at org.jboss.resteasy.resteasy-client@4.7.4.Final//org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.createProxyBuilder(ClientWebTarget.java:107)
        at org.jboss.resteasy.resteasy-client@4.7.4.Final//org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.proxy(ClientWebTarget.java:94)
        at deployment.keycloak-user-mapper-0.0.1-SNAPSHOT.jar//org.myorg.UserAttributeMapper.<init>(UserAttributeMapper.java:55)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
        at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:780)
        ... 17 more
Caused by: java.lang.ClassNotFoundException: org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl from [Module "org.jboss.as.server" version 18.0.4.Final from local module loader @66c92293 (finder: local module finder @332796d3 (roots: /opt/jboss/keycloak/modules,/opt/jboss/keycloak/modules/system/layers/keycloak,/opt/jboss/keycloak/modules/system/layers/base))]
        at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:200)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
        at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
        at org.jboss.resteasy.resteasy-client-api@4.7.4.Final//org.jboss.resteasy.client.jaxrs.ProxyBuilder.builder(ProxyBuilder.java:35)
        ... 25 more

显然Wildfly自己的org.jboss.as.server模块配置不正确,所以它的CLASSPATH上没有org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl ,但它存在于我的 jar 上CLASSPATH ,因为我可以成功执行

Class.forName("org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl")

在我的 class 的构造函数中。

解决方法我将<module name="org.jboss.resteasy.resteasy-client"/>添加到modules/system/layers/base/org/jboss/as/server/main/module.xml并且它现在可以工作,但它没有这似乎是一个很好的解决方案,我该如何处理这个配置?

更新我怀疑问题可能出在热重新部署上,如果我jar复制到keycloak ,然后再启动keycloak ,则CLASSPATH不存在任何问题。 但是,如果我在keycloak运行时将jar复制到standalone/deployments中,则会抛出ClassNotFoundException 我试过keycloak-17.0.0.zipkeycloak-17.0.1.zipkeycloak-18.0.0.zip (基于WildFly

这是重现该问题的脚本。 调用它:

bash script.sh [17.0.0 | 17.0.1 | 18.0.0]

jar部署到本地keycloak (如果之前未下载过,脚本将自动下载keycloakzip存档)。

(*) 方括号内参数可选,默认版本为18.0.0

#! /bin/bash

set -x

mkdir -p so72280865 && cd so72280865 || {
    echo "Unable to create a working directory"
    exit 1
}

cat <<EOF > pom.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.myorg</groupId>
    <artifactId>keycloak-so-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.keycloak</groupId>
                <artifactId>keycloak-parent</artifactId>
                <version>17.0.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-core</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-server-spi</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-server-spi-private</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-services</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxrs</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-client</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jackson2-provider</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>
EOF

mkdir -p src/main/java/org/myorg/

cat <<EOF > src/main/java/org/myorg/App.java
package org.myorg;

import org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget;
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
import org.keycloak.provider.ProviderConfigProperty;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.UriBuilder;
import java.util.Collections;
import java.util.List;

public class App extends AbstractIdentityProviderMapper {

    private static final String URL_PATH = "https://api.myip.com";
    private final CustomFetcher fetcher;

    public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER};

    protected static final List<ProviderConfigProperty> configProperties = Collections.emptyList();

    public App() {
        final Client client = ClientBuilder.newBuilder()
                .register(new org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider())
                .build();
        ClientWebTarget target = (ClientWebTarget) client.target(UriBuilder.fromPath(URL_PATH));
        fetcher = target.proxy(CustomFetcher.class);
    System.out.println(fetcher.get().toString());
    }

    @Path("/")
    public interface CustomFetcher {
        @GET String get();
    }

    @Override
    public String[] getCompatibleProviders() {
        return COMPATIBLE_PROVIDERS;
    }

    @Override
    public String getDisplayCategory() {
        return "Attribute Importer";
    }

    @Override
    public String getDisplayType() {
        return "Custom Fetcher";
    }

    @Override
    public String getHelpText() {
        return "Custom Fetcher";
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        return configProperties;
    }

    @Override
    public String getId() {
        return "custom-fetcher-idp-mapper";
    }
}
EOF

mkdir -p src/main/resources/META-INF/services
cat <<EOF > src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
org.myorg.App
EOF

mvn package

if [ "$?" -ne "0" ] ; then
    exit 1
fi



KEYCLOAK_VERSION=${1:-18.0.0}
[ -f "keycloak-legacy-${KEYCLOAK_VERSION}.zip" ] || {
    curl -LO "https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/keycloak-legacy-${KEYCLOAK_VERSION}.zip"
}

[ -d "keycloak-${KEYCLOAK_VERSION}" ] || {
    unzip "keycloak-legacy-${KEYCLOAK_VERSION}.zip"
} && cp target/keycloak-so-demo-0.0.1-SNAPSHOT.jar "keycloak-${KEYCLOAK_VERSION}"/standalone/deployments &&
    ./"keycloak-${KEYCLOAK_VERSION}"/bin/standalone.sh &

trap "./keycloak-${KEYCLOAK_VERSION}/bin/jboss-cli.sh --connect --command=:shutdown" EXIT

TIMEOUT=180
while true ; do
    started=$(ss -lt | grep 9990 | wc -l)
    [ "$started" -eq "1" ] && break

    [ "$TIMEOUT" -le "0" ] && {
        echo "Timeout reached starting keycloak"
        exit 1
    }
    TIMEOUT=$((TIMEOUT - 10))
    sleep 10
done

cp target/keycloak-so-demo-0.0.1-SNAPSHOT.jar "keycloak-${KEYCLOAK_VERSION}"/standalone/deployments 
sleep 10

org.jboss.as.server不应依赖于 RESTEasy 模块。 您需要您的部署依赖于它。 如果定义了jaxrs子系统,这应该默认发生。

如果 jaxrs 子系统不存在,您可以使用jboss-deployment-structure.xml或清单条目将依赖项添加到您的部署中。 对于清单条目,只需将Dependencies: org.jboss.resteasy.resteasy-client services添加到您的 JAR 中的META-INF/MANIFEST.MF中。请注意,这些条目是逗号分隔的,因此如果您需要类似 JSON 提供商的内容,您将需要就像是:

Dependencies: org.jboss.resteasy.resteasy-client services, org.jboss.resteasy.resteasy-json-p-provider services

“服务”部分只是导入服务。 在某些情况下可能不需要这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM