Корректное получение JSON ответа с помощью Apache.HttpClient

Tags:

У Apache HttpClient есть небольшая, но неприятная бага. Всплыла она при работе с REST API Confluence (вообще очень много баг всплывает при работе с API  продуктов Atlassian, но это все лирика).

В чем, собственно, проблема? Проблема в том, что Confluence при запросе у него данных с Accept: application/json (собственно все JSON REST API) не выставляет заголовок content-encoding для отдаваемых данных. В целом, его можно понять т.к. по стандарту JSON всегда должен быть UTF-8, но HttpClient не понимает и потому разбирает входящие данные как ISO.

Соответственно, дальше JSONObject при парсинге Entity превращает русский текст в совершенно непотребное.

Лечится это элементарно, просто при работае с Entity принудительно указываем ей что кодировка у нас UTF-8.

Вот так:

JSONObject jsonObj = new JSONObject(EntityUtils.toString(response.getEntity, "UTF-8"));

После этого русский текст внутри JSON будет в нормальном UTF-8 и с ним можно спокойно работать.

Работаем с самбой из Java с помощью JCIFS

Tags:

Простые примеры работы с самбой при помощи JCIFS

Ниже показан пример класса для копирования файла на самба-шару и просмотра содержимого заданной шары

import jcifs.Config;
import jcifs.smb.*;
import java.io.*;

public class SambaTest {
  // Нормальный конструктор я тут делать не буду, для тестового примера это не нужно
static final String USER_NAME = "username";
static final String PASSWORD = "password";
static final String DOMAIN = "user_domain";

// Путь к сетевой папке с которой будем работать
static final String NETWORK_FOLDER = "smb://server/share/";


// Копируем файл на шару.
// К сожалению SmbFile ничего не знает о методе copyTo из File,
// так что придется этот метод эмулировать руками. Халява не прокатила :(
// В обратную сторону все тоже самое, только потоки будут в обратную сторону.
public boolean copyFileToSamba(String srcFilePath, String destPath) {
    boolean successful = false;
    try{
        // Создаем объект аутентификатор
        NtlmPasswordAuthentication auth =
          new NtlmPasswordAuthentication(DOMAIN, USER_NAME, PASSWORD);

        // Читаем содержимое исходного файла
        File srcFile = new File(srcFilePath);
        InputStream localFile = new FileInputStream(srcFile);

        // Создаем объект для потока куда мы будем писать наша файл
        SmbFileOutputStream destFileName = new SmbFileOutputStream(
          new SmbFile(destPath+File.separator+srcFile.getName(), auth));

        // Ну и копируем все из исходного потока в поток назначения.
        BufferedReader brl = new BufferedReader(
          new InputStreamReader(localFile));
        String b = null;
        while((b=brl.readLine())!=null){
            destFileName.write(b.getBytes());
        }
        destFileName.flush();


        successful = true;
    } catch (Exception e) {
        successful = false;
        e.printStackTrace();
    }
    return successful;
}

// Читаем
public boolean readShareContent() {
    boolean successful = false;
    try{
        // Создаем объект для аутентификации на шаре
        NtlmPasswordAuthentication auth =
          new NtlmPasswordAuthentication(DOMAIN, USER_NAME, PASSWORD);
        String path = NETWORK_FOLDER;

        // Ресолвим путь назначения в SmbFile
        SmbFile baseDir = new SmbFile(path, auth);

        // Вычитываем все содержимое шары в массив
        SmbFile[] files = baseDir.listFiles();

        // Делаем что-нибудь со списком файлов
        for (int i = 0; i < files.length; i++) {
          SmbFile file = files[i];
          if (file.isDirectory()) {
                System.out.println("Is DIR: "+file.toString());
                continue;
          } else {
                System.out.println("Is FILE: "+file.toString());
          }
        }

        successful = true;
    } catch (Exception e) {
        successful = false;
        e.printStackTrace();
    }
    return successful;
  }
}

Если все работы с шарой невероятно тупят - то нужно сменить режим ресолвинга сервера и шары.

В конструктор добавляем следующее:

Config.setProperty( "jcifs.resolveOrder", "DNS");

Этим мы указываем что ресолвить имя сервера мы будем ТОЛЬКО через DNS. Можно туда добавить всякие NetBIOS и прочее, но на практике я с необходимостью это делать не сталкивался. Естественно, что если у вас в сети нет локального DNS сервера который будет ресолвить именя локальным машин - то механизм надо сменить на другой. Выбор механизмов ресолвинга будет проходить в порядке указанном в конфиге.

Если предполагается копирование больших бинарных файлов, то код копирования надо заменить с:

BufferedReader brl = new BufferedReader(new InputStreamReader(localFile)); String b = null; while((b=brl.readLine())!=null){ destFileName.write(b.getBytes()); }

на:

byte[] buffer = new byte[1024000]; int noOfBytes = 0;

while ((noOfBytes = localFile.read(buffer)) != -1) { destFileName.write(buffer, 0, noOfBytes); }

Если этого не сделать - то большие файлы будут копироваться криво.

Яндекс.Метрика