JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
Owner | Jonathan Giles |
Type | Feature |
Scope | JDK |
Status | Closed / Delivered |
Release | 9 |
Component | javafx / controls |
Discussion | openjfx dash dev at openjdk dot java dot net |
Effort | L |
Duration | L |
Reviewed by | Anton Tarasov, Kevin Rushforth, Leif Samuelsson, Victor Dyakov |
Endorsed by | Kevin Rushforth |
Created | 2015/04/01 01:16 |
Updated | 2017/03/10 13:29 |
Issue | 8076423 |
Summary
Define public APIs for the JavaFX UI controls and CSS functionality that is presently only available via internal APIs and will hence become inaccessible due to modularization.
Goals
Many developers who use the UI controls and CSS functionality of JavaFX
have historically ignored the warnings to avoid the internal com.sun.*
APIs. In many cases, to achieve a desired result, developers have no
choice but to use these internal APIs. With the forthcoming release of
Java 9, and in particular with the introduction of strong boundaries
between modules in Project Jigsaw, developers will find that their
code will no longer compile or run since the com.sun.*
packages will no
longer be accessible. The goal of this JEP is to define public APIs for
the functionality presently offered by the internal APIs.
Non-Goals
Given the implications of modularization, that is, the forthcoming
inaccessibility of the com.sun.*
packages, there is no way to do this
in a manner that retains any degree of backward compatibility. It is,
therefore, not a goal of this JEP to retain backward compatibility. This
does not mean that we can break anything we like; our intention is to
only introduce new API (and evolve existing private API) that is directly
broken by the enforcement of module boundaries. All other existing APIs
that are not impacted by modularization will remain the same.
Success Metrics
Success can be measured in two ways:
-
Projects that depend on JavaFX internal APIs, in particular Scene Builder, ControlsFX, and JFXtras, continue to work after updating to the new API with no loss of functionality. These three projects are all open source, and they will provide an excellent test bed to ensure that all necessary APIs have been provided.
-
The result of discussions around new APIs, such as the input-map work required for control behaviors, results in improved functionality that developers have long requested. Ultimately, if all works to plan, third-party controls should be buildable without any dependency upon internal APIs.
Motivation
Without this work being done, many projects will need to significantly reduce the functionality that they offer, and for some projects this may prove fatal. For example, without access to the internal API that Scene Builder currently has, it may struggle to be viable---certainly its ability to offer functionality around CSS styling and manipulation of control properties will be severely undermined, and these are two of the core pieces of functionality of Scene Builder. The same argument holds for most other JavaFX-based projects with any degree of custom control or CSS implementation.
Description
This JEP is broken down into two semi-related subprojects, each of which is important in reaching the final goal. There is no particular order to which these projects must be undertaken.
Project One: Make UI control skins into public APIs
At present all skins are located in
com.sun.javafx.scene.control.skin
. This means that third parties who
have extended a skin (e.g., the TextFieldSkin
) to add additional
functionality, to override an existing method, or otherwise to modify the
visuals or behavior of the control skin, will be left without a
functioning application in JDK 9. Of course, this is the fault of users
who depended on non-public APIs, but we have long discussed making this
API public so as to better enable third party modification of UI
controls.
The intention is to move many JavaFX control skins into the appropriate
public package, most probably javafx.scene.control.skin
. There is no
intent to also move the related behavior classes.
The vast bulk of this work is to review each existing skin class, ensuring the following:
-
That there is API consistency between skins,
-
That high-quality Javadoc and unit tests exist, and
-
That the API in each class is kept to a minimum by changing public methods to private.
This research is already quite far progressed in a separate sandbox repo,
and whilst time-consuming, there are only a few classes of concern, such
as utility classes, duplicated classes, and truly implementation-only
classes, that need further analysis. On top of this, there is a handful
of classes that may qualify for being brought into the
javafx.scene.control
package or, at the least, will need further
consideration since they are not truly skins. These include FXVK
(the
virtual keyboard), ColorPalette
, CustomColorDialog
,
DatePickerContent
, and InputField
. Finally, there are a few classes
where, ideally, methods would be made private, except for the fact that
other, implementation-only classes rely on this API. Solutions will be
investigated for all of these issues, and no major concerns exist.
The intent of making the skins into public API in 9 is to ensure their continued availability. The API will be purposefully kept to the bare minimum and reduced as significantly as possible, with the intention to follow this up in subsequent releases with more useful APIs that developers request. As is well appreciated, APIs are (mostly) forever, so allowing for the public skin API to mature over a few update releases seems like the best course of action.
As of mid June, this project is at the point where almost all code is moved and cleaned up. The intention is to make this public in a JDK 9 build around mid-July to early August. The following is a list of all classes that have moved into javafx.scene.control.skin
as public API:
AccordionSkin
ButtonBarSkin
ButtonSkin
CellSkinBase
CheckBoxSkin
ChoiceBoxSkin
ColorPickerSkin
ComboBoxBaseSkin
ComboBoxListViewSkin
ComboBoxPopupControl
ContextMenuSkin
DateCellSkin
DatePickerSkin
HyperlinkSkin
LabelSkin
LabeledSkinBase
ListCellSkin
ListViewSkin
MenuBarSkin
MenuButtonSkin
MenuButtonSkinBase
NestedTableColumnHeader
PaginationSkin
ProgressBarSkin
ProgressIndicatorSkin
RadioButtonSkin
ScrollBarSkin
ScrollPaneSkin
SeparatorSkin
SliderSkin
SpinnerSkin
SplitMenuButtonSkin
SplitPaneSkin
TabPaneSkin
TableCellSkin
TableCellSkinBase
TableColumnHeader
TableHeaderRow
TableRowSkin
TableRowSkinBase
TableViewSkin
TableViewSkinBase
TextAreaSkin
TextFieldSkin
TextInputControlSkin
TitledPaneSkin
ToggleButtonSkin
ToolBarSkin
TooltipSkin
TreeCellSkin
TreeTableCellSkin
TreeTableRowSkin
TreeTableViewSkin
TreeViewSkin
VirtualContainerBase
VirtualFlow
These classes, as of mid-June, are stripped of almost any API that is not inherited from SkinBase. Moving forward, the intention is to add back useful API as feedback is received based on early access builds. Some classes, such as the text input controls and virtualised controls, have additional API already to support their functionality.
Project Two: Review and make public relevant CSS APIs
As with Project One, this project relates to bringing out into the public
APIs that currently reside in com.sun.*
packages. Again, this will
require code review to minimise the API, as well as additional unit tests
and vastly more documentation.
The driver for this work will be to continue to allow for Scene Builder to compile in JDK 9, with the appropriate modifications.
As of mid June, this project is at the point where almost all code is moved and cleaned up. The intention is to make this public in a JDK 9 build around mid-July to early August. The following is a list of all classes that have moved into javafx.css
as public 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() {
Summary
The end result of these two projects is the creation of:
-
A new package
javafx.scene.control.skin
for UI control skins, after being reviewed, documented, and tested; -
The moving and review, documentation, and testing of necessary CSS-related classes.
Testing
Testing will be limited to additional unit tests that have no special platform or hardware requirements.
Risks and Assumptions
The primary risk is that the scope of work exceeds what is anticipated. Some research has been done to better understand the requirements, but there is no denying that producing good APIs will require a decent investment of time.