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
相关产品推荐
相关产品推荐

