SimpleFlatMapper icon indicating copy to clipboard operation
SimpleFlatMapper copied to clipboard

Converting "Y"/"N" to boolean values

Open Yuri-Harel opened this issue 6 years ago • 8 comments

Hey,

I use SFM in conjunction with JOOQ, and for whatever reason, boolean values are stored as a single character, either as "Y" or "N". I have tried to implement a converter this way :

public class StringToBoolConverterFactoryProducer extends AbstractConverterFactoryProducer {

  @Override
  public void produce(Consumer<? super ConverterFactory<?, ?>> consumer) {
    constantConverter(consumer, CharSequence.class, Boolean.class, new StringBoolConverter());
  }

  private class StringBoolConverter implements Converter<CharSequence, Boolean> {

    @Override
    public Boolean convert(CharSequence in) {

      if (in == null) {
        return false;
      }
      String inString = in.toString();
      return "Y".equalsIgnoreCase(inString) || Boolean.valueOf(inString);
    }
  }
}

As well as a reference to it in : org.simpleflatmapper.converter.ConverterFactoryProducer.

The converter is picked on, but it isn't being called. I have a similar issue with a converter I have tried to write that performs trim on every string, the converter being from CharSequence to String. I have also tried String to String.

Do you know what I am missing ? I'm assuming my converters are losing in priority or something similar.

Yuri-Harel avatar Jun 02 '19 11:06 Yuri-Harel

Yea the converter is not automatically picked on the best way is to provide getter for that field, I’ll had a sample for that later.

arnaudroger avatar Jun 02 '19 12:06 arnaudroger

I saw that works, but I need a converter on every String and Boolean field, that is manually defnining hundreds of properties, is there no other way ?

Yuri-Harel avatar Jun 02 '19 12:06 Yuri-Harel

Yes not really able to give you an example just at the minute, there is some new code in the last few commits that aims at making it easier jdbcgetterfactory... with a test as an example if you want to have a look

arnaudroger avatar Jun 02 '19 12:06 arnaudroger

I made it work with the JdbcGetterFactoryProperty, but I have stumbled on a limitation.

As far as I understand, we map ResultSet to type P, but there can only be one such mapping, no matter what the type P is, however I need several such mappings.

Because I want to map both all strings, and all booleans, the source of both is ResultSet, but the output is different. The only way to tell which converter to use, is by the type on the target. If the target has a property of type boolean, then use the StringToBolean converter, otherwise the StringToTrimmedString converter.

I will keep looking into this.

Yuri-Harel avatar Jun 02 '19 14:06 Yuri-Harel

Well, I ended with this for now :

public class JdbcGetterFactoryProperty {

  public static <T> GetterFactoryProperty complexConverter() {
    GetterFactory<ResultSet, JdbcColumnKey> setterFactory = new GetterFactory<>() {

      @Override
      public Getter<ResultSet, ? extends Object> newGetter(Type target, JdbcColumnKey key, Object... properties) {

        final int i = key.getIndex();

        if (target.equals(boolean.class)) {
          return new ResultSetGetterAdapter<Boolean>(SFMConverters::ynConverter, i);
        }

        if (target.equals(String.class)) {
          return new ResultSetGetterAdapter<String>(SFMConverters::stringTrimmer, i);
        }

        return null;
      }
    };
    return new GetterFactoryProperty(setterFactory);
  }
  public interface ResultSetGetter<T> {
    T get(ResultSet ps, int i) throws SQLException;
  }

  private static class ResultSetGetterAdapter<T> implements Getter<ResultSet, T> {
    private final ResultSetGetter<T> getter;
    private final int index;

    public ResultSetGetterAdapter(ResultSetGetter<T> getter, int index) {
      this.getter = getter;
      this.index = index;
    }

    @Override
    public T get(ResultSet target) throws Exception {
      return getter.get(target, index);
    }
  }
}

Yuri-Harel avatar Jun 02 '19 15:06 Yuri-Harel

yes that would be the idea, for now, will try to make it better. and your example will help. this kind of customisation is right now a bit laborious and not well documented .... it was raised a few weeks ago considering enums. my goal for the next release is to make that easier, that will be via helper method and dsl.

arnaudroger avatar Jun 02 '19 20:06 arnaudroger

following up on that was it mapping from a jooq record? what is the type of the Field in jooq? what's the type in the db? what db is it ?

arnaudroger avatar Jun 18 '19 20:06 arnaudroger

I was mapping from a ResultSet, because the query was a join of multiple tables, so no record existed, but I use JOOQ to generate the query. The field type in the result set in both cases was String. The DB is IBM Db2 for i.

Yuri-Harel avatar Jun 24 '19 09:06 Yuri-Harel