class ResponseReader {

  public <T extends Response> T read(Class<T> type, SerialPort serialPort) {
    try {
      T response = type.getConstructor(DataInputFactory.class).newInstance(this.dataInputFactory);
      byte[] header = serialPort.readBytes(HEADER_SIZE);
      LOGGER.debug(format("Read header from port: %s", toHexString(header)));
      ResponseHeader responseHeader = readHeader(header);

      int expectedPayloadSize = responseHeader.getPacketSize() - (HEADER_SIZE + TRAILER_SIZE);
      LOGGER.debug(format("Expected payload of [%d] bytes", expectedPayloadSize));

      byte[] payload = new byte[0];
      if (expectedPayloadSize > 0) {
        payload = serialPort.readBytes(expectedPayloadSize);
        LOGGER.debug(format("Read payload from port: %s", toHexString(payload)));
        response.fromBytes(payload);
      } else {
        LOGGER.debug("No payload expected, skipping to trailer...");
      }

      byte[] crc16 = serialPort.readBytes(TRAILER_SIZE);
      LOGGER.debug(format("Read crc16 from port: %s", toHexString(crc16)));
      validateCrc(Bytes.concat(header, payload, crc16), crc16);

      return response;
    } catch (Exception e) {
      throw Throwables.propagate(e);
    }
  }

  @Inject public  ResponseReader(DataInputFactory dataInputFactory);

}