在Quarkus中使用SpEL(或其他表达式语言)实现对象转换
在Quarkus中用表达式语言处理对象转换(支持GraalVM)
一、轻量集成SpEL的方案
Quarkus提供了对Spring核心模块的扩展支持,不用引入全量Spring就能用SpEL,完全满足基础对象转换需求:
- 添加依赖
直接在pom.xml里引入Spring核心扩展:
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-spring-core</artifactId> </dependency>
Gradle用户对应在build.gradle里添加implementation 'io.quarkus:quarkus-spring-core'
- 封装SpEL转换器
创建一个应用级的Bean来封装SpEL的解析逻辑,方便复用:
import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class SpelObjectConverter { private final ExpressionParser parser = new SpelExpressionParser(); public <T> T convert(Object source, String spelExpr, Class<T> targetType) { Expression expression = parser.parseExpression(spelExpr); return expression.getValue(source, targetType); } }
- 实际使用示例
比如把User对象转成UserDto,直接注入转换器后用SpEL表达式描述转换逻辑:
import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @Path("/convert") public class ConvertResource { @Inject SpelObjectConverter converter; @GET public UserDto convertUser() { User user = new User("Johnny", 30); // 用SpEL直接构造DTO,支持属性提取、方法调用等 return converter.convert(user, "new com.example.UserDto(name, age)", UserDto.class); } }
- GraalVM适配注意
- 确保Quarkus版本在2.10以上,这个版本对Spring扩展的原生镜像支持更稳定
- 如果转换逻辑用到自定义类的构造、字段或方法,需要添加反射配置。在
src/main/resources/native-image.properties里加:quarkus.native.additional-build-args=--reflect-config-file=reflect-config.json
reflect-config.json里配置需要反射的类:[ { "name": "com.example.User", "allPublicFields": true, "allDeclaredConstructors": true }, { "name": "com.example.UserDto", "allPublicFields": true, "allDeclaredConstructors": true } ]
二、Quarkus原生EL替代方案
如果不想依赖Spring相关组件,Quarkus自带的EL 3.0扩展更轻量,而且原生支持GraalVM:
- 添加依赖
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-el</artifactId> </dependency>
- 封装EL转换器
import jakarta.el.ExpressionFactory; import jakarta.el.ValueExpression; import jakarta.enterprise.context.ApplicationScoped; import jakarta.el.StandardELContext; @ApplicationScoped public class ElObjectConverter { private final ExpressionFactory exprFactory = ExpressionFactory.newInstance(); public <T> T convert(Object source, String elExpr, Class<T> targetType) { StandardELContext context = new StandardELContext(exprFactory); // 把源对象设为EL上下文里的变量,方便表达式引用 context.getVariableMapper().setVariable("source", exprFactory.createValueExpression(source, source.getClass())); ValueExpression expression = exprFactory.createValueExpression(context, elExpr, targetType); return targetType.cast(expression.getValue(context)); } }
- 使用示例
@Path("/el-convert") public class ElConvertResource { @Inject ElObjectConverter converter; @GET public UserDto convertUser() { User user = new User("Johnny", 30); // 通过source变量访问原对象属性,构造DTO return converter.convert(user, "new com.example.UserDto(source.name, source.age)", UserDto.class); } }
- GraalVM适配
这个扩展原生支持GraalVM,只要你的自定义类能被Quarkus的构建工具扫描到,基本不用额外配置,测试时直接用quarkus build --native构建镜像验证即可。
三、避免冗余的实用技巧
- 只引入所需的轻量依赖,别用全量Spring或Camel,避免不必要的包体积和复杂度
- 可以把转换表达式抽离到配置文件中,用
@ConfigProperty注入,方便统一管理:@ConfigProperty(name = "conversion.user-to-dto") String userToDtoExpr; // 使用时直接传入表达式 converter.convert(user, userToDtoExpr, UserDto.class); - 原生镜像构建前,先在JVM模式下测试转换逻辑,确保表达式正确,再构建原生镜像排查兼容性问题
内容的提问来源于stack exchange,提问作者Johnny Miller
相关产品推荐
相关产品推荐

