2015-02-02 2 views
1

Я намерен написать структурированные данные для доступа к ресурсу через HTTP-клиент. API для этого (для JSON, YAML, XML), как правило, заставляют меня передавать им OutputStream, на которые они будут писать - они не дают мне InputStream.Могу ли я пропустить реализацию HttpEntity # getContent()?

К счастью, HTTP-компоненты Apache HttpClient - это клиент, который используется здесь. (Другие библиотеки, которые мы используем, зависят от этого. Это не совсем плохо по большей части и по крайней мере не заставляет нас использовать странные нитки-локальные хаки, чтобы получить нормальное поведение, в отличие от java.net.URL.)

При оформлении запроса , HttpEntityEnclosingRequestBase (в HttpClient) заставляет меня установить HttpEntity для получения любых данных на сервер. HttpEntity, казалось бы, заставляет меня реализовать getContent(), возвращая InputStream.

не имеет InputStream, поэтому я вынужден выбирать между двумя обходными:

A) сериализацией всех данных в массив байт в памяти, а затем поток все это обратно. Я не хочу этого делать, потому что, как правило, сериализованная форма данных занимает гораздо больше памяти, чем сами данные, и в некоторых случаях мы даже не имеем ее в памяти в первую очередь, так что это просите о неприятностях.

B) Создать Pipe. Вращайте второй поток, чтобы записать объект в конец трубы OutputStream. Верните конец InputStream. Это фактически не может быть сделано в самом HttpEntity, потому что HttpEntity понятия не имеет, когда поток данных больше не нужен. (Можно было бы предположить, что это будет сделано, когда вы достигнете конца потока, но если соединение с сервером упадет наполовину, вы оставите трубу открытой навсегда.) Это означает, что я в конечном итоге перемещаю обходной путь к каждому где происходит соединение, что представляет собой много структурного дублирования.

Ни один из этих обходных решений не является большим, но я предполагаю, что (B) - «меньше дерьма», потому что он по крайней мере не разрушит все приложение, когда переносится большой объект.

Вот насколько я получил:

public class WriteLogicEntity extends AbstractHttpEntity { 
    private final WriteLogic writeLogic; 

    public InputStreamEntity(WriteLogic writeLogic) { 
     this(instream, null); 
    } 

    public InputStreamEntity(WriteLogic writeLogic, 
          ContentType contentType) { 
     this.writeLogic = writeLogic; 
     if(contentType != null) { 
      this.setContentType(contentType.toString()); 
     } 
    } 

    @Override 
    public boolean isRepeatable() { 
     // We could enforce that all WriteLogic be repeatable 
     // or add a similar method there, but at least for now, 
     // assuming it isn't repeatable is safe. 
     return false; 
    } 

    @Override 
    public long getContentLength() { 
     // We really don't know. 
     return -1L; 
    } 

    @Override 
    public InputStream getContent() throws IOException { 
     //TODO: What do we do here? 
    } 

    @Override 
    public void writeTo(OutputStream outstream) throws IOException { 
     writeLogic.withOutputStream(outstream); 
    } 

    @Override 
    public boolean isStreaming() { 
     return true; //TODO: Verify this choice 
    } 
} 

public interface WriteLogic { 
    void withOutputStream(OutputStream stream) throws IOException; 
} 

Теперь мне интересно, если getContent() может просто бросить UnsupportedOperationException. Разумеется, при подаче запроса они будут использовать writeTo() в любом случае, не так ли? Ну, я не могу понять. Даже если он работает в одном эксперименте, это не заверило бы меня, что невозможно, чтобы какой-либо запрос потребовал позвонить по телефону getContent().

Так что мне интересно, может ли кто-нибудь, кто знает эту библиотеку лучше меня, позвонить на нее - безопасно ли пропустить реализацию этого метода?

(Этот метод getContent() просто кажется, что он не должен быть в API. Или он должен быть документирован, чтобы хотя бы разрешить мне какой-либо выход из его реализации. В любом случае я намерен записать ошибку об этом, потому что это чрезвычайно неудобно принудительно предоставлять InputStream, когда вы пытаетесь написать запрос.)

+0

Я думаю, было бы безопасно предположить, что ваш объект запроса не будет вызван методом getContent, это именно то, что предлагает этот вопрос - http: // stackoverflow.ком/вопросы/10146692/как-делать-я-записи к ан-OutputStream-используя-defaulthttpclient. Я думаю, если вы хотите быть уверенным, что можете запросить список рассылки hc. – stringy05

+0

Разве вы не знаете, когда вызывающий абонент закончил «InputStream», когда они его закрыли? – immibis

+0

@immibis Зачем они закрывают его? Я открыл его, поэтому он принадлежит мне. – Trejkaz

ответ

1

Если содержимое объекта не может быть представлено как метод InputStream getContent, то он может вызывать UnsupportedOperationException. Внутренне HttpClient использует writeTo для потоковой передачи содержимого объекта в базовое HTTP-соединение.

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