Практикум Swing — XML-валидатор
О практикуме
Соберём десктопное приложение "XML Validator" на Swing и Maven — два редактора (XML и XSD), кнопка "Проверить", панель результата с номерами строк и столбцов ошибок. Пользователь может выбрать файлы через диалог или вставить текст прямо в окно — типичный сценарий утилиты поддержки, когда нужно быстро проверить фрагмент конфигурации или целый документ.
Стек проекта:
- Maven JAR — стандартная структура Java-проекта (структура и сборки);
- Swing (
javax.swing) — окно, панели, кнопки,JTextArea,JFileChooser(обзор GUI, рецепты элементов); javax.xml.validation— валидация XML по XSD из JDK, без сторонних библиотек (общая база по разметке — XML);SwingWorker— проверка в фоне, чтобы UI не "замирал" (EDT и потоки).
Для новых desktop-проектов чаще берут JavaFX, но Swing остаётся в JDK, встречается в legacy-утилитах и internal tools. Здесь — полноценный Maven-проект с разделением model / service / ui, фоновой задачей и работой с XML. Те же идеи переносятся на JavaFX: Task вместо SwingWorker, Platform.runLater вместо SwingUtilities.invokeLater — см. Swing и потоки.
Well-formed и valid — два уровня проверки XML
Прежде чем писать код, разделим два понятия из раздела про XML:
| Уровень | Вопрос | Кто отвечает |
|---|---|---|
| Well-formed | Документ синтаксически корректен? (закрытые теги, одна корневая нода) | SAX-парсер |
| Valid | Документ соответствует схеме (XSD)? | Validator из javax.xml.validation |
Наш валидатор проверяет valid относительно загруженной XSD. Если XML вообще не парсится, SAX вернёт fatal-ошибку — мы покажем её так же, как ошибку схемы.
XML Schema (XSD) — язык описания структуры — имена элементов, типы полей, обязательные атрибуты, кардинальность (maxOccurs="unbounded"). Валидатор компилирует XSD в объект Schema, создаёт Validator и прогоняет через него XML. При нарушении правил вызывается ErrorHandler с номером строки и столбца — именно эти координаты мы выводим пользователю.
Архитектура приложения
В нашем приложении три слоя — упрощённый layered architecture, близкий к MVC:
| Слой | Роль | Классы | Зависит от |
|---|---|---|---|
| Model | Результат проверки, без UI | ValidationResult | только JDK |
| Service | Логика XSD-валидации | XsdValidatorService | model, javax.xml.* |
| UI (View + Controller) | Окно, ввод, реакция на кнопки | XmlValidatorFrame, FilePanel, ResultPanel | model, service, Swing |
Точка входа — XmlValidatorApp.main, как в первой программе и точке входа JVM. UI не импортирует SAX напрямую — frame вызывает сервис, сервис возвращает ValidationResult, панель результата только отображает данные. Так проще тестировать сервис без Swing и позже заменить UI на JavaFX, не трогая валидацию.
Пользователь → FilePanel / кнопки → XmlValidatorFrame
│
▼ (SwingWorker, фон)
XsdValidatorService
│
▼
ValidationResult → ResultPanel
Ключевые термины
- Swing — графическая библиотека JDK (
javax.swing); рисует "лёгкие" компоненты на Java, не зависит от нативных виджетов ОС. Обзор — JavaFX и GUI, экосистема Java. - EDT (Event Dispatch Thread) — единственный поток, где безопасно создавать и менять Swing-компоненты. Старт UI — через
SwingUtilities.invokeLater. Подробнее — Особенности разработки десктопных приложений. SwingWorker— шаблон "долгая работа в фоне → результат в EDT";doInBackground()не трогает UI,done()обновляет виджеты.JFrame— главное окно приложения; содержитcontentPaneс layout-менеджерами.SchemaFactory/Validator— APIjavax.xml.validation: фабрика компилирует XSD, валидатор проверяет XML.ErrorHandler(SAX) — интерфейс обратных вызововwarning,error,fatalErrorс координатамиSAXParseException.JFileChooser— диалог выбора файла; фильтр расширений —FileNameExtensionFilter(Справочник по JavaFX и Swing — элементы UI — JFileChooser).JSplitPane— разделитель между областями; пользователь тянет границу мышью.- Look-and-Feel (L&F) — тема оформления Swing (Metal, Nimbus, System); задаётся через
UIManager.setLookAndFeel.
Почему именно этот проект
- охватывает сценарий форма + фоновая операция + structured errors — основа многих desktop-утилит;
- Swing без внешних GUI-зависимостей — только JDK;
- сочетает I/O файлов (Ввод-вывод и файлы в Java) и XML API стандартной библиотеки;
- показывает разделение слоёв — навык из культуры кода;
- компактен для одного вечера (2–3 часа), но близок к реальным internal tools;
- после прохождения проще читать JavaFX и GUI и Lab — Swing.
Предварительные знания:
- JDK 17+, Maven 3.8+;
- классы, пакеты,
final, record (ООП); - базовый Swing или Lab — 1143;
- желательно — структура Maven-проекта, исключения.
Готовый проект для сверки: F:\Projects\JVM\Java\JavaXMLValidator.
Что получится
| Действие пользователя | Компонент Swing | Что происходит |
|---|---|---|
| "Обзор…" для XML/XSD | JFileChooser, JTextArea | Файл читается в редактор |
| Вставить текст вручную | JTextArea | Валидация по строкам, без файла на диске |
| "Проверить" | JButton, SwingWorker | XSD проверяет XML, результат внизу |
| "Очистить" | JButton | Сброс полей и статуса |
| Невалидный XML | ResultPanel | Список ошибок с [error], строка, столбец |
| Enter в форме | getRootPane().setDefaultButton | Тот же сценарий, что и клик "Проверить" |
Карта этапов
| Этап | Фокус | Результат |
|---|---|---|
| 0 | Каркас Maven | Пустая структура каталогов |
| 1 | pom.xml | JAR, mainClass, shade |
| 2 | ValidationResult | Модель результата |
| 3 | XsdValidatorService | Валидация по файлу и строкам |
| 4 | FilePanel | Редактор + выбор файла |
| 5 | ResultPanel | Статус и список ошибок |
| 6 | XmlValidatorFrame | Компоновка, SwingWorker |
| 7 | XmlValidatorApp | Точка входа, Look-and-Feel |
| 8 | Примеры XML/XSD | Тестовые данные в examples/ |
| 9 | Запуск и проверка | mvn package, GUI, сценарии |
После каждого этапа имеет смысл mvn -q compile — привычка из разработки и отладки: маленькие шаги, частая проверка.
Этап 0 — каркас проекта
Цель этапа — создать стандартную структуру JAR-проекта Maven и разложить пакеты по слоям.
Desktop vs web — другая точка входа
В отличие от JSF (практикум "Список задач"), desktop-приложение начинается с public static void main. JVM загружает класс XmlValidatorApp, вызывает main, тот делегирует создание окна методу XmlValidatorFrame.launch(). Контейнер servlet'ов не нужен — процесс живёт, пока открыто окно (или пока не завершатся не-daemon потоки). См. точку входа JVM и архитектуру десктопа.
Maven для таких проектов использует packaging jar и каталог src/main/java — подробно в Структура и сборки Java-проектов.
Создание каталогов
Корневая папка:
mkdir java-xml-validator && cd java-xml-validator
Windows PowerShell:
New-Item -ItemType Directory -Force -Path `
src/main/java/com/xmlvalidator/model, `
src/main/java/com/xmlvalidator/service, `
src/main/java/com/xmlvalidator/ui, `
src/test/java/com/xmlvalidator/service, `
examples
Итоговая схема:
java-xml-validator/
├── pom.xml
├── examples/
│ ├── book.xsd
│ ├── book-valid.xml
│ └── book-invalid.xml
└── src/
├── main/java/com/xmlvalidator/
│ ├── XmlValidatorApp.java
│ ├── model/ValidationResult.java
│ ├── service/XsdValidatorService.java
│ └── ui/
│ ├── XmlValidatorFrame.java
│ ├── FilePanel.java
│ └── ResultPanel.java
└── test/java/com/xmlvalidator/service/
└── XsdValidatorServiceTest.java
Разбор структуры
src/main/java— компилируемый код; путь папок = имя пакета (com.xmlvalidator.service).model— plain Java, без Swing и безjavax.xml; удобно покрыть unit-тестами.service— доменная логика валидации; UI только вызываетvalidate(...).ui— только Swing; классыFilePanelиResultPanelpackage-private — детали реализации, наружу торчитXmlValidatorFrame.launch().examples— образцы для ручной проверки и тестов; не в classpath, путь относительно корня проекта приmvn test.src/test/java— зеркало production-пакетов; тестируем сервис без поднятия GUI.
Этап 1 — pom.xml
Цель этапа — описать координаты артефакта, Java 17, JUnit для тестов и исполняемый JAR.
Зависимости и JDK-модули
Swing (javax.swing, java.awt) и XML Validation (javax.xml.validation, org.xml.sax) входят в JDK — в <dependencies> для runtime ничего не кладём. Это отличие от JavaFX, где OpenJFX подключают отдельно.
Единственная зависимость — JUnit 5 со scope test: GUI мы проверяем вручную, сервис — автоматически.
Плагин maven-shade-plugin соберёт "fat JAR" — один файл со всеми классами и манифестом Main-Class, удобно передать коллеге без IDE.
Создайте pom.xml в корне:
Код ITЗагрузка примера кода…
Разбор pom.xml
| Элемент | Назначение |
|---|---|
groupId / artifactId / version | Координаты артефакта в Maven-репозитории |
project.build.sourceEncoding UTF-8 | Кириллица в строках и XML без "кракозябр" |
maven.compiler.release 17 | Язык и API JDK 17; в модели используем record |
maven-jar-plugin + mainClass | Тонкий JAR: java -jar target/java-xml-validator-1.0.0.jar |
maven-shade-plugin | Fat JAR после mvn package — один файл для раздачи |
maven-surefire-plugin | Запуск JUnit 5 на фазе test |
JUnit 5 (scope test) | Только тесты; не попадает в production JAR |
Проверка синтаксиса POM:
mvn -q validate
Если Maven не находит артефакты — проверьте интернет и настройки репозитория (первая программа на Java).
Этап 2 — модель ValidationResult
Цель этапа — описать результат валидации в типах Java — успех, список ошибок с координатами, краткий summary для заголовка панели.
Зачем отдельная model, а не boolean
UI мог бы интерпретировать true/false, но реальным пользователям нужны детали — сколько ошибок, на какой строке, warning или error. Модель инкапсулирует три случая:
- документ валиден;
- документ не валиден, список
ValidationError; - ошибка конфигурации (пустой ввод, битая XSD, файл не найден) — не путать с нарушением схемы в XML.
Файл src/main/java/com/xmlvalidator/model/ValidationResult.java:
Код ITЗагрузка примера кода…
Построчный разбор
| Фрагмент | Смысл |
|---|---|
public final class | Класс не наследуют; явный value-object для результата |
Приватный конструктор + фабрики success / failure / configurationError | Единые точки создания; снаружи нельзя собрать неконсистентное состояние |
List.copyOf(errors) | Иммутабельная копия — UI не испортит список после получения |
record ValidationError | Компактный DTO (современный синтаксис); поля Integer, а не int, чтобы отличать "нет координаты" от нуля |
formatted() | Presentation-логика для JTextArea; сервис не знает про Swing |
Вложенный Builder | SAX вызывает ErrorHandler многократно; накапливаем ошибки, в конце build() |
На этом этапе:
mvn -q compile
Этап 3 — сервис XsdValidatorService
Цель этапа — реализовать валидацию по путям файлов и по строкам из редакторов, скрыв детали SAX/XML API от UI.
Цепочка API javax.xml.validation
Типичный pipeline (см. также JAXP в документации JDK):
SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI)— фабрика для XSD 1.0.factory.newSchema(xsdSource)— компиляция XSD; синтаксическая ошибка в схеме →SAXExceptionздесь.schema.newValidator()— экземпляр валидатора для этой схемы.validator.setErrorHandler(...)— куда стекаются warning/error/fatal.validator.validate(xmlSource)— один проход по XML.
Источники — javax.xml.transform.Source; для файлов удобен StreamSource, для строк из редактора — ByteArrayInputStream + UTF-8.
Два публичных метода validate
| Метод | Когда используется |
|---|---|
validate(Path xml, Path xsd) | Текст в редакторе совпадает с файлом на диске — читаем напрямую с systemId = URI файла |
validate(String xml, String xsd) | Пользователь редактировал текст или не выбирал файл |
Frame (этап 6) решает, какой overload вызвать, сравнивая textArea.getText() с Files.readString(path).
Файл src/main/java/com/xmlvalidator/service/XsdValidatorService.java:
Код ITЗагрузка примера кода…
Разбор сервиса
Проверки на входе (Path)
Files.isRegularFile— отсекаем каталоги и несуществующие пути до SAX; возвращаемconfigurationErrorс понятным текстом для UI.
setSystemId
- Для файла — URI файла; для inline — псевдо-имя
inline.xml. БезsystemIdсообщения SAX иногда бесполезны ("unknown location").
ACCESS_EXTERNAL_DTD / ACCESS_EXTERNAL_SCHEMA
- Начиная с JDK 8+ ужесточили загрузку внешних сущностей (XXE). Пустая строка запрещает DTD из сети;
"file"для schema — разумный компромисс для локальных XSD.
CollectingErrorHandler
warning— замечание, валидация может продолжиться;error— нарушение схемы;fatalError— записываем и пробрасываемSAXException(контракт SAX); дублирующий catch дляSAXParseExceptionвvalidateподстраховывает обрыв с одной fatal-ошибкой.
Pattern matching instanceof SAXParseException parseEx
- Java 16+; альтернатива — отдельная переменная после cast (современный синтаксис).
Проверка:
mvn -q compile
Этап 4 — панель FilePanel
Цель этапа — переиспользуемый блок — путь к файлу, кнопка "Обзор…", моноширинный редактор текста.
Компоненты Swing в этой панели
| Класс | Роль в UI |
|---|---|
JPanel | Контейнер с BorderLayout |
JTextField | Read-only путь к выбранному файлу |
JButton | Открывает JFileChooser |
JTextArea | Многострочный редактор XML/XSD |
JScrollPane | Прокрутка длинного текста |
JLabel | Подсказка пользователю |
Один класс FilePanel параметризуется заголовком и расширением — DRY: две панели (XML и XSD) без копипасты. Подробнее про виджеты — Справочник по JavaFX и Swing — элементы UI — Swing.
Файл src/main/java/com/xmlvalidator/ui/FilePanel.java:
Код ITЗагрузка примера кода…
Разбор компоновки и поведения
Layout
BorderLayoutна корневой панели — NORTH (путь), CENTER (редактор), SOUTH (подсказка). Отступы8, 8между зонами (Справочник по JavaFX и Swing — элементы UI — BorderLayout).createTitledBorder(title)— визуальная группа "XML-документ" / "XSD-схема".
Шрифт и перенос
Font.MONOSPACED— выравнивание вложенных тегов;setTabSize(2)— два пробела на уровень отступа.setLineWrap(false)— XML обычно не переносят по словам; горизонтальная прокрутка черезJScrollPane.
chooseFile()
showOpenDialog(this)— модальный диалог относительно панели.FileNameExtensionFilter— в списке только.xmlили.xsd.Files.readString— Java 11+, UTF-8 по умолчанию (Ввод-вывод и файлы в Java).- Ошибки чтения —
JOptionPaneсERROR_MESSAGE, не silent fail.
Инкапсуляция
final class, package-private — снаружи пакетаuiвиден только frame; методыgetText/clearбез модификатора — API дляXmlValidatorFrame.
Этап 5 — панель ResultPanel
Цель этапа — показать статус (цвет + краткий текст) и детали ошибок в читаемом виде.
Машина состояний UI
Панель результата проходит четыре состояния:
| Состояние | Метод | Что видит пользователь |
|---|---|---|
| Готов | reset() | Серый текст "Готов к проверке", пустая область деталей |
| Идёт проверка | showPending() | "Проверка…", кнопки disabled (управляет frame) |
| Результат | showResult(ValidationResult) | ✓ зелёный или ✗ красный + список ошибок |
| Сбой worker | showError(String) | ✗ "Ошибка" + текст исключения |
Такой паттерн описан в Особенности разработки десктопных приложений для любых long-running операций в desktop.
Файл src/main/java/com/xmlvalidator/ui/ResultPanel.java:
Код ITЗагрузка примера кода…
Разбор
JLabel+JTextArea— заголовок статуса крупнее (deriveFont(BOLD, 14f)), детали — моноширинный многострочный блок.setEditable(false)— область только для чтения; пользователь копирует текст ошибки в буфер.setLineWrap(true)в details — длинные сообщения SAX переносятся; в редакторах XML wrap выключен намеренно.- Нумерация
1. 2. 3.— удобно ссылаться при разборе с коллегой ("смотри ошибку 2"). setCaretPosition(0)— после обновления прокрутка в начало, а не в конец.
Этап 6 — главное окно XmlValidatorFrame
Цель этапа — собрать layout, обработчики кнопок и SwingWorker для валидации без блокировки EDT.
Иерархия компонентов окна
JFrame "XML Validator — проверка по XSD"
└── content (BorderLayout)
├── CENTER: JSplitPane (VERTICAL)
│ ├── TOP: JPanel GridLayout(1,2)
│ │ ├── FilePanel "XML-документ"
│ │ └── FilePanel "XSD-схема"
│ └── BOTTOM: ResultPanel
└── SOUTH: JPanel FlowLayout — [Очистить] [Проверить]
Layout-менеджеры (теория — JavaFX и GUI — геометрия Swing):
BorderLayout— якорные зоны frame;GridLayout(1, 2)— два редактора одинаковой ширины;JSplitPane.VERTICAL_SPLIT— пользователь меняет долю места редакторам и результату;FlowLayout(RIGHT)— кнопки прижаты к правому краю, порядок "Очистить" → "Проверить".
Почему SwingWorker, а не голый Thread
Валидация большого XML может занять секунды. Если вызвать validator.validate прямо в ActionListener, EDT занят — окно не перерисовывается, курсор "часики", пользователь думает, что приложение зависло.
SwingWorker:
doInBackground()— worker-поток; здесь только сервис и чтение текста.done()— снова EDT; включаем кнопки, вызываемresultPanel.showResult(get()).
Аналог в JavaFX — Task + Platform.runLater (Первая программа на JavaFX).
Файл src/main/java/com/xmlvalidator/ui/XmlValidatorFrame.java:
Код ITЗагрузка примера кода…
Разбор ключевых решений
| Решение | Пояснение |
|---|---|
EXIT_ON_CLOSE | JVM завершится при закрытии окна — иначе процесс может висеть (JavaFX и GUI — типичные ошибки) |
setMinimumSize(960, 640) | Два редактора + результат не сжимаются в нечитаемую полоску |
setLocationRelativeTo(null) | Окно по центру экрана при первом показе |
resizeWeight(0.72) | При ресайзе окна ~72% высоты split — редакторам |
continuousLayout(true) | Панели перерисовываются во время перетаскивания разделителя |
| Сравнение текста с файлом | Если пользователь правил текст после "Обзор…", валидируем строки, а не устаревший файл на диске |
setDefaultButton(validateButton) | Enter в форме = "Проверить" |
setMnemonic Alt+V / Alt+C | Клавиатурная доступность |
| Nimbus → System L&F | Единый современный вид; если Nimbus нет — native (Справочник по конфигурациям в Java — swing.defaultlaf) |
Вызов validator.validate(...) напрямую в ActionListener на больших файлах "подвесит" окно. Всегда выносите тяжёлую работу в SwingWorker или фоновый поток + SwingUtilities.invokeLater — см. Swing и потоки и 112.md.
Замечание про потоки и UI: в doInBackground() мы читаем getText() из Swing-компонентов. Формально Swing не потокобезопасен; здесь worker стартует сразу после клика, до параллельного редактирования — для учебного проекта достаточно. В production надёжнее снимать snapshot строк в EDT перед worker.execute() и передавать их в worker через constructor — см. JVM и потоки.
Этап 7 — точка входа XmlValidatorApp
Цель этапа — минимальный main, делегирующий запуск окну; отделить bootstrap от UI-кода.
Роль класса с main
| Обязанность | Где живёт |
|---|---|
| Точка входа JVM | XmlValidatorApp.main |
EDT + L&F + setVisible | XmlValidatorFrame.launch() |
| Разметка и события | конструктор XmlValidatorFrame |
Так Maven shade-plugin, IDE Run Configuration и документация ссылаются на одно имя класса — com.xmlvalidator.XmlValidatorApp.
Файл src/main/java/com/xmlvalidator/XmlValidatorApp.java:
package com.xmlvalidator;
import com.xmlvalidator.ui.XmlValidatorFrame;
public final class XmlValidatorApp {
public static void main(String[] args) {
XmlValidatorFrame.launch();
}
}
Почему не main прямо во frame
JFrameне обязан знать проmain— проще тестировать и переиспользовать frame из другого launcher'а.launch()вызывают до любого Swing-кода — сначала L&F, потомinvokeLater.- Соответствует рекомендациям по структуре — тонкий entry point.
Запуск:
- IDE — Run на
XmlValidatorApp(отладка); - Maven (если добавите
exec-maven-plugin):
mvn -q exec:java -Dexec.mainClass=com.xmlvalidator.XmlValidatorApp
В эталонном проекте достаточно Run в IDEA или java -jar после package.
Этап 8 — примеры XML и XSD
Цель этапа — добавить файлы для ручной проверки, разбора схемы и unit-тестов.
Схема book.xsd
Описывает каталог книг: корень library, внутри ноль или больше book. У каждой книги обязательны title, author, year (положительное целое) и атрибут isbn.
Код ITЗагрузка примера кода…
Разбор XSD
xmlns:xs="http://www.w3.org/2001/XMLSchema"— префиксxs:для встроенных типов (string,positiveInteger).complexType+sequence— дочерние элементы в фиксированном порядке.maxOccurs="unbounded"— список книг любой длины.use="required"на атрибуте — безisbnэлементbookinvalid.
Валидный документ book-valid.xml
<?xml version="1.0" encoding="UTF-8"?>
<library>
<book isbn="978-0-123456-78-9">
<title>Java XML Processing</title>
<author>Jane Doe</author>
<year>2024</year>
</book>
</library>
Все элементы на месте, year > 0, атрибут isbn задан — ожидаем ✓ в UI.
Невалидный документ book-invalid.xml
<?xml version="1.0" encoding="UTF-8"?>
<library>
<book>
<title>Missing ISBN and bad year</title>
<author>John Smith</author>
<year>-1</year>
</book>
</library>
Две ошибки схемы
- нет обязательного атрибута
isbn; -1не укладывается вxs:positiveInteger.
Валидатор может вернуть несколько записей в ValidationResult — проверьте нумерацию в ResultPanel.
Unit-тест сервиса
GUI не гоняем в JUnit — тестируем сервис (Артефакты качества в проекте — тестирование). Три сценария — valid file, invalid file, inline strings (text blocks Java 15+).
Файл src/test/java/com/xmlvalidator/service/XsdValidatorServiceTest.java:
Код ITЗагрузка примера кода…
Разбор тестов
examplesDir = Path.of("examples").toAbsolutePath()— работает, еслиmvn testзапускают из корня проекта (рабочая директория Maven = каталог сpom.xml).@BeforeEach— новый сервис на каждый тест, без shared state.- Третий тест — минимальная XSD "корень = строка"; проверяет overload
validate(String, String)без файлов.
mvn -q test
Этап 9 — сборка, запуск и проверка
Цель этапа — убедиться, что JAR собирается и все пользовательские сценарии в GUI работают.
mvn clean package
java -jar target/java-xml-validator-1.0.0.jar
После package в target/ появятся и обычный JAR, и shaded (fat) — оба с Main-Class в манифесте.
Чек-лист ручного тестирования
- Окно открывается 960×640, заголовок "XML Validator — проверка по XSD".
- "Обзор…" для XML и XSD — загружаются
book-valid.xmlиbook.xsd→ "Проверить" → зелёный ✓. - Заменить XML на содержимое
book-invalid.xml(вставкой или вторым файлом) → "Проверить" → список ошибок с номерами строк. - "Очистить" — поля и статус "Готов к проверке".
- Вставить минимальный XML/XSD без выбора файла → проверка по строкам работает.
- Пустой XML → сообщение "XML не может быть пустым" (
configurationError, не SAX). - Во время проверки кнопки неактивны, статус "Проверка…" — UI отзывчив (можно двигать разделитель split).
- Alt+V / Enter — запуск проверки (mnemonic и default button).
Импортируйте Maven-проект в IntelliJ IDEA. Полезные breakpoint'ы: XsdValidatorService.validate (логика XSD), CollectingErrorHandler.add (каждая SAX-ошибка), SwingWorker.done (граница фон / UI). Общие приёмы — Отладка Java-кода в IDE.
Схема потока данных
[XmlValidatorApp.main]
│
▼
XmlValidatorFrame.launch() ──► EDT + Nimbus L&F
│
▼
Пользователь: XML + XSD (файл или текст)
│
▼
SwingWorker.doInBackground()
│
▼
XsdValidatorService.validate(...)
│
├── SchemaFactory.newSchema(XSD)
├── Validator.validate(XML)
└── ErrorHandler → ValidationResult.Builder
│
▼
SwingWorker.done() → ResultPanel.showResult()
Что вы освоили за практикум
- Maven JAR с mainClass и shade (Структура и сборки Java-проектов);
- Swing — layout, события, диалоги, split pane (Справочник по JavaFX и Swing — элементы UI);
- EDT и SwingWorker — отзывчивый UI (Особенности разработки десктопных приложений);
- Layered design — model / service / ui;
- javax.xml.validation — XSD и SAX ErrorHandler;
- JUnit 5 для сервиса без GUI.
Частые ошибки
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| Окно не появляется | UI создан не в EDT | SwingUtilities.invokeLater в launch() |
| UI "замирает" при проверке | Валидация в ActionListener | Перенести в SwingWorker |
UnsupportedOperationException на L&F | Nimbus недоступен | Fallback на system L&F уже в коде |
Тесты не находят examples/ | Запуск не из корня проекта | mvn test из каталога с pom.xml |
| Кракозябры в XML | Не UTF-8 | Кодировка файлов и project.build.sourceEncoding |
| Пустой список ошибок при невалидном XML | Пустая XSD или не та схема | Содержимое панели XSD |
| JVM не завершается после закрытия | Не EXIT_ON_CLOSE | setDefaultCloseOperation в конструкторе frame |
| "Ошибка схемы" при валидном XML | XSD syntactically broken | Откройте XSD отдельно, проверьте well-formed |
| Разные результаты file vs paste | Текст в редакторе ≠ файл | Логика сравнения в runValidation() |
Куда развивать дальше
- Меню "Файл" — открыть/сохранить XML, недавние файлы (Справочник по JavaFX и Swing — элементы UI — JMenuBar).
- Подсветка строки с ошибкой —
Highlighter/DefaultHighlighterвJTextAreaXML-панели. - Snapshot текста в EDT — передавать строки в
SwingWorkerчерез constructor (потокобезопасность). - DTD и Relax NG — другие grammar / сторонние библиотеки; XSD остаётся стандартом для конфигов (XML — обзор).
- Drag-and-drop —
TransferHandlerдля.xml/.xsdна панели. - JavaFX-версия — те же
model/service, UI наTextArea+Task(Первая программа на JavaFX). - CI —
mvn testв pipeline (Gradle — практический старт).
Связанные статьи
- JavaFX и GUI — обзор Swing, EDT,
SwingWorker - Справочник JavaFX и Swing — элементы UI —
JButton,JTextArea,JFileChooser - Lab — Java Swing — построчный разбор простых окон
- Структура и сборки Java-проектов — Maven, JAR, плагины
- Ввод-вывод и файлы —
Path,Files.readString - XML — well-formed, valid, пространства имён
- Особенности десктопных приложений — EDT, отзывчивость UI
- Архитектура десктопных приложений — элементы UI, MVC
- Отладка Java-кода в IDE — breakpoint в сервисе и UI
- Современный синтаксис Java — record, pattern matching
- Практикум JSF — список задач — другой Maven-практикум в разделе Java
Десктоп на Java — JavaFX и GUI, Первая программа на JavaFX, Практикум Swing — XML-валидатор, Lab — Swing, Архитектура десктопа.