简体   繁体   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

I need to add a RESTEasy client to keycloak ( WildFly based distribution).我需要将RESTEasy客户端添加到keycloak (基于WildFly的发行版)。

  1. I create a new class by extending org.keycloak.broker.provider.AbstractIdentityProviderMapper我通过扩展org.keycloak.broker.provider.AbstractIdentityProviderMapper
  2. I define the following code in its constructor我在其构造函数中定义了以下代码
Client client = ClientBuilder.newBuilder().build();
ClientWebTarget target = (ClientWebTarget) client.target(UriBuilder.fromPath(URL_PATH));
CustomFetcher fetcher = target.proxy(CustomFetcher.class);
  1. I add the class to src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper我将 class 添加到src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper

When I copy the jar to keycloak 's standalone/deployments directory I get当我将 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

Apparently Wildfly 's own org.jboss.as.server module is not configured properly, so it doesn't have org.jboss.resteasy.client.jaxrs.internal.proxy.ProxyBuilderImpl on its CLASSPATH , but it exists on the my jar's CLASSPATH , because I can successfully execute显然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")

in the constructor of my class.在我的 class 的构造函数中。

WORKAROUND I added <module name="org.jboss.resteasy.resteasy-client"/> to modules/system/layers/base/org/jboss/as/server/main/module.xml and it works now, but it doesn't seem like a good solution, how do I approach this configuration?解决方法我将<module name="org.jboss.resteasy.resteasy-client"/>添加到modules/system/layers/base/org/jboss/as/server/main/module.xml并且它现在可以工作,但它没有这似乎是一个很好的解决方案,我该如何处理这个配置?

UPDATE I suspect the problem might be with hot redeploy, if I copy the jar to keycloak first and after it I start keycloak , no problems with the CLASSPATH exist.更新我怀疑问题可能出在热重新部署上,如果我jar复制到keycloak ,然后再启动keycloak ,则CLASSPATH不存在任何问题。 But if I copy the jar into standalone/deployments when keycloak is running, then ClassNotFoundException is thrown.但是,如果我在keycloak运行时将jar复制到standalone/deployments中,则会抛出ClassNotFoundException I have tried keycloak-17.0.0.zip , keycloak-17.0.1.zip , keycloak-18.0.0.zip ( WildFly based)我试过keycloak-17.0.0.zipkeycloak-17.0.1.zipkeycloak-18.0.0.zip (基于WildFly

Here is a script to reproduce the issue.这是重现该问题的脚本。 Invoke it with:调用它:

bash script.sh [17.0.0 | 17.0.1 | 18.0.0]

to deploy the jar to local keycloak (the script will download keycloak 's zip archive automatically if it hasn't been downloaded previously).jar部署到本地keycloak (如果之前未下载过,脚本将自动下载keycloakzip存档)。

(*) Parameters in square brackets are optional, default version is 18.0.0 (*) 方括号内参数可选,默认版本为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

The org.jboss.as.server should not have a dependency on the RESTEasy module. org.jboss.as.server不应依赖于 RESTEasy 模块。 You need your deployment to have a dependency on it.您需要您的部署依赖于它。 This should happen by default if the jaxrs subsystem is defined.如果定义了jaxrs子系统,这应该默认发生。

If the jaxrs subsystem is not present, you can add the dependencies to your deployment with either a jboss-deployment-structure.xml or with a manifest entry.如果 jaxrs 子系统不存在,您可以使用jboss-deployment-structure.xml或清单条目将依赖项添加到您的部署中。 For the manifest entry simply add Dependencies: org.jboss.resteasy.resteasy-client services to your META-INF/MANIFEST.MF in your JAR. Note these are comma separated entries so if you need something like the JSON provider you'd need something like:对于清单条目,只需将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

The "services" part just imports the services. “服务”部分只是导入服务。 This may not be required in some cases.在某些情况下可能不需要这样做。

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

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