JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
Подготовка API элементов управления UI и CSS в JavaFX к модуляризации
| Ответственный | Jonathan Giles |
| Тип | Feature |
| Область | JDK |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Компонент | javafx / controls |
| Обсуждение | openjfx dash dev at openjdk dot java dot net |
| Трудоёмкость | L |
| Длительность | L |
| Рецензенты | Anton Tarasov, Kevin Rushforth, Leif Samuelsson, Victor Dyakov |
| Одобрен | Kevin Rushforth |
| Создан | 2015/04/01 01:16 |
| Обновлён | 2017/03/10 13:29 |
| Задача | 8076423 |
Аннотация
Определить публичные API для элементов управления UI и функциональности CSS в JavaFX, которые сейчас доступны только через внутренние API и поэтому станут недоступны из-за модуляризации.
Цели
Многие разработчики, использующие элементы управления UI и функциональность CSS в JavaFX, по давней практике игнорировали предупреждения о том, что следует избегать внутренних API com.sun.*. Во многих случаях, чтобы добиться нужного результата, у разработчиков нет другого выбора, кроме как использовать эти внутренние API. С предстоящим выпуском Java 9, и в особенности с введением строгих границ между модулями в Project Jigsaw, разработчики обнаружат, что их код больше не компилируется и не запускается, поскольку пакеты com.sun.* больше не будут доступны. Цель этого JEP — определить публичные API для функциональности, которую сейчас предоставляют внутренние API.
Что не является целью
С учётом последствий модуляризации, а именно предстоящей недоступности пакетов com.sun.*, сделать это с сохранением хоть какой-то степени обратной совместимости невозможно. Поэтому сохранение обратной совместимости не является целью этого JEP. Это не значит, что мы можем ломать всё, что захотим: мы намерены вводить новые API (и развивать существующие закрытые API) только там, где их напрямую ломает соблюдение границ модулей. Все остальные существующие API, которых модуляризация не затрагивает, останутся прежними.
Критерии успеха
Успех можно оценить двумя способами:
-
Проекты, зависящие от внутренних API JavaFX, в частности Scene Builder, ControlsFX и JFXtras, продолжают работать после перехода на новый API без потери функциональности. Все три проекта имеют открытый исходный код и станут отличным испытательным стендом, чтобы убедиться, что все необходимые API предоставлены.
-
Обсуждения новых API, например работы над input map, необходимой для поведения элементов управления, приводят к улучшению функциональности, о котором разработчики давно просили. В конечном счёте, если всё пойдёт по плану, сторонние элементы управления можно будет создавать без какой-либо зависимости от внутренних API.
Мотивация
Если эту работу не выполнить, многим проектам придётся существенно сократить предоставляемую функциональность, а для некоторых проектов это может оказаться фатальным. Например, без доступа к внутреннему API, который сейчас есть у Scene Builder, ему может быть трудно оставаться жизнеспособным — во всяком случае, его возможности, связанные со стилизацией CSS и изменением свойств элементов управления, будут серьёзно подорваны, а это две ключевые части функциональности Scene Builder. То же самое относится и к большинству других проектов на основе JavaFX, в которых есть хоть какая-то собственная реализация элементов управления или CSS.
Описание
Этот JEP разбит на два частично связанных подпроекта, каждый из которых важен для достижения конечной цели. Нет какого-либо определённого порядка, в котором эти проекты должны выполняться.
Проект первый: сделать скины элементов управления UI публичными API
Сейчас все скины находятся в com.sun.javafx.scene.control.skin. Это значит, что у сторонних разработчиков, которые расширили скин (например, TextFieldSkin), чтобы добавить функциональность, переопределить существующий метод или иным образом изменить внешний вид или поведение скина элемента управления, в JDK 9 приложение перестанет работать. Разумеется, в этом виноваты пользователи, которые зависели от непубличных API, но мы давно обсуждали, чтобы сделать этот API публичным и тем самым лучше поддержать изменение элементов управления UI сторонними разработчиками.
Предполагается перенести многие скины элементов управления JavaFX в соответствующий публичный пакет, скорее всего javafx.scene.control.skin. Переносить заодно связанные классы поведения не планируется.
Основная часть этой работы — проверить каждый существующий класс скина и обеспечить следующее:
-
согласованность API между скинами,
-
наличие качественной документации Javadoc и модульных тестов, а также
-
минимальный объём API в каждом классе за счёт того, что публичные методы делаются закрытыми.
Это исследование уже довольно далеко продвинулось в отдельном репозитории-песочнице, и, хотя оно отнимает много времени, есть лишь несколько проблемных классов, требующих дальнейшего анализа, например вспомогательные классы, дублирующиеся классы и классы, которые действительно относятся только к реализации. Кроме того, есть несколько классов, которые, возможно, стоит перенести в пакет javafx.scene.control или, по крайней мере, нужно рассмотреть дополнительно, поскольку по сути они не являются скинами. К ним относятся FXVK (виртуальная клавиатура), ColorPalette, CustomColorDialog, DatePickerContent и InputField. Наконец, есть несколько классов, методы которых в идеале следовало бы сделать закрытыми, если бы не то, что на этот API опираются другие классы, относящиеся только к реализации. Решения для всех этих проблем будут исследованы, серьёзных опасений нет.
Цель превращения скинов в публичный API в 9 — обеспечить их дальнейшую доступность. API будет намеренно сведён к необходимому минимуму и сокращён настолько, насколько возможно, с намерением в последующих выпусках дополнить его более полезными API, которые запросят разработчики. Как хорошо известно, API (в большинстве случаев) остаются навсегда, поэтому дать публичному API скинов созреть на протяжении нескольких выпусков обновлений представляется лучшим вариантом.
По состоянию на середину июня этот проект находится на этапе, когда почти весь код перенесён и приведён в порядок. Предполагается сделать его публичным в сборке JDK 9 примерно в период с середины июля до начала августа. Ниже приведён список всех классов, перенесённых в javafx.scene.control.skin в качестве публичного API:
AccordionSkinButtonBarSkinButtonSkinCellSkinBaseCheckBoxSkinChoiceBoxSkinColorPickerSkinComboBoxBaseSkinComboBoxListViewSkinComboBoxPopupControlContextMenuSkinDateCellSkinDatePickerSkinHyperlinkSkinLabelSkinLabeledSkinBaseListCellSkinListViewSkinMenuBarSkinMenuButtonSkinMenuButtonSkinBaseNestedTableColumnHeaderPaginationSkinProgressBarSkinProgressIndicatorSkinRadioButtonSkinScrollBarSkinScrollPaneSkinSeparatorSkinSliderSkinSpinnerSkinSplitMenuButtonSkinSplitPaneSkinTabPaneSkinTableCellSkinTableCellSkinBaseTableColumnHeaderTableHeaderRowTableRowSkinTableRowSkinBaseTableViewSkinTableViewSkinBaseTextAreaSkinTextFieldSkinTextInputControlSkinTitledPaneSkinToggleButtonSkinToolBarSkinTooltipSkinTreeCellSkinTreeTableCellSkinTreeTableRowSkinTreeTableViewSkinTreeViewSkinVirtualContainerBaseVirtualFlow
По состоянию на середину июня у этих классов удалён почти весь API, не унаследованный от SkinBase. В дальнейшем предполагается возвращать полезный API по мере получения отзывов о сборках Early Access (ранний доступ). У некоторых классов, например у элементов управления для ввода текста и виртуализированных элементов управления, уже есть дополнительный API для поддержки их функциональности.
Проект второй: проверить соответствующие API CSS и сделать их публичными
Как и Проект первый, этот проект связан с выводом в публичные API того, что сейчас находится в пакетах com.sun.*. Здесь также потребуется ревью кода, чтобы минимизировать API, а также дополнительные модульные тесты и значительно больший объём документации.
Движущая сила этой работы — сохранить возможность компиляции Scene Builder в JDK 9 при внесении соответствующих изменений.
По состоянию на середину июня этот проект находится на этапе, когда почти весь код перенесён и приведён в порядок. Предполагается сделать его публичным в сборке JDK 9 примерно в период с середины июля до начала августа. Ниже приведён список всех классов, перенесённых в javafx.css в качестве публичного API:
CascadingStyle.java:public class CascadingStyle implements Comparable<CascadingStyle> {
CascadingStyle.java: public Style getStyle() {
CascadingStyle.java: public CascadingStyle(final Style style, Set<PseudoClass> pseudoClasses,
CascadingStyle.java: public String getProperty() {
CascadingStyle.java: public Selector getSelector() {
CascadingStyle.java: public Rule getRule() {
CascadingStyle.java: public StyleOrigin getOrigin() {
CascadingStyle.java: public ParsedValueImpl getParsedValueImpl() {
CompoundSelector.java:final public class CompoundSelector extends Selector {
CompoundSelector.java: public List<SimpleSelector> getSelectors() {
CompoundSelector.java: public CompoundSelector(List<SimpleSelector> selectors, List<Combinator> relationships)
CompoundSelector.java: public Match createMatch() {
CssError.java:public class CssError {
CssError.java: public static void setCurrentScene(Scene scene) {
CssError.java: public final String getMessage() {
CssError.java: public CssError(String message) {
CssError.java: public final static class PropertySetError extends CssError {
CssError.java: public PropertySetError(CssMetaData styleableProperty,
Declaration.java:final public class Declaration {
Declaration.java: public ParsedValue getParsedValue() {
Declaration.java: public String getProperty() {
Declaration.java: public Rule getRule() {
Rule.java:final public class Rule {
Rule.java: public final ObservableList<Declaration> getDeclarations() {
Rule.java: public final ObservableList<Selector> getSelectors() {
Rule.java: public Stylesheet getStylesheet() {
Rule.java: public StyleOrigin getOrigin() {
Selector.java:abstract public class Selector {
Selector.java: public Rule getRule() {
Selector.java: public void setOrdinal(int ordinal) {
Selector.java: public int getOrdinal() {
Selector.java: public abstract Match createMatch();
Selector.java: public abstract boolean applies(Styleable styleable);
Selector.java: public abstract boolean applies(Styleable styleable, Set<PseudoClass>[] triggerStates, int bit);
Selector.java: public abstract boolean stateMatches(Styleable styleable, Set<PseudoClass> state);
Selector.java: public static Selector createSelector(final String cssSelector) {
Selector.java: protected void writeBinary(DataOutputStream os, StringStore stringStore)
SimpleSelector.java:final public class SimpleSelector extends Selector {
SimpleSelector.java: public String getName() {
SimpleSelector.java: public List<String> getStyleClasses() {
SimpleSelector.java: public Set<StyleClass> getStyleClassSet() {
SimpleSelector.java: public String getId() {
SimpleSelector.java: public NodeOrientation getNodeOrientation() {
Size.java:final public class Size {
Size.java: public Size(double value, SizeUnits units) {
Size.java: public double getValue() {
Size.java: public SizeUnits getUnits() {
Size.java: public boolean isAbsolute() {
Size.java: public double pixels(double multiplier, Font font) {
Size.java: public double pixels(Font font) {
Size.java: public double pixels() {
Style.java:final public class Style {
Style.java: public Selector getSelector() {
Style.java: public Declaration getDeclaration() {
Style.java: public Style(Selector selector, Declaration declaration) {
Stylesheet.java:public class Stylesheet {
Stylesheet.java: public String getUrl() {
Stylesheet.java: public StyleOrigin getOrigin() {
Stylesheet.java: public void setOrigin(StyleOrigin origin) {
Stylesheet.java: public List<Rule> getRules() {
Stylesheet.java: public List<FontFace> getFontFaces() {
Stylesheet.java: public static Stylesheet loadBinary(URL url) throws IOException {
Stylesheet.java: public static void convertToBinary(File source, File destination) throws IOException {
CssParser.java:final public class CssParser {
CssParser.java: public CssParser() {
CssParser.java: public Stylesheet parse(final String stylesheetText) {
CssParser.java: public Stylesheet parse(final URL url) throws IOException {
CssParser.java: public Stylesheet parseInlineStyle(final Styleable node) {
CssParser.java: public ParsedValueImpl parseExpr(String property, String expr) {
CssParser.java: public static ObservableList<CssError> errorsProperty() {
Аннотация
Конечный результат этих двух проектов:
-
новый пакет
javafx.scene.control.skinдля скинов элементов управления UI, проверенных, задокументированных и протестированных; -
перенос, проверка, документирование и тестирование необходимых классов, связанных с CSS.
Тестирование
Тестирование будет ограничено дополнительными модульными тестами, не предъявляющими особых требований к платформе или оборудованию.
Риски и допущения
Основной риск состоит в том, что объём работы превысит ожидаемый. Было проведено некоторое исследование, чтобы лучше понять требования, но нельзя отрицать, что создание хороших API потребует значительных затрат времени.