class PropertyUtils {

  public static <T, U> void bindBidirectionalWithConverter(
      Property<T> sourceProperty,
      Property<U> bindingTarget,
      Function<? super T, ? extends U> t2uConverter,
      Function<? super U, ? extends T> u2tConverter) {
    U targetValue = bindingTarget.getValue();
    sourceProperty.setValue(targetValue == null ? null : u2tConverter.apply(targetValue));
    sourceProperty.addListener((__, old, newValue) -> {
      U newMappedValue = newValue == null ? null : t2uConverter.apply(newValue);
      if (EqualityUtils.isDifferent(bindingTarget.getValue(), newMappedValue)) {
        bindingTarget.setValue(newMappedValue);
      }
    });
    bindingTarget.addListener((__, old, newValue) -> {
      T newMappedValue = newValue == null ? null : u2tConverter.apply(newValue);
      if (EqualityUtils.isDifferent(sourceProperty.getValue(), newMappedValue)) {
        sourceProperty.setValue(newMappedValue);
      }
    });
  }

  private  PropertyUtils();

}