class AbstractLabelTooltipItem implements PropertyEditor.Item {
    
    protected static final UnaryOperator<Node> NO_DECORATOR = n -> n;
    
    private final String label;
    private final String tooltip;
    private final Map<ObservableValue<Object>, ChangeListener<Object>> listeners;
    private final UnaryOperator<Node> editorDecorator;
    
    /**
     * Creates an instance of this class. This constructor lets the caller 
     * supply a decorator that will be applied to the created editor.
     * 
     * @param label           the description label text
     * @param tooltip         the tooltip text
     * @param editorDecorator the editor decorator
     */
    protected AbstractLabelTooltipItem(String label, String tooltip, UnaryOperator<Node> editorDecorator){
        requireNonNull(label,           "A label must be assigned.");
        requireNonNull(tooltip,         "A tooltip must be assigned");
        requireNonNull(editorDecorator, "An editor decorator must be assigned");
        
        this.label           = label;
        this.tooltip         = tooltip;
        this.editorDecorator = editorDecorator;
        
        this.listeners = new HashMap<>();
    }
    
    @Override
    public Node createLabel() {
        final Label l = new Label(label);
        l.setTooltip( new Tooltip(tooltip) );
        return l;
    }

    @Override
    public final Node createEditor() {
        final Node editor = createUndecoratedEditor();
        return editorDecorator.apply(editor);
    }
    
    @Override
    public final void onRemove(){
        listeners.forEach(ObservableValue::removeListener);
    }
    
    /**
     * Creates an editor without applying any decorators. This is called 
     * internally by the base class to produce a decorated editor.
     * 
     * @return  the created editor
     */
    protected abstract Node createUndecoratedEditor();
    
    /**
     * Attaches a ChangeListener to the ObservableValue, and also stores their relationship.
     * <p>
     * Knowledge of their relationship is used when this PropertyEditor.Item is
     * removed from the PropertySheet, to detach the listeners again. This will avoid
     * memory leaks, as listeners otherwise prevent the observable from being garbage 
     * collected.
     * 
     * @param <T>  type of the ObservableValue and the ChangeListener
     * @param observable  the ObservableValue
     * @param listener    the ChangeListener 
     */
    protected final <T> void attachListener(ObservableValue<T> observable, ChangeListener<T> listener) {<FILL_FUNCTION_BODY>}
}

        @SuppressWarnings("unchecked")
        final ObservableValue<Object> key = (ObservableValue<Object>) observable;
        
        @SuppressWarnings("unchecked")
        final ChangeListener<Object> value = (ChangeListener<Object>) listener;
        
        listeners.put(key, value);
        observable.addListener(listener);
    
<no_super_class>