Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8214699: Node.getPseudoClassStates must return the same instance on every call #253

wants to merge 2 commits into from
Changes from 1 commit
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.


Just for now

@@ -9367,12 +9367,13 @@ public final void pseudoClassStateChanged(PseudoClass pseudoClass, boolean activ

// package so that StyleHelper can get at it
final ObservableSet<PseudoClass> pseudoClassStates = new PseudoClassState();
final ObservableSet<PseudoClass> unmodifiablePseudoClassStates =
private final ObservableSet<PseudoClass> unmodifiablePseudoClassStates =
* @return The active pseudo-class states of this Node, wrapped in an unmodifiable ObservableSet
* @since JavaFX 8.0
public final ObservableSet<PseudoClass> getPseudoClassStates() {
return unmodifiablePseudoClassStates;
@@ -28,6 +28,8 @@
import com.sun.javafx.scene.DirtyBits;

import javafx.collections.ObservableSet;
import javafx.css.PseudoClass;
import javafx.scene.transform.Transform;

public class NodeShim {
@@ -75,4 +77,8 @@ public static void updateBounds(Node n) {
public static <P extends NGNode> P getPeer(Node n) {
return n.getPeer();

public static ObservableSet<PseudoClass> pseudoClassStates(Node n) {
return n.pseudoClassStates;
@@ -44,7 +44,10 @@
import com.sun.javafx.util.Utils;
import javafx.beans.InvalidationListener;
import javafx.collections.SetChangeListener;
import javafx.css.PseudoClass;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.geometry.NodeOrientation;
@@ -59,8 +62,11 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.Set;

import javafx.scene.Group;
import javafx.scene.GroupShim;
import javafx.scene.Node;
@@ -164,8 +170,53 @@
public void testGetPseudoClassStatesShouldReturnSameSet() {
Rectangle node = new Rectangle();
Set<PseudoClass> set1 = node.getPseudoClassStates();
Set<PseudoClass> set2 = node.getPseudoClassStates();
assertSame("getPseudoClassStates() should always return the same instance",
node.getPseudoClassStates(), node.getPseudoClassStates());
set1, set2);

public void testPseudoClassStatesIsUnmodifiable() {
Node node = new Rectangle();

public void testUnmodifiablePseudoClassStatesEqualsBackingStates() {
Rectangle node = new Rectangle();
PseudoClass pseudo = PseudoClass.getPseudoClass("Pseudo");
node.pseudoClassStateChanged(pseudo, true);
assertEquals(1, node.getPseudoClassStates().size());
assertEquals(NodeShim.pseudoClassStates(node).size(), node.getPseudoClassStates().size());

private boolean isInvalidationListenerInvoked;
private boolean isChangeListenerInvoked;
public void testPseudoClassStatesListenersAreInvoked() {
Rectangle node = new Rectangle();
node.getPseudoClassStates().addListener((InvalidationListener) inv -> {
isInvalidationListenerInvoked = true;
node.getPseudoClassStates().addListener((SetChangeListener<PseudoClass>) c -> {
isChangeListenerInvoked = true;

PseudoClass pseudo = PseudoClass.getPseudoClass("Pseudo");
node.pseudoClassStateChanged(pseudo, true);

public void testPseudoClassStatesNotGCed() {
Node node = new Rectangle();
WeakReference<Set<?>> weakRef = new WeakReference<>(node.getPseudoClassStates());
assertNotNull("pseudoClassStates must not be gc'ed", weakRef.get());

// TODO disable this because it depends on TestNode
@@ -30,6 +30,7 @@
import com.sun.prism.paint.Color;
import javafx.scene.Node;

import java.lang.ref.WeakReference;
import java.lang.reflect.Method;

import static org.junit.Assert.*;
@@ -126,4 +127,20 @@ public static Object getObjectValue(Node node, String pgPropertyName, boolean is
public static Object getObjectValue(Node node, String pgPropertyName) throws Exception {
return getObjectValue(node, pgPropertyName, false);

public static void attemptGC(WeakReference<?> weakRef) {
for (int i = 0; i < 10; i++) {

if (weakRef.get() == null) {
try {
} catch (InterruptedException e) {
fail("InterruptedException occurred during Thread.sleep()");
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.