I want to use spring boot with protobuf. Briefly I write demo code with belowing structure;
RestController->get entity->Postgres DB Repo->entity to protobuf object->return protobuf object
pom proto dependency;
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.12.4</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.13.0</version>
</dependency>
Proto file
syntax = "proto3";
package demo;
option java_package = "demo.model";
option java_outer_classname = "DemoProtos";
message DemoDto {
int64 id = 1;
string description = 2;
}
gen.sh file
#!/usr/bin/env bash
SRC_DIR=`pwd`
DST_DIR=`pwd`/../src/main/
echo source: $SRC_DIR
echo destination root: $DST_DIR
function gen(){
D=$1
echo $D
OUT=$DST_DIR/$D
mkdir -p $OUT
sudo protoc -I=$SRC_DIR --${D}_out=$OUT $SRC_DIR/demo.proto
}
gen java
My RestController
@RestController
class DemoRestController {
@Autowired
private DemoRepository demoRepository;
@RequestMapping("/demo/{id}")
ResponseEntity<DemoProtos.DemoDto> date(@PathVariable Integer id) {
Optional<Demo> demo = this.demoRepository.findById(id);
if (demo.isPresent()) {
Demo dt = demo.get();
DemoProtos.DemoDto tempDemo = DemoProtos.DemoDto.newBuilder()
.setDescription(dt.getDescription())
.setId(id)
.build();
return new ResponseEntity<>(tempDemo, HttpStatus.OK);
}
return null;
}
}
Demo Entity Object
@Entity
@Table(name = "DEMO_TABLE", schema = "SDEMO")
@Data
public class Demo {
@Id
private Integer id;
@Column(name = "description")
private String description;
}
And application class
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
When I request the http://localhost:8080/demo/2 occuring exception like this;
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet$Parser]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: demo.model.DemoProtos.DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.37.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
...
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet$Parser]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: demo.model.DemoProtos.DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:341) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:287) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
...
2020-08-17 12:49:48.031 ERROR 1708168 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet$Parser]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: demo.model.DemoProtos.DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.google.protobuf.UnknownFieldSet$Parser and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: demo.model.DemoProtos.DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["parserForType"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.11.1.jar:2.11.1]
...
Then I added this parameter to properties file.
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
Exception changed to;
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: demo.model.DemoProtos$DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.37.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.37.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.37.jar:9.0.37]
...
Caused by: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: demo.model.DemoProtos$DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:341) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104) ~[spring-web-5.2.8.RELEASE.jar:5.2.8.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:287) ~[spring-webmvc-5.2.8.RELEASE.jar:5.2.8.RELEASE]
...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: demo.model.DemoProtos$DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:945) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:722) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerBase.serializeFields(XmlBeanSerializerBase.java:212) ~[jackson-dataformat-xml-2.11.1.jar:2.11.1]
...
2020-08-17 11:56:07.430 ERROR 1691529 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.google.protobuf.UnknownFieldSet]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: demo.model.DemoProtos$DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])] with root cause
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: demo.model.DemoProtos$DemoDto["unknownFields"]->com.google.protobuf.UnknownFieldSet["defaultInstanceForType"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:945) ~[jackson-databind-2.11.1.jar:2.11.1]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:722) ~[jackson-databind-2.11.1.jar:2.11.1]
...
What is wrong for me, is there any comment my problem? Thanks
I had this error and along as M.Deinum mentioned, headers mattered.
I was calling the route from a python script and added this, and the call started working:
headers={"Content-Type": mimetypes.PROTO, "Accept": mimetypes.PROTO},
I also encountered the same problem and solved it through other means.
Reason: I found that the reason for my problem is that I encountered the serialization error mentioned above when converting the grpc Response field to Object.
Solution: Redefine the type and place the response value into the new type, which solves this problem.
The code is as follows:
@GetMapping("/hello_grpc")
public Object helloGrpc(@RequestParam(defaultValue = "hello") String content, @RequestParam(defaultValue = "0") Integer sleep) {
LoadRequestParam param = LoadRequestParam.newBuilder().setContent(content).setSleep(sleep).build();
HelloResponse response = ratingsGrpcClient.hello(HelloRequest.newBuilder().setParam(param).build());
Map<String,String> result = new HashMap<>(4);
result.put("content",response.getContent());
result.put("ip",response.getIp());
return result;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With