GraphQL SPQR返回Null值问题:如何确保使用Jackson而非Gson?
解决SPQR使用Jackson而非Gson进行序列化的问题
问题背景
我们在Spring Boot应用中已配置Jackson ObjectMapper,设置SerializationInclusion.NON_NULL避免返回Null值,但直接通过SPQR返回实体给前端时仍出现Null值。本地用Jackson转换实体时无Null值,且项目因其他依赖引入了Gson,怀疑SPQR优先使用了Gson而非自定义的Jackson配置。SPQR版本从0.12.1升级到0.12.3后问题依旧。
解决方案
1. 强制SPQR使用自定义Jackson ObjectMapper
SPQR会根据类路径中的序列化库自动选择实现,当Gson存在时可能优先选用。要强制指定使用你的自定义Jackson配置,需在构建GraphQLSchemaGenerator时显式传入ObjectMapper:
import io.leangen.graphql.GraphQLSchemaGenerator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GraphQLConfig { @Autowired private ObjectMapper customObjectMapper; // 注入BootstrapConfig中定义的ObjectMapper @Bean public GraphQLSchema graphQLSchema() { return new GraphQLSchemaGenerator() .withObjectMapper(customObjectMapper) // 关键:指定SPQR使用Jackson序列化 .withOperationsFromSingleton(new EntityMutation()) // 替换为你的业务实现类 // 其他SPQR配置(如添加查询类、自定义类型等) .generate(); } }
2. 排除不必要的Gson依赖(可选)
如果项目中不需要Gson,可以通过Gradle排除其他依赖引入的Gson,从根源避免SPQR选择它:
// 针对单个依赖排除Gson implementation('com.example:some-dependency:1.0.0') { exclude group: 'com.google.code.gson', module: 'gson' } // 全局排除Gson(谨慎使用,确保不会影响其他依赖) configurations.all { exclude group: 'com.google.code.gson', module: 'gson' }
3. 确保自定义Jackson实例为Spring容器首选
在BootstrapConfig的ObjectMapper Bean上添加@Primary注解,保证Spring注入的是你的自定义实例,而非默认生成的:
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; @Configuration public class BootstrapConfig { private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; @Primary // 标记为首选ObjectMapper @Bean public ObjectMapper objectMapper() { final SimpleDateFormat zuluDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US); zuluDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); final ObjectMapper jsonMapper = new ObjectMapper(); jsonMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); jsonMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); jsonMapper.registerModule(new JavaTimeModule()); jsonMapper.setDateFormat(zuluDateFormat); jsonMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return jsonMapper; } }
内容的提问来源于stack exchange,提问作者Navjeet
相关产品推荐
相关产品推荐

