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

Reactive方式返回Token遇序列化异常:无UniOnItemTransform序列化器

解决Hilla/Quarkus Reactive接口返回Uni的序列化异常

问题描述

在使用Hilla的@BrowserCallable接口AuthenticationApi中,尝试通过Reactive方式返回Token时,遭遇序列化异常:

Failed to serialize endpoint 'AuthenticationApi' method 'token' response. Double check method's return type or specify a custom mapper bean with qualifier 'endpointMapperFactory': com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class io.smallrye.mutiny.operators.uni.UniOnItemTransform and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

核心代码:

@Inject
private final CurrentIdentityAssociation identityAssociation;

public Uni<String> token() {
    return identityAssociation.getDeferredIdentity()
        .onItem().transform(identity -> identity.getCredential(AccessTokenCredential.class))
        .onItem().transform(accessTokenCredential -> accessTokenCredential.getToken());
}

完整接口类:

package net.shamil.dcc.api;

import java.util.List;

import com.vaadin.flow.server.auth.AnonymousAllowed;

import dev.hilla.BrowserCallable;
import dev.hilla.Nonnull;
import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.oidc.UserInfo;
import io.quarkus.security.identity.CurrentIdentityAssociation;
import io.smallrye.mutiny.Uni;
import lombok.AllArgsConstructor;
import net.shamil.dcc.authentication.OidcUser;
import net.shamil.dcc.authentication.SingleSignOnContext;
import net.shamil.dcc.authentication.SingleSignOnData;

@BrowserCallable
@AnonymousAllowed
@AllArgsConstructor
public class AuthenticationApi {
    private final SingleSignOnContext context;
    private final UserInfo userInfo;
    private final CurrentIdentityAssociation identityAssociation;


    public @Nonnull SingleSignOnData fetchAll() {
        return context.getSingleSignOnData();
    }

    // public String token() {
    //     return Optional.ofNullable(securityIdentity.getCredential(AccessTokenCredential.class)).map(token -> token.getToken()).orElse(null);
    // }

    public Uni<String> token() {
        return identityAssociation.getDeferredIdentity()
        .onItem().transform(identity -> identity.getCredential(AccessTokenCredential.class))
        .onItem().transform(accessTokenCredential -> accessTokenCredential.getToken());
    }

    public @Nonnull List<@Nonnull String> getRegisteredProviders() {
        return context.getRegisteredProviders();
    }

    public OidcUser getAuthenticatedUser() {
        return context.getSingleSignOnData().isAuthenticated() ? OidcUser.fromUserInfo(userInfo) : null;
    }
}

当前依赖包含:

quarkus-resteasy-reactive
quarkus-resteasy-reactive-jackson
quarkus-oidc-client-reactive-filter

原因分析

Hilla的端点序列化机制默认未配置对SmallRye Mutiny Uni类型的支持,Jackson无法找到对应的序列化器,因此抛出序列化异常。

解决方案

方案1:添加Mutiny-Jackson序列化依赖(推荐)

在pom.xml中添加SmallRye Mutiny与Jackson的集成依赖,让Jackson能够正确序列化Uni类型:

<dependency>
    <groupId>io.smallrye</groupId>
    <artifactId>smallrye-mutiny-jackson</artifactId>
</dependency>

添加后,Hilla端点会自动订阅Uni并返回最终的String结果,无需修改现有代码。

方案2:改为同步返回String(适合不需要Reactive的场景)

如果业务场景允许同步获取Token,可以修改token()方法,通过await()获取Uni的结果:

public String token() {
    return Optional.ofNullable(identityAssociation.getDeferredIdentity()
            .await().indefinitely()
            .getCredential(AccessTokenCredential.class))
            .map(AccessTokenCredential::getToken)
            .orElse(null);
}

注意:await().indefinitely()会阻塞当前线程,需确保在允许阻塞的上下文环境中使用。

方案3:临时禁用Jackson空Bean序列化检查(不推荐)

仅作为临时调试手段,添加配置绕过异常,但无法正确返回Token:
在application.properties中添加:

quarkus.jackson.serialization.fail-on-empty-beans=false

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:13:13