On Fri, 12 Dec 2025 23:38:49 GMT, Andy Goryachev <[email protected]> wrote:
> ### Summary
>
> This PR makes the `DataFormat` constructor private:
>
> private DataFormat(@NamedArg("ids") String... ids)
>
>
> and replaces it with
>
> public static DataFormat of(String ... ids)
>
>
> ### Problem
>
> There seems to be several issues with DataFormat API and implementation
> discovered during a Clipboard-related code review:
>
> 1. `static DataFormat::lookupMimeType(String)` is not thread safe: while
> iterating over previously registered entries in the `DATA_FORMAT_LIST`
> another thread might create a new instance (DataFormat L227)
>
> 2. `public DataFormat(String...)` constructor might throw an
> `IllegalArgumentException` if one of the given mime types is already assigned
> to another `DataFormat`. The origin of this requirement is unclear, but one
> possible issue I can see is if the application has two libraries that both
> attempt to create a `DataFormat` for let's say `"text/css"`. Then, depending
> on the timing or the exact code path, an exception will be thrown for which
> the library(-ies) might not be prepared. The constructor is also not thread
> safe.
>
> 3. To avoid a situation mentioned in bullet 2, a developer would is typically
> call `lookupMimeType()` to obtain an already registered instance, followed by
> a constructor call if such an instance has not been found. An example of such
> code can be seen in webkit/UIClientImpl:299 - but even then, despite that
> two-step process being synchronized, the code might still fail if *some
> other* library or the application attempts to create a new instance of
> DataFormat, since the constructor itself is not synchronized.
>
> 4. `DataFormat(new String[] { null })` is allowed but makes no sense!
>
> Why do we need to have the registry of previously created instances? Unclear.
> My theory is that the DataFormat allows to have multiple mime-types (ids) -
> example being `DataFormat.FILES = new
> DataFormat("application/x-java-file-list", "java.file-list");` - and the
> registry was added to prevent creation of a `DataFormat` with just one id for
> some reason.
>
> What should be done?
> - find out why we need this registry in the first place i.e. what could
> happen if we have multiple DataFormat instances with overlapping ids.
> - if the registry is needed add a new factory method, something like
> `DataFormat::of(String ...)` which is properly synchronized. This method will
> be called by the constructor to retain the backward compatibility.
> - deprecate (possibly for removal) `DataFormat::lookupMimeType(String)`, or
> keep it but have it properly synchronized
>
> ### Da...
Removing the constructor is an incompatible change.
modules/javafx.graphics/src/main/java/javafx/scene/input/DataFormat.java line
133:
> 131: */
> 132: @Deprecated(since = "27")
> 133: private DataFormat(@NamedArg("ids") String... ids) {
This is an incompatible change. You will need to go through the usual process
for such changes where it is deprecated for removal in one release and removed
in a subsequent release.
-------------
PR Review: https://git.openjdk.org/jfx/pull/2006#pullrequestreview-3684486211
PR Review Comment: https://git.openjdk.org/jfx/pull/2006#discussion_r2710227940