Проблемы кодирования IntelliJ IDEA в проекте GradleJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Проблемы кодирования IntelliJ IDEA в проекте Gradle

Сообщение Anonymous »

Обычно я не задаю здесь вопросов, но проблемы, с которыми я сталкиваюсь, настолько жуткие, что я больше не могу бороться с ними в одиночку, я измотан. В любом случае, я собираюсь описать все, что я нашел, и я нашел много интересных вещей, которые, я хочу верить, помогут кому-то помочь мне.

Версии программного обеспечения:
- ОС: Windows 10 Pro, версия: 1909, сборка: 18363.720
- IntelliJ IDEA: 2019.2.4 Ultimate
- Версия оболочки Gradle: 5.2.1-all
- jdk: 8

Проблема лежит в кодировки, особенно в выводе консоли в проекте Gradle.

Вот мой файл build.gradle:

Код: Выделить всё

plugins {
id 'java'
id 'idea'
id 'application'
}

group 'com.diceeee.mentoring'
version 'release'

sourceCompatibility = 1.8
application.mainClassName('D')
compileJava.options.encoding = 'utf-8'

tasks.withType(JavaCompile) {
options.encoding = 'utf-8'
}

repositories {
mavenCentral()
jcenter()
}

dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
Мои источники имеют кодировку UTF-8 с CRLF, поэтому в build.gradle я установил, что источники должны компилироваться с кодировкой utf-8 вместо моей системной кодировки Windows-1251 по умолчанию.

Вот D.java:

Код: Выделить всё

import java.io.FileWriter;
import java.io.IOException;

public class D {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));

String testLine = "Проверка работоспособности И Ш";
System.out.println(testLine);

FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
Также у меня есть gradle.properties с одной строкой:

Код: Выделить всё

org.gradle.jvmargs=-Dfile.encoding=utf-8
Я проверил, работает ли он, и убедился, что он работает, кодировка Encoder в System.out действительно изменилась на utf-8.

Когда я запускаю свой проект gradle, я получаю это:

Код: Выделить всё

21:04:53: Executing task 'D.main()'...

> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE

> Task :D.main()
UTF-8
�������� ����������������� � �

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.2.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 0s
2 actionable tasks: 1 executed, 1 up-to-date
21:04:54: Task execution finished 'D.main()'.
Появляется дополнительная информация.
1) Я не случайно оставил вывод в файле в коде. Если мы попытаемся просмотреть файл, то увидим следующее:

Код: Выделить всё

Проверка работоспособности И Ш
Я не уверен, правильно ли это, но я пришел к выводу, что проблема кроется где-то в консоли, потому что, если бы возникла проблема с кодировкой по умолчанию, средство записи файлов использовало неправильную кодировку для файла, и выходные данные были бы равны. Но этого не происходит.

2) Я отладил внутренности классов PrintStream, OutputStreamWriter и StreamEncoder. StreamEncoder действительно использует кодировку utf-8, а также закодировал текст utf-8 в нужную последовательность байт:
String testLine = "Проверка работоспособности И Ш";
Каждая буква кириллицы - 2 байта, пробелы - 1 байт, если посчитать все буквы, то получим 57.

Теперь посмотрите здесь:
Экран отладки кодировщика с результатом байт

Итак, как мы видим, мы получаем первые 57 байт (остальные — из других входов, буфер использует ограничения):

Код: Выделить всё

[-48, -97, -47, -128, -48, -66, -48, -78, -48, -75, -47, -128, -48, -70, -48, -80, 32, -47, -128, -48, -80, -48, -79, -48, -66, -47, -126, -48, -66, -47, -127, -48, -65, -48, -66, -47, -127, -48, -66, -48, -79, -48, -67, -48, -66, -47, -127, -47, -126, -48, -72, 32, -48, -104, 32, -48, -88, 91]
Выглядит правильно, кириллические буквы закодированы как [-48, -97], [-47, -128] и другие группы по 2 байта, выглядит красиво, пробелы тоже совпадают. Итак, энкодер отлично справляется со своей задачей, работает, но что тогда происходит?
Я не знаю. Серьезно. Но есть дополнительная информация. Если это не показалось вам умопомрачительным, я приготовил для вас кое-что еще.

Я создал чистый Java-проект без каких-либо gradle/maven и т. д., только свой собственный jdk и ничего больше.
Программа та же:

Код: Выделить всё

package com.company;

import java.io.FileWriter;
import java.io.IOException;

public class Main {

public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));

String testLine = "Проверка работоспособности И Ш";
System.out.println(testLine);

FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
Я запустил его и что я получу?

Код: Выделить всё

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\lib\idea_rt.jar=58901:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\\IdeaProjects\test\out\production\test" com.company.Main
UTF-8
Проверка работоспособности И Ш

Process finished with exit code 0
И после этого я просто умер. Что происходит??? Вернёмся на минутку к проекту gradle. Я внес небольшую модификацию:

Код: Выделить всё

import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class D {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));

String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "windows-1251");
System.out.println(testLine);

FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
И теперь вывод:

Код: Выделить всё

21:43:06: Executing task 'D.main()'...

> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes

> Task :D.main()
UTF-8
Проверка работоспособности �? Ш

Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.2.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed
21:43:06: Task execution finished 'D.main()'.
В файле:

Код: Выделить всё

Проверка работоспособности � Ш
Кроме того, этот вывод в консоли — первое, что подтолкнуло меня к определению, что происходит не так, я только что писал код и обнаружил, что с кириллицей «И» действительно что-то не так. Я пытался решить ее, и снова, и снова... и теперь я здесь, потому что я в тупике, я перепробовал все, что нашел в подобных вопросах и темах о проблемах с кодировкой, у меня есть несколько статей о кодировке по умолчанию в Java, о том, что Windows использует кодировку cp866 в консоли, кодировку Windows-1251 по умолчанию, что нам нужно явно определить кодировку с помощью -Dfile.encoding=UTF-8, ничего не помогает, я даже не знаю, что искать, чтобы найти проблему. Я думал, что gradle не распознал свойство, а кодировка все еще была Windows-1251, но отладка показала, что я ошибался.

Ну, вот полный список того, что я пытался решить проблему:
1) Установите -Dfile.encoding=UTF-8 в idea.exe.vmoptions и idea64.exe.vmoptions с перезапуском. Не помогло.
2) Установите UTF-8 в IntelliJ IDEA -> Настройки -> Редактор -> Кодировки файлов везде. Не помогло.
3) Установите кодировку компилятора Gradle на utf-8. Не помогло.
4) Установите параметр gradle jvm org.gradle.jvmargs=-Dfile.encoding=utf-8. Не помогло.
5) Проверил, что в Windows по умолчанию стоит русский язык для программ, не поддерживающих юникод, для поддержки кириллицы. Не помогло.

Я не уверен, в чем проблема с gradle, потому что чистый проект без gradle работает отлично, вывод на консоль в порядке. Но в Gradle кириллические символы неверны. Кроме того, я пытался как-то исправить вывод на консоль с помощью метода/конструктора getBytes(charset) и new String(byte[], charset), я пробовал эти варианты:

Код: Выделить всё

String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "windows-1251");

Output:
Проверка работоспособности �? Ш
Не работает.

Код: Выделить всё

String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "cp866");

Output:
?�?�???????�???? ?�???????�???�?????�?????????�?�?? ?� ?�
Не работает.

Код: Выделить всё

String testLine = new String("Проверка работоспособности И Ш".getBytes(StandardCharsets.UTF_8), "utf-8");

Output:
�������� ����������������� � �
Результат мы получаем без каких-либо преобразований.

Кроме того, я попробовал еще одну вещь — обертку System.out для установки другой кодировки консоли.

Код: Выделить всё

public class D {
public static void main(String[] args) throws IOException {
System.out.println(System.getProperty("file.encoding"));

System.setOut(new PrintStream(System.out, true, "utf-8"));
String testLine = "Проверка работоспособности И Ш";
System.out.println(testLine);

FileWriter writer = new FileWriter("D:\\test.txt");
writer.write(testLine);
writer.close();
}
}
А у нас по-прежнему ничего не выходит, оно даже не изменилось:

Код: Выделить всё

> Task :D.main()
UTF-8
�������� ����������������� � �
Ну, судя по всей этой информации, я думаю, что с самой консолью действительно что-то не так, потому что даже последнее выполнение кода выше имеет такой вывод в файле:

Код: Выделить всё

Проверка работоспособности И Ш
Это кодировка utf-8, это правильный вывод. Но System.out.println выводит в консоль что-то иррациональное, даже если Encoder работает нормально. Я не знаю, что за херня происходит (извините за грязные разговоры), если проблема действительно в gradle, как это проверить? Или как позволить gradle использовать другую кодировку для вывода на консоль? Или, может быть, это все еще что-то с IntelliJ IDEA, даже если вывод в проекте без gradle правильный?

Я чувствую себя детективом, но я застрял, застрял в этом деле. Буду благодарен, если кто-нибудь мне поможет.

Подробнее здесь: https://stackoverflow.com/questions/608 ... le-project
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»