2

Обратите внимание: Хотя этот вопрос конкретно упоминается Dropwizard, я верю кто с опытом Джерси/JAX-RS должен быть в состоянии ответить на этот вопрос, как я предположил бы, что Dropwizard просто следующий Джерси/JAX-RS под капотом.Dropwizard и протокола Буферы на примере


У меня есть Dropwizard сервис, Красненькая/пишет в формате JSON и прекрасно работает.

Теперь я хотел бы переключить его на чтение/запись двоичных данных (чтобы минимизировать ширину полосы сети). Я вижу, что есть Dropwizard-Protobuf lib, но у меня есть несколько проблем с реализацией двоичной сериализации в Dropwizard.

Во-первых, вот важный материал из моей текущей (JSON-ориентированный) код:

// Groovy pseudo-code 

// Domain entity/POJO 
@JsonIgnoreProperties(ignoreUnknown = true) 
@JsonInclude(JsonInclude.Include.NON_NULL) 
class Fizz { 
    @JsonProperty 
    String name 

    @JsonProperty 
    boolean isBuzz  
} 

// The Dropwizard app entry point 
class FizzService extends Application<FizzConfiguration> { 
    @Override 
    void run(FizzConfiguration fizzCfg, Environment env) throws Exception { 
     // ... lots of stuff 

     env.jersey().register(new FizzService()) 
    } 
} 

// JAX-RS resource with a sample GET endpoint 
@Path(value = "/fizz") 
@Produces(MediaType.APPLICATION_JSON) 
class FizzResource { 
    @GET 
    @Path("/{id}") 
    Fizz getFizzById(@PathParam("id") int id) { 
     // Look up a 'Fizz' in a DB and return it. 
     lookupFizzinDB(id) 
    } 
} 

Так как вы можете видеть, GET /fizz конечная точка ожидает объект запроса JSON, который содержит элемент называется id типа int. Он возвращает объект ответа Fizz, который соответствует предоставленному id.

Я хочу переключить это из JSON в двоичное через Google Protocol Buffers.

Согласно документации Dropwizard-Protobuf, это так просто, как просто добавить это к моему FizzService#run(...) метод:

environment.jersey().register(new ProtocolBufferMessageBodyProvider()) 

Проблема заключается в том, что в настоящее время все мое приложение подключается к сериализации/десериализации в/из JSON. Аннотации @JsonProperty на моем классе Fizz имеют значение для Dropwizard. Важную роль также играет аннотация @Produces(MediaType.APPLICATION_JSON) на FizzResource. Я волнуюсь, что создание моего приложения Dropwizard для чтения/записи протобуфа-порожденного двоичного кода не так просто, как 1-футовый, размещенный в документах.

Я не женат на этой библиотеке. Если у кого-либо есть опыт настройки конечных точек REST в приложении Dropwizard для приема/получения бинарного файла, полученного от protobuf, все, о чем я забочусь, - это эффективное, эффективное решение. Идеи?

ответ

4

Вы правы, это не так просто, как один лайнер. Вам нужно, чтобы protobuf генерировал код для его работы. Проверьте номер Protocol Buffers Documentation. Сначала вам нужно иметь файл proto, который вы компилируете вместе с компилятором protobuf, который генерирует код для вас. Этот сгенерированный код - это то, что вы используете для создания объектов домена/модели. Поставщик protobuf от Dropwizard работает с этим скомпилированным кодом. Независимо от того, используете ли вы поставщик Dropwizard, вам все равно нужно использовать сгенерированный код. См. Раздел «Как начать» в приведенной выше ссылке.

После того, как у вас есть сгенерированный код, то в вашем методе ресурсов сгенерированный класс/тип - это то, что вам нужно будет вернуть поставщику, чтобы он мог его сериализовать. Вам также необходимо будет иметь @Produces("application/x-protobuf") или @Produces(ProtocolBufferMediaType.APPLICATION_PROTOBUF) свой метод ресурсов или класс ресурсов, поэтому Джерси знает, как найти поставщика для типа носителя.

Вы можете поддерживать как application/json, так и application/x-protobuf, так как у вас может быть больше одного типа медиа в @Produces. Просто используйте синтаксис @Produces({ .. , .. }).

Это еще не все.Так как вам нужно будет возвращать два различных типа, то есть ваш простой POJO для JSON или сгенерированного типа для Protobuf, вам нужно будет либо для проверки заголовка в методе ресурса

@Produces({"application/json", "application/x-protobuf"}) 
public Response getFoo(@Context HttpHeaders headers) { 
    List<MediaType> accepts = headers.getAcceptableMediaTypes(); 
    if (accepts.contains(MediaType.APPLICATION_JSON_TYPE) { 
     return Response.ok(new Foo()); 
    } else if (accepts.contains(ProtocolBufferMediaType.APPLICATION_PROTOBUF_TYPE) { 
     return Reponse.ok(new ProtoBufFoo()); 
    } else { 
     // default 
     return Response.ok(new Foo()); 
    } 
} 

Или вы можете иметь два различных метод, один для каждого типа

@Produces("application/json") 
public Response getFooJson() { 
    return Response.ok(new Foo()); 
} 

@Produces("application/x-protobuf") 
public Response getFooProto() { 
    return Response.ok(new ProtoBufFoo()); 
} 

Независимо клиент посылает в качестве заголовка Accept, то есть тип, который будет разослан. Например Accept: application/json или Accept: application/x-protobuf

Смотрите также:

+0

Удивительный, удивительный ответ @peeskillet (+1) - один быстрый период наблюдения, если вы не возражаете: это вызывает мое OCD, что я должен поддерживать 2 разных набора POJO (один для JSON, один для Protobuf). Любой способ объединить их в один POJO? Может быть, взломанный, но я думал, что задача Gradle/Maven создает Protobuf POJO из файла '.proto', а затем последующую задачу добавить необходимые JSON-аннотации в сгенерированный исходный файл? Будет ли это работать?!? Или есть больше для поколения Протобуф, чем просто это? Еще раз спасибо! – smeeb

+1

Я не знаю, что это довольно сложно, что вы говорите. Я на самом деле никогда не использовал Protobuf с Джерси, поэтому я никогда не изучал возможности слияния двух. К сожалению :(( –

+0

) Имеет смысл, и да, это, по общему признанию, kludgy :-) Извините, я забыл один важный (окончательный - обещаю!) Followup: если я использую ваш код выше в качестве руководства, мне все еще нужно использовать это 1 -liner из Dropwizard-Protobuf lib (где я регистрирую поставщика Protobuf)? Я предполагаю, что это то, что ищет запросы, где для типа 'Accept' установлено значение« * application/x-protobuf * »? Еще раз спасибо! – smeeb

Смежные вопросы