Skip to content

Commit

Permalink
io.quarkus.builder.ChainBuildException: Cycle detected fix #860
Browse files Browse the repository at this point in the history
  • Loading branch information
ppalaga committed Aug 16, 2023
1 parent 9579173 commit 52da654
Show file tree
Hide file tree
Showing 5 changed files with 3 additions and 74 deletions.
2 changes: 1 addition & 1 deletion docs/modules/ROOT/examples/calculator-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.quarkiverse.cxf</groupId>
<artifactId>quarkus-cxf-integration-tests</artifactId>
<version>2.2.1-SNAPSHOT</version>
<version>2.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 0 additions & 2 deletions docs/modules/ROOT/pages/includes/quarkus-cxf.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,6 @@ If `true`, the client dynamic proxy class generated by native compiler will be i

Setting this to `true` makes sense if your service endpoint interface references some class initialized at runtime in its method signatures. E.g. Say, your service interface has method `int add(Operands o)` and the `Operands` class was requested to be initialized at runtime. Then, without setting this configuration parameter to `true`, the native compiler will throw an exception saying something like `Classes that should be initialized at run time got initialized during image building: org.acme.Operands ... jdk.proxy<some-number>.$Proxy<some-number> caused initialization of this class`. `jdk.proxy<some-number>.$Proxy<some-number>` is the proxy class generated by the native compiler.

While `quarkus-cxf` can auto-detect the proper setting in some cases, the auto-detection is not perfect. This is because runtime initialization of classes can be requested in many ways out of which only the ones done via Quarkus `RuntimeInitializedClassBuildItem` and `RuntimeInitializedPackageBuildItem` can safely be observed by `quarkus-cxf`. In other cases, you'll have to set this manually.

ifdef::add-copy-button-to-env-var[]
Environment variable: env_var_with_copy_button:+++QUARKUS_CXF_CLIENT__CLIENTS__NATIVE_RUNTIME_INITIALIZED+++[]
endif::add-copy-button-to-env-var[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import jakarta.enterprise.context.ApplicationScoped;
Expand Down Expand Up @@ -54,8 +52,6 @@
import io.quarkus.deployment.builditem.NativeImageFeatureBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedPackageBuildItem;
import io.quarkus.deployment.util.IoUtil;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
Expand All @@ -75,21 +71,12 @@ public class CxfClientProcessor {
void collectClients(
CxfFixedConfig config,
CombinedIndexBuildItem combinedIndexBuildItem,
List<RuntimeInitializedClassBuildItem> runtimeInitializedClasses,
List<RuntimeInitializedPackageBuildItem> runtimeInitializedPackages,
BuildProducer<NativeImageFeatureBuildItem> nativeImageFeatures,
BuildProducer<NativeImageProxyDefinitionBuildItem> proxies,
BuildProducer<CxfClientBuildItem> clients,
BuildProducer<ClientSeiBuildItem> clientSeis) {
IndexView index = combinedIndexBuildItem.getIndex();

final Set<String> rtInitClasses = runtimeInitializedClasses.stream()
.map(RuntimeInitializedClassBuildItem::getClassName)
.collect(Collectors.toSet());
final Set<String> rtInitPackages = runtimeInitializedPackages.stream()
.map(RuntimeInitializedPackageBuildItem::getPackageName)
.collect(Collectors.toSet());

final AtomicBoolean hasRuntimeInitializedProxy = new AtomicBoolean(false);
final Map<String, ClientFixedConfig> clientSEIsInUse = findClientSEIsInUse(index, config);
CxfDeploymentUtils.webServiceAnnotations(index)
Expand Down Expand Up @@ -121,8 +108,6 @@ void collectClients(
Optional.ofNullable(clientConfig.native_).map(native_ -> native_.runtimeInitialized)
.orElse(false),
wsClassInfo,
rtInitClasses,
rtInitPackages,
index);
proxies.produce(new NativeImageProxyDefinitionBuildItem(proxyInfo.interfaces));

Expand Down Expand Up @@ -469,70 +454,19 @@ private static class ProxyInfo {
public static ProxyInfo of(
boolean refersToRuntimeInitializedClasses,
ClassInfo wsClassInfo,
Set<String> rtInitClasses,
Set<String> rtInitPackages,
IndexView index) {
final List<String> result = new ArrayList<>();
result.add(wsClassInfo.name().toString());
result.add(BindingProvider.class.getName());
result.add("java.io.Closeable");
result.add(Client.class.getName());

if (!refersToRuntimeInitializedClasses) {
/* Try to auto-detect unless the user decided himself */
Predicate<String> isRuntimeInitializedClass = className -> rtInitClasses.contains(className)
|| rtInitPackages.contains(getPackage(className));
refersToRuntimeInitializedClasses = refersToRuntimeInitializedClasses(
wsClassInfo,
isRuntimeInitializedClass,
index);
}

if (refersToRuntimeInitializedClasses) {
result.add(io.quarkiverse.cxf.CxfClientProducer.RUNTIME_INITIALIZED_PROXY_MARKER_INTERFACE_NAME);
}
return new ProxyInfo(result, refersToRuntimeInitializedClasses);
}

static String getPackage(String className) {
int lastDot = className.lastIndexOf('.');
if (lastDot < 0) {
return "";
}
return className.substring(0, lastDot);
}

private static boolean refersToRuntimeInitializedClasses(ClassInfo wsClassInfo,
Predicate<String> isRuntimeInitializedClass, IndexView index) {
if (isRuntimeInitializedClass.test(wsClassInfo.name().toString())) {
return true;
}
boolean ownMethods = wsClassInfo.methods().stream()
.filter(m -> (m.flags() & java.lang.reflect.Modifier.STATIC) == 0) // only non-static methods
.anyMatch(m -> isRuntimeInitializedClass.test(m.returnType().name().toString())
|| m.parameterTypes().stream()
.map(Type::name)
.map(DotName::toString)
.anyMatch(isRuntimeInitializedClass));
if (ownMethods) {
return true;
}

/* Do the same recursively for all interfaces */
return wsClassInfo.interfaceNames().stream()
.map(intf -> {
final ClassInfo cl = index.getClassByName(intf);
if (cl == null) {
LOGGER.warnf(
"Could not check whether %s refers to runtime initialized classes because it was not found in Jandex",
intf);
}
return cl;
})
.filter(cl -> cl != null)
.anyMatch(cl -> refersToRuntimeInitializedClasses(cl, isRuntimeInitializedClass, index));
}

private ProxyInfo(List<String> interfaces, boolean isRuntimeInitialized) {
super();
this.interfaces = interfaces;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ public static class NativeClientFixedConfig {
* configuration parameter to {@code true}, the native compiler will throw an exception saying something like
* {@code Classes that should be initialized at run time got initialized during image building: org.acme.Operands ... jdk.proxy<some-number>.$Proxy<some-number> caused initialization of this class}.
* {@code jdk.proxy<some-number>.$Proxy<some-number>} is the proxy class generated by the native compiler.
* <p>
* While {@code quarkus-cxf} can auto-detect the proper setting in some cases, the auto-detection is not perfect.
* This is because runtime initialization of classes can be requested in many ways out of which only the ones
* done via Quarkus {@code RuntimeInitializedClassBuildItem} and {@code RuntimeInitializedPackageBuildItem}
* can safely be observed by {@code quarkus-cxf}. In other cases, you'll have to set this manually.
*/
@ConfigItem(defaultValue = "false")
public boolean runtimeInitialized;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ quarkus.cxf.client.imageServiceClient.client-endpoint-url = http://localhost:${q
quarkus.cxf.client.imageServiceClient.service-interface = io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageService
quarkus.cxf.client.imageServiceClient.endpoint-namespace = "https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test/mtom-awt"
quarkus.cxf.client.imageServiceClient.endpoint-name = ImageService
quarkus.cxf.client.imageServiceClient.native.runtime-initialized = true

quarkus.cxf.endpoint."/mtom-aws-with-wrappers".implementor = io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageServiceWithWrappersImpl
quarkus.cxf.endpoint."/mtom-aws-with-wrappers".features = org.apache.cxf.ext.logging.LoggingFeature
Expand All @@ -16,3 +17,4 @@ quarkus.cxf.client.imageServiceClientWithWrappers.client-endpoint-url = http://l
quarkus.cxf.client.imageServiceClientWithWrappers.service-interface = io.quarkiverse.cxf.it.ws.mtom.awt.server.ImageServiceWithWrappers
quarkus.cxf.client.imageServiceClientWithWrappers.endpoint-namespace = "https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test/mtom-awt-with-wrappers"
quarkus.cxf.client.imageServiceClientWithWrappers.endpoint-name = ImageServiceWithWrappers
quarkus.cxf.client.imageServiceClientWithWrappers.native.runtime-initialized = true

0 comments on commit 52da654

Please sign in to comment.