Jan*_*žek 8 java exception protocol-buffers jackson spring-boot
我正在使用具有这个具体定义的 protobufs。
message Hash {
string category = 1;
repeated KVPair content = 2;
}
message KVPair {
string key = 1;
string value = 2;
}
Run Code Online (Sandbox Code Playgroud)
我想将它作为 JSON 与我的 spring-boot 应用程序一起发送。我将此包添加到我的 gradle 依赖项中:
compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.6.1'
Run Code Online (Sandbox Code Playgroud)
当我尝试使用以下代码输出哈希生成的对象时:
@RestController
@RequestMapping("/api/crm/")
public class KVController {
private final KVService kvService;
public KVController(KVService kvService) {
this.kvService = kvService;
}
@GetMapping("kv/{category}")
public Hash getHash(@PathVariable String category) {
Hash hash = kvService.retrieve(category);
return hash;
}
}
Run Code Online (Sandbox Code Playgroud)
它抛出这个最终异常:
引起:com.fasterxml.jackson.databind.exc.InvalidDefinitionException:直接自引用导致循环(通过引用链:com.blaazha.crm.proto.Hash["unknownFields"]->com.google.protobuf.UnknownFieldSet ["defaultInstanceForType"]) 在 com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson。 databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:944) ~ [jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:721) ~[jackson-databind-2.9.6.jar:2.9。6] 在 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson.databind。 ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) ~ [jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.6.jar: 2.9.6] 在 com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson.databind。 ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) ~[jackson-databind-2.9.6.jar:2.9.6] 在 com.fasterxml.jackson.databind.ObjectWriter$ Prefetch.serialize(ObjectWriter.java:1396) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913) ~[jackson-databind] -2.9.6.jar:2.9.6] 在 org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:286) ~[spring-web-4.3.18.RELEASE.jar:4.3.18. RELEASE] ... 省略了 58 个常用帧serialize(ObjectWriter.java:1396) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913) ~[jackson-databind-2.9] .6.jar:2.9.6] 在 org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:286) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE] ... 省略了 58 个常用帧serialize(ObjectWriter.java:1396) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:913) ~[jackson-databind-2.9] .6.jar:2.9.6] 在 org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:286) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE] ... 省略了 58 个常用帧
kvService 只从 redis 返回数据。它将 Hash 数据类型(https://redis.io/topics/data-types)解析为 proto 中定义的 Hash 对象。其中 Hash->category 是 hash 的主键,hash redis 数据类型中的值被转换为 proto 中定义的 KVPair。我无法显示所有源代码,因为它调用了其他系统并且源代码很长。
kvService 返回有效的 Hash 对象,但是当我返回这个 Hash 对象并且 spring 尝试将其转换为 JSON 时会发生异常。
我的 build.gradle 中的重要依赖项:
def versions = [
logback: '1.2.3',
owner: '1.0.10',
jackson: '2.9.6',
guava: '25.1-jre',
guice: '4.2.0',
grpc: '1.9.1',
protoc: '3.5.1',
redis: '2.9.0',
]
Run Code Online (Sandbox Code Playgroud)
依赖{
compile group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback
compile group: 'org.aeonbits.owner', name: 'owner', version: versions.owner
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: versions.jackson
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: versions.jackson
compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: versions.jackson
compile group: 'com.google.guava', name: 'guava', version: versions.guava
compile group: 'com.google.inject', name: 'guice', version: versions.guice
compile group: 'io.grpc', name: 'grpc-netty', version: versions.grpc
compile group: 'io.grpc', name: 'grpc-protobuf', version: versions.grpc
compile group: 'io.grpc', name: 'grpc-stub', version: versions.grpc
compile 'org.glassfish:javax.annotation:10.0-b28'
compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.1'
compile group: 'javax.activation', name: 'activation', version: '1.1.1'
compile group: 'redis.clients', name: 'jedis', version: versions.redis
Run Code Online (Sandbox Code Playgroud)
}
正如您在我的 protobuf 定义中看到的那样,它不是任何自引用。
有没有办法解决这个问题?
If you're using Spring WebFlux and trying to produces
application/json
here is what you can do to make it works for all mappings returning protobuf Message type:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.defaultCodecs().jackson2JsonEncoder(
new Jackson2JsonEncoder(Jackson2ObjectMapperBuilder.json().serializerByType(
Message.class, new JsonSerializer<Message>() {
@Override
public void serialize(Message value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
String str = JsonFormat.printer().omittingInsignificantWhitespace().print(value);
gen.writeRawValue(str);
}
}
).build())
);
}
Run Code Online (Sandbox Code Playgroud)
类UnknownFieldSet
(通过生成的方法到达Hash.getUnknownFields()
)包含 getter getDefaultInstanceForType()
,它返回 的单例实例UnknownFieldSet
。此单例实例引用自身,getDefaultInstanceForType()
并且 Jackson-databind 无法自动处理此问题(请参阅下面的 edit2)。
您可能想要使用JsonFormat,其中com.google.protobuf:protobuf-java-util
使用规范编码而不是 Jackson。
祝你好运!
编辑> 对于 Spring 有ProtobufJsonFormatHttpMessageConverter
EDIT2> 当然,您可以使用Mix-in Annotations来处理这种情况,但恕我直言, JsonFormat 绝对是正确的选择......
归档时间: |
|
查看次数: |
4894 次 |
最近记录: |