Just wondering if there is (can't find at the moment), or if someone is planning on, implementing protobuf support for decoding/encoding? I write the etcd-rest library which is currently using jclouds (api only) in the backend for communicating with etcd's v2 api. Their v3 api uses protobuf to and from the server and I wanted to take a stab at doing things feign rather jclouds as it appears this library is potentially more flexible and lighter weight.
there's no plan, but if you end up creating a codec, we could open a repo
in OpenFeign to host it.
This is very simple. Create a FiegnConfiguration and override the encoder and decoder
@Configuration
public class MyFeignConfiguration {
//Autowire the message converters.
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
//add the protobuf http message converter
@Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
//override the encoder
@Bean
public Encoder springEncoder(){
return new SpringEncoder(this.messageConverters);
}
//override the encoder
@Bean
public Decoder springDecoder(){
return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
}
}
This works perfectly and is able to do the encoding/decoding. Make sure the APIResource endpoints has the consumes="application/x-protobuf" and produces="application/x-protobuf".
@FeignClient(name = "my-service", configuration=MyFeignConfiguration.class)
public interface PaymentsApiResource {
@RequestMapping(value="/v1/api/tryitout", method = RequestMethod.GET, consumes="application/x-protobuf", produces="application/x-protobuf")
public ResponseEntity<MyResponse> tryitout();
}
@ashokayengar this requires adding spring deps to the path right?
I think something like square wire or protobuf itself is more appropriate for this org. spring stuff usually is best in the spring repo (spring-cloud-netflix), since there are spring experts there to help maintain it.
if a protobuf decoder is still needed i've developed a simple decoder not based on spring
new Decoder() {
Map<Type, Message> protoMessagesCache = new HashMap<>();
@Override
public Object decode(Response response, Type type) throws IOException {
if(response.body() == null) return null;
Message protoMessage = protoMessagesCache.computeIfAbsent(type, t -> {
try {
Class<?> typeClass = Class.forName(type.getTypeName());
if (Message.class.isAssignableFrom(typeClass)) {
Method builderMethod = typeClass.getMethod("newBuilder");
return ((Message.Builder) builderMethod.invoke(typeClass)).getDefaultInstanceForType();
}
} catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
throw new RuntimeException(e);
}
throw new NoClassDefFoundError();
});
return protoMessage.toBuilder().mergeFrom(response.body().asInputStream()).build();
}
}
the protoMessagesCache is used only to cache the result of reflection calls used to build a new protobuf message and increase performace (java.lang.reflect methods are very slow)
this class was developed using protobuf-java v 3.1.0
hope it helps someone
Very cool solution. I'll keep this in mind should I swing back around to things.
Most helpful comment
if a protobuf decoder is still needed i've developed a simple decoder not based on spring
the protoMessagesCache is used only to cache the result of reflection calls used to build a new protobuf message and increase performace (java.lang.reflect methods are very slow)
this class was developed using protobuf-java v 3.1.0
hope it helps someone