You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus 2.16.x/Camel 3.20.1迁移时Validator组件抛出IllegalArgumentException

问题描述

将Quarkus从2.15.0.Final迁移至2.16.x.Final,同时升级Apache Camel从3.19.0到3.20.1后,Validator组件在集成测试和运行时抛出异常,单元测试可正常执行。

旧版本下正常运行的路由代码片段:

from("someUrl")
    .to("validator:schemas/<some xsd>")
    .to("direct:anotherRoute")

新版本抛出的异常:

Caused by: java.lang.IllegalArgumentException: http://www.w3.org/2001/XMLSchema


附加信息

XSD文件

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="header/v1" xmlns:head="header/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="header/v1" elementFormDefault="qualified" version="1">
    <xs:element name="Header" type="Header"/>
    <xs:complexType name="Header">
        <xs:sequence>
            <xs:element name="CorrelationId" type="xs:string" minOccurs="1" maxOccurs="1"/>
            <xs:element name="Caller" type="xs:string" minOccurs="1" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

完整路由代码

import org.apache.camel.PropertyInject;
import org.apache.camel.builder.RouteBuilder;

import javax.enterprise.context.ApplicationScoped;

/**
 * The route.
 */
@ApplicationScoped
public class ValidatorTestEntry extends RouteBuilder {


    @PropertyInject("x.sftp.host")
    private String host;
    @PropertyInject("x.sftp.port")
    private int port;
    @PropertyInject("x.sftp.path")
    private String path;
    @PropertyInject("x.sftp.username")
    private String username;
    @PropertyInject("x.sftp.password")
    private String password;

    /**
     * Ingång i flödet.
     *
     */
    public void configure() {

        from(getSftp())
            .routeId("validatorTestEntry")
            .to("log:info?showAll=true")
            .to("validator:schemas/header_v1.xsd")
            .to("direct:validatorTestExit");
    }

    private String getSftp() {
        return "sftp://" + host + ":" + port + "/" + path +
            "?username=" + username +
            "&password=" + password +
            "&delete=true" +
            "&binary=true" +
            "&knownHostsFile=known_hosts" +
            "&throwExceptionOnConnectFailed=true" +
            "&autoCreate=false" +
            "&readLock=changed" +
            "&bridgeErrorHandler=true";
    }

}

正常运行的单元测试代码

import org.apache.camel.Exchange;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWith;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.support.DefaultExchange;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * The unit test.
 */
public class ValidatorTestEntryTest extends CamelTestSupport {

    @Override
    public boolean isUseAdviceWith() {
        return true;
    }

    @Override
    protected RoutesBuilder createRouteBuilder() {
        return new ValidatorTestEntry();
    }

    @Test
    public void sunshine() throws Exception {

        // arrange
        AdviceWith.adviceWith(context, "validatorTestEntry", route -> {
            route.replaceFromWith("direct:start");
            route.weaveByToUri("direct:validatorTestExit").replace().to("mock:exit");
        });

        MockEndpoint exitMock = getMockEndpoint("mock:exit");
        exitMock.expectedMessageCount(1);

        Exchange exchange = new DefaultExchange(context);
        String body = "<head:Header xmlns:head=\"header/v1\">" +
                "<head:CorrelationId>String</head:CorrelationId>" +
                "<head:Caller>String</head:Caller>" +
                "</head:Header>";
        exchange.getIn().setBody(body);

        // act
        context.start();
        template.send("direct:start", exchange);

        // assert
        exitMock.assertIsSatisfied();
        assertEquals(body, exchange.getIn().getBody(String.class));
    }

}

失败的集成测试代码

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusIntegrationTest;
import org.apache.camel.ConsumerTemplate;
import org.apache.camel.Exchange;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;


/**
 * Integration test with Testcontainers.
 */
@QuarkusTestResource(SftpResources.class)
@QuarkusIntegrationTest
public class ValidatorTestIT {

    private ProducerTemplate producerTemplate;
    private ConsumerTemplate consumerTemplate;

    @BeforeEach
    public void setup() {

        DefaultCamelContext context = new DefaultCamelContext();
        context.start();

        producerTemplate = context.createProducerTemplate();

        consumerTemplate = context.createConsumerTemplate();
    }

    /**
     * End to end.
     */
    @Test
    public void shouldPassEndToEnd() {

        // arrange
        String fileName = "test.xml";

        String expectedBody = "<head:Header xmlns:head=\"header/v1\">" +
                "<head:CorrelationId>String</head:CorrelationId>" +
                "<head:Caller>String</head:Caller>" +
                "</head:Header>";

        String endpointUri = "sftp://localhost:{{x.sftp.port}}/upload" +
                "?username={{x.sftp.username}}&password={{x.sftp.password}}&fileName=" + fileName;
        producerTemplate.sendBody(endpointUri, expectedBody);

        // act
        Exchange actualExchange = consumerTemplate.receive("direct:validatorTestExit", 10000);

        // assert
        assertEquals(expectedBody, actualExchange.getIn().getBody(String.class));
        assertEquals(fileName, actualExchange.getIn().getHeader(Exchange.FILE_NAME, fileName));
    }
}

解决方案

该问题源于Quarkus 2.16.x升级后默认启用了Bean Validation严格模式,导致Validator组件加载XSD时无法正常处理w3c标准Schema引用。以下是几种修复方案:

方法1:快速禁用严格模式

在application.properties中添加配置,关闭Bean Validation的严格模式:

quarkus.bean-validation.strict=false

方法2:配置Validator组件使用Schema缓存

修改路由中的Validator端点,添加schemaCache=true参数,强制缓存已加载的Schema:

.to("validator:schemas/header_v1.xsd?schemaCache=true")

方法3:修正集成测试上下文问题

集成测试中手动创建DefaultCamelContext会脱离Quarkus的托管上下文,导致配置不生效。应注入Quarkus管理的Camel上下文:

import jakarta.inject.Inject;
import org.apache.camel.CamelContext;

// ...

@Inject
CamelContext camelContext;

@BeforeEach
public void setup() {
    producerTemplate = camelContext.createProducerTemplate();
    consumerTemplate = camelContext.createConsumerTemplate();
}

其中方法1是最简便的快速修复方式,方法3能确保集成测试与运行时环境一致,避免配置差异引发的问题。

内容的提问来源于stack exchange,提问作者Magnus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:44:54