java在springboot中将protobuf作为JSON发送
我使用protobufs来定义这个具体的定义
message Hash {
string category = 1;
repeated KVPair content = 2;
}
message KVPair {
string key = 1;
string value = 2;
}
我想将它作为JSON与我的spring boot应用程序一起发送。 我已将此包添加到我的gradle依赖项中:
compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.6.1'
当我尝试使用以下代码输出哈希生成的对象时:
@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;
}
}
它抛出了一个终极例外:
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: com.blaazha.crm.proto.Hash["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"]) at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.9.6.jar:2.9.6] at 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] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:721) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.6.jar:2.9.6] at 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] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.6.jar:2.9.6] at 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.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) ~[jackson-databind-2.9.6.jar:2.9.6] at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) ~[jackson-databind-2.9.6.jar:2.9.6] at 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] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:286) ~[spring-web-4.3.18.RELEASE.jar:4.3.18.RELEASE] ... 58 common frames omitted
kvService仅从redis返回数据。它将散列数据类型(https://redis.io/topics/data-types)解析为proto中定义的散列对象。其中哈希->;category是hash的主键,hash redis数据类型中的值被转换为proto中定义的KVPair。我不能显示所有的源代码,因为它调用其他系统,并且源代码很长
kvService返回有效的散列对象,但当我返回此散列对象并spring尝试将其转换为JSON时,会发生异常
我的构建中的重要依赖项。格拉德尔:
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',
]
依赖关系{
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
}
正如您在我的protobuf中所看到的,它的定义不是任何自引用
有什么可能的方法来解决这个问题吗
# 1 楼答案
要将protobuf对象转换为JSON,应该使用包
com.google.protobuf.util.JsonFormat
中的以下类作为:# 2 楼答案
如果您使用的是SpringWebFlux并试图},那么您可以这样做,以使其适用于所有返回protobuf消息的映射类型:
produces
{# 3 楼答案
类
UnknownFieldSet
(通过生成的方法Hash.getUnknownFields()
到达)包含gettergetDefaultInstanceForType()
,它返回UnknownFieldSet
的单例实例。此单例实例在getDefaultInstanceForType()
中引用自身,Jackson databind无法自动处理此问题(请参见下面的edit2)您可能希望使用来自
com.google.protobuf:protobuf-java-util
的JsonFormat,它使用canonical encoding而不是Jackson祝你好运
编辑>;春天有ProtobufJsonFormatHttpMessageConverter
编辑部2>;当然,您可以使用Mix-in Annotations处理这种情况,但IMHO JsonFormat绝对是一种解决方法